Merge pull request #247 from PolyhedralDev/dev/functionalevents

Abstract event system with functional default implementation
This commit is contained in:
dfsek 2021-07-22 10:11:53 -07:00 committed by GitHub
commit 9359ba0c97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 517 additions and 465 deletions

View File

@ -25,8 +25,8 @@ import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon; import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author; import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version; import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.EventListener;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.injection.annotations.Inject; import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
@ -35,7 +35,7 @@ import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeSource;
@Addon("biome-provider-pipeline") @Addon("biome-provider-pipeline")
@Author("Terra") @Author("Terra")
@Version("1.0.0") @Version("1.0.0")
public class BiomePipelineAddon extends TerraAddon implements EventListener { public class BiomePipelineAddon extends TerraAddon {
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@ -44,11 +44,10 @@ public class BiomePipelineAddon extends TerraAddon implements EventListener {
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager().registerListener(this, this); main.getEventManager()
} .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
public void onPackLoad(ConfigPackPreLoadEvent event) { .then(event -> event.getPack().applyLoader(BIOME_SOURCE_BUILDER_TOKEN.getType(), new SourceLoader())
event.getPack().applyLoader(BIOME_SOURCE_BUILDER_TOKEN.getType(), new SourceLoader())
.applyLoader(Stage.class, new StageLoader()) .applyLoader(Stage.class, new StageLoader())
.applyLoader(ExpanderStage.Type.class, (c, o, l) -> ExpanderStage.Type.valueOf((String) o)) .applyLoader(ExpanderStage.Type.class, (c, o, l) -> ExpanderStage.Type.valueOf((String) o))
.applyLoader(MutatorStage.Type.class, (c, o, l) -> MutatorStage.Type.valueOf((String) o)) .applyLoader(MutatorStage.Type.class, (c, o, l) -> MutatorStage.Type.valueOf((String) o))
@ -60,6 +59,7 @@ public class BiomePipelineAddon extends TerraAddon implements EventListener {
.applyLoader(SmoothMutator.class, SmoothMutatorTemplate::new) .applyLoader(SmoothMutator.class, SmoothMutatorTemplate::new)
.applyLoader(ExpanderStage.class, ExpanderStageTemplate::new) .applyLoader(ExpanderStage.class, ExpanderStageTemplate::new)
.applyLoader(BiomePipelineProvider.class, () -> new BiomePipelineTemplate(main)) .applyLoader(BiomePipelineProvider.class, () -> new BiomePipelineTemplate(main))
.applyLoader(BIOME_PROVIDER_BUILDER_TOKEN.getType(), new BiomeProviderLoader()); .applyLoader(BIOME_PROVIDER_BUILDER_TOKEN.getType(), new BiomeProviderLoader()))
.failThrough();
} }
} }

View File

@ -10,35 +10,41 @@ import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon; import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author; import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version; import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.EventListener;
import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent; import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.injection.annotations.Inject; import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.registry.exception.DuplicateEntryException;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.generator.ChunkGeneratorProvider; import com.dfsek.terra.api.world.generator.ChunkGeneratorProvider;
@Addon("chunk-generator-noise-3d") @Addon("chunk-generator-noise-3d")
@Author("Terra") @Author("Terra")
@Version("1.0.0") @Version("1.0.0")
public class NoiseChunkGenerator3DAddon extends TerraAddon implements EventListener { public class NoiseChunkGenerator3DAddon extends TerraAddon {
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager().registerListener(this, this); main.getEventManager()
} .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
public void onPackLoad(ConfigPackPreLoadEvent event) throws DuplicateEntryException { .then(event -> {
event.getPack().getOrCreateRegistry(ChunkGeneratorProvider.class).register("NOISE_3D", pack -> new NoiseChunkGenerator3D(pack, main)); event.getPack().getOrCreateRegistry(ChunkGeneratorProvider.class).register("NOISE_3D", pack -> new NoiseChunkGenerator3D(pack, main));
event.getPack().applyLoader(SlantHolder.class, new SlantHolderLoader()) event.getPack()
.applyLoader(SlantHolder.class, new SlantHolderLoader())
.applyLoader(PaletteHolder.class, new PaletteHolderLoader()); .applyLoader(PaletteHolder.class, new PaletteHolderLoader());
} })
.failThrough();
public void onBiomeLoad(ConfigurationLoadEvent event) { main.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(this, ConfigurationLoadEvent.class)
.then(event -> {
if(event.is(TerraBiome.class)) { if(event.is(TerraBiome.class)) {
event.getLoadedObject(TerraBiome.class).getContext().put(event.load(new BiomePaletteTemplate()).get()); event.getLoadedObject(TerraBiome.class).getContext().put(event.load(new BiomePaletteTemplate()).get());
} }
})
.failThrough();
} }
} }

View File

@ -7,24 +7,26 @@ import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon; import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author; import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version; import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.EventListener;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.injection.annotations.Inject; import com.dfsek.terra.api.injection.annotations.Inject;
@Addon("config-biome") @Addon("config-biome")
@Author("Terra") @Author("Terra")
@Version("1.0.0") @Version("1.0.0")
public class BiomeAddon extends TerraAddon implements EventListener { public class BiomeAddon extends TerraAddon {
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager().registerListener(this, this); main.getEventManager()
} .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
public void onPackLoad(ConfigPackPreLoadEvent event) { .then(event -> {
event.getPack().registerConfigType(new BiomeConfigType(event.getPack()), "BIOME", 5); event.getPack().registerConfigType(new BiomeConfigType(event.getPack()), "BIOME", 5);
event.getPack().applyLoader(PaletteHolder.class, new PaletteHolderLoader()); event.getPack().applyLoader(PaletteHolder.class, new PaletteHolderLoader());
})
.failThrough();
} }
} }

View File

@ -10,8 +10,8 @@ import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon; import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author; import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version; import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.EventListener;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.injection.annotations.Inject; import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.structure.feature.Distributor; import com.dfsek.terra.api.structure.feature.Distributor;
@ -22,23 +22,24 @@ import java.util.function.Supplier;
@Addon("config-distributors") @Addon("config-distributors")
@Version("1.0.0") @Version("1.0.0")
@Author("Terra") @Author("Terra")
public class DistributorAddon extends TerraAddon implements EventListener { public class DistributorAddon extends TerraAddon {
public static final TypeKey<Supplier<ObjectTemplate<Distributor>>> DISTRIBUTOR_TOKEN = new TypeKey<>() {}; public static final TypeKey<Supplier<ObjectTemplate<Distributor>>> DISTRIBUTOR_TOKEN = new TypeKey<>() {};
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager().registerListener(this, this); main.getEventManager()
} .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
.then(event -> {
public void packPreLoad(ConfigPackPreLoadEvent event) {
CheckedRegistry<Supplier<ObjectTemplate<Distributor>>> distributorRegistry = event.getPack().getOrCreateRegistry(DISTRIBUTOR_TOKEN); CheckedRegistry<Supplier<ObjectTemplate<Distributor>>> distributorRegistry = event.getPack().getOrCreateRegistry(DISTRIBUTOR_TOKEN);
distributorRegistry.register("NOISE", NoiseDistributorTemplate::new); distributorRegistry.register("NOISE", NoiseDistributorTemplate::new);
distributorRegistry.register("POINTS", PointSetDistributorTemplate::new); distributorRegistry.register("POINTS", PointSetDistributorTemplate::new);
event.getPack() event.getPack()
.applyLoader(Point.class, PointTemplate::new); .applyLoader(Point.class, PointTemplate::new);
})
.failThrough();
} }
} }

View File

@ -5,23 +5,23 @@ import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon; import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author; import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version; import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.EventListener;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.injection.annotations.Inject; import com.dfsek.terra.api.injection.annotations.Inject;
@Addon("config-feature") @Addon("config-feature")
@Version("1.0.0") @Version("1.0.0")
@Author("Terra") @Author("Terra")
public class FeatureAddon extends TerraAddon implements EventListener { public class FeatureAddon extends TerraAddon {
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager().registerListener(this, this); main.getEventManager()
} .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
public void onPackLoad(ConfigPackPreLoadEvent event) { .then(event -> event.getPack().registerConfigType(new FeatureConfigType(), "FEATURE", 2))
event.getPack().registerConfigType(new FeatureConfigType(), "FEATURE", 2); .failThrough();
} }
} }

View File

@ -7,25 +7,26 @@ import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon; import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author; import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version; import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.EventListener;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.injection.annotations.Inject; import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.registry.exception.DuplicateEntryException;
@Addon("config-flora") @Addon("config-flora")
@Author("Terra") @Author("Terra")
@Version("0.1.0") @Version("0.1.0")
public class FloraAddon extends TerraAddon implements EventListener { public class FloraAddon extends TerraAddon {
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager().registerListener(this, this); main.getEventManager()
} .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
public void onPackLoad(ConfigPackPreLoadEvent event) throws DuplicateEntryException { .then(event -> {
event.getPack().registerConfigType(new FloraConfigType(), "FLORA", 2); event.getPack().registerConfigType(new FloraConfigType(), "FLORA", 2);
event.getPack().applyLoader(BlockLayer.class, BlockLayerTemplate::new); event.getPack().applyLoader(BlockLayer.class, BlockLayerTemplate::new);
})
.failThrough();
} }
} }

View File

@ -8,8 +8,8 @@ import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon; import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author; import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version; import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.EventListener;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.injection.annotations.Inject; import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.structure.feature.Locator; import com.dfsek.terra.api.structure.feature.Locator;
@ -20,7 +20,7 @@ import java.util.function.Supplier;
@Addon("config-locators") @Addon("config-locators")
@Version("1.0.0") @Version("1.0.0")
@Author("Terra") @Author("Terra")
public class LocatorAddon extends TerraAddon implements EventListener { public class LocatorAddon extends TerraAddon {
public static final TypeKey<Supplier<ObjectTemplate<Locator>>> LOCATOR_TOKEN = new TypeKey<>() {}; public static final TypeKey<Supplier<ObjectTemplate<Locator>>> LOCATOR_TOKEN = new TypeKey<>() {};
@Inject @Inject
@ -28,12 +28,14 @@ public class LocatorAddon extends TerraAddon implements EventListener {
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager().registerListener(this, this); main.getEventManager()
} .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
public void onPackLoad(ConfigPackPreLoadEvent event) { .then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<Locator>>> locatorRegistry = event.getPack().getOrCreateRegistry(LOCATOR_TOKEN); CheckedRegistry<Supplier<ObjectTemplate<Locator>>> locatorRegistry = event.getPack().getOrCreateRegistry(LOCATOR_TOKEN);
locatorRegistry.register("SURFACE", () -> new SurfaceLocatorTemplate(main)); locatorRegistry.register("SURFACE", () -> new SurfaceLocatorTemplate(main));
locatorRegistry.register("RANDOM", RandomLocatorTemplate::new); locatorRegistry.register("RANDOM", RandomLocatorTemplate::new);
})
.failThrough();
} }
} }

View File

@ -30,8 +30,8 @@ import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon; import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author; import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version; import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.EventListener;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.injection.annotations.Inject; import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.api.registry.CheckedRegistry;
@ -44,7 +44,7 @@ import java.util.function.Supplier;
@Addon("config-noise-function") @Addon("config-noise-function")
@Author("Terra") @Author("Terra")
@Version("1.0.0") @Version("1.0.0")
public class NoiseAddon extends TerraAddon implements EventListener { public class NoiseAddon extends TerraAddon {
@Inject @Inject
private TerraPlugin plugin; private TerraPlugin plugin;
@ -52,10 +52,10 @@ public class NoiseAddon extends TerraAddon implements EventListener {
@Override @Override
public void initialize() { public void initialize() {
plugin.getEventManager().registerListener(this, this); plugin.getEventManager()
} .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
public void packPreLoad(ConfigPackPreLoadEvent event) { .then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<NoiseSampler>>> noiseRegistry = event.getPack().getOrCreateRegistry(NOISE_SAMPLER_TOKEN); CheckedRegistry<Supplier<ObjectTemplate<NoiseSampler>>> noiseRegistry = event.getPack().getOrCreateRegistry(NOISE_SAMPLER_TOKEN);
event.getPack() event.getPack()
.applyLoader(CellularSampler.DistanceFunction.class, (t, o, l) -> CellularSampler.DistanceFunction.valueOf((String) o)) .applyLoader(CellularSampler.DistanceFunction.class, (t, o, l) -> CellularSampler.DistanceFunction.valueOf((String) o))
@ -100,5 +100,7 @@ public class NoiseAddon extends TerraAddon implements EventListener {
NoiseConfigPackTemplate template = new NoiseConfigPackTemplate(); NoiseConfigPackTemplate template = new NoiseConfigPackTemplate();
event.loadTemplate(template); event.loadTemplate(template);
packFunctions.putAll(template.getNoiseBuilderMap()); packFunctions.putAll(template.getNoiseBuilderMap());
})
.failThrough();
} }
} }

View File

@ -5,27 +5,28 @@ import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon; import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author; import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version; import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.EventListener;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.injection.annotations.Inject; import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.registry.exception.DuplicateEntryException;
import com.dfsek.terra.api.world.generator.GenerationStageProvider; import com.dfsek.terra.api.world.generator.GenerationStageProvider;
@Addon("config-ore") @Addon("config-ore")
@Author("Terra") @Author("Terra")
@Version("1.0.0") @Version("1.0.0")
public class OreAddon extends TerraAddon implements EventListener { public class OreAddon extends TerraAddon {
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager().registerListener(this, this); main.getEventManager()
} .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
public void onPackLoad(ConfigPackPreLoadEvent event) throws DuplicateEntryException { .then(event -> {
event.getPack().registerConfigType(new OreConfigType(), "ORE", 1); event.getPack().registerConfigType(new OreConfigType(), "ORE", 1);
event.getPack().getOrCreateRegistry(GenerationStageProvider.class).register("ORE", pack -> new OrePopulator(main)); event.getPack().getOrCreateRegistry(GenerationStageProvider.class).register("ORE", pack -> new OrePopulator(main));
})
.failThrough();
} }
} }

View File

@ -7,24 +7,26 @@ import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon; import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author; import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version; import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.EventListener;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.injection.annotations.Inject; import com.dfsek.terra.api.injection.annotations.Inject;
@Addon("config-palette") @Addon("config-palette")
@Author("Terra") @Author("Terra")
@Version("1.0.0") @Version("1.0.0")
public class PaletteAddon extends TerraAddon implements EventListener { public class PaletteAddon extends TerraAddon {
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager().registerListener(this, this); main.getEventManager()
} .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
public void onPackLoad(ConfigPackPreLoadEvent event) { .then(event -> {
event.getPack().registerConfigType(new PaletteConfigType(main), "PALETTE", 2); event.getPack().registerConfigType(new PaletteConfigType(main), "PALETTE", 2);
event.getPack().applyLoader(PaletteLayerHolder.class, new PaletteLayerLoader()); event.getPack().applyLoader(PaletteLayerHolder.class, new PaletteLayerLoader());
})
.failThrough();
} }
} }

View File

@ -5,24 +5,24 @@ import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon; import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author; import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version; import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.EventListener;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.injection.annotations.Inject; import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.structure.configured.ConfiguredStructure; import com.dfsek.terra.api.structure.configured.ConfiguredStructure;
@Addon("config-structure") @Addon("config-structure")
@Version("1.0.0") @Version("1.0.0")
@Author("Terra") @Author("Terra")
public class StructureAddon extends TerraAddon implements EventListener { public class StructureAddon extends TerraAddon {
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager().registerListener(this, this); main.getEventManager()
} .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
public void onConfigLoad(ConfigPackPreLoadEvent event) { .then(event -> event.getPack().applyLoader(ConfiguredStructure.class, (t, o, l) -> null))
event.getPack().applyLoader(ConfiguredStructure.class, (t, o, l) -> null); .failThrough();
} }
} }

View File

@ -6,9 +6,9 @@ import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon; import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author; import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version; import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.EventListener;
import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent; import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.injection.annotations.Inject; import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.generator.GenerationStageProvider; import com.dfsek.terra.api.world.generator.GenerationStageProvider;
@ -16,22 +16,26 @@ import com.dfsek.terra.api.world.generator.GenerationStageProvider;
@Addon("generation-stage-feature") @Addon("generation-stage-feature")
@Version("1.0.0") @Version("1.0.0")
@Author("Terra") @Author("Terra")
public class FeatureGenerationAddon extends TerraAddon implements EventListener { public class FeatureGenerationAddon extends TerraAddon {
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager().registerListener(this, this); main.getEventManager()
} .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
.then(event -> event.getPack().getOrCreateRegistry(GenerationStageProvider.class).register("FEATURE", pack -> new FeatureGenerationStage(main)))
.failThrough();
public void onPackLoad(ConfigPackPreLoadEvent event) { main.getEventManager()
event.getPack().getOrCreateRegistry(GenerationStageProvider.class).register("FEATURE", pack -> new FeatureGenerationStage(main)); .getHandler(FunctionalEventHandler.class)
} .register(this, ConfigurationLoadEvent.class)
.then(event -> {
public void onBiomeLoad(ConfigurationLoadEvent event) {
if(event.is(TerraBiome.class)) { if(event.is(TerraBiome.class)) {
event.getLoadedObject(TerraBiome.class).getContext().put(event.load(new BiomeFeaturesTemplate()).get()); event.getLoadedObject(TerraBiome.class).getContext().put(event.load(new BiomeFeaturesTemplate()).get());
} }
})
.failThrough();
} }
} }

View File

@ -5,9 +5,9 @@ import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon; import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author; import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version; import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.EventListener;
import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent; import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.injection.annotations.Inject; import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.generator.GenerationStageProvider; import com.dfsek.terra.api.world.generator.GenerationStageProvider;
@ -15,24 +15,30 @@ import com.dfsek.terra.api.world.generator.GenerationStageProvider;
@Addon("generation-stage-flora") @Addon("generation-stage-flora")
@Version("1.0.0") @Version("1.0.0")
@Author("Terra") @Author("Terra")
public class FloraGenerationAddon extends TerraAddon implements EventListener { public class FloraGenerationAddon extends TerraAddon {
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager().registerListener(this, this); main.getEventManager()
} .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
public void onPackLoad(ConfigPackPreLoadEvent event) { .then(event -> {
event.getPack().applyLoader(FloraLayer.class, FloraLayerLoader::new); event.getPack().applyLoader(FloraLayer.class, FloraLayerLoader::new);
event.getPack().getOrCreateRegistry(GenerationStageProvider.class).register("FLORA", pack -> new FloraGenerationStage(main)); event.getPack().getOrCreateRegistry(GenerationStageProvider.class).register("FLORA", pack -> new FloraGenerationStage(main));
} })
.failThrough();
public void onBiomeLoad(ConfigurationLoadEvent event) { main.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(this, ConfigurationLoadEvent.class)
.then(event -> {
if(event.is(TerraBiome.class)) { if(event.is(TerraBiome.class)) {
event.getLoadedObject(TerraBiome.class).getContext().put(event.load(new BiomeFloraTemplate()).get()); event.getLoadedObject(TerraBiome.class).getContext().put(event.load(new BiomeFloraTemplate()).get());
} }
})
.failThrough();
} }
} }

View File

@ -6,26 +6,26 @@ import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon; import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author; import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version; import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.EventListener;
import com.dfsek.terra.api.event.events.config.ConfigurationDiscoveryEvent; import com.dfsek.terra.api.event.events.config.ConfigurationDiscoveryEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.injection.annotations.Inject; import com.dfsek.terra.api.injection.annotations.Inject;
@Addon("language-yaml") @Addon("language-yaml")
@Version("1.0.0") @Version("1.0.0")
@Author("Terra") @Author("Terra")
public class YamlAddon extends TerraAddon implements EventListener { public class YamlAddon extends TerraAddon {
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager().registerListener(this, this); main.getEventManager()
} .getHandler(FunctionalEventHandler.class)
.register(this, ConfigurationDiscoveryEvent.class)
public void loadYamlConfigs(ConfigurationDiscoveryEvent event) { .then(event -> event.getLoader().open("", ".yml").thenEntries(entries -> entries.forEach(entry -> {
event.getLoader().open("", ".yml").thenEntries(entries -> entries.forEach(entry -> {
main.getDebugLogger().info("Discovered config " + entry.getKey()); main.getDebugLogger().info("Discovered config " + entry.getKey());
event.register(entry.getKey(), new YamlConfiguration(entry.getValue(), entry.getKey())); event.register(entry.getKey(), new YamlConfiguration(entry.getValue(), entry.getKey()));
})); })))
.failThrough();
} }
} }

View File

@ -1,6 +1,5 @@
package com.dfsek.terra.addons.terrascript; package com.dfsek.terra.addons.terrascript;
import com.dfsek.tectonic.exception.ConfigException;
import com.dfsek.tectonic.exception.LoadException; import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException; import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException;
import com.dfsek.terra.addons.terrascript.script.StructureScript; import com.dfsek.terra.addons.terrascript.script.StructureScript;
@ -9,11 +8,10 @@ import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon; import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author; import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version; import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.EventListener;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.injection.annotations.Inject; import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.exception.DuplicateEntryException;
import com.dfsek.terra.api.structure.LootTable; import com.dfsek.terra.api.structure.LootTable;
import com.dfsek.terra.api.structure.Structure; import com.dfsek.terra.api.structure.Structure;
@ -23,31 +21,29 @@ import java.util.Map;
@Addon("structure-terrascript-loader") @Addon("structure-terrascript-loader")
@Author("Terra") @Author("Terra")
@Version("1.0.0") @Version("1.0.0")
public class TerraScriptAddon extends TerraAddon implements EventListener { public class TerraScriptAddon extends TerraAddon {
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager().registerListener(this, this); main.getEventManager()
} .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
public void onPackLoad(ConfigPackPreLoadEvent event) throws ConfigException { .then(event -> {
CheckedRegistry<Structure> structureRegistry = event.getPack().getOrCreateRegistry(Structure.class); CheckedRegistry<Structure> structureRegistry = event.getPack().getOrCreateRegistry(Structure.class);
CheckedRegistry<LootTable> lootRegistry = event.getPack().getOrCreateRegistry(LootTable.class); CheckedRegistry<LootTable> lootRegistry = event.getPack().getOrCreateRegistry(LootTable.class);
event.getPack().getLoader().open("", ".tesf").thenEntries(entries -> { event.getPack().getLoader().open("", ".tesf").thenEntries(entries -> {
for(Map.Entry<String, InputStream> entry : entries) { for(Map.Entry<String, InputStream> entry : entries) {
try { try {
StructureScript structureScript = new StructureScript(entry.getValue(), main, structureRegistry, lootRegistry, event.getPack().getRegistryFactory().create()); StructureScript structureScript = new StructureScript(entry.getValue(), main, structureRegistry, lootRegistry, event.getPack().getRegistryFactory().create());
try {
structureRegistry.register(structureScript.getId(), structureScript); structureRegistry.register(structureScript.getId(), structureScript);
} catch(DuplicateEntryException e) {
throw new LoadException("Duplicate structure: ", e);
}
} catch(ParseException e) { } catch(ParseException e) {
throw new LoadException("Failed to load script: ", e); throw new LoadException("Failed to load script: ", e);
} }
} }
}).close(); }).close();
})
.failThrough();
} }
} }

View File

@ -0,0 +1,7 @@
package com.dfsek.terra.api.event;
import com.dfsek.terra.api.event.events.Event;
public interface EventHandler {
void handle(Event event);
}

View File

@ -1,12 +0,0 @@
package com.dfsek.terra.api.event;
import com.dfsek.terra.api.event.events.Event;
/**
* Marker interface for a class that contains event listener methods.
*
* @see Event
* @see EventManager
*/
public interface EventListener {
}

View File

@ -1,7 +1,8 @@
package com.dfsek.terra.api.event; package com.dfsek.terra.api.event;
import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.event.events.Event; import com.dfsek.terra.api.event.events.Event;
import com.dfsek.terra.api.event.functional.EventContext;
import com.dfsek.terra.api.util.reflection.TypeKey;
/** /**
* Manages event registration and triggering. * Manages event registration and triggering.
@ -11,15 +12,10 @@ public interface EventManager {
* Call an event, and return the execution status. * Call an event, and return the execution status.
* *
* @param event Event to pass to all registered EventListeners. * @param event Event to pass to all registered EventListeners.
* @return False if the event is cancellable and has been cancelled, otherwise true.
*/ */
boolean callEvent(Event event); void callEvent(Event event);
/** <T extends EventHandler> void registerHandler(Class<T> clazz, T handler);
* Register an {@link EventListener} under an {@link TerraAddon}.
* <T extends EventHandler> T getHandler(Class<T> clazz);
* @param addon Addon to register listener for.
* @param listener Listener to register.
*/
void registerListener(TerraAddon addon, EventListener listener);
} }

View File

@ -1,17 +0,0 @@
package com.dfsek.terra.api.event.annotations;
import com.dfsek.terra.api.event.events.PackEvent;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specifies that an event handler is to handle all {@link PackEvent}s, regardless of whether the pack
* depends on the com.dfsek.terra.addon's listener.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Global {
}

View File

@ -1,39 +0,0 @@
package com.dfsek.terra.api.event.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotated listener methods will have a specific priority set.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Priority {
/**
* Highest possible priority. Listeners with this priority will always be invoked last.
*/
int HIGHEST = Integer.MAX_VALUE;
/**
* Lowest possible priority. Listeners with this priority will always be invoked first.
*/
int LOWEST = Integer.MIN_VALUE;
/**
* Default priority.
*/
int NORMAL = 0;
/**
* High priority.
*/
int HIGH = 1;
/**
* Low Priority.
*/
int LOW = -1;
/**
* @return Priority of this event. Events are executed from lowest to highest priorities.
*/
int value();
}

View File

@ -0,0 +1,8 @@
package com.dfsek.terra.api.event.events;
/**
* An event which (optionally) passes exceptions thrown by listeners to
* the event caller.
*/
public interface FailThroughEvent extends Event {
}

View File

@ -1,13 +1,12 @@
package com.dfsek.terra.api.event.events; package com.dfsek.terra.api.event.events;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.event.annotations.Global;
/** /**
* An event with functionality directly linked to a {@link ConfigPack}. * An event with functionality directly linked to a {@link ConfigPack}.
* <p> * <p>
* PackEvents are only invoked when the pack specifies the com.dfsek.terra.addon in its * PackEvents are only invoked when the pack specifies the addon in its
* {@code com.dfsek.terra.addon} key (or when the listener is annotated {@link Global}). * {@code addon} key (or when the listener is global).
*/ */
@SuppressWarnings("InterfaceMayBeAnnotatedFunctional") @SuppressWarnings("InterfaceMayBeAnnotatedFunctional")
public interface PackEvent extends Event { public interface PackEvent extends Event {

View File

@ -3,6 +3,7 @@ package com.dfsek.terra.api.event.events.config;
import com.dfsek.tectonic.config.Configuration; import com.dfsek.tectonic.config.Configuration;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.Loader; import com.dfsek.terra.api.config.Loader;
import com.dfsek.terra.api.event.events.FailThroughEvent;
import com.dfsek.terra.api.event.events.PackEvent; import com.dfsek.terra.api.event.events.PackEvent;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
@ -14,7 +15,7 @@ import java.util.function.Consumer;
* Addons should listen to this event if they wish to add * Addons should listen to this event if they wish to add
* another configuration format. * another configuration format.
*/ */
public class ConfigurationDiscoveryEvent implements PackEvent { public class ConfigurationDiscoveryEvent implements PackEvent, FailThroughEvent {
private final ConfigPack pack; private final ConfigPack pack;
private final Loader loader; private final Loader loader;

View File

@ -4,6 +4,7 @@ import com.dfsek.tectonic.abstraction.AbstractConfiguration;
import com.dfsek.tectonic.config.ConfigTemplate; import com.dfsek.tectonic.config.ConfigTemplate;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.ConfigType; import com.dfsek.terra.api.config.ConfigType;
import com.dfsek.terra.api.event.events.FailThroughEvent;
import com.dfsek.terra.api.event.events.PackEvent; import com.dfsek.terra.api.event.events.PackEvent;
import com.dfsek.terra.api.util.reflection.ReflectionUtil; import com.dfsek.terra.api.util.reflection.ReflectionUtil;
@ -15,7 +16,7 @@ import java.util.function.Consumer;
* Addons should listen to this event if they wish to add * Addons should listen to this event if they wish to add
* config values to existing {@link ConfigType}s. * config values to existing {@link ConfigType}s.
*/ */
public class ConfigurationLoadEvent implements PackEvent { public class ConfigurationLoadEvent implements PackEvent, FailThroughEvent {
private final ConfigPack pack; private final ConfigPack pack;
private final AbstractConfiguration configuration; private final AbstractConfiguration configuration;
private final Consumer<ConfigTemplate> loader; private final Consumer<ConfigTemplate> loader;

View File

@ -3,12 +3,13 @@ package com.dfsek.terra.api.event.events.config.pack;
import com.dfsek.tectonic.config.ConfigTemplate; import com.dfsek.tectonic.config.ConfigTemplate;
import com.dfsek.tectonic.exception.ConfigException; import com.dfsek.tectonic.exception.ConfigException;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.event.events.FailThroughEvent;
import com.dfsek.terra.api.event.events.PackEvent; import com.dfsek.terra.api.event.events.PackEvent;
/** /**
* An event related to the loading process of config packs. * An event related to the loading process of config packs.
*/ */
public abstract class ConfigPackLoadEvent implements PackEvent { public abstract class ConfigPackLoadEvent implements PackEvent, FailThroughEvent {
private final ConfigPack pack; private final ConfigPack pack;
private final ExceptionalConsumer<ConfigTemplate> configLoader; private final ExceptionalConsumer<ConfigTemplate> configLoader;

View File

@ -2,11 +2,12 @@ package com.dfsek.terra.api.event.events.config.type;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.ConfigType; import com.dfsek.terra.api.config.ConfigType;
import com.dfsek.terra.api.event.events.FailThroughEvent;
import com.dfsek.terra.api.event.events.PackEvent; import com.dfsek.terra.api.event.events.PackEvent;
import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.util.reflection.ReflectionUtil; import com.dfsek.terra.api.util.reflection.ReflectionUtil;
public abstract class ConfigTypeLoadEvent implements PackEvent { public abstract class ConfigTypeLoadEvent implements PackEvent, FailThroughEvent {
private final ConfigType<?, ?> type; private final ConfigType<?, ?> type;
private final CheckedRegistry<?> registry; private final CheckedRegistry<?> registry;

View File

@ -4,7 +4,7 @@ import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.ConfigType; import com.dfsek.terra.api.config.ConfigType;
import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.api.registry.CheckedRegistry;
public class ConfigTypePostLoadEvent extends ConfigTypeLoadEvent{ public class ConfigTypePostLoadEvent extends ConfigTypeLoadEvent {
public ConfigTypePostLoadEvent(ConfigType<?, ?> type, CheckedRegistry<?> registry, ConfigPack pack) { public ConfigTypePostLoadEvent(ConfigType<?, ?> type, CheckedRegistry<?> registry, ConfigPack pack) {
super(type, registry, pack); super(type, registry, pack);
} }

View File

@ -4,7 +4,7 @@ import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.ConfigType; import com.dfsek.terra.api.config.ConfigType;
import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.api.registry.CheckedRegistry;
public class ConfigTypePreLoadEvent extends ConfigTypeLoadEvent{ public class ConfigTypePreLoadEvent extends ConfigTypeLoadEvent {
public ConfigTypePreLoadEvent(ConfigType<?, ?> type, CheckedRegistry<?> registry, ConfigPack pack) { public ConfigTypePreLoadEvent(ConfigType<?, ?> type, CheckedRegistry<?> registry, ConfigPack pack) {
super(type, registry, pack); super(type, registry, pack);
} }

View File

@ -0,0 +1,16 @@
package com.dfsek.terra.api.event.functional;
import com.dfsek.terra.api.event.EventManager;
import com.dfsek.terra.api.event.events.Event;
import java.util.function.Consumer;
public interface EventContext<T extends Event> {
EventContext<T> then(Consumer<T> action);
EventContext<T> priority(int priority);
EventContext<T> failThrough();
EventContext<T> global();
}

View File

@ -0,0 +1,12 @@
package com.dfsek.terra.api.event.functional;
import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.event.EventHandler;
import com.dfsek.terra.api.event.events.Event;
import com.dfsek.terra.api.util.reflection.TypeKey;
public interface FunctionalEventHandler extends EventHandler {
<T extends Event> EventContext<T> register(TerraAddon addon, Class<T> clazz);
<T extends Event> EventContext<T> register(TerraAddon addon, TypeKey<T> clazz);
}

View File

@ -0,0 +1,85 @@
package com.dfsek.terra.event;
import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.event.events.Event;
import com.dfsek.terra.api.event.events.FailThroughEvent;
import com.dfsek.terra.api.event.functional.EventContext;
import com.dfsek.terra.api.util.reflection.ReflectionUtil;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class EventContextImpl<T extends Event> implements EventContext<T>, Comparable<EventContextImpl<?>> {
private final List<Consumer<T>> actions = new ArrayList<>();
private int priority;
private boolean failThrough = false;
private boolean global = false;
private final TerraAddon addon;
private final Type eventType;
private final FunctionalEventHandlerImpl parent;
public EventContextImpl(TerraAddon addon, Type eventType, FunctionalEventHandlerImpl parent) {
this.addon = addon;
this.eventType = eventType;
this.parent = parent;
}
public void handle(T event) {
actions.forEach(action -> action.accept(event));
}
@Override
public EventContext<T> then(Consumer<T> action) {
actions.add(action);
return this;
}
@Override
public EventContext<T> priority(int priority) {
this.priority = priority;
parent.recomputePriorities(eventType);
return this;
}
@Override
public EventContext<T> failThrough() {
if(!FailThroughEvent.class.isAssignableFrom(ReflectionUtil.getRawType(eventType))) {
throw new IllegalStateException("Cannot fail-through on event which does not implement FailThroughEvent: " + ReflectionUtil.typeToString(eventType));
}
this.failThrough = true;
return this;
}
@Override
public EventContext<T> global() {
this.global = true;
return this;
}
@Override
public int compareTo(@NotNull EventContextImpl<?> o) {
return this.priority - o.priority;
}
public boolean isGlobal() {
return global;
}
public int getPriority() {
return priority;
}
public TerraAddon getAddon() {
return addon;
}
public boolean isFailThrough() {
return failThrough;
}
}

View File

@ -1,111 +1,38 @@
package com.dfsek.terra.event; package com.dfsek.terra.event;
import com.dfsek.terra.api.TerraPlugin; import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.addon.TerraAddon; import com.dfsek.terra.api.event.EventHandler;
import com.dfsek.terra.api.event.EventListener;
import com.dfsek.terra.api.event.EventManager; import com.dfsek.terra.api.event.EventManager;
import com.dfsek.terra.api.event.annotations.Global;
import com.dfsek.terra.api.event.annotations.Priority;
import com.dfsek.terra.api.event.events.Cancellable;
import com.dfsek.terra.api.event.events.Event; import com.dfsek.terra.api.event.events.Event;
import com.dfsek.terra.api.event.events.PackEvent; import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.util.reflection.ReflectionUtil;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
public class EventManagerImpl implements EventManager { public class EventManagerImpl implements EventManager {
private final Map<Class<? extends Event>, List<ListenerHolder>> listeners = new HashMap<>(); private final Map<Class<?>, EventHandler> handlers = new HashMap<>();
private final TerraPlugin main; private final TerraPlugin main;
public EventManagerImpl(TerraPlugin main) { public EventManagerImpl(TerraPlugin main) {
this.main = main; this.main = main;
registerHandler(FunctionalEventHandler.class, new FunctionalEventHandlerImpl(main)); // default handler
} }
@Override @Override
public boolean callEvent(Event event) { public void callEvent(Event event) {
listeners.getOrDefault(event.getClass(), Collections.emptyList()).forEach(listenerHolder -> { handlers.values().forEach(handler -> handler.handle(event));
try {
if(event instanceof PackEvent && !listenerHolder.global) {
PackEvent packEvent = (PackEvent) event;
if(packEvent
.getPack()
.addons()
.contains(listenerHolder.addon)) {
listenerHolder.method.invoke(listenerHolder.listener, event);
} }
} else {
listenerHolder.method.invoke(listenerHolder.listener, event); @Override
} public <T extends EventHandler> void registerHandler(Class<T> clazz, T handler) {
} catch(InvocationTargetException e) { handlers.put(clazz, handler);
StringWriter writer = new StringWriter();
e.getTargetException().printStackTrace(new PrintWriter(writer));
main.logger().warning("Exception occurred during event handling:");
main.logger().warning(writer.toString());
main.logger().warning("Report this to the maintainers of " + listenerHolder.method.getName());
} catch(Exception e) {
StringWriter writer = new StringWriter();
e.printStackTrace(new PrintWriter(writer));
main.logger().warning("Exception occurred during event handling:");
main.logger().warning(writer.toString());
main.logger().warning("Report this to the maintainers of " + listenerHolder.method.getName());
}
}
);
if(event instanceof Cancellable) return !((Cancellable) event).isCancelled();
return true;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public void registerListener(TerraAddon addon, EventListener listener) { public <T extends EventHandler> T getHandler(Class<T> clazz) {
Class<? extends EventListener> listenerClass = listener.getClass(); return (T) handlers.computeIfAbsent(clazz, c -> {
Method[] methods = ReflectionUtil.getMethods(listenerClass); throw new IllegalArgumentException("No event handler registered for class " + clazz.getCanonicalName());
});
for(Method method : methods) {
if(method.getParameterCount() != 1) continue; // Check that parameter count is only 1.
Class<?> eventParam = method.getParameterTypes()[0];
if(!Event.class.isAssignableFrom(eventParam)) continue; // Check that parameter is an Event.
Priority p = method.getAnnotation(Priority.class);
int priority = p == null ? 0 : p.value();
method.setAccessible(true);
List<ListenerHolder> holders = listeners.computeIfAbsent((Class<? extends Event>) eventParam, e -> new ArrayList<>());
holders.add(new ListenerHolder(method, listener, priority, addon, method.getAnnotation(Global.class) != null));
holders.sort(Comparator.comparingInt(ListenerHolder::getPriority)); // Sort priorities.
}
}
private static final class ListenerHolder {
private final Method method;
private final EventListener listener;
private final int priority;
private final TerraAddon addon;
private final boolean global;
private ListenerHolder(Method method, EventListener listener, int priority, TerraAddon addon, boolean global) {
this.method = method;
this.listener = listener;
this.priority = priority;
this.addon = addon;
this.global = global;
}
public int getPriority() {
return priority;
}
} }
} }

View File

@ -0,0 +1,71 @@
package com.dfsek.terra.event;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.event.events.Event;
import com.dfsek.terra.api.event.events.FailThroughEvent;
import com.dfsek.terra.api.event.events.PackEvent;
import com.dfsek.terra.api.event.functional.EventContext;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.util.reflection.TypeKey;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class FunctionalEventHandlerImpl implements FunctionalEventHandler {
private final Map<Type, List<EventContextImpl<?>>> contextMap = new HashMap<>();
private final TerraPlugin main;
public FunctionalEventHandlerImpl(TerraPlugin main) {
this.main = main;
}
@SuppressWarnings("unchecked")
@Override
public void handle(Event event) {
contextMap.getOrDefault(event.getClass(), Collections.emptyList()).forEach(context -> {
try {
if(event instanceof PackEvent) {
if((context.isGlobal() || ((PackEvent) event).getPack().addons().contains(context.getAddon()))) {
((EventContextImpl<Event>) context).handle(event);
}
} else {
((EventContextImpl<Event>) context).handle(event);
}
} catch(Exception e) {
if(context.isFailThrough() && event instanceof FailThroughEvent) throw e; // Rethrow if it's fail-through.
StringWriter writer = new StringWriter();
e.printStackTrace(new PrintWriter(writer));
main.logger().warning("Exception occurred during event handling:");
main.logger().warning(writer.toString());
main.logger().warning("Report this to the maintainers of " + context.getAddon().getName() + ", " + context.getAddon().getAuthor());
}
});
}
@Override
public <T extends Event> EventContext<T> register(TerraAddon addon, Class<T> clazz) {
EventContextImpl<T> eventContext = new EventContextImpl<>(addon, clazz, this);
contextMap.computeIfAbsent(clazz, c -> new ArrayList<>()).add(eventContext);
return eventContext;
}
@Override
public <T extends Event> EventContext<T> register(TerraAddon addon, TypeKey<T> clazz) {
EventContextImpl<T> eventContext = new EventContextImpl<>(addon, clazz.getType(), this);
contextMap.computeIfAbsent(clazz.getType(), c -> new ArrayList<>()).add(eventContext);
return eventContext;
}
public void recomputePriorities(Type target) {
contextMap.get(target).sort(Comparator.naturalOrder());
}
}

View File

@ -33,7 +33,6 @@ import com.dfsek.terra.bukkit.handles.BukkitWorldHandle;
import com.dfsek.terra.bukkit.listeners.CommonListener; import com.dfsek.terra.bukkit.listeners.CommonListener;
import com.dfsek.terra.bukkit.listeners.PaperListener; import com.dfsek.terra.bukkit.listeners.PaperListener;
import com.dfsek.terra.bukkit.listeners.SpigotListener; import com.dfsek.terra.bukkit.listeners.SpigotListener;
import com.dfsek.terra.bukkit.listeners.TerraListener;
import com.dfsek.terra.bukkit.util.PaperUtil; import com.dfsek.terra.bukkit.util.PaperUtil;
import com.dfsek.terra.bukkit.world.BukkitBiome; import com.dfsek.terra.bukkit.world.BukkitBiome;
import com.dfsek.terra.bukkit.world.BukkitWorld; import com.dfsek.terra.bukkit.world.BukkitWorld;
@ -343,7 +342,7 @@ public class TerraBukkitPlugin extends JavaPlugin implements TerraPlugin {
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager().registerListener(this, new TerraListener(main));
} }
} }
} }

View File

@ -1,33 +0,0 @@
package com.dfsek.terra.bukkit.listeners;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.event.EventListener;
import com.dfsek.terra.api.event.annotations.Global;
import com.dfsek.terra.api.event.annotations.Priority;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.registry.exception.DuplicateEntryException;
import com.dfsek.terra.api.world.Tree;
import com.dfsek.terra.bukkit.world.BukkitAdapter;
import com.dfsek.terra.bukkit.world.BukkitTree;
import org.bukkit.TreeType;
public class TerraListener implements EventListener {
private final TerraPlugin main;
public TerraListener(TerraPlugin main) {
this.main = main;
}
@Global
@Priority(Priority.LOWEST)
public void injectTrees(ConfigPackPreLoadEvent event) {
for(TreeType value : TreeType.values()) {
try {
String id = BukkitAdapter.TREE_TRANSFORMER.translate(value);
event.getPack().getCheckedRegistry(Tree.class).register(id, new BukkitTree(value, main));
event.getPack().getCheckedRegistry(Tree.class).get(id); // Platform trees should never be marked "dead"
} catch(DuplicateEntryException ignore) { // If another com.dfsek.terra.addon has already registered trees, do nothing.
}
}
}
}

View File

@ -14,13 +14,10 @@ import com.dfsek.terra.api.command.CommandManager;
import com.dfsek.terra.api.command.exception.MalformedCommandException; import com.dfsek.terra.api.command.exception.MalformedCommandException;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.PluginConfig; import com.dfsek.terra.api.config.PluginConfig;
import com.dfsek.terra.api.event.EventListener;
import com.dfsek.terra.api.event.EventManager; import com.dfsek.terra.api.event.EventManager;
import com.dfsek.terra.api.event.annotations.Global;
import com.dfsek.terra.api.event.annotations.Priority;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.events.config.type.ConfigTypePostLoadEvent; import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.handle.ItemHandle; import com.dfsek.terra.api.handle.ItemHandle;
import com.dfsek.terra.api.handle.WorldHandle; import com.dfsek.terra.api.handle.WorldHandle;
import com.dfsek.terra.api.lang.Language; import com.dfsek.terra.api.lang.Language;
@ -69,7 +66,6 @@ import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.gen.decorator.Decorator; import net.minecraft.world.gen.decorator.Decorator;
import net.minecraft.world.gen.decorator.NopeDecoratorConfig; import net.minecraft.world.gen.decorator.NopeDecoratorConfig;
import net.minecraft.world.gen.feature.ConfiguredFeature; import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraft.world.gen.feature.ConfiguredFeatures;
import net.minecraft.world.gen.feature.DefaultFeatureConfig; import net.minecraft.world.gen.feature.DefaultFeatureConfig;
import net.minecraft.world.gen.feature.FeatureConfig; import net.minecraft.world.gen.feature.FeatureConfig;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
@ -288,16 +284,15 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
@Addon("Terra-Fabric") @Addon("Terra-Fabric")
@Author("Terra") @Author("Terra")
@Version("1.0.0") @Version("1.0.0")
public final class FabricAddon extends TerraAddon implements EventListener { public final class FabricAddon extends TerraAddon {
private final Map<ConfigPack, Pair<PreLoadCompatibilityOptions, PostLoadCompatibilityOptions>> templates = new HashMap<>(); private final Map<ConfigPack, Pair<PreLoadCompatibilityOptions, PostLoadCompatibilityOptions>> templates = new HashMap<>();
@Override @Override
public void initialize() { public void initialize() {
eventManager.registerListener(this, this); eventManager
} .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
@Global .then(event -> {
public void onPackLoad(ConfigPackPreLoadEvent event) {
PreLoadCompatibilityOptions template = new PreLoadCompatibilityOptions(); PreLoadCompatibilityOptions template = new PreLoadCompatibilityOptions();
try { try {
event.loadTemplate(template); event.loadTemplate(template);
@ -317,12 +312,13 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
}); });
} }
templates.put(event.getPack(), Pair.of(template, null)); templates.put(event.getPack(), Pair.of(template, null));
})
.global();
} eventManager
.getHandler(FunctionalEventHandler.class)
@Priority(Priority.HIGHEST) .register(this, ConfigPackPostLoadEvent.class)
@Global .then(event -> {
public void createInjectionOptions(ConfigPackPostLoadEvent event) {
PostLoadCompatibilityOptions template = new PostLoadCompatibilityOptions(); PostLoadCompatibilityOptions template = new PostLoadCompatibilityOptions();
try { try {
@ -332,24 +328,34 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
} }
templates.get(event.getPack()).setRight(template); templates.get(event.getPack()).setRight(template);
} })
.priority(100)
.global();
@Global eventManager
public void injectBiomes(BiomeRegistrationEvent event) { .getHandler(FunctionalEventHandler.class)
.register(this, BiomeRegistrationEvent.class)
.then(event -> {
logger.info("Registering biomes..."); logger.info("Registering biomes...");
Registry<Biome> biomeRegistry = event.getRegistryManager().get(Registry.BIOME_KEY); Registry<Biome> biomeRegistry = event.getRegistryManager().get(Registry.BIOME_KEY);
configRegistry.forEach(pack -> pack.getCheckedRegistry(TerraBiome.class).forEach((id, biome) -> FabricUtil.registerOrOverwrite(biomeRegistry, Registry.BIOME_KEY, new Identifier("terra", FabricUtil.createBiomeID(pack, id)), FabricUtil.createBiome(biome, pack, event.getRegistryManager())))); // Register all Terra biomes. configRegistry.forEach(pack -> pack.getCheckedRegistry(TerraBiome.class).forEach((id, biome) -> FabricUtil.registerOrOverwrite(biomeRegistry, Registry.BIOME_KEY, new Identifier("terra", FabricUtil.createBiomeID(pack, id)), FabricUtil.createBiome(biome, pack, event.getRegistryManager())))); // Register all Terra biomes.
logger.info("Biomes registered."); logger.info("Biomes registered.");
} })
.global();
@Global eventManager
public void initializePacks(GameInitializationEvent event) { .getHandler(FunctionalEventHandler.class)
.register(this, GameInitializationEvent.class)
.then(event -> {
TerraFabricPlugin main = TerraFabricPlugin.getInstance(); TerraFabricPlugin main = TerraFabricPlugin.getInstance();
main.logger().info("Loading config packs..."); main.logger().info("Loading config packs...");
configRegistry.loadAll(TerraFabricPlugin.this); configRegistry.loadAll(TerraFabricPlugin.this);
logger.info("Loaded packs."); logger.info("Loaded packs.");
})
.global();
} }
private void injectTree(CheckedRegistry<Tree> registry, String id, ConfiguredFeature<?, ?> tree) { private void injectTree(CheckedRegistry<Tree> registry, String id, ConfiguredFeature<?, ?> tree) {
try { try {
registry.register(id, (Tree) tree); registry.register(id, (Tree) tree);