From c36d9a4964169d432147267c6e43e61094ef2583 Mon Sep 17 00:00:00 2001 From: mine_diver Date: Thu, 2 May 2024 18:11:58 +0500 Subject: [PATCH 01/22] First version of tool items update --- .../sltest/block/Blocks.java | 2 +- .../sltest/item/ItemListener.java | 4 +- .../tags/blocks/mineable/pickaxe.json | 5 ++ .../tags/blocks/needs_iron_tool.json | 5 ++ .../tags/blocks/needs_tool_level_modded.json | 6 +++ .../api/item/tool/StationHoeItem.java | 1 - .../api/item/tool/StationShearsItem.java | 1 - .../api/item/tool/StationSwordItem.java | 1 - .../api/item/tool/StationToolItem.java | 1 - .../api/item/tool/StationToolMaterial.java | 36 +------------- .../stationapi/api/item/tool/ToolLevel.java | 1 - .../api/item/tool/ToolMaterialFactory.java | 1 - .../impl/item/HijackShearsImplV1.java | 1 - .../impl/item/ToolEffectivenessImplV1.java | 30 ++++++++++-- .../mixin/tools/ToolMaterialMixin.java | 47 ++----------------- .../item/tool/VanillaToolFixImpl.java | 11 ++--- .../tags/blocks/needs_diamond_tool.json | 1 + .../tags/blocks/needs_iron_tool.json | 1 + 18 files changed, 60 insertions(+), 95 deletions(-) create mode 100644 src/test/resources/data/minecraft/stationapi/tags/blocks/mineable/pickaxe.json create mode 100644 src/test/resources/data/minecraft/stationapi/tags/blocks/needs_iron_tool.json create mode 100644 src/test/resources/data/sltest/stationapi/tags/blocks/needs_tool_level_modded.json diff --git a/src/test/java/net/modificationstation/sltest/block/Blocks.java b/src/test/java/net/modificationstation/sltest/block/Blocks.java index b30536a68..278cf6bfd 100644 --- a/src/test/java/net/modificationstation/sltest/block/Blocks.java +++ b/src/test/java/net/modificationstation/sltest/block/Blocks.java @@ -16,7 +16,7 @@ public enum Blocks { - TEST_BLOCK("test_block", "testBlock", id -> new TemplateBlock(id, Material.CLAY).setHardness(1)), + TEST_BLOCK("test_block", "testBlock", id -> new TemplateBlock(id, Material.STONE).setHardness(1)), TEST_ANIMATED_BLOCK("test_animated_block", "testAnimatedBlock", id -> new ModdedMetaBlock(id, Material.NETHER_PORTAL)), CUSTOM_MODEL_BLOCK("farlands_block", "farlands_block", id -> new ModdedModelBlock(id, Material.SOIL).setHardness(1)), FREEZER("freezer", "freezer", id -> new BlockFreezer(id).setHardness(2.5F).setSoundGroup(TemplateBlock.DEFAULT_SOUND_GROUP)), diff --git a/src/test/java/net/modificationstation/sltest/item/ItemListener.java b/src/test/java/net/modificationstation/sltest/item/ItemListener.java index ee725ed40..523a847b3 100644 --- a/src/test/java/net/modificationstation/sltest/item/ItemListener.java +++ b/src/test/java/net/modificationstation/sltest/item/ItemListener.java @@ -7,8 +7,10 @@ import net.modificationstation.sltest.block.VariationBlock; import net.modificationstation.stationapi.api.event.registry.ItemRegistryEvent; import net.modificationstation.stationapi.api.item.tool.ToolMaterialFactory; +import net.modificationstation.stationapi.api.registry.BlockRegistry; import net.modificationstation.stationapi.api.registry.ItemRegistry; import net.modificationstation.stationapi.api.registry.Registry; +import net.modificationstation.stationapi.api.tag.TagKey; import net.modificationstation.stationapi.api.template.item.BlockStateItem; import static net.modificationstation.sltest.SLTest.NAMESPACE; @@ -18,7 +20,7 @@ public class ItemListener { @EventListener public void registerItems(ItemRegistryEvent event) { testItem = new ModdedItem(NAMESPACE.id("test_item")).setTranslationKey(NAMESPACE, "testItem"); //8475 - testMaterial = ToolMaterialFactory.create("testMaterial", 3, Integer.MAX_VALUE, Float.MAX_VALUE, Integer.MAX_VALUE - 2); + testMaterial = ToolMaterialFactory.create("testMaterial", 3, Integer.MAX_VALUE, Float.MAX_VALUE, Integer.MAX_VALUE - 2).miningLevelTag(TagKey.of(BlockRegistry.KEY, NAMESPACE.id("needs_tool_level_modded"))); testPickaxe = new ModdedPickaxeItem(NAMESPACE.id("test_pickaxe"), testMaterial).setTranslationKey(NAMESPACE, "testPickaxe"); //8476 testNBTItem = new NBTItem(NAMESPACE.id("nbt_item")).setTranslationKey(NAMESPACE, "nbt_item"); //8477 testModelItem = new ModelItem(NAMESPACE.id("model_item")).setMaxCount(1).setTranslationKey(NAMESPACE, "idkSomething"); diff --git a/src/test/resources/data/minecraft/stationapi/tags/blocks/mineable/pickaxe.json b/src/test/resources/data/minecraft/stationapi/tags/blocks/mineable/pickaxe.json new file mode 100644 index 000000000..04f9bde83 --- /dev/null +++ b/src/test/resources/data/minecraft/stationapi/tags/blocks/mineable/pickaxe.json @@ -0,0 +1,5 @@ +{ + "values": [ + "sltest:test_block" + ] +} \ No newline at end of file diff --git a/src/test/resources/data/minecraft/stationapi/tags/blocks/needs_iron_tool.json b/src/test/resources/data/minecraft/stationapi/tags/blocks/needs_iron_tool.json new file mode 100644 index 000000000..2dd664728 --- /dev/null +++ b/src/test/resources/data/minecraft/stationapi/tags/blocks/needs_iron_tool.json @@ -0,0 +1,5 @@ +{ + "values": [ + "#sltest:needs_tool_level_modded" + ] +} \ No newline at end of file diff --git a/src/test/resources/data/sltest/stationapi/tags/blocks/needs_tool_level_modded.json b/src/test/resources/data/sltest/stationapi/tags/blocks/needs_tool_level_modded.json new file mode 100644 index 000000000..b15b2bb24 --- /dev/null +++ b/src/test/resources/data/sltest/stationapi/tags/blocks/needs_tool_level_modded.json @@ -0,0 +1,6 @@ +{ + "values": [ + "#needs_stone_tool", + "sltest:test_block" + ] +} \ No newline at end of file diff --git a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationHoeItem.java b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationHoeItem.java index 5f6ca48dc..9115fe99e 100644 --- a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationHoeItem.java +++ b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationHoeItem.java @@ -7,7 +7,6 @@ import net.modificationstation.stationapi.api.util.Util; public interface StationHoeItem extends ToolLevel { - @Override default void setEffectiveBlocks(TagKey effectiveBlocks) { Util.assertImpl(); diff --git a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationShearsItem.java b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationShearsItem.java index f0d24982d..b6904d204 100644 --- a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationShearsItem.java +++ b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationShearsItem.java @@ -7,7 +7,6 @@ import net.modificationstation.stationapi.api.util.Util; public interface StationShearsItem extends ToolLevel { - @Override default void setEffectiveBlocks(TagKey effectiveBlocks) { Util.assertImpl(); diff --git a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationSwordItem.java b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationSwordItem.java index 2cac4fec5..0f648e8d9 100644 --- a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationSwordItem.java +++ b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationSwordItem.java @@ -7,7 +7,6 @@ import net.modificationstation.stationapi.api.util.Util; public interface StationSwordItem extends ToolLevel { - @Override default void setEffectiveBlocks(TagKey effectiveBlocks) { Util.assertImpl(); diff --git a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationToolItem.java b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationToolItem.java index 57998fd5a..f23cdbc75 100644 --- a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationToolItem.java +++ b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationToolItem.java @@ -7,7 +7,6 @@ import net.modificationstation.stationapi.api.util.Util; public interface StationToolItem extends ToolLevel { - @Override default void setEffectiveBlocks(TagKey effectiveBlocks) { Util.assertImpl(); diff --git a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationToolMaterial.java b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationToolMaterial.java index b9676af8a..e404b21bb 100644 --- a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationToolMaterial.java +++ b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationToolMaterial.java @@ -1,48 +1,16 @@ package net.modificationstation.stationapi.api.item.tool; -import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; -import it.unimi.dsi.fastutil.objects.ReferenceSet; import net.minecraft.block.Block; import net.minecraft.item.ToolMaterial; -import net.modificationstation.stationapi.api.block.BlockState; -import net.modificationstation.stationapi.api.util.Identifier; import net.modificationstation.stationapi.api.tag.TagKey; import net.modificationstation.stationapi.api.util.Util; -import java.util.function.BiPredicate; -import java.util.function.Predicate; - public interface StationToolMaterial { - - ReferenceSet> ALL_TOOL_MATERIAL_TAGS = new ReferenceOpenHashSet<>(); - - default ToolMaterial inheritsFrom(ToolMaterial... toolMaterials) { + default ToolMaterial miningLevelTag(TagKey tag) { return Util.assertImpl(); } - default ToolMaterial requiredBlockTag(Identifier tag) { + default TagKey getMiningLevelTag() { return Util.assertImpl(); } - - default ReferenceSet getParentMaterials() { - return Util.assertImpl(); - } - - default TagKey getRequiredBlockTag() { - return Util.assertImpl(); - } - - default boolean matches(BlockState state) { - return ALL_TOOL_MATERIAL_TAGS.stream().noneMatch(state::isIn) || matches0(state); - } - - private boolean matches0(BlockState state) { - TagKey tag = getRequiredBlockTag(); - if (tag != null) { - if (state.isIn(tag)) return true; - BiPredicate matches0 = StationToolMaterial::matches0; - Predicate matchesThis = t -> matches0.test(t, state); - return getParentMaterials().stream().anyMatch(matchesThis); - } else return false; - } } diff --git a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/ToolLevel.java b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/ToolLevel.java index 84bb3fb87..d12cf4528 100644 --- a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/ToolLevel.java +++ b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/ToolLevel.java @@ -6,7 +6,6 @@ import net.modificationstation.stationapi.api.tag.TagKey; public interface ToolLevel { - void setEffectiveBlocks(TagKey effectiveBlocks); TagKey getEffectiveBlocks(ItemStack stack); diff --git a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/ToolMaterialFactory.java b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/ToolMaterialFactory.java index e0b52131a..8ecfecadd 100644 --- a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/ToolMaterialFactory.java +++ b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/ToolMaterialFactory.java @@ -4,7 +4,6 @@ import net.modificationstation.stationapi.api.factory.EnumFactory; public class ToolMaterialFactory { - public static ToolMaterial create(String materialName, int miningLevel, int durability, float miningSpeed, int attackDamage) { return EnumFactory.addEnum( ToolMaterial.class, materialName, diff --git a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/impl/item/HijackShearsImplV1.java b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/impl/item/HijackShearsImplV1.java index ef0f81f1a..873ee30c3 100644 --- a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/impl/item/HijackShearsImplV1.java +++ b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/impl/item/HijackShearsImplV1.java @@ -7,7 +7,6 @@ @EventListener(phase = StationAPI.INTERNAL_PHASE) public class HijackShearsImplV1 { - //TODO: Make this match anything that has shear tool properties. Not sure how to go around this at the moment. @EventListener private static void hijackShearsEvent(ShearsOverrideEvent event) { diff --git a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/impl/item/ToolEffectivenessImplV1.java b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/impl/item/ToolEffectivenessImplV1.java index 258205d1d..791131f69 100644 --- a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/impl/item/ToolEffectivenessImplV1.java +++ b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/impl/item/ToolEffectivenessImplV1.java @@ -3,6 +3,7 @@ import net.mine_diver.unsafeevents.listener.EventListener; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.item.ToolMaterial; import net.modificationstation.stationapi.api.StationAPI; import net.modificationstation.stationapi.api.block.BlockState; import net.modificationstation.stationapi.api.event.item.IsItemSuitableForStateEvent; @@ -17,6 +18,7 @@ import net.modificationstation.stationapi.api.util.Namespace; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -25,7 +27,6 @@ @Entrypoint(eventBus = @EventBusPolicy(registerInstance = false)) @EventListener(phase = StationAPI.INTERNAL_PHASE) public class ToolEffectivenessImplV1 { - public static final List VANILLA_TOOLS = new ArrayList<>(); @EventListener(priority = LOW) @@ -55,15 +56,36 @@ private static void getItems(ItemRegistryEvent event) { @EventListener private static void isEffective(IsItemSuitableForStateEvent event) { - event.suitable = event.suitable || isSuitable(event.itemStack, event.state); + // Disable custom tool logic if both the block and the tool are vanilla + // This is done to preserve the vanilla mining speeds + if (VANILLA_TOOLS.contains(ItemRegistry.INSTANCE.getId(event.itemStack.getItem())) + && Objects.requireNonNull(BlockRegistry.INSTANCE.getId(event.state.getBlock())).namespace == Namespace.MINECRAFT) return; + + event.suitable = isSuitable(event.itemStack, event.state); } @EventListener private static void getStrength(ItemMiningSpeedMultiplierOnStateEvent event) { - if (!(VANILLA_TOOLS.contains(ItemRegistry.INSTANCE.getId(event.itemStack.getItem())) && Objects.requireNonNull(BlockRegistry.INSTANCE.getId(event.state.getBlock())).namespace == Namespace.MINECRAFT) && isSuitable(event.itemStack, event.state)) event.miningSpeedMultiplier = ((ToolLevel) event.itemStack.getItem()).getMaterial(event.itemStack).getMiningSpeedMultiplier(); + // Disable custom tool logic if both the block and the tool are vanilla + // This is done to preserve the vanilla mining speeds + if (VANILLA_TOOLS.contains(ItemRegistry.INSTANCE.getId(event.itemStack.getItem())) + && Objects.requireNonNull(BlockRegistry.INSTANCE.getId(event.state.getBlock())).namespace == Namespace.MINECRAFT) return; + + if (!isSuitable(event.itemStack, event.state)) return; + + event.miningSpeedMultiplier = ((ToolLevel) event.itemStack.getItem()).getMaterial(event.itemStack).getMiningSpeedMultiplier(); } private static boolean isSuitable(ItemStack item, BlockState state) { - return item.getItem() instanceof ToolLevel toolLevel && state.isIn(toolLevel.getEffectiveBlocks(item)) && toolLevel.getMaterial(item).matches(state); + return item.getItem() instanceof ToolLevel toolLevel + && state.isIn(toolLevel.getEffectiveBlocks(item)) + && + ( + state.isIn(toolLevel.getMaterial(item).getMiningLevelTag()) + || Arrays + .stream(ToolMaterial.values()) + .filter(toolMaterial -> toolMaterial.getMiningLevelTag() != null) + .noneMatch(toolMaterial -> state.isIn(toolMaterial.getMiningLevelTag())) + ); } } diff --git a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/mixin/tools/ToolMaterialMixin.java b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/mixin/tools/ToolMaterialMixin.java index 3429c86b5..820859da2 100644 --- a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/mixin/tools/ToolMaterialMixin.java +++ b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/mixin/tools/ToolMaterialMixin.java @@ -1,64 +1,27 @@ package net.modificationstation.stationapi.mixin.tools; -import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; -import it.unimi.dsi.fastutil.objects.ReferenceSet; -import it.unimi.dsi.fastutil.objects.ReferenceSets; import net.minecraft.block.Block; import net.minecraft.item.ToolMaterial; import net.modificationstation.stationapi.api.item.tool.StationToolMaterial; -import net.modificationstation.stationapi.api.registry.BlockRegistry; import net.modificationstation.stationapi.api.tag.TagKey; -import net.modificationstation.stationapi.api.util.Identifier; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.Collections; @Mixin(ToolMaterial.class) class ToolMaterialMixin implements StationToolMaterial { @Unique - private TagKey stationapi_requiredBlockTag; - @Unique - private ReferenceSet stationapi_parentMaterials; - @Unique - private ReferenceSet stationapi_parentMaterialsView; - - @Inject( - method = "(Ljava/lang/String;IIIFI)V", - at = @At("RETURN") - ) - private void stationapi_init(String i, int j, int k, int f, float l, int par6, CallbackInfo ci) { - stationapi_parentMaterials = new ReferenceOpenHashSet<>(); - stationapi_parentMaterialsView = ReferenceSets.unmodifiable(stationapi_parentMaterials); - } - - @Override - @Unique - public ToolMaterial inheritsFrom(ToolMaterial... toolMaterials) { - Collections.addAll(stationapi_parentMaterials, toolMaterials); - return ToolMaterial.class.cast(this); - } + private TagKey stationapi_miningLevelTag; @Override @Unique - public ToolMaterial requiredBlockTag(Identifier tag) { - ALL_TOOL_MATERIAL_TAGS.remove(stationapi_requiredBlockTag); - ALL_TOOL_MATERIAL_TAGS.add(stationapi_requiredBlockTag = TagKey.of(BlockRegistry.INSTANCE.getKey(), tag)); + public ToolMaterial miningLevelTag(TagKey tag) { + stationapi_miningLevelTag = tag; return ToolMaterial.class.cast(this); } @Override @Unique - public ReferenceSet getParentMaterials() { - return stationapi_parentMaterialsView; - } - - @Override - @Unique - public TagKey getRequiredBlockTag() { - return stationapi_requiredBlockTag; + public TagKey getMiningLevelTag() { + return stationapi_miningLevelTag; } } diff --git a/station-vanilla-fix-v0/src/main/java/net/modificationstation/stationapi/impl/vanillafix/item/tool/VanillaToolFixImpl.java b/station-vanilla-fix-v0/src/main/java/net/modificationstation/stationapi/impl/vanillafix/item/tool/VanillaToolFixImpl.java index c9cffd6bc..0c9cedfa7 100644 --- a/station-vanilla-fix-v0/src/main/java/net/modificationstation/stationapi/impl/vanillafix/item/tool/VanillaToolFixImpl.java +++ b/station-vanilla-fix-v0/src/main/java/net/modificationstation/stationapi/impl/vanillafix/item/tool/VanillaToolFixImpl.java @@ -6,6 +6,8 @@ import net.modificationstation.stationapi.api.event.registry.ItemRegistryEvent; import net.modificationstation.stationapi.api.mod.entrypoint.Entrypoint; import net.modificationstation.stationapi.api.mod.entrypoint.EventBusPolicy; +import net.modificationstation.stationapi.api.registry.BlockRegistry; +import net.modificationstation.stationapi.api.tag.TagKey; import static net.modificationstation.stationapi.api.util.Identifier.of; @@ -17,11 +19,8 @@ private static void fixToolMaterials(ItemRegistryEvent event) { ToolMaterial stone = ToolMaterial.STONE; ToolMaterial iron = ToolMaterial.IRON; ToolMaterial diamond = ToolMaterial.DIAMOND; - stone.inheritsFrom(ToolMaterial.WOOD, ToolMaterial.GOLD); - stone.requiredBlockTag(of("needs_stone_tool")); - iron.inheritsFrom(ToolMaterial.STONE); - iron.requiredBlockTag(of("needs_iron_tool")); - diamond.inheritsFrom(ToolMaterial.IRON); - diamond.requiredBlockTag(of("needs_diamond_tool")); + stone.miningLevelTag(TagKey.of(BlockRegistry.KEY, of("needs_stone_tool"))); + iron.miningLevelTag(TagKey.of(BlockRegistry.KEY, of("needs_iron_tool"))); + diamond.miningLevelTag(TagKey.of(BlockRegistry.KEY, of("needs_diamond_tool"))); } } diff --git a/station-vanilla-fix-v0/src/main/resources/data/minecraft/stationapi/tags/blocks/needs_diamond_tool.json b/station-vanilla-fix-v0/src/main/resources/data/minecraft/stationapi/tags/blocks/needs_diamond_tool.json index 54d961641..7e914dc50 100644 --- a/station-vanilla-fix-v0/src/main/resources/data/minecraft/stationapi/tags/blocks/needs_diamond_tool.json +++ b/station-vanilla-fix-v0/src/main/resources/data/minecraft/stationapi/tags/blocks/needs_diamond_tool.json @@ -1,5 +1,6 @@ { "values": [ + "#needs_iron_tool", "obsidian" ] } \ No newline at end of file diff --git a/station-vanilla-fix-v0/src/main/resources/data/minecraft/stationapi/tags/blocks/needs_iron_tool.json b/station-vanilla-fix-v0/src/main/resources/data/minecraft/stationapi/tags/blocks/needs_iron_tool.json index 58f40dc96..d0bdd018c 100644 --- a/station-vanilla-fix-v0/src/main/resources/data/minecraft/stationapi/tags/blocks/needs_iron_tool.json +++ b/station-vanilla-fix-v0/src/main/resources/data/minecraft/stationapi/tags/blocks/needs_iron_tool.json @@ -1,5 +1,6 @@ { "values": [ + "#needs_stone_tool", "diamond_block", "diamond_ore", "gold_block", From 433fa82c627193c731b648bf0c499937c52e19cb Mon Sep 17 00:00:00 2001 From: mine_diver Date: Wed, 8 May 2024 03:02:38 +0500 Subject: [PATCH 02/22] Mining levels graph --- .../sltest/item/ItemListener.java | 10 +++++- .../tags/blocks/needs_iron_tool.json | 5 --- .../tags/blocks/needs_tool_level_modded.json | 1 - .../api/item/tool/MiningLevelManager.java | 33 +++++++++++++++++++ .../api/item/tool/StationToolMaterial.java | 6 ++-- .../impl/item/ToolEffectivenessImplV1.java | 14 +++----- .../mixin/tools/ToolMaterialMixin.java | 13 ++++---- .../item/tool/VanillaToolFixImpl.java | 16 +++++---- .../tags/blocks/needs_diamond_tool.json | 1 - .../tags/blocks/needs_iron_tool.json | 1 - 10 files changed, 64 insertions(+), 36 deletions(-) delete mode 100644 src/test/resources/data/minecraft/stationapi/tags/blocks/needs_iron_tool.json create mode 100644 station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/MiningLevelManager.java diff --git a/src/test/java/net/modificationstation/sltest/item/ItemListener.java b/src/test/java/net/modificationstation/sltest/item/ItemListener.java index 523a847b3..89a2a712d 100644 --- a/src/test/java/net/modificationstation/sltest/item/ItemListener.java +++ b/src/test/java/net/modificationstation/sltest/item/ItemListener.java @@ -6,6 +6,7 @@ import net.modificationstation.sltest.block.Blocks; import net.modificationstation.sltest.block.VariationBlock; import net.modificationstation.stationapi.api.event.registry.ItemRegistryEvent; +import net.modificationstation.stationapi.api.item.tool.MiningLevelManager; import net.modificationstation.stationapi.api.item.tool.ToolMaterialFactory; import net.modificationstation.stationapi.api.registry.BlockRegistry; import net.modificationstation.stationapi.api.registry.ItemRegistry; @@ -19,8 +20,13 @@ public class ItemListener { @EventListener public void registerItems(ItemRegistryEvent event) { + MiningLevelManager.LevelNode moddedNode = new MiningLevelManager.LevelNode(TagKey.of(BlockRegistry.KEY, NAMESPACE.id("needs_tool_level_modded"))); + MiningLevelManager.GRAPH.putEdge(ToolMaterial.STONE.getMiningLevelNode(), moddedNode); + MiningLevelManager.GRAPH.putEdge(moddedNode, ToolMaterial.IRON.getMiningLevelNode()); + MiningLevelManager.invalidateCache(); + testItem = new ModdedItem(NAMESPACE.id("test_item")).setTranslationKey(NAMESPACE, "testItem"); //8475 - testMaterial = ToolMaterialFactory.create("testMaterial", 3, Integer.MAX_VALUE, Float.MAX_VALUE, Integer.MAX_VALUE - 2).miningLevelTag(TagKey.of(BlockRegistry.KEY, NAMESPACE.id("needs_tool_level_modded"))); + testMaterial = ToolMaterialFactory.create("testMaterial", 3, Integer.MAX_VALUE, Float.MAX_VALUE, Integer.MAX_VALUE - 2).miningLevelNode(moddedNode); testPickaxe = new ModdedPickaxeItem(NAMESPACE.id("test_pickaxe"), testMaterial).setTranslationKey(NAMESPACE, "testPickaxe"); //8476 testNBTItem = new NBTItem(NAMESPACE.id("nbt_item")).setTranslationKey(NAMESPACE, "nbt_item"); //8477 testModelItem = new ModelItem(NAMESPACE.id("model_item")).setMaxCount(1).setTranslationKey(NAMESPACE, "idkSomething"); @@ -32,6 +38,8 @@ public void registerItems(ItemRegistryEvent event) { testShears = new TestShearsItem(NAMESPACE.id("test_shears")).setTranslationKey(NAMESPACE, "test_shears"); pacifistSword = new PacifistSwordItem(NAMESPACE.id("pacifist_sword")).setTranslationKey(NAMESPACE, "pacifist_sword"); dullPickaxe = new DullPickaxeItem(NAMESPACE.id("dull_pickaxe")).setTranslationKey(NAMESPACE, "dull_pickaxe"); + + } public static Item testItem; diff --git a/src/test/resources/data/minecraft/stationapi/tags/blocks/needs_iron_tool.json b/src/test/resources/data/minecraft/stationapi/tags/blocks/needs_iron_tool.json deleted file mode 100644 index 2dd664728..000000000 --- a/src/test/resources/data/minecraft/stationapi/tags/blocks/needs_iron_tool.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "values": [ - "#sltest:needs_tool_level_modded" - ] -} \ No newline at end of file diff --git a/src/test/resources/data/sltest/stationapi/tags/blocks/needs_tool_level_modded.json b/src/test/resources/data/sltest/stationapi/tags/blocks/needs_tool_level_modded.json index b15b2bb24..04f9bde83 100644 --- a/src/test/resources/data/sltest/stationapi/tags/blocks/needs_tool_level_modded.json +++ b/src/test/resources/data/sltest/stationapi/tags/blocks/needs_tool_level_modded.json @@ -1,6 +1,5 @@ { "values": [ - "#needs_stone_tool", "sltest:test_block" ] } \ No newline at end of file diff --git a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/MiningLevelManager.java b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/MiningLevelManager.java new file mode 100644 index 000000000..205f3b7db --- /dev/null +++ b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/MiningLevelManager.java @@ -0,0 +1,33 @@ +package net.modificationstation.stationapi.api.item.tool; + +import com.google.common.graph.GraphBuilder; +import com.google.common.graph.MutableGraph; +import it.unimi.dsi.fastutil.objects.Object2BooleanMap; +import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap; +import lombok.val; +import net.minecraft.block.Block; +import net.modificationstation.stationapi.api.block.BlockState; +import net.modificationstation.stationapi.api.tag.TagKey; + +import java.util.stream.Collectors; + +public final class MiningLevelManager { + public record LevelNode(TagKey blockTag) {} + private record CacheKey(LevelNode levelNode, BlockState state) {} + + public static final MutableGraph GRAPH = GraphBuilder.directed().build(); + private static final Object2BooleanMap CACHE = new Object2BooleanOpenHashMap<>(); + + public static boolean isSuitable(LevelNode levelNode, BlockState state) { + return CACHE.computeIfAbsent(new CacheKey(levelNode, state), (CacheKey key) -> { + val nodes = GRAPH.nodes().stream().filter(node -> key.state.isIn(node.blockTag)).collect(Collectors.toSet()); + if (nodes.isEmpty()) return true; + val pred = GRAPH.predecessors(key.levelNode); + return nodes.stream().anyMatch(node -> key.levelNode.equals(node) || pred.contains(node)); + }); + } + + public static void invalidateCache() { + CACHE.clear(); + } +} diff --git a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationToolMaterial.java b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationToolMaterial.java index e404b21bb..a8aa7d932 100644 --- a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationToolMaterial.java +++ b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/api/item/tool/StationToolMaterial.java @@ -1,16 +1,14 @@ package net.modificationstation.stationapi.api.item.tool; -import net.minecraft.block.Block; import net.minecraft.item.ToolMaterial; -import net.modificationstation.stationapi.api.tag.TagKey; import net.modificationstation.stationapi.api.util.Util; public interface StationToolMaterial { - default ToolMaterial miningLevelTag(TagKey tag) { + default ToolMaterial miningLevelNode(MiningLevelManager.LevelNode levelNode) { return Util.assertImpl(); } - default TagKey getMiningLevelTag() { + default MiningLevelManager.LevelNode getMiningLevelNode() { return Util.assertImpl(); } } diff --git a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/impl/item/ToolEffectivenessImplV1.java b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/impl/item/ToolEffectivenessImplV1.java index 791131f69..9f4d161d6 100644 --- a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/impl/item/ToolEffectivenessImplV1.java +++ b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/impl/item/ToolEffectivenessImplV1.java @@ -1,14 +1,15 @@ package net.modificationstation.stationapi.impl.item; +import com.google.common.graph.GraphBuilder; import net.mine_diver.unsafeevents.listener.EventListener; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.item.ToolMaterial; import net.modificationstation.stationapi.api.StationAPI; import net.modificationstation.stationapi.api.block.BlockState; import net.modificationstation.stationapi.api.event.item.IsItemSuitableForStateEvent; import net.modificationstation.stationapi.api.event.item.ItemMiningSpeedMultiplierOnStateEvent; import net.modificationstation.stationapi.api.event.registry.ItemRegistryEvent; +import net.modificationstation.stationapi.api.item.tool.MiningLevelManager; import net.modificationstation.stationapi.api.item.tool.ToolLevel; import net.modificationstation.stationapi.api.mod.entrypoint.Entrypoint; import net.modificationstation.stationapi.api.mod.entrypoint.EventBusPolicy; @@ -18,7 +19,6 @@ import net.modificationstation.stationapi.api.util.Namespace; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -73,19 +73,13 @@ private static void getStrength(ItemMiningSpeedMultiplierOnStateEvent event) { if (!isSuitable(event.itemStack, event.state)) return; + GraphBuilder.directed().allowsSelfLoops(true).build(); event.miningSpeedMultiplier = ((ToolLevel) event.itemStack.getItem()).getMaterial(event.itemStack).getMiningSpeedMultiplier(); } private static boolean isSuitable(ItemStack item, BlockState state) { return item.getItem() instanceof ToolLevel toolLevel && state.isIn(toolLevel.getEffectiveBlocks(item)) - && - ( - state.isIn(toolLevel.getMaterial(item).getMiningLevelTag()) - || Arrays - .stream(ToolMaterial.values()) - .filter(toolMaterial -> toolMaterial.getMiningLevelTag() != null) - .noneMatch(toolMaterial -> state.isIn(toolMaterial.getMiningLevelTag())) - ); + && MiningLevelManager.isSuitable(toolLevel.getMaterial(item).getMiningLevelNode(), state); } } diff --git a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/mixin/tools/ToolMaterialMixin.java b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/mixin/tools/ToolMaterialMixin.java index 820859da2..aa4265349 100644 --- a/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/mixin/tools/ToolMaterialMixin.java +++ b/station-tools-api-v1/src/main/java/net/modificationstation/stationapi/mixin/tools/ToolMaterialMixin.java @@ -1,27 +1,26 @@ package net.modificationstation.stationapi.mixin.tools; -import net.minecraft.block.Block; import net.minecraft.item.ToolMaterial; +import net.modificationstation.stationapi.api.item.tool.MiningLevelManager; import net.modificationstation.stationapi.api.item.tool.StationToolMaterial; -import net.modificationstation.stationapi.api.tag.TagKey; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; @Mixin(ToolMaterial.class) class ToolMaterialMixin implements StationToolMaterial { @Unique - private TagKey stationapi_miningLevelTag; + private MiningLevelManager.LevelNode stationapi_levelNode; @Override @Unique - public ToolMaterial miningLevelTag(TagKey tag) { - stationapi_miningLevelTag = tag; + public ToolMaterial miningLevelNode(MiningLevelManager.LevelNode levelNode) { + stationapi_levelNode = levelNode; return ToolMaterial.class.cast(this); } @Override @Unique - public TagKey getMiningLevelTag() { - return stationapi_miningLevelTag; + public MiningLevelManager.LevelNode getMiningLevelNode() { + return stationapi_levelNode; } } diff --git a/station-vanilla-fix-v0/src/main/java/net/modificationstation/stationapi/impl/vanillafix/item/tool/VanillaToolFixImpl.java b/station-vanilla-fix-v0/src/main/java/net/modificationstation/stationapi/impl/vanillafix/item/tool/VanillaToolFixImpl.java index 0c9cedfa7..f51cceb4c 100644 --- a/station-vanilla-fix-v0/src/main/java/net/modificationstation/stationapi/impl/vanillafix/item/tool/VanillaToolFixImpl.java +++ b/station-vanilla-fix-v0/src/main/java/net/modificationstation/stationapi/impl/vanillafix/item/tool/VanillaToolFixImpl.java @@ -4,6 +4,7 @@ import net.minecraft.item.ToolMaterial; import net.modificationstation.stationapi.api.StationAPI; import net.modificationstation.stationapi.api.event.registry.ItemRegistryEvent; +import net.modificationstation.stationapi.api.item.tool.MiningLevelManager; import net.modificationstation.stationapi.api.mod.entrypoint.Entrypoint; import net.modificationstation.stationapi.api.mod.entrypoint.EventBusPolicy; import net.modificationstation.stationapi.api.registry.BlockRegistry; @@ -16,11 +17,14 @@ public final class VanillaToolFixImpl { @EventListener private static void fixToolMaterials(ItemRegistryEvent event) { - ToolMaterial stone = ToolMaterial.STONE; - ToolMaterial iron = ToolMaterial.IRON; - ToolMaterial diamond = ToolMaterial.DIAMOND; - stone.miningLevelTag(TagKey.of(BlockRegistry.KEY, of("needs_stone_tool"))); - iron.miningLevelTag(TagKey.of(BlockRegistry.KEY, of("needs_iron_tool"))); - diamond.miningLevelTag(TagKey.of(BlockRegistry.KEY, of("needs_diamond_tool"))); + MiningLevelManager.LevelNode stoneNode = new MiningLevelManager.LevelNode(TagKey.of(BlockRegistry.KEY, of("needs_stone_tool"))); + MiningLevelManager.LevelNode ironNode = new MiningLevelManager.LevelNode(TagKey.of(BlockRegistry.KEY, of("needs_iron_tool"))); + MiningLevelManager.LevelNode diamondNode = new MiningLevelManager.LevelNode(TagKey.of(BlockRegistry.KEY, of("needs_diamond_tool"))); + MiningLevelManager.GRAPH.putEdge(stoneNode, ironNode); + MiningLevelManager.GRAPH.putEdge(ironNode, diamondNode); + MiningLevelManager.invalidateCache(); + ToolMaterial.STONE.miningLevelNode(stoneNode); + ToolMaterial.IRON.miningLevelNode(ironNode); + ToolMaterial.DIAMOND.miningLevelNode(diamondNode); } } diff --git a/station-vanilla-fix-v0/src/main/resources/data/minecraft/stationapi/tags/blocks/needs_diamond_tool.json b/station-vanilla-fix-v0/src/main/resources/data/minecraft/stationapi/tags/blocks/needs_diamond_tool.json index 7e914dc50..54d961641 100644 --- a/station-vanilla-fix-v0/src/main/resources/data/minecraft/stationapi/tags/blocks/needs_diamond_tool.json +++ b/station-vanilla-fix-v0/src/main/resources/data/minecraft/stationapi/tags/blocks/needs_diamond_tool.json @@ -1,6 +1,5 @@ { "values": [ - "#needs_iron_tool", "obsidian" ] } \ No newline at end of file diff --git a/station-vanilla-fix-v0/src/main/resources/data/minecraft/stationapi/tags/blocks/needs_iron_tool.json b/station-vanilla-fix-v0/src/main/resources/data/minecraft/stationapi/tags/blocks/needs_iron_tool.json index d0bdd018c..58f40dc96 100644 --- a/station-vanilla-fix-v0/src/main/resources/data/minecraft/stationapi/tags/blocks/needs_iron_tool.json +++ b/station-vanilla-fix-v0/src/main/resources/data/minecraft/stationapi/tags/blocks/needs_iron_tool.json @@ -1,6 +1,5 @@ { "values": [ - "#needs_stone_tool", "diamond_block", "diamond_ore", "gold_block", From a6dfbdcecfb32bb4b57c2ad1bf44dae91639b732 Mon Sep 17 00:00:00 2001 From: calmilamsy Date: Mon, 8 Jul 2024 17:52:06 +0100 Subject: [PATCH 03/22] Fix a bad mixin declaration in lifecycle events --- .../main/resources/station-lifecycle-events-v0.mixins.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/station-lifecycle-events-v0/src/main/resources/station-lifecycle-events-v0.mixins.json b/station-lifecycle-events-v0/src/main/resources/station-lifecycle-events-v0.mixins.json index bdfda5905..93d37150f 100644 --- a/station-lifecycle-events-v0/src/main/resources/station-lifecycle-events-v0.mixins.json +++ b/station-lifecycle-events-v0/src/main/resources/station-lifecycle-events-v0.mixins.json @@ -3,12 +3,10 @@ "minVersion": "0.8", "package": "net.modificationstation.stationapi.mixin.lifecycle", "compatibilityLevel": "JAVA_17", - "mixins": [ - "server.ServerPlayNetworkHandlerMixin" - ], "server": [ "server.MinecraftServerMixin", - "server.ServerLoginNetworkHandlerMixin" + "server.ServerLoginNetworkHandlerMixin", + "server.ServerPlayNetworkHandlerMixin" ], "client": [ "client.ClientNetworkHandlerMixin", From 6a63f392ef631fa6e8b9366833d35177a7f9b60f Mon Sep 17 00:00:00 2001 From: calmilamsy Date: Tue, 9 Jul 2024 17:39:05 +0100 Subject: [PATCH 04/22] Add RegistriesFrozenEvent --- .../event/registry/RegistriesFrozenEvent.java | 16 ++++++++++++++++ .../mixin/registry/client/MinecraftMixin.java | 3 +++ 2 files changed, 19 insertions(+) create mode 100644 station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/event/registry/RegistriesFrozenEvent.java diff --git a/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/event/registry/RegistriesFrozenEvent.java b/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/event/registry/RegistriesFrozenEvent.java new file mode 100644 index 000000000..d9a13dcd5 --- /dev/null +++ b/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/event/registry/RegistriesFrozenEvent.java @@ -0,0 +1,16 @@ +package net.modificationstation.stationapi.api.event.registry; + +import net.mine_diver.unsafeevents.Event; +import net.mine_diver.unsafeevents.event.EventPhases; +import net.modificationstation.stationapi.api.StationAPI; + +/** + * This is the last init event called by StAPI. + * Called after registries are frozen. + * {@link net.modificationstation.stationapi.mixin.registry.client.MinecraftMixin} + */ +@SuppressWarnings("JavadocReference") // Shut, I know. +@EventPhases(StationAPI.INTERNAL_PHASE) +public class RegistriesFrozenEvent extends Event { + +} diff --git a/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/mixin/registry/client/MinecraftMixin.java b/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/mixin/registry/client/MinecraftMixin.java index e31a1526f..4bb983462 100644 --- a/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/mixin/registry/client/MinecraftMixin.java +++ b/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/mixin/registry/client/MinecraftMixin.java @@ -1,6 +1,8 @@ package net.modificationstation.stationapi.mixin.registry.client; import net.minecraft.client.Minecraft; +import net.modificationstation.stationapi.api.StationAPI; +import net.modificationstation.stationapi.api.event.registry.RegistriesFrozenEvent; import net.modificationstation.stationapi.api.registry.Registries; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -16,5 +18,6 @@ class MinecraftMixin { ) private void stationapi_freeze(CallbackInfo ci) { Registries.bootstrap(); + StationAPI.EVENT_BUS.post(new RegistriesFrozenEvent()); } } From 94629ef628523de24ea81d985ddcf93a018d600d Mon Sep 17 00:00:00 2001 From: Atilist <71230342+Atilist@users.noreply.github.com> Date: Thu, 9 May 2024 16:44:56 +0200 Subject: [PATCH 05/22] Start of Celestial Events Added CelestialEvent. Added the Register Event. Added Test Items. Current Features: - Adjustable Intervals - Day Offset to offset the Interval - Custom Day Length - Custom Chance for successful Activation - Mutually exclusive Events # Conflicts: # src/test/java/net/modificationstation/sltest/item/ItemListener.java --- .../sltest/celestial/CelestialListener.java | 24 +++++++ .../sltest/item/CelestialTestItem.java | 21 ++++++ .../sltest/item/CelestialToggleItem.java | 35 ++++++++++ .../sltest/item/ItemListener.java | 4 ++ src/test/resources/fabric.mod.json | 4 +- .../api/celestial/CelestialEvent.java | 68 +++++++++++++++++++ .../celestial/CelestialRegisterEvent.java | 7 ++ .../mixin/world/WorldPropertiesMixin.java | 11 +++ 8 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java create mode 100644 src/test/java/net/modificationstation/sltest/item/CelestialTestItem.java create mode 100644 src/test/java/net/modificationstation/sltest/item/CelestialToggleItem.java create mode 100644 station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java create mode 100644 station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java diff --git a/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java b/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java new file mode 100644 index 000000000..760d6eaf9 --- /dev/null +++ b/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java @@ -0,0 +1,24 @@ +package net.modificationstation.sltest.celestial; + +import net.mine_diver.unsafeevents.listener.EventListener; +import net.modificationstation.sltest.SLTest; +import net.modificationstation.stationapi.api.celestial.CelestialEvent; +import net.modificationstation.stationapi.api.event.celestial.CelestialRegisterEvent; + +public class CelestialListener { + + private boolean hasRegistered = false; // Workaround to prevent excessive registering + + public static CelestialEvent flyingDimando; + public static CelestialEvent fallingDimando; + + @EventListener + public void registerCelestialEvents(CelestialRegisterEvent event) { + if (hasRegistered) return; + hasRegistered = true; + SLTest.LOGGER.info("Register celestial events for testing"); + flyingDimando = new CelestialEvent(2); + fallingDimando = new CelestialEvent(4); + flyingDimando.addIncompatibleEvent(fallingDimando); + } +} diff --git a/src/test/java/net/modificationstation/sltest/item/CelestialTestItem.java b/src/test/java/net/modificationstation/sltest/item/CelestialTestItem.java new file mode 100644 index 000000000..3c5807852 --- /dev/null +++ b/src/test/java/net/modificationstation/sltest/item/CelestialTestItem.java @@ -0,0 +1,21 @@ +package net.modificationstation.sltest.item; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.modificationstation.sltest.celestial.CelestialListener; +import net.modificationstation.stationapi.api.template.item.TemplateItem; +import net.modificationstation.stationapi.api.util.Identifier; + +public class CelestialTestItem extends TemplateItem { + public CelestialTestItem(Identifier identifier) { + super(identifier); + } + + @Override + public ItemStack use(ItemStack item, World world, PlayerEntity player) { + if (CelestialListener.flyingDimando.isActive()) System.out.println("Event is happening"); + else System.out.println("No event"); + return super.use(item, world, player); + } +} diff --git a/src/test/java/net/modificationstation/sltest/item/CelestialToggleItem.java b/src/test/java/net/modificationstation/sltest/item/CelestialToggleItem.java new file mode 100644 index 000000000..c18c8821e --- /dev/null +++ b/src/test/java/net/modificationstation/sltest/item/CelestialToggleItem.java @@ -0,0 +1,35 @@ +package net.modificationstation.sltest.item; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.modificationstation.sltest.celestial.CelestialListener; +import net.modificationstation.stationapi.api.template.item.TemplateItem; +import net.modificationstation.stationapi.api.util.Identifier; + +public class CelestialToggleItem extends TemplateItem { + public CelestialToggleItem(Identifier identifier) { + super(identifier); + } + + @Override + public ItemStack use(ItemStack item, World world, PlayerEntity player) { + if (CelestialListener.fallingDimando.isActive()) { + CelestialListener.fallingDimando.stopEvent(); + System.out.println("Stopping Falling Dimando"); + } else if (CelestialListener.fallingDimando.activateEvent(world.getTime(), random)) { + System.out.println("Activating Falling Dimando"); + } else { + System.out.println("Falling Dimando not activated"); + } + if (CelestialListener.flyingDimando.isActive()) { + CelestialListener.flyingDimando.stopEvent(); + System.out.println("Stopping Flying Dimando"); + } else if (CelestialListener.flyingDimando.activateEvent(world.getTime(), random)) { + System.out.println("Activating Flying Dimando"); + } else { + System.out.println("Flying Dimando not activated"); + } + return super.use(item, world, player); + } +} diff --git a/src/test/java/net/modificationstation/sltest/item/ItemListener.java b/src/test/java/net/modificationstation/sltest/item/ItemListener.java index 523a847b3..d5dfb3096 100644 --- a/src/test/java/net/modificationstation/sltest/item/ItemListener.java +++ b/src/test/java/net/modificationstation/sltest/item/ItemListener.java @@ -32,6 +32,8 @@ public void registerItems(ItemRegistryEvent event) { testShears = new TestShearsItem(NAMESPACE.id("test_shears")).setTranslationKey(NAMESPACE, "test_shears"); pacifistSword = new PacifistSwordItem(NAMESPACE.id("pacifist_sword")).setTranslationKey(NAMESPACE, "pacifist_sword"); dullPickaxe = new DullPickaxeItem(NAMESPACE.id("dull_pickaxe")).setTranslationKey(NAMESPACE, "dull_pickaxe"); + celestialTestItem = new CelestialTestItem(NAMESPACE.id("test_celestial")).setTranslationKey(NAMESPACE, "test_celestial"); + celestialToggleItem = new CelestialToggleItem(NAMESPACE.id("toggle_celestial")).setTranslationKey(NAMESPACE, "toggle_celestial"); } public static Item testItem; @@ -47,4 +49,6 @@ public void registerItems(ItemRegistryEvent event) { public static Item testShears; public static Item pacifistSword; public static Item dullPickaxe; + public static Item celestialTestItem; + public static Item celestialToggleItem; } diff --git a/src/test/resources/fabric.mod.json b/src/test/resources/fabric.mod.json index e25a35906..b3db2af61 100644 --- a/src/test/resources/fabric.mod.json +++ b/src/test/resources/fabric.mod.json @@ -32,7 +32,9 @@ "net.modificationstation.sltest.item.tool.ToolListener", "net.modificationstation.sltest.datafixer.DataFixerListener", "net.modificationstation.sltest.worldgen.TestWorldgenListener", - "net.modificationstation.sltest.bonemeal.BonemealListener" + "net.modificationstation.sltest.bonemeal.BonemealListener", + "net.modificationstation.sltest.dispenser.DispenserListener", + "net.modificationstation.sltest.celestial.CelestialListener" ], "stationapi:event_bus_client": [ "net.modificationstation.sltest.gui.GuiListener", diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java new file mode 100644 index 000000000..d4b599138 --- /dev/null +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java @@ -0,0 +1,68 @@ +package net.modificationstation.stationapi.api.celestial; + +import java.util.LinkedList; +import java.util.List; +import java.util.Random; + +public class CelestialEvent { + private final int frequency; + private final float chance; + private final int dayLength; + private final int dayOffset; + private boolean active; + private final List incompatibleEvents = new LinkedList<>(); + + public CelestialEvent(int frequency, float chance, int dayLength, int dayOffset) { + this.frequency = frequency; + this.chance = chance; + this.dayLength = dayLength; + this.dayOffset = dayOffset; + } + + public CelestialEvent(int frequency, float chance, int dayLength) { + this(frequency, chance, dayLength, 0); + } + + public CelestialEvent(int frequency, float chance) { + this(frequency, chance, 24000); + } + + public CelestialEvent(int frequency) { + this(frequency, 1); + } + + public boolean activateEvent(long worldTime, Random random) { + if (active) { + return true; + } + for (CelestialEvent otherEvent : incompatibleEvents) { + if (otherEvent == null) continue; + if (otherEvent.isActive()) { + active = false; + return false; + } + } + long days = worldTime / dayLength + dayOffset; + active = days % frequency == 0 && random.nextFloat() <= chance; + return active; + } + + public void stopEvent() { + active = false; + } + + public boolean isActive() { + return active; + } + + /** + * Adds events to prevent them from happening simultaneously. + * Automatically adds incompatibility for both directions. + * @param otherEvent + */ + public void addIncompatibleEvent(CelestialEvent otherEvent) { + if (incompatibleEvents.contains(otherEvent)) return; + incompatibleEvents.add(otherEvent); + otherEvent.addIncompatibleEvent(this); + } +} diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java new file mode 100644 index 000000000..f0d0b72d3 --- /dev/null +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java @@ -0,0 +1,7 @@ +package net.modificationstation.stationapi.api.event.celestial; + +import lombok.experimental.SuperBuilder; +import net.mine_diver.unsafeevents.Event; + +@SuperBuilder +public class CelestialRegisterEvent extends Event {} \ No newline at end of file diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java index f45b3006d..9e64e77bc 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java @@ -3,6 +3,7 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.world.WorldProperties; import net.modificationstation.stationapi.api.StationAPI; +import net.modificationstation.stationapi.api.event.celestial.CelestialRegisterEvent; import net.modificationstation.stationapi.api.event.world.WorldPropertiesEvent; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -37,4 +38,14 @@ private void stationapi_onSaveToTag(NbtCompound arg, NbtCompound arg1, CallbackI .build() ); } + + @Inject( + method = "setTime", + at = @At("HEAD") + ) + private void stationapi_postCelestialEvent(CallbackInfo ci) { // This gets called more than once. Does not really make sense with the way the events work + StationAPI.EVENT_BUS.post( + CelestialRegisterEvent.builder().build() + ); + } } From c798dd1529ea6596e323e89e3bcf61d9a75a57e8 Mon Sep 17 00:00:00 2001 From: Atilist <71230342+Atilist@users.noreply.github.com> Date: Thu, 9 May 2024 18:28:47 +0200 Subject: [PATCH 06/22] Time Manager Added Mixin for CelestialTimeManager. Celestial Events now automatically start and stop if added to the Time Manager. Starting Point can be customized to 4 Times of the Day: - Morning - Noon - Evening - Midnight Events always stop half a Day after they start. Time Manager has been designed to work with abrupt Time Jumps. Added Debug Messages for Event Starts and Stops. Added Name Parameter to CelestialEvent. --- .../sltest/celestial/CelestialListener.java | 7 +- .../api/celestial/CelestialEvent.java | 18 ++- .../api/celestial/CelestialTimeManager.java | 129 ++++++++++++++++++ .../mixin/world/WorldPropertiesMixin.java | 24 ++++ 4 files changed, 169 insertions(+), 9 deletions(-) create mode 100644 station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java diff --git a/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java b/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java index 760d6eaf9..5b2b5f1c1 100644 --- a/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java +++ b/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java @@ -3,6 +3,7 @@ import net.mine_diver.unsafeevents.listener.EventListener; import net.modificationstation.sltest.SLTest; import net.modificationstation.stationapi.api.celestial.CelestialEvent; +import net.modificationstation.stationapi.api.celestial.CelestialTimeManager; import net.modificationstation.stationapi.api.event.celestial.CelestialRegisterEvent; public class CelestialListener { @@ -17,8 +18,10 @@ public void registerCelestialEvents(CelestialRegisterEvent event) { if (hasRegistered) return; hasRegistered = true; SLTest.LOGGER.info("Register celestial events for testing"); - flyingDimando = new CelestialEvent(2); - fallingDimando = new CelestialEvent(4); + flyingDimando = new CelestialEvent(2, "Flying Dimando"); + fallingDimando = new CelestialEvent(4, "Falling Dimando"); flyingDimando.addIncompatibleEvent(fallingDimando); + CelestialTimeManager.addMorningEvent(flyingDimando); + CelestialTimeManager.addNoonEvent(fallingDimando); } } diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java index d4b599138..9feeead61 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java @@ -5,6 +5,7 @@ import java.util.Random; public class CelestialEvent { + private final String name; private final int frequency; private final float chance; private final int dayLength; @@ -12,26 +13,28 @@ public class CelestialEvent { private boolean active; private final List incompatibleEvents = new LinkedList<>(); - public CelestialEvent(int frequency, float chance, int dayLength, int dayOffset) { + public CelestialEvent(int frequency, float chance, int dayLength, int dayOffset, String name) { this.frequency = frequency; this.chance = chance; this.dayLength = dayLength; this.dayOffset = dayOffset; + this.name = name; } - public CelestialEvent(int frequency, float chance, int dayLength) { - this(frequency, chance, dayLength, 0); + public CelestialEvent(int frequency, float chance, int dayLength, String name) { + this(frequency, chance, dayLength, 0, name); } - public CelestialEvent(int frequency, float chance) { - this(frequency, chance, 24000); + public CelestialEvent(int frequency, float chance, String name) { + this(frequency, chance, 24000, name); } - public CelestialEvent(int frequency) { - this(frequency, 1); + public CelestialEvent(int frequency, String name) { + this(frequency, 1, name); } public boolean activateEvent(long worldTime, Random random) { + System.out.println("Attempt activation for event " + name); if (active) { return true; } @@ -48,6 +51,7 @@ public boolean activateEvent(long worldTime, Random random) { } public void stopEvent() { + System.out.println("Stopping event " + name); active = false; } diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java new file mode 100644 index 000000000..ab46646ad --- /dev/null +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java @@ -0,0 +1,129 @@ +package net.modificationstation.stationapi.api.celestial; + +import java.util.LinkedList; +import java.util.List; +import java.util.Random; + +public class CelestialTimeManager { + private static final List MORNING_LIST = new LinkedList<>(); + private static final List NOON_LIST = new LinkedList<>(); + private static final List EVENING_LIST = new LinkedList<>(); + private static final List MIDNIGHT_LIST = new LinkedList<>(); + + private static boolean morningActivation = false; + private static boolean noonActivation = false; + private static boolean eveningActivation = false; + private static boolean midnightActivation = false; + + private static long lastCheckedDay = 0; + + private static final Random RANDOM = new Random(); + + public static void addMorningEvent(CelestialEvent celestialEvent) { + MORNING_LIST.add(celestialEvent); + } + + public static void addNoonEvent(CelestialEvent celestialEvent) { + NOON_LIST.add(celestialEvent); + } + + public static void addEveningEvent(CelestialEvent celestialEvent) { + EVENING_LIST.add(celestialEvent); + } + + public static void addMidnightEvent(CelestialEvent celestialEvent) { + MIDNIGHT_LIST.add(celestialEvent); + } + + public static void startMorningEvents(long time, long currentDay) { + if (morningActivation && lastCheckedDay == currentDay) return; + stopMorningEvents(); + lastCheckedDay = currentDay; + morningActivation = true; + noonActivation = false; + eveningActivation = false; + midnightActivation = false; + for (CelestialEvent celestialEvent : MORNING_LIST) { + if (celestialEvent == null) continue; + celestialEvent.activateEvent(time, RANDOM); + } + stopNoonEvents(); + stopEveningEvents(); + } + + public static void startNoonEvents(long time, long currentDay) { + if (noonActivation && lastCheckedDay == currentDay) return; + stopNoonEvents(); + lastCheckedDay = currentDay; + morningActivation = false; + noonActivation = true; + eveningActivation = false; + midnightActivation = false; + for (CelestialEvent celestialEvent : NOON_LIST) { + if (celestialEvent == null) continue; + celestialEvent.activateEvent(time, RANDOM); + } + stopEveningEvents(); + stopMidnightEvents(); + } + + public static void startEveningEvents(long time, long currentDay) { + if (eveningActivation && lastCheckedDay == currentDay) return; + stopEveningEvents(); + lastCheckedDay = currentDay; + morningActivation = false; + noonActivation = false; + eveningActivation = true; + midnightActivation = false; + for (CelestialEvent celestialEvent : EVENING_LIST) { + if (celestialEvent == null) continue; + celestialEvent.activateEvent(time, RANDOM); + } + stopMidnightEvents(); + stopMorningEvents(); + } + + public static void startMidnightEvents(long time, long currentDay) { + if (midnightActivation && lastCheckedDay == currentDay) return; + stopMidnightEvents(); + lastCheckedDay = currentDay; + morningActivation = false; + noonActivation = false; + eveningActivation = false; + midnightActivation = true; + for (CelestialEvent celestialEvent : MIDNIGHT_LIST) { + if (celestialEvent == null) continue; + celestialEvent.activateEvent(time, RANDOM); + } + stopMorningEvents(); + stopNoonEvents(); + } + + public static void stopMorningEvents() { + for (CelestialEvent celestialEvent : MORNING_LIST) { + if (celestialEvent == null) continue; + celestialEvent.stopEvent(); + } + } + + public static void stopNoonEvents() { + for (CelestialEvent celestialEvent : NOON_LIST) { + if (celestialEvent == null) continue; + celestialEvent.stopEvent(); + } + } + + public static void stopEveningEvents() { + for (CelestialEvent celestialEvent : EVENING_LIST) { + if (celestialEvent == null) continue; + celestialEvent.stopEvent(); + } + } + + public static void stopMidnightEvents() { + for (CelestialEvent celestialEvent : MIDNIGHT_LIST) { + if (celestialEvent == null) continue; + celestialEvent.stopEvent(); + } + } +} diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java index 9e64e77bc..3bce85a8a 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java @@ -3,15 +3,21 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.world.WorldProperties; import net.modificationstation.stationapi.api.StationAPI; +import net.modificationstation.stationapi.api.celestial.CelestialTimeManager; import net.modificationstation.stationapi.api.event.celestial.CelestialRegisterEvent; import net.modificationstation.stationapi.api.event.world.WorldPropertiesEvent; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(WorldProperties.class) public class WorldPropertiesMixin { + @Shadow private long time; + + @Shadow private long lastPlayed; + @Inject( method = "(Lnet/minecraft/nbt/NbtCompound;)V", at = @At("RETURN") @@ -48,4 +54,22 @@ private void stationapi_postCelestialEvent(CallbackInfo ci) { // This gets calle CelestialRegisterEvent.builder().build() ); } + + @Inject( + method = "setTime", + at = @At("HEAD") + ) + private void stationapi_celestialEventTimeManager(CallbackInfo ci) { + long daytime = time % 24000; + long currentDay = time / 24000; + if (daytime >= 0 && daytime < 6000) { + CelestialTimeManager.startMorningEvents(time, currentDay); + } else if (daytime >= 6000 && daytime < 12000) { + CelestialTimeManager.startNoonEvents(time, currentDay); + } else if (daytime >= 12000 && daytime < 18000) { + CelestialTimeManager.startEveningEvents(time, currentDay); + } else if (daytime >= 18000) { + CelestialTimeManager.startMidnightEvents(time, currentDay); + } + } } From d639f065fee0385825bbc8fc03dbe15d4fbc62f0 Mon Sep 17 00:00:00 2001 From: Atilist <71230342+Atilist@users.noreply.github.com> Date: Thu, 9 May 2024 18:49:34 +0200 Subject: [PATCH 07/22] Improved Object Creation and more Tests CelestialEvent now has 1 Constructor and Methods for changing other Values. Fixed Falling Dimando being impossible to happen. Added Spinning Dimando and Burning Dimando. --- .../sltest/celestial/CelestialListener.java | 10 +++++-- .../api/celestial/CelestialEvent.java | 30 +++++++++---------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java b/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java index 5b2b5f1c1..a7731b550 100644 --- a/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java +++ b/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java @@ -12,16 +12,22 @@ public class CelestialListener { public static CelestialEvent flyingDimando; public static CelestialEvent fallingDimando; + public static CelestialEvent spinningDimando; + public static CelestialEvent burningDimando; @EventListener public void registerCelestialEvents(CelestialRegisterEvent event) { if (hasRegistered) return; hasRegistered = true; SLTest.LOGGER.info("Register celestial events for testing"); - flyingDimando = new CelestialEvent(2, "Flying Dimando"); - fallingDimando = new CelestialEvent(4, "Falling Dimando"); + flyingDimando = new CelestialEvent(4, "Flying Dimando"); + fallingDimando = new CelestialEvent(2, "Falling Dimando"); + spinningDimando = new CelestialEvent(4, "Spinning Dimando").setDayOffset(1); + burningDimando = new CelestialEvent(2, "Burning Dimando").setDayOffset(1); flyingDimando.addIncompatibleEvent(fallingDimando); CelestialTimeManager.addMorningEvent(flyingDimando); CelestialTimeManager.addNoonEvent(fallingDimando); + CelestialTimeManager.addEveningEvent(spinningDimando); + CelestialTimeManager.addMidnightEvent(burningDimando); } } diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java index 9feeead61..abf997e08 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java @@ -7,34 +7,33 @@ public class CelestialEvent { private final String name; private final int frequency; - private final float chance; - private final int dayLength; - private final int dayOffset; + private float chance = 1; + private int dayLength = 24000; + private int dayOffset = 0; private boolean active; private final List incompatibleEvents = new LinkedList<>(); - public CelestialEvent(int frequency, float chance, int dayLength, int dayOffset, String name) { + public CelestialEvent(int frequency, String name) { this.frequency = frequency; - this.chance = chance; - this.dayLength = dayLength; - this.dayOffset = dayOffset; this.name = name; } - public CelestialEvent(int frequency, float chance, int dayLength, String name) { - this(frequency, chance, dayLength, 0, name); + public CelestialEvent setChance(float chance) { + this.chance = chance; + return this; } - public CelestialEvent(int frequency, float chance, String name) { - this(frequency, chance, 24000, name); + public CelestialEvent setDayLength(int dayLength) { + this.dayLength = dayLength; + return this; } - public CelestialEvent(int frequency, String name) { - this(frequency, 1, name); + public CelestialEvent setDayOffset(int dayOffset) { + this.dayOffset = dayOffset; + return this; } public boolean activateEvent(long worldTime, Random random) { - System.out.println("Attempt activation for event " + name); if (active) { return true; } @@ -47,11 +46,12 @@ public boolean activateEvent(long worldTime, Random random) { } long days = worldTime / dayLength + dayOffset; active = days % frequency == 0 && random.nextFloat() <= chance; + if (active) System.out.println("Starting event " + name); return active; } public void stopEvent() { - System.out.println("Stopping event " + name); + if (active) System.out.println("Stopping event " + name); active = false; } From 3344e9aa3e20b8f2dc8e7f2f2a6fd9fdd1b85c43 Mon Sep 17 00:00:00 2001 From: Atilist <71230342+Atilist@users.noreply.github.com> Date: Thu, 9 May 2024 23:26:11 +0200 Subject: [PATCH 08/22] Time Management Overhaul Events are now fully flexible with Start and End Time of Day. Events are still updated correctly when Time Jumps happen. It is now possible to make Events last for multiple Days. Added Time Machine to quickly change Time. Added Enumeration for different Times of Day. --- .../sltest/block/Blocks.java | 4 +- .../sltest/block/TimeMachineBlock.java | 19 ++++ .../sltest/celestial/CelestialListener.java | 13 ++- .../sltest/texture/TextureListener.java | 1 + .../assets/sltest/stationapi/lang/en_US.lang | 3 +- .../textures/blocks/timeMachineBlock.png | Bin 0 -> 312 bytes .../api/celestial/CelestialEvent.java | 30 ++++++- .../api/celestial/CelestialTimeManager.java | 83 ++++++------------ .../stationapi/api/celestial/DayQuarter.java | 5 ++ 9 files changed, 91 insertions(+), 67 deletions(-) create mode 100644 src/test/java/net/modificationstation/sltest/block/TimeMachineBlock.java create mode 100644 src/test/resources/assets/sltest/stationapi/textures/blocks/timeMachineBlock.png create mode 100644 station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/DayQuarter.java diff --git a/src/test/java/net/modificationstation/sltest/block/Blocks.java b/src/test/java/net/modificationstation/sltest/block/Blocks.java index 278cf6bfd..4fe7810b3 100644 --- a/src/test/java/net/modificationstation/sltest/block/Blocks.java +++ b/src/test/java/net/modificationstation/sltest/block/Blocks.java @@ -22,7 +22,9 @@ public enum Blocks { FREEZER("freezer", "freezer", id -> new BlockFreezer(id).setHardness(2.5F).setSoundGroup(TemplateBlock.DEFAULT_SOUND_GROUP)), ALTAR("altar", "altar", id -> new BlockAltar(id, Material.STONE).setHardness(3)), VARIATION_BLOCK("variation_block", "variationBlock", id -> new VariationBlock(id, Material.STONE).setHardness(.5F).setSoundGroup(Block.DEFAULT_SOUND_GROUP).disableAutoItemRegistration()), - EMISSION_CHECKER("emission_checker", "emissionChecker", LampBlock::new); + EMISSION_CHECKER("emission_checker", "emissionChecker", LampBlock::new), + INDISPENSABLE_BLOCK("indispensable_block", "indispensableBlock", IndispensableBlock::new), + TIME_MACHINE_BLOCK("time_machine_block", "timeMachineBlock", TimeMachineBlock::new); private final Runnable register; private Block block; diff --git a/src/test/java/net/modificationstation/sltest/block/TimeMachineBlock.java b/src/test/java/net/modificationstation/sltest/block/TimeMachineBlock.java new file mode 100644 index 000000000..333eac16a --- /dev/null +++ b/src/test/java/net/modificationstation/sltest/block/TimeMachineBlock.java @@ -0,0 +1,19 @@ +package net.modificationstation.sltest.block; + +import net.minecraft.block.Material; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.world.World; +import net.modificationstation.stationapi.api.template.block.TemplateBlock; +import net.modificationstation.stationapi.api.util.Identifier; + +public class TimeMachineBlock extends TemplateBlock { + public TimeMachineBlock(Identifier identifier) { + super(identifier, Material.METAL); + } + + @Override + public boolean onUse(World world, int x, int y, int z, PlayerEntity player) { + world.setTime(world.getTime() + 1000); + return true; + } +} diff --git a/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java b/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java index a7731b550..3cc47af61 100644 --- a/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java +++ b/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java @@ -4,6 +4,7 @@ import net.modificationstation.sltest.SLTest; import net.modificationstation.stationapi.api.celestial.CelestialEvent; import net.modificationstation.stationapi.api.celestial.CelestialTimeManager; +import net.modificationstation.stationapi.api.celestial.DayQuarter; import net.modificationstation.stationapi.api.event.celestial.CelestialRegisterEvent; public class CelestialListener { @@ -14,6 +15,7 @@ public class CelestialListener { public static CelestialEvent fallingDimando; public static CelestialEvent spinningDimando; public static CelestialEvent burningDimando; + public static CelestialEvent longDimando; @EventListener public void registerCelestialEvents(CelestialRegisterEvent event) { @@ -24,10 +26,13 @@ public void registerCelestialEvents(CelestialRegisterEvent event) { fallingDimando = new CelestialEvent(2, "Falling Dimando"); spinningDimando = new CelestialEvent(4, "Spinning Dimando").setDayOffset(1); burningDimando = new CelestialEvent(2, "Burning Dimando").setDayOffset(1); + longDimando = new CelestialEvent(12, "Long Dimando").setExtraDays(4); flyingDimando.addIncompatibleEvent(fallingDimando); - CelestialTimeManager.addMorningEvent(flyingDimando); - CelestialTimeManager.addNoonEvent(fallingDimando); - CelestialTimeManager.addEveningEvent(spinningDimando); - CelestialTimeManager.addMidnightEvent(burningDimando); + spinningDimando.addIncompatibleEvent(burningDimando); + CelestialTimeManager.addCelestialEvent(flyingDimando, DayQuarter.MORNING, DayQuarter.MORNING); + CelestialTimeManager.addCelestialEvent(fallingDimando, DayQuarter.NOON, DayQuarter.MIDNIGHT); + CelestialTimeManager.addCelestialEvent(spinningDimando, DayQuarter.EVENING, DayQuarter.NOON); + CelestialTimeManager.addCelestialEvent(burningDimando, DayQuarter.MIDNIGHT, DayQuarter.EVENING); + CelestialTimeManager.addCelestialEvent(longDimando, DayQuarter.MIDNIGHT, DayQuarter.MIDNIGHT); } } diff --git a/src/test/java/net/modificationstation/sltest/texture/TextureListener.java b/src/test/java/net/modificationstation/sltest/texture/TextureListener.java index 308c04099..08a9a4e61 100644 --- a/src/test/java/net/modificationstation/sltest/texture/TextureListener.java +++ b/src/test/java/net/modificationstation/sltest/texture/TextureListener.java @@ -25,6 +25,7 @@ public void registerTextures(TextureRegisterEvent event) { TEST_ANIMATED_BLOCK.get().textureId = terrain.addTexture(of(NAMESPACE, "blocks/testAnimatedBlock")).index; FREEZER.get().textureId = terrain.addTexture(of(NAMESPACE, "blocks/FreezerTop")).index; ((BlockFreezer) FREEZER.get()).sideTexture = terrain.addTexture(of(NAMESPACE, "blocks/FreezerSide")).index; + TIME_MACHINE_BLOCK.get().textureId = terrain.addTexture(of(NAMESPACE, "blocks/timeMachineBlock")).index; altarTextures[Direction.DOWN.ordinal()] = terrain.addTexture(of(NAMESPACE, "blocks/altar_bottom")).index; altarTextures[Direction.UP.ordinal()] = terrain.addTexture(of(NAMESPACE, "blocks/altar_top")).index; diff --git a/src/test/resources/assets/sltest/stationapi/lang/en_US.lang b/src/test/resources/assets/sltest/stationapi/lang/en_US.lang index 93dd6cc4a..1bba96a15 100644 --- a/src/test/resources/assets/sltest/stationapi/lang/en_US.lang +++ b/src/test/resources/assets/sltest/stationapi/lang/en_US.lang @@ -17,4 +17,5 @@ item.@.variationBlockPassive.name=Variation Block Passive item.@.variationBlockActive.name=Variation Block Active item.@.test_shears.name=Test Shears item.@.pacifist_sword.name=Pacifist Sword -item.@.dull_pickaxe.name=Dull Pickaxe \ No newline at end of file +item.@.dull_pickaxe.name=Dull Pickaxe +tile.@.timeMachineBlock.name=Time Machine diff --git a/src/test/resources/assets/sltest/stationapi/textures/blocks/timeMachineBlock.png b/src/test/resources/assets/sltest/stationapi/textures/blocks/timeMachineBlock.png new file mode 100644 index 0000000000000000000000000000000000000000..e8743cf6e0d40bd5561c6fedfdb0bdc24affa032 GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G}Z0G|-o_V)IMh6WcG{uL`$Y}l~j-n|KP=gwWcc=3NAU|@Lo@S(9WcSS`7 z!~g%2CQbU!kXKYBu^~ru-#*P*i4nJ@ErzW#^d=bQh<(xybANZ#ftKIN8Mz!QyjA_`%W{tp?F|Q?IT1Ary4Za! z+a;!}`){;Z>BxFNtG)l8tMPGo$%Flh7w5_9RxtEPyiId4vuF>QCm6iQIA!0vGfSr? zpHp1+>3QPRx3eBuy>#`yt6j-?X|>eP=XC*3IQB3m?`LmOE)uB#x{1Nl)z4*}Q$iB} DJG6aL literal 0 HcmV?d00001 diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java index abf997e08..6b9e23ba8 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java @@ -10,6 +10,9 @@ public class CelestialEvent { private float chance = 1; private int dayLength = 24000; private int dayOffset = 0; + private int startingDaytime = 0; + private int endingDaytime = 0; + private int extraDays = 0; private boolean active; private final List incompatibleEvents = new LinkedList<>(); @@ -33,6 +36,11 @@ public CelestialEvent setDayOffset(int dayOffset) { return this; } + public CelestialEvent setExtraDays(int extraDays) { + this.extraDays = extraDays; + return this; + } + public boolean activateEvent(long worldTime, Random random) { if (active) { return true; @@ -46,13 +54,29 @@ public boolean activateEvent(long worldTime, Random random) { } long days = worldTime / dayLength + dayOffset; active = days % frequency == 0 && random.nextFloat() <= chance; - if (active) System.out.println("Starting event " + name); + if (active) System.out.println(name + " has begun"); return active; } + public void updateEvent(long worldTime) { + if (!active) return; + worldTime -= startingDaytime; + worldTime += endingDaytime; + long days = worldTime / dayLength + dayOffset; + active = days % frequency <= extraDays; + if (!active) System.out.println(name + " is over"); + } + public void stopEvent() { - if (active) System.out.println("Stopping event " + name); - active = false; + if (active) { + System.out.println("Stopping event " + name); + active = false; + } + } + + public void setInterval(int startingDaytime, int endingDaytime) { + this.startingDaytime = startingDaytime; + this.endingDaytime = endingDaytime; } public boolean isActive() { diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java index ab46646ad..556237ab3 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java @@ -5,10 +5,11 @@ import java.util.Random; public class CelestialTimeManager { - private static final List MORNING_LIST = new LinkedList<>(); - private static final List NOON_LIST = new LinkedList<>(); - private static final List EVENING_LIST = new LinkedList<>(); - private static final List MIDNIGHT_LIST = new LinkedList<>(); + private static final List MORNING_START = new LinkedList<>(); + private static final List NOON_START = new LinkedList<>(); + private static final List EVENING_START = new LinkedList<>(); + private static final List MIDNIGHT_START = new LinkedList<>(); + private static final List ALL_EVENTS = new LinkedList<>(); private static boolean morningActivation = false; private static boolean noonActivation = false; @@ -19,111 +20,77 @@ public class CelestialTimeManager { private static final Random RANDOM = new Random(); - public static void addMorningEvent(CelestialEvent celestialEvent) { - MORNING_LIST.add(celestialEvent); - } - - public static void addNoonEvent(CelestialEvent celestialEvent) { - NOON_LIST.add(celestialEvent); - } - - public static void addEveningEvent(CelestialEvent celestialEvent) { - EVENING_LIST.add(celestialEvent); - } - - public static void addMidnightEvent(CelestialEvent celestialEvent) { - MIDNIGHT_LIST.add(celestialEvent); + public static void addCelestialEvent(CelestialEvent celestialEvent, DayQuarter start, DayQuarter stop) { + switch (start) { + case MORNING -> MORNING_START.add(celestialEvent); + case NOON -> NOON_START.add(celestialEvent); + case EVENING -> EVENING_START.add(celestialEvent); + case MIDNIGHT -> MIDNIGHT_START.add(celestialEvent); + } + ALL_EVENTS.add(celestialEvent); + celestialEvent.setInterval(start.ordinal() * 6000, Math.abs(stop.ordinal() * 6000 - start.ordinal() * 6000)); } public static void startMorningEvents(long time, long currentDay) { if (morningActivation && lastCheckedDay == currentDay) return; - stopMorningEvents(); lastCheckedDay = currentDay; morningActivation = true; noonActivation = false; eveningActivation = false; midnightActivation = false; - for (CelestialEvent celestialEvent : MORNING_LIST) { + updateEvents(time); + for (CelestialEvent celestialEvent : MORNING_START) { if (celestialEvent == null) continue; celestialEvent.activateEvent(time, RANDOM); } - stopNoonEvents(); - stopEveningEvents(); } public static void startNoonEvents(long time, long currentDay) { if (noonActivation && lastCheckedDay == currentDay) return; - stopNoonEvents(); lastCheckedDay = currentDay; morningActivation = false; noonActivation = true; eveningActivation = false; midnightActivation = false; - for (CelestialEvent celestialEvent : NOON_LIST) { + updateEvents(time); + for (CelestialEvent celestialEvent : NOON_START) { if (celestialEvent == null) continue; celestialEvent.activateEvent(time, RANDOM); } - stopEveningEvents(); - stopMidnightEvents(); } public static void startEveningEvents(long time, long currentDay) { if (eveningActivation && lastCheckedDay == currentDay) return; - stopEveningEvents(); lastCheckedDay = currentDay; morningActivation = false; noonActivation = false; eveningActivation = true; midnightActivation = false; - for (CelestialEvent celestialEvent : EVENING_LIST) { + updateEvents(time); + for (CelestialEvent celestialEvent : EVENING_START) { if (celestialEvent == null) continue; celestialEvent.activateEvent(time, RANDOM); } - stopMidnightEvents(); - stopMorningEvents(); } public static void startMidnightEvents(long time, long currentDay) { if (midnightActivation && lastCheckedDay == currentDay) return; - stopMidnightEvents(); lastCheckedDay = currentDay; morningActivation = false; noonActivation = false; eveningActivation = false; midnightActivation = true; - for (CelestialEvent celestialEvent : MIDNIGHT_LIST) { + updateEvents(time); + for (CelestialEvent celestialEvent : MIDNIGHT_START) { if (celestialEvent == null) continue; celestialEvent.activateEvent(time, RANDOM); } - stopMorningEvents(); - stopNoonEvents(); - } - - public static void stopMorningEvents() { - for (CelestialEvent celestialEvent : MORNING_LIST) { - if (celestialEvent == null) continue; - celestialEvent.stopEvent(); - } - } - - public static void stopNoonEvents() { - for (CelestialEvent celestialEvent : NOON_LIST) { - if (celestialEvent == null) continue; - celestialEvent.stopEvent(); - } - } - - public static void stopEveningEvents() { - for (CelestialEvent celestialEvent : EVENING_LIST) { - if (celestialEvent == null) continue; - celestialEvent.stopEvent(); - } } - public static void stopMidnightEvents() { - for (CelestialEvent celestialEvent : MIDNIGHT_LIST) { + public static void updateEvents(long time) { + for (CelestialEvent celestialEvent : ALL_EVENTS) { if (celestialEvent == null) continue; - celestialEvent.stopEvent(); + celestialEvent.updateEvent(time); } } } diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/DayQuarter.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/DayQuarter.java new file mode 100644 index 000000000..61acb9948 --- /dev/null +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/DayQuarter.java @@ -0,0 +1,5 @@ +package net.modificationstation.stationapi.api.celestial; + +public enum DayQuarter { + MORNING, NOON, EVENING, MIDNIGHT +} From d15a44f8b152025d70ddb119055df1901eb192c6 Mon Sep 17 00:00:00 2001 From: Atilist <71230342+Atilist@users.noreply.github.com> Date: Wed, 22 May 2024 21:37:33 +0200 Subject: [PATCH 09/22] New useful Methods and more Examples Added onActivation and onDeactivation to call Actions precisely at the Start and End of an Event. Made CelestialRegisterEvent extend WorldEvent to get Access to the World. Celestial Events can now directly access the World. Moved the Posting of CelestialRegisterEvent into the WorldMixin. Added all Sorts of Changes to Game Mechanics for the Test Events. Moved some Debug Prints into a Test Mod Class. Started Work on a Saving System for the Activity State, currently unfinished. --- .../sltest/block/TimeMachineBlock.java | 15 ++++++ .../sltest/celestial/CelestialListener.java | 17 ++++--- .../sltest/celestial/DebugCelestialEvent.java | 22 +++++++++ .../sltest/celestial/FlyingDimando.java | 16 +++++++ .../sltest/mixin/EntityMixin.java | 48 +++++++++++++++++++ .../sltest/mixin/GrassBlockMixin.java | 26 ++++++++++ src/test/resources/sltest.mixins.json | 4 +- .../api/celestial/CelestialEvent.java | 34 +++++++++++-- .../CelestialEventActivityState.java | 22 +++++++++ .../celestial/CelestialRegisterEvent.java | 4 +- .../stationapi/mixin/world/WorldMixin.java | 4 ++ .../mixin/world/WorldPropertiesMixin.java | 10 ---- 12 files changed, 197 insertions(+), 25 deletions(-) create mode 100644 src/test/java/net/modificationstation/sltest/celestial/DebugCelestialEvent.java create mode 100644 src/test/java/net/modificationstation/sltest/celestial/FlyingDimando.java create mode 100644 src/test/java/net/modificationstation/sltest/mixin/EntityMixin.java create mode 100644 src/test/java/net/modificationstation/sltest/mixin/GrassBlockMixin.java create mode 100644 station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java diff --git a/src/test/java/net/modificationstation/sltest/block/TimeMachineBlock.java b/src/test/java/net/modificationstation/sltest/block/TimeMachineBlock.java index 333eac16a..3b560608c 100644 --- a/src/test/java/net/modificationstation/sltest/block/TimeMachineBlock.java +++ b/src/test/java/net/modificationstation/sltest/block/TimeMachineBlock.java @@ -1,14 +1,21 @@ package net.modificationstation.sltest.block; import net.minecraft.block.Material; +import net.minecraft.entity.ItemEntity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; import net.minecraft.world.World; +import net.modificationstation.sltest.celestial.CelestialListener; import net.modificationstation.stationapi.api.template.block.TemplateBlock; import net.modificationstation.stationapi.api.util.Identifier; +import java.util.Random; + public class TimeMachineBlock extends TemplateBlock { public TimeMachineBlock(Identifier identifier) { super(identifier, Material.METAL); + this.setTickRandomly(true); } @Override @@ -16,4 +23,12 @@ public boolean onUse(World world, int x, int y, int z, PlayerEntity player) { world.setTime(world.getTime() + 1000); return true; } + + @Override + public void onTick(World world, int x, int y, int z, Random random) { + super.onTick(world, x, y, z, random); + if (CelestialListener.flyingDimando.isActive()) { + world.method_287(new ItemEntity(world, x + 0.5, y + 1, z + 0.5, new ItemStack(Item.DIAMOND))); + } + } } diff --git a/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java b/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java index 3cc47af61..f091b8e8c 100644 --- a/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java +++ b/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java @@ -8,8 +8,7 @@ import net.modificationstation.stationapi.api.event.celestial.CelestialRegisterEvent; public class CelestialListener { - - private boolean hasRegistered = false; // Workaround to prevent excessive registering + private boolean alreadyRegistered = false; public static CelestialEvent flyingDimando; public static CelestialEvent fallingDimando; @@ -19,14 +18,14 @@ public class CelestialListener { @EventListener public void registerCelestialEvents(CelestialRegisterEvent event) { - if (hasRegistered) return; - hasRegistered = true; + if (alreadyRegistered) return; + alreadyRegistered = true; SLTest.LOGGER.info("Register celestial events for testing"); - flyingDimando = new CelestialEvent(4, "Flying Dimando"); - fallingDimando = new CelestialEvent(2, "Falling Dimando"); - spinningDimando = new CelestialEvent(4, "Spinning Dimando").setDayOffset(1); - burningDimando = new CelestialEvent(2, "Burning Dimando").setDayOffset(1); - longDimando = new CelestialEvent(12, "Long Dimando").setExtraDays(4); + flyingDimando = new FlyingDimando(4, "flying_dimando", event.world); + fallingDimando = new DebugCelestialEvent(2, "falling_dimando", event.world); + spinningDimando = new DebugCelestialEvent(4, "spinning_dimando", event.world).setDayOffset(1); + burningDimando = new DebugCelestialEvent(2, "burning_dimando", event.world).setDayOffset(1); + longDimando = new DebugCelestialEvent(12, "long_dimando", event.world).setExtraDays(4); flyingDimando.addIncompatibleEvent(fallingDimando); spinningDimando.addIncompatibleEvent(burningDimando); CelestialTimeManager.addCelestialEvent(flyingDimando, DayQuarter.MORNING, DayQuarter.MORNING); diff --git a/src/test/java/net/modificationstation/sltest/celestial/DebugCelestialEvent.java b/src/test/java/net/modificationstation/sltest/celestial/DebugCelestialEvent.java new file mode 100644 index 000000000..c854bd3a4 --- /dev/null +++ b/src/test/java/net/modificationstation/sltest/celestial/DebugCelestialEvent.java @@ -0,0 +1,22 @@ +package net.modificationstation.sltest.celestial; + +import net.minecraft.world.World; +import net.modificationstation.stationapi.api.celestial.CelestialEvent; + +public class DebugCelestialEvent extends CelestialEvent { + public DebugCelestialEvent(int frequency, String name, World world) { + super(frequency, name, world); + } + + @Override + public void onActivation() { + super.onActivation(); + System.out.println(this.getName() + " has begun"); + } + + @Override + public void onDeactivation() { + super.onDeactivation(); + System.out.println(this.getName() + " is over"); + } +} diff --git a/src/test/java/net/modificationstation/sltest/celestial/FlyingDimando.java b/src/test/java/net/modificationstation/sltest/celestial/FlyingDimando.java new file mode 100644 index 000000000..7eb289f0d --- /dev/null +++ b/src/test/java/net/modificationstation/sltest/celestial/FlyingDimando.java @@ -0,0 +1,16 @@ +package net.modificationstation.sltest.celestial; + +import net.minecraft.world.World; + +public class FlyingDimando extends DebugCelestialEvent { + public FlyingDimando(int frequency, String name, World world) { + super(frequency, name, world); + } + + @Override + public void onActivation() { + super.onActivation(); + world.method_262().setRaining(true); + world.method_262().setRainTime(200); + } +} diff --git a/src/test/java/net/modificationstation/sltest/mixin/EntityMixin.java b/src/test/java/net/modificationstation/sltest/mixin/EntityMixin.java new file mode 100644 index 000000000..c9a3352cd --- /dev/null +++ b/src/test/java/net/modificationstation/sltest/mixin/EntityMixin.java @@ -0,0 +1,48 @@ +package net.modificationstation.sltest.mixin; + +import net.minecraft.entity.Entity; +import net.modificationstation.sltest.celestial.CelestialListener; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Entity.class) +public class EntityMixin { + + @Shadow public float yaw; + + @Shadow public float pitch; + + @Shadow public double velocityY; + + @Shadow public double velocityX; + + @Shadow public double velocityZ; + + @Inject( + method = "tick", + at = @At("HEAD") + ) + public void spinEntity(CallbackInfo ci) { + if (CelestialListener.spinningDimando.isActive()) { + this.yaw = (this.yaw + 0.1F) % 360.0F; + this.pitch = (this.pitch + 0.1F) % 360.0F; + } + if (CelestialListener.flyingDimando.isActive()) { + if (this.velocityY < 0.5F) { + this.velocityY += 0.05F; + } + } + if (CelestialListener.fallingDimando.isActive()) { + if (this.velocityY > -0.1F) { + this.velocityY -= 0.05F; + } + } + if (CelestialListener.longDimando.isActive()) { + this.velocityX *= 1.1F; + this.velocityZ *= 1.1F; + } + } +} diff --git a/src/test/java/net/modificationstation/sltest/mixin/GrassBlockMixin.java b/src/test/java/net/modificationstation/sltest/mixin/GrassBlockMixin.java new file mode 100644 index 000000000..ba743a569 --- /dev/null +++ b/src/test/java/net/modificationstation/sltest/mixin/GrassBlockMixin.java @@ -0,0 +1,26 @@ +package net.modificationstation.sltest.mixin; + +import net.minecraft.block.Block; +import net.minecraft.block.GrassBlock; +import net.minecraft.world.World; +import net.modificationstation.sltest.celestial.CelestialListener; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Random; + +@Mixin(GrassBlock.class) +public class GrassBlockMixin { + @Inject( + method = "onTick", + at = @At("TAIL") + ) + public void setStuffOnFire(World world, int x, int y, int z, Random random, CallbackInfo ci) { + if (CelestialListener.burningDimando.isActive()) { + if (random.nextInt(100) == 0 && world.getBlockId(x, y + 1, z) == 0) world.method_200(x, y + 1, z, Block.FIRE.id); + } + } + +} diff --git a/src/test/resources/sltest.mixins.json b/src/test/resources/sltest.mixins.json index 483f20575..8268c2b53 100644 --- a/src/test/resources/sltest.mixins.json +++ b/src/test/resources/sltest.mixins.json @@ -8,7 +8,9 @@ "MixinLevel", "MixinNetherLevelSource", "MixinObsidian", - "OverworldTestMixin" + "OverworldTestMixin", + "GrassBlockMixin", + "EntityMixin" ], "server": [ ], diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java index 6b9e23ba8..4da8323c1 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java @@ -1,5 +1,7 @@ package net.modificationstation.stationapi.api.celestial; +import net.minecraft.world.World; + import java.util.LinkedList; import java.util.List; import java.util.Random; @@ -15,10 +17,12 @@ public class CelestialEvent { private int extraDays = 0; private boolean active; private final List incompatibleEvents = new LinkedList<>(); + public final World world; - public CelestialEvent(int frequency, String name) { + public CelestialEvent(int frequency, String name, World world) { this.frequency = frequency; this.name = name; + this.world = world; } public CelestialEvent setChance(float chance) { @@ -54,20 +58,40 @@ public boolean activateEvent(long worldTime, Random random) { } long days = worldTime / dayLength + dayOffset; active = days % frequency == 0 && random.nextFloat() <= chance; - if (active) System.out.println(name + " has begun"); + if (active) { + onActivation(); + } return active; } + public void onActivation() { + } + + public void onDeactivation() { + } + public void updateEvent(long worldTime) { + /* + This piece of code for saving the activity state should probably be moved somewhere else. It is also incomplete and not fully functional + CelestialEventActivityState activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); + if (activityState == null) { + activityState = new CelestialEventActivityState(this.name); + this.world.setState(this.name, activityState); + System.out.println("Did not find activity state"); + } else { + System.out.println("Found existing activity state"); + } + */ if (!active) return; worldTime -= startingDaytime; worldTime += endingDaytime; long days = worldTime / dayLength + dayOffset; active = days % frequency <= extraDays; - if (!active) System.out.println(name + " is over"); + if (!active) onDeactivation(); } public void stopEvent() { + onDeactivation(); if (active) { System.out.println("Stopping event " + name); active = false; @@ -83,6 +107,10 @@ public boolean isActive() { return active; } + public String getName() { + return this.name; + } + /** * Adds events to prevent them from happening simultaneously. * Automatically adds incompatibility for both directions. diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java new file mode 100644 index 000000000..2c18dfb59 --- /dev/null +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java @@ -0,0 +1,22 @@ +package net.modificationstation.stationapi.api.celestial; + +import net.minecraft.nbt.NbtCompound; +import net.minecraft.world.PersistentState; + +public class CelestialEventActivityState extends PersistentState { + public boolean active; + + public CelestialEventActivityState(String id) { + super(id); + } + + @Override + public void readNbt(NbtCompound nbt) { + this.active = nbt.getBoolean("active"); + } + + @Override + public void writeNbt(NbtCompound nbt) { + nbt.putBoolean("active", active); + } +} diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java index f0d0b72d3..e421a0c72 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java @@ -1,7 +1,7 @@ package net.modificationstation.stationapi.api.event.celestial; import lombok.experimental.SuperBuilder; -import net.mine_diver.unsafeevents.Event; +import net.modificationstation.stationapi.api.event.world.WorldEvent; @SuperBuilder -public class CelestialRegisterEvent extends Event {} \ No newline at end of file +public class CelestialRegisterEvent extends WorldEvent {} \ No newline at end of file diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java index 8e41280c1..3eee7a60b 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java @@ -2,6 +2,7 @@ import net.minecraft.world.World; import net.modificationstation.stationapi.api.StationAPI; +import net.modificationstation.stationapi.api.event.celestial.CelestialRegisterEvent; import net.modificationstation.stationapi.api.event.world.WorldEvent; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -20,6 +21,9 @@ class WorldMixin { ) private void stationapi_onCor1(CallbackInfo ci) { StationAPI.EVENT_BUS.post(WorldEvent.Init.builder().world(World.class.cast(this)).build()); + StationAPI.EVENT_BUS.post( + CelestialRegisterEvent.builder().world(World.class.cast(this)).build() + ); } @Inject( diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java index 3bce85a8a..02a0c25cd 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java @@ -45,16 +45,6 @@ private void stationapi_onSaveToTag(NbtCompound arg, NbtCompound arg1, CallbackI ); } - @Inject( - method = "setTime", - at = @At("HEAD") - ) - private void stationapi_postCelestialEvent(CallbackInfo ci) { // This gets called more than once. Does not really make sense with the way the events work - StationAPI.EVENT_BUS.post( - CelestialRegisterEvent.builder().build() - ); - } - @Inject( method = "setTime", at = @At("HEAD") From a0829db4894221a29e35b7803c343d030e78d57e Mon Sep 17 00:00:00 2001 From: Atilist <71230342+Atilist@users.noreply.github.com> Date: Fri, 24 May 2024 19:44:12 +0200 Subject: [PATCH 10/22] Functional Saving and Loading Celestial Events now save and load their Activity Status from NBT, meaning that their Activity gets preserved after closing the Game. Added Initialization Logic to ensure correct Loading of NBT Data when the Game is started. --- .../api/celestial/CelestialEvent.java | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java index 4da8323c1..fc4833f60 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java @@ -16,6 +16,7 @@ public class CelestialEvent { private int endingDaytime = 0; private int extraDays = 0; private boolean active; + private boolean initializationNeeded = true; private final List incompatibleEvents = new LinkedList<>(); public final World world; @@ -71,25 +72,32 @@ public void onDeactivation() { } public void updateEvent(long worldTime) { - /* - This piece of code for saving the activity state should probably be moved somewhere else. It is also incomplete and not fully functional CelestialEventActivityState activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); - if (activityState == null) { - activityState = new CelestialEventActivityState(this.name); - this.world.setState(this.name, activityState); - System.out.println("Did not find activity state"); - } else { - System.out.println("Found existing activity state"); + if (initializationNeeded) { + activityState = initializeEvent(activityState); } - */ if (!active) return; worldTime -= startingDaytime; worldTime += endingDaytime; long days = worldTime / dayLength + dayOffset; active = days % frequency <= extraDays; + activityState.active = active; + activityState.markDirty(); if (!active) onDeactivation(); } + private CelestialEventActivityState initializeEvent(CelestialEventActivityState activityState) { + initializationNeeded = false; + activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); + if (activityState == null) { + activityState = new CelestialEventActivityState(this.name); + this.world.setState(this.name, activityState); + } else { + active = activityState.active; + } + return activityState; + } + public void stopEvent() { onDeactivation(); if (active) { From d5d9f1077f22294838dc3db09d422306ff590b44 Mon Sep 17 00:00:00 2001 From: Atilist <71230342+Atilist@users.noreply.github.com> Date: Fri, 24 May 2024 20:58:27 +0200 Subject: [PATCH 11/22] Improvements to Saving and Loading Fixed incorrect Loading for Edge Cases. Fixed Activation Method not properly saving the Activity State. Added State for attempted Activation to ensure that Events do not activate again when it already was attempted in the valid Time Frame. Event Registering and Time Management now automatically clean themselves up. --- .../sltest/celestial/CelestialListener.java | 3 -- .../api/celestial/CelestialEvent.java | 30 +++++++++++++++++-- .../CelestialEventActivityState.java | 3 ++ .../api/celestial/CelestialTimeManager.java | 15 ++++++++++ .../stationapi/mixin/world/WorldMixin.java | 7 +++-- 5 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java b/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java index f091b8e8c..6aa477783 100644 --- a/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java +++ b/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java @@ -8,7 +8,6 @@ import net.modificationstation.stationapi.api.event.celestial.CelestialRegisterEvent; public class CelestialListener { - private boolean alreadyRegistered = false; public static CelestialEvent flyingDimando; public static CelestialEvent fallingDimando; @@ -18,8 +17,6 @@ public class CelestialListener { @EventListener public void registerCelestialEvents(CelestialRegisterEvent event) { - if (alreadyRegistered) return; - alreadyRegistered = true; SLTest.LOGGER.info("Register celestial events for testing"); flyingDimando = new FlyingDimando(4, "flying_dimando", event.world); fallingDimando = new DebugCelestialEvent(2, "falling_dimando", event.world); diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java index fc4833f60..3bec81d79 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java @@ -47,19 +47,34 @@ public CelestialEvent setExtraDays(int extraDays) { } public boolean activateEvent(long worldTime, Random random) { + CelestialEventActivityState activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); + if (initializationNeeded) { + activityState = initializeEvent(activityState); + } if (active) { + activityState.active = true; + activityState.attemptedActivation = true; + activityState.markDirty(); return true; } for (CelestialEvent otherEvent : incompatibleEvents) { if (otherEvent == null) continue; if (otherEvent.isActive()) { active = false; + activityState.active = false; + activityState.attemptedActivation = true; + activityState.markDirty(); return false; } } long days = worldTime / dayLength + dayOffset; - active = days % frequency == 0 && random.nextFloat() <= chance; + if (!activityState.attemptedActivation) { + active = days % frequency == 0 && random.nextFloat() <= chance; + } if (active) { + activityState.active = true; + activityState.attemptedActivation = true; + activityState.markDirty(); onActivation(); } return active; @@ -76,14 +91,17 @@ public void updateEvent(long worldTime) { if (initializationNeeded) { activityState = initializeEvent(activityState); } - if (!active) return; + if (!active && !activityState.active) return; worldTime -= startingDaytime; worldTime += endingDaytime; long days = worldTime / dayLength + dayOffset; active = days % frequency <= extraDays; activityState.active = active; + if (!active) { + onDeactivation(); + activityState.attemptedActivation = false; + } activityState.markDirty(); - if (!active) onDeactivation(); } private CelestialEventActivityState initializeEvent(CelestialEventActivityState activityState) { @@ -129,4 +147,10 @@ public void addIncompatibleEvent(CelestialEvent otherEvent) { incompatibleEvents.add(otherEvent); otherEvent.addIncompatibleEvent(this); } + + public void markForInitialization() { + CelestialEventActivityState activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); + initializeEvent(activityState); + initializationNeeded = false; + } } diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java index 2c18dfb59..856e6217f 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java @@ -5,6 +5,7 @@ public class CelestialEventActivityState extends PersistentState { public boolean active; + public boolean attemptedActivation; public CelestialEventActivityState(String id) { super(id); @@ -13,10 +14,12 @@ public CelestialEventActivityState(String id) { @Override public void readNbt(NbtCompound nbt) { this.active = nbt.getBoolean("active"); + this.attemptedActivation = nbt.getBoolean("attemptedActivation"); } @Override public void writeNbt(NbtCompound nbt) { nbt.putBoolean("active", active); + nbt.putBoolean("attemptedActivation", attemptedActivation); } } diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java index 556237ab3..da7b83b4c 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java @@ -93,4 +93,19 @@ public static void updateEvents(long time) { celestialEvent.updateEvent(time); } } + + public static void clearLists() { + MORNING_START.clear(); + NOON_START.clear(); + EVENING_START.clear(); + MIDNIGHT_START.clear(); + ALL_EVENTS.clear(); + } + + public static void initializeEvents() { + for (CelestialEvent celestialEvent : ALL_EVENTS) { + if (celestialEvent == null) continue; + celestialEvent.markForInitialization(); + } + } } diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java index 3eee7a60b..9b89b8dc3 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java @@ -2,6 +2,7 @@ import net.minecraft.world.World; import net.modificationstation.stationapi.api.StationAPI; +import net.modificationstation.stationapi.api.celestial.CelestialTimeManager; import net.modificationstation.stationapi.api.event.celestial.CelestialRegisterEvent; import net.modificationstation.stationapi.api.event.world.WorldEvent; import org.spongepowered.asm.mixin.Mixin; @@ -20,10 +21,10 @@ class WorldMixin { at = @At("RETURN") ) private void stationapi_onCor1(CallbackInfo ci) { + CelestialTimeManager.clearLists(); StationAPI.EVENT_BUS.post(WorldEvent.Init.builder().world(World.class.cast(this)).build()); - StationAPI.EVENT_BUS.post( - CelestialRegisterEvent.builder().world(World.class.cast(this)).build() - ); + StationAPI.EVENT_BUS.post(CelestialRegisterEvent.builder().world(World.class.cast(this)).build()); + CelestialTimeManager.initializeEvents(); } @Inject( From fef6ae6d1835aa718bbdd2a7840b84fb23d25dc8 Mon Sep 17 00:00:00 2001 From: Atilist <71230342+Atilist@users.noreply.github.com> Date: Sat, 25 May 2024 11:21:15 +0200 Subject: [PATCH 12/22] API Documentation and small Fixes. Documented all important API Components down to the Details. Introduced Lombok Getters. Added NBT Data Updating to the stopEvent() Method in CelestialEvent. Removed some redundant Code. Added Newline to CelestialRegisterEvent as requested. --- .../api/celestial/CelestialEvent.java | 108 ++++++++++++++++-- .../CelestialEventActivityState.java | 3 + .../api/celestial/CelestialTimeManager.java | 49 ++++++++ .../stationapi/api/celestial/DayQuarter.java | 3 + .../celestial/CelestialRegisterEvent.java | 2 +- 5 files changed, 154 insertions(+), 11 deletions(-) diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java index 3bec81d79..2619d1c8d 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java @@ -1,12 +1,19 @@ package net.modificationstation.stationapi.api.celestial; +import lombok.Getter; import net.minecraft.world.World; import java.util.LinkedList; import java.util.List; import java.util.Random; +/** + * Contains the most important logic for automatically starting and stopping the event. + * It is recommended to add the event to CelestialTimeManger for automatic management. + * Inheritance is possible to add custom logic. + */ public class CelestialEvent { + @Getter private final String name; private final int frequency; private float chance = 1; @@ -15,37 +22,81 @@ public class CelestialEvent { private int startingDaytime = 0; private int endingDaytime = 0; private int extraDays = 0; + @Getter private boolean active; private boolean initializationNeeded = true; private final List incompatibleEvents = new LinkedList<>(); public final World world; + /** + * Primary constructor for the event, containing the required parameters. + * + * @param frequency Specifies how many day apart the events should be. The bigger the number, the longer the distance. + * @param name Event name, snake_casing is recommended. + * @param world World object, obtained from the register event. + */ public CelestialEvent(int frequency, String name, World world) { this.frequency = frequency; this.name = name; this.world = world; } + /** + * Builder method for optional chance value. + * + * @param chance Value ranging from 0.0F to 1.0F, representing percentage chance. + * @return The object itself. + */ public CelestialEvent setChance(float chance) { this.chance = chance; return this; } + /** + * Builder method for optional day length value. + * Intended to be used in dimensions where day time is different. + * This will however need a custom time manager to account for the different day length. + * + * @param dayLength Length of day specified in ticks. + * @return The object itself. + */ public CelestialEvent setDayLength(int dayLength) { this.dayLength = dayLength; return this; } + /** + * Builder method for optional day offset. + * + * @param dayOffset Offsets the frequency by the specified number of days. + * @return The object itself. + */ public CelestialEvent setDayOffset(int dayOffset) { this.dayOffset = dayOffset; return this; } + /** + * Builder method for optional extra days. + * + * @param extraDays Extends the event duration by the specified number of days. + * @return The object itself. + */ public CelestialEvent setExtraDays(int extraDays) { this.extraDays = extraDays; return this; } + /** + * Attempts to activate the event. Checks if the activation already was attempted within the valid time frame. + * Takes activation chance and incompatible events into account. + * Method gets called by CelestialTimeManager in case the event is added to it. + * Can be called manually as well. + * + * @param worldTime Current time in the world measured in ticks. + * @param random Locally used randomizer, seed is irrelevant. + * @return True if the event met the criteria to be activated, otherwise false. + */ public boolean activateEvent(long worldTime, Random random) { CelestialEventActivityState activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); if (initializationNeeded) { @@ -60,7 +111,6 @@ public boolean activateEvent(long worldTime, Random random) { for (CelestialEvent otherEvent : incompatibleEvents) { if (otherEvent == null) continue; if (otherEvent.isActive()) { - active = false; activityState.active = false; activityState.attemptedActivation = true; activityState.markDirty(); @@ -80,12 +130,29 @@ public boolean activateEvent(long worldTime, Random random) { return active; } + /** + * Called precisely on event activation. + * Can be customized by inheriting from this class. + * Has access to the world object for more versatility. + */ public void onActivation() { } + /** + * Called precisely on event deactivation. + * Can be customized by inheriting from this class. + * Has access to the world object for more versatility. + */ public void onDeactivation() { } + /** + * Updates the activity status of an already active event. + * Used by CelestialTimeManager 4 times per day. + * Checks for validity of the time interval but not for chance and incompatibility. + * + * @param worldTime Current time in the world measured in ticks. + */ public void updateEvent(long worldTime) { CelestialEventActivityState activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); if (initializationNeeded) { @@ -104,6 +171,13 @@ public void updateEvent(long worldTime) { activityState.markDirty(); } + /** + * Initializes the event by synchronizing it with NBT data. + * Only used internally. + * + * @param activityState CelestialEventActivityState (custom PersistentState) used for accessing NBT data. + * @return The initialized CelestialEventActivityState. + */ private CelestialEventActivityState initializeEvent(CelestialEventActivityState activityState) { initializationNeeded = false; activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); @@ -116,31 +190,42 @@ private CelestialEventActivityState initializeEvent(CelestialEventActivityState return activityState; } + /** + * Manual way of stopping event. + * Intended for command systems. + */ public void stopEvent() { onDeactivation(); if (active) { + CelestialEventActivityState activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); + if (initializationNeeded) { + activityState = initializeEvent(activityState); + } + activityState.active = false; + activityState.markDirty(); System.out.println("Stopping event " + name); active = false; } } + /** + * Called by CelestialTimeManager to specify the valid time frame of the event. + * Time values can be specified as 4 values representing ticks in a day: + * Morning: 0, Noon: 6000, Evening: 12000, Midnight: 18000 + * + * @param startingDaytime Beginning daytime of the event. + * @param endingDaytime Ending daytime of the event. + */ public void setInterval(int startingDaytime, int endingDaytime) { this.startingDaytime = startingDaytime; this.endingDaytime = endingDaytime; } - public boolean isActive() { - return active; - } - - public String getName() { - return this.name; - } - /** * Adds events to prevent them from happening simultaneously. * Automatically adds incompatibility for both directions. - * @param otherEvent + * + * @param otherEvent Event to be added to the incompatibility list. */ public void addIncompatibleEvent(CelestialEvent otherEvent) { if (incompatibleEvents.contains(otherEvent)) return; @@ -148,6 +233,9 @@ public void addIncompatibleEvent(CelestialEvent otherEvent) { otherEvent.addIncompatibleEvent(this); } + /** + * Used by CelestialTimeManager to handle an edge-case where events would not be loaded when reloading the same world. + */ public void markForInitialization() { CelestialEventActivityState activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); initializeEvent(activityState); diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java index 856e6217f..49dee6132 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java @@ -3,6 +3,9 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.world.PersistentState; +/** + * Manages important NBT data to ensure correct saving and loading of active celestial events. + */ public class CelestialEventActivityState extends PersistentState { public boolean active; public boolean attemptedActivation; diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java index da7b83b4c..e53d6d659 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java @@ -4,6 +4,13 @@ import java.util.List; import java.util.Random; +/** + * Manages the activation and deactivation of celestial events. + * Has been injected into WorldProperties using the WorldPropertiesMixin in station-world-events, does not need to be handled by mods. + * Events need to be added during the registering process. + * Uses lists to schedule event updates during the correct time of day. + * Called four times per day. + */ public class CelestialTimeManager { private static final List MORNING_START = new LinkedList<>(); private static final List NOON_START = new LinkedList<>(); @@ -20,6 +27,13 @@ public class CelestialTimeManager { private static final Random RANDOM = new Random(); + /** + * Add a celestial event to the time manager. + * + * @param celestialEvent Event to be added. + * @param start Time of day at which the event begins. + * @param stop Time of day at which the event ends. + */ public static void addCelestialEvent(CelestialEvent celestialEvent, DayQuarter start, DayQuarter stop) { switch (start) { case MORNING -> MORNING_START.add(celestialEvent); @@ -31,6 +45,12 @@ public static void addCelestialEvent(CelestialEvent celestialEvent, DayQuarter s celestialEvent.setInterval(start.ordinal() * 6000, Math.abs(stop.ordinal() * 6000 - start.ordinal() * 6000)); } + /** + * Attempts to start all morning events. Called once per day. + * + * @param time World time in ticks. + * @param currentDay Current day in the world. + */ public static void startMorningEvents(long time, long currentDay) { if (morningActivation && lastCheckedDay == currentDay) return; lastCheckedDay = currentDay; @@ -45,6 +65,12 @@ public static void startMorningEvents(long time, long currentDay) { } } + /** + * Attempts to start all noon events. Called once per day. + * + * @param time World time in ticks. + * @param currentDay Current day in the world. + */ public static void startNoonEvents(long time, long currentDay) { if (noonActivation && lastCheckedDay == currentDay) return; lastCheckedDay = currentDay; @@ -59,6 +85,12 @@ public static void startNoonEvents(long time, long currentDay) { } } + /** + * Attempts to start all evening events. Called once per day. + * + * @param time World time in ticks. + * @param currentDay Current day in the world. + */ public static void startEveningEvents(long time, long currentDay) { if (eveningActivation && lastCheckedDay == currentDay) return; lastCheckedDay = currentDay; @@ -73,6 +105,12 @@ public static void startEveningEvents(long time, long currentDay) { } } + /** + * Attempts to start all midnight events. Called once per day. + * + * @param time World time in ticks. + * @param currentDay Current day in the world. + */ public static void startMidnightEvents(long time, long currentDay) { if (midnightActivation && lastCheckedDay == currentDay) return; lastCheckedDay = currentDay; @@ -87,6 +125,11 @@ public static void startMidnightEvents(long time, long currentDay) { } } + /** + * Updates activity state of all events. Called four times per day. + * + * @param time World time in ticks. + */ public static void updateEvents(long time) { for (CelestialEvent celestialEvent : ALL_EVENTS) { if (celestialEvent == null) continue; @@ -94,6 +137,9 @@ public static void updateEvents(long time) { } } + /** + * Clears all lists. Ensures that no duplicates show up after switching worlds. + */ public static void clearLists() { MORNING_START.clear(); NOON_START.clear(); @@ -102,6 +148,9 @@ public static void clearLists() { ALL_EVENTS.clear(); } + /** + * Initializes all events when the world is loaded, ensures correct loading of active events. + */ public static void initializeEvents() { for (CelestialEvent celestialEvent : ALL_EVENTS) { if (celestialEvent == null) continue; diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/DayQuarter.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/DayQuarter.java index 61acb9948..69ddfdda9 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/DayQuarter.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/DayQuarter.java @@ -1,5 +1,8 @@ package net.modificationstation.stationapi.api.celestial; +/** + * Used for celestial event time management. + */ public enum DayQuarter { MORNING, NOON, EVENING, MIDNIGHT } diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java index e421a0c72..75bdd7b76 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java @@ -4,4 +4,4 @@ import net.modificationstation.stationapi.api.event.world.WorldEvent; @SuperBuilder -public class CelestialRegisterEvent extends WorldEvent {} \ No newline at end of file +public class CelestialRegisterEvent extends WorldEvent {} From 3997c4012f25387edbc0d85ccc180ca1b25c8d68 Mon Sep 17 00:00:00 2001 From: Atilist <71230342+Atilist@users.noreply.github.com> Date: Fri, 31 May 2024 09:43:39 +0200 Subject: [PATCH 13/22] Improved Initialization Logic Moved Initializing Process to CelestialInitializer. All Events are automatically added to it. Now Events without a Time Manager are initialized properly. --- .../api/celestial/CelestialEvent.java | 1 + .../api/celestial/CelestialInitializer.java | 37 +++++++++++++++++++ .../api/celestial/CelestialTimeManager.java | 10 ----- .../stationapi/mixin/world/WorldMixin.java | 4 +- 4 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialInitializer.java diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java index 2619d1c8d..2f5c2db95 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java @@ -39,6 +39,7 @@ public CelestialEvent(int frequency, String name, World world) { this.frequency = frequency; this.name = name; this.world = world; + CelestialInitializer.addEvent(this); } /** diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialInitializer.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialInitializer.java new file mode 100644 index 000000000..535d0614e --- /dev/null +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialInitializer.java @@ -0,0 +1,37 @@ +package net.modificationstation.stationapi.api.celestial; + +import java.util.LinkedList; +import java.util.List; + +/** + * Automatically handles initialization of celestial events. + * Ensures that all celestial events are loaded correctly. + */ +public class CelestialInitializer { + private static final List ALL_EVENTS = new LinkedList<>(); + + /** + * Called automatically by every celestial event. + * @param celestialEvent The event to be added. + */ + public static void addEvent(CelestialEvent celestialEvent) { + ALL_EVENTS.add(celestialEvent); + } + + /** + * Prevents duplicates when worlds are switched. + */ + public static void clearList() { + ALL_EVENTS.clear(); + } + + /** + * Initializes all events when the world is loaded, ensures correct loading of active events. + */ + public static void initializeEvents() { + for (CelestialEvent celestialEvent : ALL_EVENTS) { + if (celestialEvent == null) continue; + celestialEvent.markForInitialization(); + } + } +} diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java index e53d6d659..f76e28636 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java @@ -147,14 +147,4 @@ public static void clearLists() { MIDNIGHT_START.clear(); ALL_EVENTS.clear(); } - - /** - * Initializes all events when the world is loaded, ensures correct loading of active events. - */ - public static void initializeEvents() { - for (CelestialEvent celestialEvent : ALL_EVENTS) { - if (celestialEvent == null) continue; - celestialEvent.markForInitialization(); - } - } } diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java index 9b89b8dc3..d30e1e5b0 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java @@ -2,6 +2,7 @@ import net.minecraft.world.World; import net.modificationstation.stationapi.api.StationAPI; +import net.modificationstation.stationapi.api.celestial.CelestialInitializer; import net.modificationstation.stationapi.api.celestial.CelestialTimeManager; import net.modificationstation.stationapi.api.event.celestial.CelestialRegisterEvent; import net.modificationstation.stationapi.api.event.world.WorldEvent; @@ -22,9 +23,10 @@ class WorldMixin { ) private void stationapi_onCor1(CallbackInfo ci) { CelestialTimeManager.clearLists(); + CelestialInitializer.clearList(); StationAPI.EVENT_BUS.post(WorldEvent.Init.builder().world(World.class.cast(this)).build()); StationAPI.EVENT_BUS.post(CelestialRegisterEvent.builder().world(World.class.cast(this)).build()); - CelestialTimeManager.initializeEvents(); + CelestialInitializer.initializeEvents(); } @Inject( From 2b01bad003aa29f12b629032c913c8a42043372f Mon Sep 17 00:00:00 2001 From: Atilist <71230342+Atilist@users.noreply.github.com> Date: Sat, 8 Jun 2024 23:54:34 +0200 Subject: [PATCH 14/22] Event Dependency Feature and important Bug Fix Events can now have Dependencies. Events only activate if their Dependencies are active. Fixed a Bug that caused attempted Activations to never be reset, leading to Events never happening again. --- .../sltest/celestial/CelestialListener.java | 4 +++ .../api/celestial/CelestialEvent.java | 31 +++++++++++++++++-- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java b/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java index 6aa477783..e1070efc1 100644 --- a/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java +++ b/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java @@ -11,6 +11,7 @@ public class CelestialListener { public static CelestialEvent flyingDimando; public static CelestialEvent fallingDimando; + public static CelestialEvent crashingDimando; public static CelestialEvent spinningDimando; public static CelestialEvent burningDimando; public static CelestialEvent longDimando; @@ -20,13 +21,16 @@ public void registerCelestialEvents(CelestialRegisterEvent event) { SLTest.LOGGER.info("Register celestial events for testing"); flyingDimando = new FlyingDimando(4, "flying_dimando", event.world); fallingDimando = new DebugCelestialEvent(2, "falling_dimando", event.world); + crashingDimando = new DebugCelestialEvent(2, "crashing_dimando", event.world); spinningDimando = new DebugCelestialEvent(4, "spinning_dimando", event.world).setDayOffset(1); burningDimando = new DebugCelestialEvent(2, "burning_dimando", event.world).setDayOffset(1); longDimando = new DebugCelestialEvent(12, "long_dimando", event.world).setExtraDays(4); flyingDimando.addIncompatibleEvent(fallingDimando); spinningDimando.addIncompatibleEvent(burningDimando); + crashingDimando.addDependency(longDimando); CelestialTimeManager.addCelestialEvent(flyingDimando, DayQuarter.MORNING, DayQuarter.MORNING); CelestialTimeManager.addCelestialEvent(fallingDimando, DayQuarter.NOON, DayQuarter.MIDNIGHT); + CelestialTimeManager.addCelestialEvent(crashingDimando, DayQuarter.NOON, DayQuarter.NOON); CelestialTimeManager.addCelestialEvent(spinningDimando, DayQuarter.EVENING, DayQuarter.NOON); CelestialTimeManager.addCelestialEvent(burningDimando, DayQuarter.MIDNIGHT, DayQuarter.EVENING); CelestialTimeManager.addCelestialEvent(longDimando, DayQuarter.MIDNIGHT, DayQuarter.MIDNIGHT); diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java index 2f5c2db95..8c72936af 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java @@ -26,6 +26,7 @@ public class CelestialEvent { private boolean active; private boolean initializationNeeded = true; private final List incompatibleEvents = new LinkedList<>(); + private final List dependencies = new LinkedList<>(); public final World world; /** @@ -118,9 +119,22 @@ public boolean activateEvent(long worldTime, Random random) { return false; } } - long days = worldTime / dayLength + dayOffset; + for (CelestialEvent otherEvent : dependencies) { + if (otherEvent == null) continue; + if (!otherEvent.isActive()) { + activityState.active = false; + activityState.attemptedActivation = true; + activityState.markDirty(); + return false; + } + } + long days = (worldTime / dayLength) + dayOffset; + if (days % frequency > extraDays) { + activityState.attemptedActivation = false; + return false; + } if (!activityState.attemptedActivation) { - active = days % frequency == 0 && random.nextFloat() <= chance; + active = days % frequency <= extraDays && random.nextFloat() <= chance; } if (active) { activityState.active = true; @@ -162,7 +176,7 @@ public void updateEvent(long worldTime) { if (!active && !activityState.active) return; worldTime -= startingDaytime; worldTime += endingDaytime; - long days = worldTime / dayLength + dayOffset; + long days = (worldTime / dayLength) + dayOffset; active = days % frequency <= extraDays; activityState.active = active; if (!active) { @@ -234,6 +248,17 @@ public void addIncompatibleEvent(CelestialEvent otherEvent) { otherEvent.addIncompatibleEvent(this); } + /** + * Adds dependency to an event, meaning another event has to happen for this one to happen. + * Dependency only gets added into one direction. + * + * @param dependency Event to be added to the dependencies list. + */ + public void addDependency(CelestialEvent dependency) { + if (dependencies.contains(dependency)) return; + dependencies.add(dependency); + } + /** * Used by CelestialTimeManager to handle an edge-case where events would not be loaded when reloading the same world. */ From eb5723eb155393590defa130e517348917d0caf8 Mon Sep 17 00:00:00 2001 From: Atilist <71230342+Atilist@users.noreply.github.com> Date: Tue, 25 Jun 2024 17:05:23 +0200 Subject: [PATCH 15/22] Add missing Newline to a Lang File --- src/test/resources/assets/sltest/stationapi/lang/en_US.lang | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/resources/assets/sltest/stationapi/lang/en_US.lang b/src/test/resources/assets/sltest/stationapi/lang/en_US.lang index 1bba96a15..802c5e2d3 100644 --- a/src/test/resources/assets/sltest/stationapi/lang/en_US.lang +++ b/src/test/resources/assets/sltest/stationapi/lang/en_US.lang @@ -19,3 +19,4 @@ item.@.test_shears.name=Test Shears item.@.pacifist_sword.name=Pacifist Sword item.@.dull_pickaxe.name=Dull Pickaxe tile.@.timeMachineBlock.name=Time Machine + From 560bb9cdf443d1fe60d35f4f0786066ce2be8533 Mon Sep 17 00:00:00 2001 From: Atilist <71230342+Atilist@users.noreply.github.com> Date: Tue, 25 Jun 2024 17:24:53 +0200 Subject: [PATCH 16/22] Reduce to single Newline --- src/test/resources/assets/sltest/stationapi/lang/en_US.lang | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/resources/assets/sltest/stationapi/lang/en_US.lang b/src/test/resources/assets/sltest/stationapi/lang/en_US.lang index 802c5e2d3..1bba96a15 100644 --- a/src/test/resources/assets/sltest/stationapi/lang/en_US.lang +++ b/src/test/resources/assets/sltest/stationapi/lang/en_US.lang @@ -19,4 +19,3 @@ item.@.test_shears.name=Test Shears item.@.pacifist_sword.name=Pacifist Sword item.@.dull_pickaxe.name=Dull Pickaxe tile.@.timeMachineBlock.name=Time Machine - From 1a78567472089472689f321fd9daea54257656a5 Mon Sep 17 00:00:00 2001 From: Atilist <71230342+Atilist@users.noreply.github.com> Date: Wed, 17 Jul 2024 13:17:46 +0200 Subject: [PATCH 17/22] Remove redundant Parameter The Method CelestialEvent.initializeEvent had a Parameter that would be declared within the Method anyway. --- .../stationapi/api/celestial/CelestialEvent.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java index 8c72936af..7dd4dc44a 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java @@ -102,7 +102,7 @@ public CelestialEvent setExtraDays(int extraDays) { public boolean activateEvent(long worldTime, Random random) { CelestialEventActivityState activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); if (initializationNeeded) { - activityState = initializeEvent(activityState); + activityState = initializeEvent(); } if (active) { activityState.active = true; @@ -171,7 +171,7 @@ public void onDeactivation() { public void updateEvent(long worldTime) { CelestialEventActivityState activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); if (initializationNeeded) { - activityState = initializeEvent(activityState); + activityState = initializeEvent(); } if (!active && !activityState.active) return; worldTime -= startingDaytime; @@ -190,12 +190,11 @@ public void updateEvent(long worldTime) { * Initializes the event by synchronizing it with NBT data. * Only used internally. * - * @param activityState CelestialEventActivityState (custom PersistentState) used for accessing NBT data. * @return The initialized CelestialEventActivityState. */ - private CelestialEventActivityState initializeEvent(CelestialEventActivityState activityState) { + private CelestialEventActivityState initializeEvent() { initializationNeeded = false; - activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); + CelestialEventActivityState activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); if (activityState == null) { activityState = new CelestialEventActivityState(this.name); this.world.setState(this.name, activityState); @@ -214,7 +213,7 @@ public void stopEvent() { if (active) { CelestialEventActivityState activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); if (initializationNeeded) { - activityState = initializeEvent(activityState); + activityState = initializeEvent(); } activityState.active = false; activityState.markDirty(); @@ -264,7 +263,7 @@ public void addDependency(CelestialEvent dependency) { */ public void markForInitialization() { CelestialEventActivityState activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); - initializeEvent(activityState); + initializeEvent(); initializationNeeded = false; } } From f3006da339d91f601ef46a01c3d72215f036a929 Mon Sep 17 00:00:00 2001 From: Atilist <71230342+Atilist@users.noreply.github.com> Date: Wed, 17 Jul 2024 14:42:09 +0200 Subject: [PATCH 18/22] Remove useless local value --- .../stationapi/api/celestial/CelestialEvent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java index 7dd4dc44a..77dff10c9 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java @@ -262,7 +262,7 @@ public void addDependency(CelestialEvent dependency) { * Used by CelestialTimeManager to handle an edge-case where events would not be loaded when reloading the same world. */ public void markForInitialization() { - CelestialEventActivityState activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); + this.world.getOrCreateState(CelestialEventActivityState.class, this.name); initializeEvent(); initializationNeeded = false; } From 1db84abe3171a795d97b1c668f91847742e7a6be Mon Sep 17 00:00:00 2001 From: calmilamsy Date: Fri, 16 Aug 2024 18:18:10 +0100 Subject: [PATCH 19/22] Yeet deprecated code --- .../screen/container/TooltipRenderEvent.java | 7 ---- .../stationapi/api/recipe/StationRecipe.java | 18 ---------- .../impl/recipe/StationShapedRecipe.java | 27 +-------------- .../impl/recipe/StationShapelessRecipe.java | 24 ++----------- .../mixin/recipe/CraftingRecipeMixin.java | 19 ----------- .../mixin/recipe/ShapedRecipeMixin.java | 34 ------------------- .../mixin/recipe/ShapelessRecipeMixin.java | 27 --------------- .../resources/station-recipes-v0.mixins.json | 3 -- 8 files changed, 3 insertions(+), 156 deletions(-) delete mode 100644 station-recipes-v0/src/main/java/net/modificationstation/stationapi/api/recipe/StationRecipe.java delete mode 100644 station-recipes-v0/src/main/java/net/modificationstation/stationapi/mixin/recipe/CraftingRecipeMixin.java delete mode 100644 station-recipes-v0/src/main/java/net/modificationstation/stationapi/mixin/recipe/ShapedRecipeMixin.java delete mode 100644 station-recipes-v0/src/main/java/net/modificationstation/stationapi/mixin/recipe/ShapelessRecipeMixin.java diff --git a/station-items-v0/src/main/java/net/modificationstation/stationapi/api/client/event/gui/screen/container/TooltipRenderEvent.java b/station-items-v0/src/main/java/net/modificationstation/stationapi/api/client/event/gui/screen/container/TooltipRenderEvent.java index 910373f32..a52aba416 100644 --- a/station-items-v0/src/main/java/net/modificationstation/stationapi/api/client/event/gui/screen/container/TooltipRenderEvent.java +++ b/station-items-v0/src/main/java/net/modificationstation/stationapi/api/client/event/gui/screen/container/TooltipRenderEvent.java @@ -21,13 +21,6 @@ public class TooltipRenderEvent extends ItemStackEvent { public final HandledScreen container; public final TextRenderer textManager; public final PlayerInventory inventory; - /** - * These will be removed in a3, due to the fact the container var already exists. - */ - @Deprecated(forRemoval = true) - public final int - containerX, - containerY; public final int mouseX, mouseY; diff --git a/station-recipes-v0/src/main/java/net/modificationstation/stationapi/api/recipe/StationRecipe.java b/station-recipes-v0/src/main/java/net/modificationstation/stationapi/api/recipe/StationRecipe.java deleted file mode 100644 index 047a084fb..000000000 --- a/station-recipes-v0/src/main/java/net/modificationstation/stationapi/api/recipe/StationRecipe.java +++ /dev/null @@ -1,18 +0,0 @@ -package net.modificationstation.stationapi.api.recipe; - -import net.minecraft.item.ItemStack; - -/** - * This entire interface is slated for removal in alpha 3. - * Stop using it, it's shit and was made specifically for HMI, for all the wrong reasons. - * - calm - */ -@Deprecated(forRemoval = true) -public interface StationRecipe { - - @Deprecated(forRemoval = true) - ItemStack[] getIngredients(); - - @Deprecated(forRemoval = true) - ItemStack[] getOutputs(); -} diff --git a/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/StationShapedRecipe.java b/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/StationShapedRecipe.java index d2d63f841..2afd4cdb9 100644 --- a/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/StationShapedRecipe.java +++ b/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/StationShapedRecipe.java @@ -5,17 +5,11 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.recipe.CraftingRecipe; -import net.modificationstation.stationapi.api.recipe.StationRecipe; -import net.modificationstation.stationapi.api.registry.ItemRegistry; import net.modificationstation.stationapi.api.tag.TagKey; import java.util.*; -import java.util.function.Function; - -public class StationShapedRecipe implements CraftingRecipe, StationRecipe { - - private static final Random RANDOM = new Random(); +public class StationShapedRecipe implements CraftingRecipe { public final int width, height; private final Either, ItemStack>[] grid; public final ItemStack output; @@ -84,25 +78,6 @@ public ItemStack getOutput() { return output; } - @Override - public ItemStack[] getIngredients() { - ItemStack[] stacks = new ItemStack[9]; - for (int h = 0; h < height; h++) - for (int w = 0; w < width; w++) { - int localId = (h * width) + w; - Either, ItemStack> ingredient = grid[localId]; - if (ingredient == null) continue; - int id = (h * 3) + w; - stacks[id] = ingredient.map(tag -> new ItemStack(ItemRegistry.INSTANCE.getEntryList(tag).orElseThrow(() -> new RuntimeException("Identifier ingredient \"" + tag.id() + "\" has no entry in the tag registry!")).getRandom(RANDOM).orElseThrow().value()), Function.identity()); - } - return stacks; - } - - @Override - public ItemStack[] getOutputs() { - return new ItemStack[] { output }; - } - public Either, ItemStack>[] getGrid() { //noinspection unchecked return (Either, ItemStack>[]) Arrays.stream(grid).map(entry -> entry == null ? null : entry.mapRight(ItemStack::copy)).toArray(Either[]::new); diff --git a/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/StationShapelessRecipe.java b/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/StationShapelessRecipe.java index b82e2eb6e..b095b311e 100644 --- a/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/StationShapelessRecipe.java +++ b/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/StationShapelessRecipe.java @@ -5,14 +5,11 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.recipe.CraftingRecipe; -import net.modificationstation.stationapi.api.recipe.StationRecipe; -import net.modificationstation.stationapi.api.registry.ItemRegistry; import net.modificationstation.stationapi.api.tag.TagKey; import java.util.*; -import java.util.function.Function; -public class StationShapelessRecipe implements CraftingRecipe, StationRecipe { +public class StationShapelessRecipe implements CraftingRecipe { private static final Random RANDOM = new Random(); @@ -78,24 +75,7 @@ public ItemStack getOutput() { return output; } - @Override - public ItemStack[] getIngredients() { - ItemStack[] inputs = new ItemStack[ingredients.length]; - for (int i = 0, ingredientsLength = ingredients.length; i < ingredientsLength; i++) - inputs[i] = ingredients[i].map(tag -> new ItemStack(ItemRegistry.INSTANCE.getEntryList(tag).orElseThrow(() -> new RuntimeException("Identifier ingredient \"" + tag.id() + "\" has no entry in the tag registry!")).getRandom(RANDOM).orElseThrow().value()), Function.identity()); - return inputs; - } - - @Override - public ItemStack[] getOutputs() { - return new ItemStack[] { output }; - } - - /** - * To be renamed to getIngredients in a3, use with caution. - */ - @Deprecated - public Either, ItemStack>[] getInputs() { + public Either, ItemStack>[] getIngredients() { //noinspection unchecked return (Either, ItemStack>[]) Arrays.stream(ingredients).map(entry -> entry == null ? null : entry.mapRight(ItemStack::copy)).toArray(Either[]::new); } diff --git a/station-recipes-v0/src/main/java/net/modificationstation/stationapi/mixin/recipe/CraftingRecipeMixin.java b/station-recipes-v0/src/main/java/net/modificationstation/stationapi/mixin/recipe/CraftingRecipeMixin.java deleted file mode 100644 index ccd3ac845..000000000 --- a/station-recipes-v0/src/main/java/net/modificationstation/stationapi/mixin/recipe/CraftingRecipeMixin.java +++ /dev/null @@ -1,19 +0,0 @@ -package net.modificationstation.stationapi.mixin.recipe; - -import net.minecraft.item.ItemStack; -import net.minecraft.recipe.CraftingRecipe; -import net.modificationstation.stationapi.api.recipe.StationRecipe; -import org.spongepowered.asm.mixin.Mixin; - -@Mixin(CraftingRecipe.class) -public interface CraftingRecipeMixin extends StationRecipe { - @Override - default ItemStack[] getIngredients() { - throw new UnsupportedOperationException("Your custom recipe registry needs to implement the methods found in \"net.modificationstation.stationapi.api.recipe.StationRecipe\"!"); - } - - @Override - default ItemStack[] getOutputs() { - throw new UnsupportedOperationException("Your custom recipe registry needs to implement the methods found in \"net.modificationstation.stationapi.api.recipe.StationRecipe\"!"); - } -} diff --git a/station-recipes-v0/src/main/java/net/modificationstation/stationapi/mixin/recipe/ShapedRecipeMixin.java b/station-recipes-v0/src/main/java/net/modificationstation/stationapi/mixin/recipe/ShapedRecipeMixin.java deleted file mode 100644 index 9f9ed3f84..000000000 --- a/station-recipes-v0/src/main/java/net/modificationstation/stationapi/mixin/recipe/ShapedRecipeMixin.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.modificationstation.stationapi.mixin.recipe; - -import net.minecraft.ShapedRecipe; -import net.minecraft.item.ItemStack; -import net.modificationstation.stationapi.api.recipe.StationRecipe; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -@Mixin(ShapedRecipe.class) -class ShapedRecipeMixin implements StationRecipe { - @Shadow private int width; - @Shadow private int height; - @Shadow private ItemStack output; - - @Shadow private ItemStack[] input; - - @Override - public ItemStack[] getIngredients() { - ItemStack[] stacks = new ItemStack[9]; - for (int h = 0; h < height; h++) { - for (int w = 0; w < width; w++) { - int localId = (h * width) + w; - int id = (h * 3) + w; - stacks[id] = input[localId]; - } - } - return stacks; - } - - @Override - public ItemStack[] getOutputs() { - return new ItemStack[] { output }; - } -} diff --git a/station-recipes-v0/src/main/java/net/modificationstation/stationapi/mixin/recipe/ShapelessRecipeMixin.java b/station-recipes-v0/src/main/java/net/modificationstation/stationapi/mixin/recipe/ShapelessRecipeMixin.java deleted file mode 100644 index 2270e4279..000000000 --- a/station-recipes-v0/src/main/java/net/modificationstation/stationapi/mixin/recipe/ShapelessRecipeMixin.java +++ /dev/null @@ -1,27 +0,0 @@ -package net.modificationstation.stationapi.mixin.recipe; - -import net.minecraft.item.ItemStack; -import net.minecraft.recipe.ShapelessRecipe; -import net.modificationstation.stationapi.api.recipe.StationRecipe; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import java.util.List; - -@Mixin(ShapelessRecipe.class) -class ShapelessRecipeMixin implements StationRecipe { - @Shadow @Final private List input; - - @Shadow @Final private ItemStack output; - - @Override - public ItemStack[] getIngredients() { - return input.toArray(ItemStack[]::new); - } - - @Override - public ItemStack[] getOutputs() { - return new ItemStack[] { output }; - } -} diff --git a/station-recipes-v0/src/main/resources/station-recipes-v0.mixins.json b/station-recipes-v0/src/main/resources/station-recipes-v0.mixins.json index ff2373bb4..cb789d3bc 100644 --- a/station-recipes-v0/src/main/resources/station-recipes-v0.mixins.json +++ b/station-recipes-v0/src/main/resources/station-recipes-v0.mixins.json @@ -5,12 +5,9 @@ "compatibilityLevel": "JAVA_17", "mixins": [ "CraftingRecipeManagerMixin", - "CraftingRecipeMixin", "CraftingResultMixin", "FurnaceBlockEntityMixin", "RecipeComparatorMixin", - "ShapedRecipeMixin", - "ShapelessRecipeMixin", "SmeltingRecipeManagerAccessor", "SmeltingRecipeManagerMixin", "StatsMixin" From bf4e97e11263f53cc22cec5ea55c30fd96503cda Mon Sep 17 00:00:00 2001 From: mineLdiver Date: Fri, 6 Sep 2024 21:05:51 +0500 Subject: [PATCH 20/22] *actually* remove deprecated stuff --- .../container/CustomTooltipRendererImpl.java | 12 ++++++++---- .../mixin/item/client/ContainerScreenMixin.java | 1 - .../mixin/item/client/HandledScreenAccessor.java | 14 ++++++++++++++ .../main/resources/station-items-v0.mixins.json | 1 + 4 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 station-items-v0/src/main/java/net/modificationstation/stationapi/mixin/item/client/HandledScreenAccessor.java diff --git a/station-items-v0/src/main/java/net/modificationstation/stationapi/impl/client/gui/screen/container/CustomTooltipRendererImpl.java b/station-items-v0/src/main/java/net/modificationstation/stationapi/impl/client/gui/screen/container/CustomTooltipRendererImpl.java index edfe77658..ac3f3173b 100644 --- a/station-items-v0/src/main/java/net/modificationstation/stationapi/impl/client/gui/screen/container/CustomTooltipRendererImpl.java +++ b/station-items-v0/src/main/java/net/modificationstation/stationapi/impl/client/gui/screen/container/CustomTooltipRendererImpl.java @@ -1,19 +1,23 @@ package net.modificationstation.stationapi.impl.client.gui.screen.container; import net.mine_diver.unsafeevents.listener.EventListener; +import net.minecraft.client.gui.DrawContext; import net.modificationstation.stationapi.api.StationAPI; import net.modificationstation.stationapi.api.client.TooltipHelper; import net.modificationstation.stationapi.api.client.event.gui.screen.container.TooltipRenderEvent; import net.modificationstation.stationapi.api.mod.entrypoint.Entrypoint; import net.modificationstation.stationapi.api.mod.entrypoint.EventBusPolicy; import net.modificationstation.stationapi.mixin.item.client.DrawContextAccessor; +import net.modificationstation.stationapi.mixin.item.client.HandledScreenAccessor; -import java.util.*; +import java.util.ArrayList; import java.util.stream.IntStream; @Entrypoint(eventBus = @EventBusPolicy(registerInstance = false)) @EventListener(phase = StationAPI.INTERNAL_PHASE) public final class CustomTooltipRendererImpl { + private static final DrawContext CONTEXT = new DrawContext(); + @EventListener private static void renderCustomTooltips(TooltipRenderEvent event) { if(event.isCanceled()) { @@ -24,9 +28,9 @@ private static void renderCustomTooltips(TooltipRenderEvent event) { if (!newTooltip.isEmpty()) { newTooltip.stream().mapToInt(event.textManager::getWidth).max().ifPresent(tooltipWidth -> { - int tooltipX = event.mouseX - event.containerX + 12; - int tooltipY = event.mouseY - event.containerY - 12; - ((DrawContextAccessor) event.container).invokeFillGradient(tooltipX - 3, tooltipY - 3, tooltipX + tooltipWidth + 3, tooltipY + (8 * newTooltip.size()) + (3 * newTooltip.size()), -1073741824, -1073741824); + int tooltipX = event.mouseX - (event.container == null ? 0 : ((event.container.width - ((HandledScreenAccessor) event.container).stationapi_getBackgroundWidth()) / 2)) + 12; + int tooltipY = event.mouseY - (event.container == null ? 0 : ((event.container.height - ((HandledScreenAccessor) event.container).stationapi_getBackgroundHeight()) / 2)) - 12; + ((DrawContextAccessor) CONTEXT).invokeFillGradient(tooltipX - 3, tooltipY - 3, tooltipX + tooltipWidth + 3, tooltipY + (8 * newTooltip.size()) + (3 * newTooltip.size()), -1073741824, -1073741824); IntStream.range(0, newTooltip.size()).forEach(currentTooltip -> event.textManager.drawWithShadow(newTooltip.get(currentTooltip), tooltipX, tooltipY + (8 * currentTooltip) + (3 * currentTooltip), -1)); }); event.cancel(); diff --git a/station-items-v0/src/main/java/net/modificationstation/stationapi/mixin/item/client/ContainerScreenMixin.java b/station-items-v0/src/main/java/net/modificationstation/stationapi/mixin/item/client/ContainerScreenMixin.java index 1f2fc98e5..d69cf53ef 100644 --- a/station-items-v0/src/main/java/net/modificationstation/stationapi/mixin/item/client/ContainerScreenMixin.java +++ b/station-items-v0/src/main/java/net/modificationstation/stationapi/mixin/item/client/ContainerScreenMixin.java @@ -36,7 +36,6 @@ private void stationapi_renderTooltip(int mouseX, int mouseY, float delta, Callb .container((HandledScreen) (Object) this) .textManager(this.textRenderer) .inventory(inventory) - .containerX(containerX).containerY(containerY) .mouseX(mouseX).mouseY(mouseY) .delta(delta) .originalTooltip(originalTooltip) diff --git a/station-items-v0/src/main/java/net/modificationstation/stationapi/mixin/item/client/HandledScreenAccessor.java b/station-items-v0/src/main/java/net/modificationstation/stationapi/mixin/item/client/HandledScreenAccessor.java new file mode 100644 index 000000000..495231844 --- /dev/null +++ b/station-items-v0/src/main/java/net/modificationstation/stationapi/mixin/item/client/HandledScreenAccessor.java @@ -0,0 +1,14 @@ +package net.modificationstation.stationapi.mixin.item.client; + +import net.minecraft.client.gui.screen.ingame.HandledScreen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(HandledScreen.class) +public interface HandledScreenAccessor { + @Accessor("backgroundWidth") + int stationapi_getBackgroundWidth(); + + @Accessor("backgroundHeight") + int stationapi_getBackgroundHeight(); +} diff --git a/station-items-v0/src/main/resources/station-items-v0.mixins.json b/station-items-v0/src/main/resources/station-items-v0.mixins.json index 77cd0e61a..2fd54f374 100644 --- a/station-items-v0/src/main/resources/station-items-v0.mixins.json +++ b/station-items-v0/src/main/resources/station-items-v0.mixins.json @@ -30,6 +30,7 @@ "client.ContainerScreenMixin", "client.DrawContextAccessor", "client.GameRendererMixin", + "client.HandledScreenAccessor", "client.InteractionManagerMixin", "client.ItemRendererMixin", "client.MultiplayerInteractionManagerMixin", From a1361bf4b2fad89fd4b70d82c0208bb45a7942c4 Mon Sep 17 00:00:00 2001 From: calmilamsy Date: Fri, 11 Oct 2024 19:52:44 +0100 Subject: [PATCH 21/22] Fix most outstanding issues --- build.gradle.kts | 4 +- gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle.kts | 1 + .../sltest/celestial/CelestialListener.java | 27 ++-- .../sltest/celestial/DebugCelestialEvent.java | 17 +-- .../sltest/celestial/FlyingDimando.java | 9 +- .../sltest/item/CelestialToggleItem.java | 8 +- station-celestial-events-v0/build.gradle.kts | 9 ++ .../CelestialActivityStateManager.java | 7 ++ .../api/celestial/CelestialEvent.java | 117 +++++++++--------- .../CelestialEventActivityState.java | 75 +++++++++++ .../api/celestial/CelestialEventRegistry.java | 34 +++++ .../api/celestial/CelestialTimeManager.java | 67 +++++----- .../stationapi/api/celestial/DayQuarter.java | 0 .../celestial/WorldPropertiesWithWorld.java | 9 ++ .../celestial/CelestialRegisterEvent.java | 10 ++ .../mixin/world/NbtCompoundAccessor.java | 17 +++ .../stationapi/mixin/world/WorldMixin.java | 63 ++++++++++ .../mixin/world/WorldPropertiesMixin.java | 51 ++++++++ .../station-celestial-events-v0/icon.png | Bin 0 -> 210839 bytes .../src/main/resources/fabric.mod.json | 38 ++++++ .../station-celestial-events-v0.mixins.json | 22 ++++ station-world-events-v0/build.gradle.kts | 2 +- .../CelestialEventActivityState.java | 28 ----- .../api/celestial/CelestialInitializer.java | 37 ------ .../celestial/CelestialRegisterEvent.java | 7 -- .../stationapi/mixin/world/WorldMixin.java | 18 +-- .../mixin/world/WorldPropertiesMixin.java | 24 ---- 28 files changed, 472 insertions(+), 231 deletions(-) create mode 100644 station-celestial-events-v0/build.gradle.kts create mode 100644 station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialActivityStateManager.java rename {station-world-events-v0 => station-celestial-events-v0}/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java (66%) create mode 100644 station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java create mode 100644 station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventRegistry.java rename {station-world-events-v0 => station-celestial-events-v0}/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java (67%) rename {station-world-events-v0 => station-celestial-events-v0}/src/main/java/net/modificationstation/stationapi/api/celestial/DayQuarter.java (100%) create mode 100644 station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/WorldPropertiesWithWorld.java create mode 100644 station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java create mode 100644 station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/NbtCompoundAccessor.java create mode 100644 station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java create mode 100644 station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java create mode 100644 station-celestial-events-v0/src/main/resources/assets/station-celestial-events-v0/icon.png create mode 100644 station-celestial-events-v0/src/main/resources/fabric.mod.json create mode 100644 station-celestial-events-v0/src/main/resources/station-celestial-events-v0.mixins.json delete mode 100644 station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java delete mode 100644 station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialInitializer.java delete mode 100644 station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java diff --git a/build.gradle.kts b/build.gradle.kts index feea36bea..330064ac0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,8 +5,8 @@ import net.modificationstation.stationapi.gradle.SubprojectHelpers.addDependency plugins { id("maven-publish") - id("fabric-loom") version "1.7.2" - id("babric-loom-extension") version "1.7.3" + id("fabric-loom") version "1.8.8" + id("babric-loom-extension") version "1.8.5" } // https://stackoverflow.com/a/40101046 - Even with kotlin, gradle can't get it's shit together. diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a4413138c..9355b4155 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/settings.gradle.kts b/settings.gradle.kts index 737ddf9bb..c83e2150c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -46,3 +46,4 @@ include(":station-gui-api-v0") include(":station-transitive-access-wideners-v0") include(":station-maths-v0") include(":station-worldgen-api-v0") +include(":station-celestial-events-v0") diff --git a/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java b/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java index e1070efc1..acee9e7c1 100644 --- a/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java +++ b/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java @@ -1,11 +1,14 @@ package net.modificationstation.sltest.celestial; import net.mine_diver.unsafeevents.listener.EventListener; +import net.modificationstation.sltest.MainTest; import net.modificationstation.sltest.SLTest; +import net.modificationstation.stationapi.api.celestial.CelestialActivityStateManager; import net.modificationstation.stationapi.api.celestial.CelestialEvent; import net.modificationstation.stationapi.api.celestial.CelestialTimeManager; import net.modificationstation.stationapi.api.celestial.DayQuarter; import net.modificationstation.stationapi.api.event.celestial.CelestialRegisterEvent; +import net.modificationstation.stationapi.api.util.Identifier; public class CelestialListener { @@ -19,20 +22,20 @@ public class CelestialListener { @EventListener public void registerCelestialEvents(CelestialRegisterEvent event) { SLTest.LOGGER.info("Register celestial events for testing"); - flyingDimando = new FlyingDimando(4, "flying_dimando", event.world); - fallingDimando = new DebugCelestialEvent(2, "falling_dimando", event.world); - crashingDimando = new DebugCelestialEvent(2, "crashing_dimando", event.world); - spinningDimando = new DebugCelestialEvent(4, "spinning_dimando", event.world).setDayOffset(1); - burningDimando = new DebugCelestialEvent(2, "burning_dimando", event.world).setDayOffset(1); - longDimando = new DebugCelestialEvent(12, "long_dimando", event.world).setExtraDays(4); + flyingDimando = new FlyingDimando(4, Identifier.of(SLTest.NAMESPACE, "flying_dimando")); + fallingDimando = new DebugCelestialEvent(2, Identifier.of(SLTest.NAMESPACE, "falling_dimando")); + crashingDimando = new DebugCelestialEvent(2, Identifier.of(SLTest.NAMESPACE, "crashing_dimando")); + spinningDimando = new DebugCelestialEvent(4, Identifier.of(SLTest.NAMESPACE, "spinning_dimando")).setDayOffset(event.world, 1); + burningDimando = new DebugCelestialEvent(2, Identifier.of(SLTest.NAMESPACE, "burning_dimando")).setDayOffset(event.world, 1); + longDimando = new DebugCelestialEvent(12, Identifier.of(SLTest.NAMESPACE, "long_dimando")).setExtraDays(event.world, 4); flyingDimando.addIncompatibleEvent(fallingDimando); spinningDimando.addIncompatibleEvent(burningDimando); crashingDimando.addDependency(longDimando); - CelestialTimeManager.addCelestialEvent(flyingDimando, DayQuarter.MORNING, DayQuarter.MORNING); - CelestialTimeManager.addCelestialEvent(fallingDimando, DayQuarter.NOON, DayQuarter.MIDNIGHT); - CelestialTimeManager.addCelestialEvent(crashingDimando, DayQuarter.NOON, DayQuarter.NOON); - CelestialTimeManager.addCelestialEvent(spinningDimando, DayQuarter.EVENING, DayQuarter.NOON); - CelestialTimeManager.addCelestialEvent(burningDimando, DayQuarter.MIDNIGHT, DayQuarter.EVENING); - CelestialTimeManager.addCelestialEvent(longDimando, DayQuarter.MIDNIGHT, DayQuarter.MIDNIGHT); + ((CelestialActivityStateManager) event.world).getCelestialTimeManager().addCelestialEvent(flyingDimando, DayQuarter.MORNING, DayQuarter.MORNING); + ((CelestialActivityStateManager) event.world).getCelestialTimeManager().addCelestialEvent(fallingDimando, DayQuarter.NOON, DayQuarter.MIDNIGHT); + ((CelestialActivityStateManager) event.world).getCelestialTimeManager().addCelestialEvent(crashingDimando, DayQuarter.NOON, DayQuarter.NOON); + ((CelestialActivityStateManager) event.world).getCelestialTimeManager().addCelestialEvent(spinningDimando, DayQuarter.EVENING, DayQuarter.NOON); + ((CelestialActivityStateManager) event.world).getCelestialTimeManager().addCelestialEvent(burningDimando, DayQuarter.MIDNIGHT, DayQuarter.EVENING); + ((CelestialActivityStateManager) event.world).getCelestialTimeManager().addCelestialEvent(longDimando, DayQuarter.MIDNIGHT, DayQuarter.MIDNIGHT); } } diff --git a/src/test/java/net/modificationstation/sltest/celestial/DebugCelestialEvent.java b/src/test/java/net/modificationstation/sltest/celestial/DebugCelestialEvent.java index c854bd3a4..d75f194fa 100644 --- a/src/test/java/net/modificationstation/sltest/celestial/DebugCelestialEvent.java +++ b/src/test/java/net/modificationstation/sltest/celestial/DebugCelestialEvent.java @@ -2,21 +2,22 @@ import net.minecraft.world.World; import net.modificationstation.stationapi.api.celestial.CelestialEvent; +import net.modificationstation.stationapi.api.util.Identifier; public class DebugCelestialEvent extends CelestialEvent { - public DebugCelestialEvent(int frequency, String name, World world) { - super(frequency, name, world); + public DebugCelestialEvent(int frequency, Identifier name) { + super(frequency, name); } @Override - public void onActivation() { - super.onActivation(); - System.out.println(this.getName() + " has begun"); + public void onActivation(World world) { + super.onActivation(world); + System.out.println(this.getIdentifier() + " has begun"); } @Override - public void onDeactivation() { - super.onDeactivation(); - System.out.println(this.getName() + " is over"); + public void onDeactivation(World world) { + super.onDeactivation(world); + System.out.println(this.getIdentifier() + " is over"); } } diff --git a/src/test/java/net/modificationstation/sltest/celestial/FlyingDimando.java b/src/test/java/net/modificationstation/sltest/celestial/FlyingDimando.java index 7eb289f0d..a03b3d37e 100644 --- a/src/test/java/net/modificationstation/sltest/celestial/FlyingDimando.java +++ b/src/test/java/net/modificationstation/sltest/celestial/FlyingDimando.java @@ -1,15 +1,16 @@ package net.modificationstation.sltest.celestial; import net.minecraft.world.World; +import net.modificationstation.stationapi.api.util.Identifier; public class FlyingDimando extends DebugCelestialEvent { - public FlyingDimando(int frequency, String name, World world) { - super(frequency, name, world); + public FlyingDimando(int frequency, Identifier name) { + super(frequency, name); } @Override - public void onActivation() { - super.onActivation(); + public void onActivation(World world) { + super.onActivation(world); world.method_262().setRaining(true); world.method_262().setRainTime(200); } diff --git a/src/test/java/net/modificationstation/sltest/item/CelestialToggleItem.java b/src/test/java/net/modificationstation/sltest/item/CelestialToggleItem.java index c18c8821e..c6c9c723a 100644 --- a/src/test/java/net/modificationstation/sltest/item/CelestialToggleItem.java +++ b/src/test/java/net/modificationstation/sltest/item/CelestialToggleItem.java @@ -15,17 +15,17 @@ public CelestialToggleItem(Identifier identifier) { @Override public ItemStack use(ItemStack item, World world, PlayerEntity player) { if (CelestialListener.fallingDimando.isActive()) { - CelestialListener.fallingDimando.stopEvent(); + CelestialListener.fallingDimando.stopEvent(world); System.out.println("Stopping Falling Dimando"); - } else if (CelestialListener.fallingDimando.activateEvent(world.getTime(), random)) { + } else if (CelestialListener.fallingDimando.activateEvent(world, world.getTime(), random)) { System.out.println("Activating Falling Dimando"); } else { System.out.println("Falling Dimando not activated"); } if (CelestialListener.flyingDimando.isActive()) { - CelestialListener.flyingDimando.stopEvent(); + CelestialListener.flyingDimando.stopEvent(world); System.out.println("Stopping Flying Dimando"); - } else if (CelestialListener.flyingDimando.activateEvent(world.getTime(), random)) { + } else if (CelestialListener.flyingDimando.activateEvent(world, world.getTime(), random)) { System.out.println("Activating Flying Dimando"); } else { System.out.println("Flying Dimando not activated"); diff --git a/station-celestial-events-v0/build.gradle.kts b/station-celestial-events-v0/build.gradle.kts new file mode 100644 index 000000000..52c0fbfe8 --- /dev/null +++ b/station-celestial-events-v0/build.gradle.kts @@ -0,0 +1,9 @@ +import net.modificationstation.stationapi.gradle.SubprojectHelpers.getSubprojectVersion +import net.modificationstation.stationapi.gradle.SubprojectHelpers.addModuleDependencies +base.archivesName.set("station-celestial-events-v0") +version = getSubprojectVersion(project, "1.0.0") + +addModuleDependencies(project, + "station-api-base", + "station-registry-api-v0", +) \ No newline at end of file diff --git a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialActivityStateManager.java b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialActivityStateManager.java new file mode 100644 index 000000000..1d14898bf --- /dev/null +++ b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialActivityStateManager.java @@ -0,0 +1,7 @@ +package net.modificationstation.stationapi.api.celestial; + +public interface CelestialActivityStateManager { + + CelestialEventActivityState getCelestialEvents(); + CelestialTimeManager getCelestialTimeManager(); +} diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java similarity index 66% rename from station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java rename to station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java index 77dff10c9..e06a14654 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java +++ b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEvent.java @@ -2,6 +2,8 @@ import lombok.Getter; import net.minecraft.world.World; +import net.modificationstation.stationapi.api.registry.Registry; +import net.modificationstation.stationapi.api.util.Identifier; import java.util.LinkedList; import java.util.List; @@ -14,7 +16,7 @@ */ public class CelestialEvent { @Getter - private final String name; + private final Identifier identifier; private final int frequency; private float chance = 1; private int dayLength = 24000; @@ -27,29 +29,27 @@ public class CelestialEvent { private boolean initializationNeeded = true; private final List incompatibleEvents = new LinkedList<>(); private final List dependencies = new LinkedList<>(); - public final World world; /** * Primary constructor for the event, containing the required parameters. * * @param frequency Specifies how many day apart the events should be. The bigger the number, the longer the distance. - * @param name Event name, snake_casing is recommended. - * @param world World object, obtained from the register event. + * @param identifier Event identifier. */ - public CelestialEvent(int frequency, String name, World world) { + public CelestialEvent(int frequency, Identifier identifier) { this.frequency = frequency; - this.name = name; - this.world = world; - CelestialInitializer.addEvent(this); + this.identifier = identifier; + Registry.register(CelestialEventRegistry.INSTANCE, identifier,this); } /** * Builder method for optional chance value. * + * @param world The world this event is being called on. * @param chance Value ranging from 0.0F to 1.0F, representing percentage chance. * @return The object itself. */ - public CelestialEvent setChance(float chance) { + public CelestialEvent setChance(World world, float chance) { this.chance = chance; return this; } @@ -59,10 +59,11 @@ public CelestialEvent setChance(float chance) { * Intended to be used in dimensions where day time is different. * This will however need a custom time manager to account for the different day length. * + * @param world The world this event is being called on. * @param dayLength Length of day specified in ticks. * @return The object itself. */ - public CelestialEvent setDayLength(int dayLength) { + public CelestialEvent setDayLength(World world, int dayLength) { this.dayLength = dayLength; return this; } @@ -70,10 +71,11 @@ public CelestialEvent setDayLength(int dayLength) { /** * Builder method for optional day offset. * + * @param world The world this event is being called on. * @param dayOffset Offsets the frequency by the specified number of days. * @return The object itself. */ - public CelestialEvent setDayOffset(int dayOffset) { + public CelestialEvent setDayOffset(World world, int dayOffset) { this.dayOffset = dayOffset; return this; } @@ -81,10 +83,11 @@ public CelestialEvent setDayOffset(int dayOffset) { /** * Builder method for optional extra days. * + * @param world The world this event is being called on. * @param extraDays Extends the event duration by the specified number of days. * @return The object itself. */ - public CelestialEvent setExtraDays(int extraDays) { + public CelestialEvent setExtraDays(World world, int extraDays) { this.extraDays = extraDays; return this; } @@ -95,52 +98,45 @@ public CelestialEvent setExtraDays(int extraDays) { * Method gets called by CelestialTimeManager in case the event is added to it. * Can be called manually as well. * + * @param world The world this event is being called on. * @param worldTime Current time in the world measured in ticks. * @param random Locally used randomizer, seed is irrelevant. * @return True if the event met the criteria to be activated, otherwise false. */ - public boolean activateEvent(long worldTime, Random random) { - CelestialEventActivityState activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); + public boolean activateEvent(World world, long worldTime, Random random) { + CelestialEventActivityState activityState = ((CelestialActivityStateManager) world).getCelestialEvents(); if (initializationNeeded) { - activityState = initializeEvent(); + activityState = initializeEvent(world); } if (active) { - activityState.active = true; - activityState.attemptedActivation = true; - activityState.markDirty(); + activityState.set(identifier, true, true); return true; } for (CelestialEvent otherEvent : incompatibleEvents) { if (otherEvent == null) continue; if (otherEvent.isActive()) { - activityState.active = false; - activityState.attemptedActivation = true; - activityState.markDirty(); + activityState.set(identifier, false, true); return false; } } for (CelestialEvent otherEvent : dependencies) { if (otherEvent == null) continue; if (!otherEvent.isActive()) { - activityState.active = false; - activityState.attemptedActivation = true; - activityState.markDirty(); + activityState.set(identifier, false, true); return false; } } - long days = (worldTime / dayLength) + dayOffset; + long days = (world.getTime() / dayLength) + dayOffset; if (days % frequency > extraDays) { - activityState.attemptedActivation = false; + activityState.setAttemptedActivate(identifier, false); return false; } - if (!activityState.attemptedActivation) { + if (!activityState.hasAttemptedActivation(identifier)) { active = days % frequency <= extraDays && random.nextFloat() <= chance; - } - if (active) { - activityState.active = true; - activityState.attemptedActivation = true; - activityState.markDirty(); - onActivation(); + if (active) { + activityState.set(identifier, true, true); + onActivation(world); + } } return active; } @@ -149,16 +145,20 @@ public boolean activateEvent(long worldTime, Random random) { * Called precisely on event activation. * Can be customized by inheriting from this class. * Has access to the world object for more versatility. + * + * @param world The world this event is being called on. */ - public void onActivation() { + public void onActivation(World world) { } /** * Called precisely on event deactivation. * Can be customized by inheriting from this class. * Has access to the world object for more versatility. + * + * @param world The world this event is being called on. */ - public void onDeactivation() { + public void onDeactivation(World world) { } /** @@ -166,22 +166,23 @@ public void onDeactivation() { * Used by CelestialTimeManager 4 times per day. * Checks for validity of the time interval but not for chance and incompatibility. * + * @param world The world this event is being called on. * @param worldTime Current time in the world measured in ticks. */ - public void updateEvent(long worldTime) { - CelestialEventActivityState activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); + public void updateEvent(World world, long worldTime) { + CelestialEventActivityState activityState = ((CelestialActivityStateManager) world).getCelestialEvents(); if (initializationNeeded) { - activityState = initializeEvent(); + activityState = initializeEvent(world); } - if (!active && !activityState.active) return; + if (!active && !activityState.isActive(identifier)) return; worldTime -= startingDaytime; worldTime += endingDaytime; long days = (worldTime / dayLength) + dayOffset; active = days % frequency <= extraDays; - activityState.active = active; + activityState.setActive(identifier, active); if (!active) { - onDeactivation(); - activityState.attemptedActivation = false; + onDeactivation(world); + activityState.setAttemptedActivate(identifier, false); } activityState.markDirty(); } @@ -190,34 +191,31 @@ public void updateEvent(long worldTime) { * Initializes the event by synchronizing it with NBT data. * Only used internally. * + * @param world The world this event is being called on. * @return The initialized CelestialEventActivityState. */ - private CelestialEventActivityState initializeEvent() { + private CelestialEventActivityState initializeEvent(World world) { initializationNeeded = false; - CelestialEventActivityState activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); - if (activityState == null) { - activityState = new CelestialEventActivityState(this.name); - this.world.setState(this.name, activityState); - } else { - active = activityState.active; - } + CelestialEventActivityState activityState = ((CelestialActivityStateManager) world).getCelestialEvents(); + active = activityState.isActive(identifier); return activityState; } /** * Manual way of stopping event. * Intended for command systems. + * + * @param world The world this event is being called on. */ - public void stopEvent() { - onDeactivation(); + public void stopEvent(World world) { + onDeactivation(world); if (active) { - CelestialEventActivityState activityState = (CelestialEventActivityState) this.world.getOrCreateState(CelestialEventActivityState.class, this.name); + CelestialEventActivityState activityState = ((CelestialActivityStateManager) world).getCelestialEvents(); if (initializationNeeded) { - activityState = initializeEvent(); + activityState = initializeEvent(world); } - activityState.active = false; - activityState.markDirty(); - System.out.println("Stopping event " + name); + activityState.setActive(identifier, false); + System.out.println("Stopping event " + identifier); active = false; } } @@ -261,9 +259,8 @@ public void addDependency(CelestialEvent dependency) { /** * Used by CelestialTimeManager to handle an edge-case where events would not be loaded when reloading the same world. */ - public void markForInitialization() { - this.world.getOrCreateState(CelestialEventActivityState.class, this.name); - initializeEvent(); + public void markForInitialization(World world) { + initializeEvent(world); initializationNeeded = false; } } diff --git a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java new file mode 100644 index 000000000..02a311ee6 --- /dev/null +++ b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java @@ -0,0 +1,75 @@ +package net.modificationstation.stationapi.api.celestial; + +import it.unimi.dsi.fastutil.objects.Object2BooleanMap; +import it.unimi.dsi.fastutil.objects.Object2BooleanMaps; +import net.minecraft.nbt.NbtByte; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.world.PersistentState; +import net.modificationstation.stationapi.api.util.Identifier; +import net.modificationstation.stationapi.mixin.world.NbtCompoundAccessor; + +import java.util.*; + +/** + * Manages important NBT data to ensure correct saving and loading of active celestial events. + */ +public class CelestialEventActivityState extends PersistentState { + + public static final String ID = "stationapi_celestial_events"; + + private HashMap activeEvents = new HashMap<>(); + private HashMap attemptedActivatedEvents = new HashMap<>(); + + public CelestialEventActivityState(String id) { + super(id); + } + + public void set(Identifier identifier, boolean active, boolean attemptedActivate) { + activeEvents.put(identifier, active); + attemptedActivatedEvents.put(identifier, attemptedActivate); + markDirty(); + } + + public void setActive(Identifier identifier, boolean active) { + activeEvents.put(identifier, active); + markDirty(); + } + + public void setAttemptedActivate(Identifier identifier, boolean attemptedActivate) { + attemptedActivatedEvents.put(identifier, attemptedActivate); + markDirty(); + } + + public boolean isActive(Identifier identifier) { + return activeEvents.containsKey(identifier) && activeEvents.get(identifier); + } + + public boolean hasAttemptedActivation(Identifier identifier) { + return attemptedActivatedEvents.containsKey(identifier) && attemptedActivatedEvents.get(identifier); + } + + @Override + public void readNbt(NbtCompound nbt) { + HashMap activeEvents = new HashMap<>(); + //noinspection unchecked + ((NbtCompoundAccessor) nbt.getCompound("activeEvents")).getEntries().forEach((ide, nbtBoolean) -> activeEvents.put(Identifier.of((String) ide), ((NbtByte) nbtBoolean).value == 1)); + this.activeEvents = activeEvents; + + HashMap attemptedActivatedEvents = new HashMap<>(); + //noinspection unchecked + ((NbtCompoundAccessor) nbt.getCompound("activeEvents")).getEntries().forEach((ide, nbtBoolean) -> activeEvents.put(Identifier.of((String) ide), ((NbtByte) nbtBoolean).value == 1)); + this.attemptedActivatedEvents = attemptedActivatedEvents; + } + + @Override + public void writeNbt(NbtCompound nbt) { + NbtCompound compound = new NbtCompound(); + activeEvents.forEach((identifier, aBoolean) -> compound.putBoolean(String.valueOf(identifier), aBoolean)); + nbt.put("activeEvents", compound); + + NbtCompound compound1 = new NbtCompound(); + attemptedActivatedEvents.forEach((identifier, aBoolean) -> compound1.putBoolean(String.valueOf(identifier), aBoolean)); + nbt.put("attemptedActivatedEvents", (NbtElement) compound); + } +} diff --git a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventRegistry.java b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventRegistry.java new file mode 100644 index 000000000..7b6b2b06b --- /dev/null +++ b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventRegistry.java @@ -0,0 +1,34 @@ +package net.modificationstation.stationapi.api.celestial; + +import com.mojang.serialization.Lifecycle; +import net.minecraft.world.World; +import net.modificationstation.stationapi.api.StationAPI; +import net.modificationstation.stationapi.api.registry.Registry; +import net.modificationstation.stationapi.api.registry.RegistryKey; +import net.modificationstation.stationapi.api.registry.SimpleRegistry; +import net.modificationstation.stationapi.api.util.Identifier; + +/** + * Automatically handles initialization of celestial events. + * Ensures that all celestial events are loaded correctly. + */ +public class CelestialEventRegistry extends SimpleRegistry { + public static final Identifier IDENTIFIER = Identifier.of(StationAPI.NAMESPACE, "celestial_events"); + public static final RegistryKey> KEY = RegistryKey.ofRegistry(IDENTIFIER); + + public static final CelestialEventRegistry INSTANCE = new CelestialEventRegistry(); + + private CelestialEventRegistry() { + super(KEY, Lifecycle.stable()); + } + + /** + * Initializes all events when the world is loaded, ensures correct loading of active events. + */ + public void initializeEvents(World world) { + stream().forEach(celestialEvent -> { + if (celestialEvent == null) return; + celestialEvent.markForInitialization(world); + }); + } +} diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java similarity index 67% rename from station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java rename to station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java index f76e28636..bd7af3b9e 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java +++ b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java @@ -1,8 +1,8 @@ package net.modificationstation.stationapi.api.celestial; -import java.util.LinkedList; -import java.util.List; -import java.util.Random; +import net.minecraft.world.World; + +import java.util.*; /** * Manages the activation and deactivation of celestial events. @@ -12,20 +12,26 @@ * Called four times per day. */ public class CelestialTimeManager { - private static final List MORNING_START = new LinkedList<>(); - private static final List NOON_START = new LinkedList<>(); - private static final List EVENING_START = new LinkedList<>(); - private static final List MIDNIGHT_START = new LinkedList<>(); - private static final List ALL_EVENTS = new LinkedList<>(); + private final List MORNING_START = new ArrayList<>(); + private final List NOON_START = new LinkedList<>(); + private final List EVENING_START = new LinkedList<>(); + private final List MIDNIGHT_START = new LinkedList<>(); + private final List ALL_EVENTS = new LinkedList<>(); + + private boolean morningActivation = false; + private boolean noonActivation = false; + private boolean eveningActivation = false; + private boolean midnightActivation = false; - private static boolean morningActivation = false; - private static boolean noonActivation = false; - private static boolean eveningActivation = false; - private static boolean midnightActivation = false; + private long lastCheckedDay = 0; - private static long lastCheckedDay = 0; + private final Random RANDOM = new Random(); - private static final Random RANDOM = new Random(); + private final World world; + + public CelestialTimeManager(World world) { + this.world = world; + } /** * Add a celestial event to the time manager. @@ -34,7 +40,7 @@ public class CelestialTimeManager { * @param start Time of day at which the event begins. * @param stop Time of day at which the event ends. */ - public static void addCelestialEvent(CelestialEvent celestialEvent, DayQuarter start, DayQuarter stop) { + public void addCelestialEvent(CelestialEvent celestialEvent, DayQuarter start, DayQuarter stop) { switch (start) { case MORNING -> MORNING_START.add(celestialEvent); case NOON -> NOON_START.add(celestialEvent); @@ -51,7 +57,7 @@ public static void addCelestialEvent(CelestialEvent celestialEvent, DayQuarter s * @param time World time in ticks. * @param currentDay Current day in the world. */ - public static void startMorningEvents(long time, long currentDay) { + public void startMorningEvents(long time, long currentDay) { if (morningActivation && lastCheckedDay == currentDay) return; lastCheckedDay = currentDay; morningActivation = true; @@ -61,7 +67,7 @@ public static void startMorningEvents(long time, long currentDay) { updateEvents(time); for (CelestialEvent celestialEvent : MORNING_START) { if (celestialEvent == null) continue; - celestialEvent.activateEvent(time, RANDOM); + celestialEvent.activateEvent(world, time, RANDOM); } } @@ -71,7 +77,7 @@ public static void startMorningEvents(long time, long currentDay) { * @param time World time in ticks. * @param currentDay Current day in the world. */ - public static void startNoonEvents(long time, long currentDay) { + public void startNoonEvents(long time, long currentDay) { if (noonActivation && lastCheckedDay == currentDay) return; lastCheckedDay = currentDay; morningActivation = false; @@ -81,7 +87,7 @@ public static void startNoonEvents(long time, long currentDay) { updateEvents(time); for (CelestialEvent celestialEvent : NOON_START) { if (celestialEvent == null) continue; - celestialEvent.activateEvent(time, RANDOM); + celestialEvent.activateEvent(world, time, RANDOM); } } @@ -91,7 +97,7 @@ public static void startNoonEvents(long time, long currentDay) { * @param time World time in ticks. * @param currentDay Current day in the world. */ - public static void startEveningEvents(long time, long currentDay) { + public void startEveningEvents(long time, long currentDay) { if (eveningActivation && lastCheckedDay == currentDay) return; lastCheckedDay = currentDay; morningActivation = false; @@ -101,7 +107,7 @@ public static void startEveningEvents(long time, long currentDay) { updateEvents(time); for (CelestialEvent celestialEvent : EVENING_START) { if (celestialEvent == null) continue; - celestialEvent.activateEvent(time, RANDOM); + celestialEvent.activateEvent(world, time, RANDOM); } } @@ -111,7 +117,7 @@ public static void startEveningEvents(long time, long currentDay) { * @param time World time in ticks. * @param currentDay Current day in the world. */ - public static void startMidnightEvents(long time, long currentDay) { + public void startMidnightEvents(long time, long currentDay) { if (midnightActivation && lastCheckedDay == currentDay) return; lastCheckedDay = currentDay; morningActivation = false; @@ -121,7 +127,7 @@ public static void startMidnightEvents(long time, long currentDay) { updateEvents(time); for (CelestialEvent celestialEvent : MIDNIGHT_START) { if (celestialEvent == null) continue; - celestialEvent.activateEvent(time, RANDOM); + celestialEvent.activateEvent(world, time, RANDOM); } } @@ -130,21 +136,10 @@ public static void startMidnightEvents(long time, long currentDay) { * * @param time World time in ticks. */ - public static void updateEvents(long time) { + public void updateEvents(long time) { for (CelestialEvent celestialEvent : ALL_EVENTS) { if (celestialEvent == null) continue; - celestialEvent.updateEvent(time); + celestialEvent.updateEvent(world, time); } } - - /** - * Clears all lists. Ensures that no duplicates show up after switching worlds. - */ - public static void clearLists() { - MORNING_START.clear(); - NOON_START.clear(); - EVENING_START.clear(); - MIDNIGHT_START.clear(); - ALL_EVENTS.clear(); - } } diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/DayQuarter.java b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/DayQuarter.java similarity index 100% rename from station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/DayQuarter.java rename to station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/DayQuarter.java diff --git a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/WorldPropertiesWithWorld.java b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/WorldPropertiesWithWorld.java new file mode 100644 index 000000000..b54ca16d5 --- /dev/null +++ b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/WorldPropertiesWithWorld.java @@ -0,0 +1,9 @@ +package net.modificationstation.stationapi.api.celestial; + +import net.minecraft.world.World; + +public interface WorldPropertiesWithWorld { + + void setWorld(World world); + World getWorld(); +} diff --git a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java new file mode 100644 index 000000000..91eceae68 --- /dev/null +++ b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java @@ -0,0 +1,10 @@ +package net.modificationstation.stationapi.api.event.celestial; + +import lombok.experimental.SuperBuilder; +import net.mine_diver.unsafeevents.Event; +import net.minecraft.world.World; + +@SuperBuilder +public class CelestialRegisterEvent extends Event { + public final World world; +} diff --git a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/NbtCompoundAccessor.java b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/NbtCompoundAccessor.java new file mode 100644 index 000000000..5d6bf238a --- /dev/null +++ b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/NbtCompoundAccessor.java @@ -0,0 +1,17 @@ +package net.modificationstation.stationapi.mixin.world; + +import net.minecraft.nbt.NbtCompound; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.*; + +@Mixin(NbtCompound.class) +public interface NbtCompoundAccessor { + + @Accessor + Map getEntries(); + + @Accessor + void setEntries(Map value); +} diff --git a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java new file mode 100644 index 000000000..c0f3eda48 --- /dev/null +++ b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java @@ -0,0 +1,63 @@ +package net.modificationstation.stationapi.mixin.world; + +import net.minecraft.world.PersistentState; +import net.minecraft.world.PersistentStateManager; +import net.minecraft.world.World; +import net.minecraft.world.WorldProperties; +import net.modificationstation.stationapi.api.celestial.CelestialActivityStateManager; +import net.modificationstation.stationapi.api.StationAPI; +import net.modificationstation.stationapi.api.celestial.CelestialEventActivityState; +import net.modificationstation.stationapi.api.celestial.CelestialEventRegistry; +import net.modificationstation.stationapi.api.celestial.CelestialTimeManager; +import net.modificationstation.stationapi.api.celestial.WorldPropertiesWithWorld; +import net.modificationstation.stationapi.api.event.celestial.CelestialRegisterEvent; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(World.class) +abstract +class WorldMixin implements CelestialActivityStateManager { + + @Shadow public abstract PersistentState getOrCreateState(Class stateClass, String id); + @Shadow public abstract void setState(String id, PersistentState state); + + @Shadow protected WorldProperties properties; + @Unique + private CelestialEventActivityState celestialEventActivityState; + @Unique + private CelestialTimeManager celestialTimeManager; + + @Inject( + method = { + "(Lnet/minecraft/world/dimension/DimensionData;Ljava/lang/String;Lnet/minecraft/world/dimension/Dimension;J)V", + "(Lnet/minecraft/world/World;Lnet/minecraft/world/dimension/Dimension;)V", + "(Lnet/minecraft/world/dimension/DimensionData;Ljava/lang/String;JLnet/minecraft/world/dimension/Dimension;)V" + }, + at = @At("RETURN") + ) + private void stationapi_onCor1(CallbackInfo ci) { + ((WorldPropertiesWithWorld) properties).setWorld((World) (Object) this); + celestialEventActivityState = (CelestialEventActivityState) getOrCreateState(CelestialEventActivityState.class, CelestialEventActivityState.ID); + if (celestialEventActivityState == null) { + celestialEventActivityState = new CelestialEventActivityState(CelestialEventActivityState.ID); + } + celestialTimeManager = new CelestialTimeManager((World) (Object) this); + setState(CelestialEventActivityState.ID, celestialEventActivityState); + StationAPI.EVENT_BUS.post(CelestialRegisterEvent.builder().world(World.class.cast(this)).build()); + CelestialEventRegistry.INSTANCE.initializeEvents((World) (Object) this); + } + + @Override + public CelestialEventActivityState getCelestialEvents() { + return celestialEventActivityState; + } + + @Override + public CelestialTimeManager getCelestialTimeManager() { + return celestialTimeManager; + } +} diff --git a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java new file mode 100644 index 000000000..d598f40d9 --- /dev/null +++ b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java @@ -0,0 +1,51 @@ +package net.modificationstation.stationapi.mixin.world; + +import net.minecraft.world.World; +import net.minecraft.world.WorldProperties; +import net.modificationstation.stationapi.api.celestial.CelestialActivityStateManager; +import net.modificationstation.stationapi.api.celestial.WorldPropertiesWithWorld; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(WorldProperties.class) +public class WorldPropertiesMixin implements WorldPropertiesWithWorld { + @Shadow private long time; + + @Unique + private World world; + + @Inject( + method = "setTime", + at = @At("HEAD") + ) + private void stationapi_celestialEventTimeManager(CallbackInfo ci) { + if (((CelestialActivityStateManager) world).getCelestialTimeManager() == null) { + return; + } + long daytime = time % 24000; + long currentDay = time / 24000; + if (daytime >= 0 && daytime < 6000) { + ((CelestialActivityStateManager) world).getCelestialTimeManager().startMorningEvents(time, currentDay); + } else if (daytime >= 6000 && daytime < 12000) { + ((CelestialActivityStateManager) world).getCelestialTimeManager().startNoonEvents(time, currentDay); + } else if (daytime >= 12000 && daytime < 18000) { + ((CelestialActivityStateManager) world).getCelestialTimeManager().startEveningEvents(time, currentDay); + } else if (daytime >= 18000) { + ((CelestialActivityStateManager) world).getCelestialTimeManager().startMidnightEvents(time, currentDay); + } + } + + @Override + public void setWorld(World world) { + this.world = world; + } + + @Override + public World getWorld() { + return world; + } +} diff --git a/station-celestial-events-v0/src/main/resources/assets/station-celestial-events-v0/icon.png b/station-celestial-events-v0/src/main/resources/assets/station-celestial-events-v0/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..0affee82903e42e3158ebaabac81d72067635359 GIT binary patch literal 210839 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

&R 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

4kbdp_*N7>$%@{$ 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 literal 0 HcmV?d00001 diff --git a/station-celestial-events-v0/src/main/resources/fabric.mod.json b/station-celestial-events-v0/src/main/resources/fabric.mod.json new file mode 100644 index 000000000..ad1caed31 --- /dev/null +++ b/station-celestial-events-v0/src/main/resources/fabric.mod.json @@ -0,0 +1,38 @@ +{ + "schemaVersion": 1, + "id": "station-celestial-events-v0", + "version": "${version}", + + "name": "Station Celestial Events (v0)", + "description": "Provides some events for time-related events.", + "authors": [ + "Modification Station" + ], + "contact": { + "homepage": "https://glass-launcher.net/repo/mod/stationapi", + "sources": "https://github.com/ModificationStation/StationAPI", + "issues": "https://github.com/ModificationStation/StationAPI/issues" + }, + + "license": "MIT", + "icon": "assets/station-celestial-events-v0/icon.png", + + "environment": "*", + "mixins": [ + "station-celestial-events-v0.mixins.json" + ], + + "depends": { + "fabricloader": "*", + "minecraft": "1.0.0-beta.7.3" + }, + + "custom": { + "modmenu:api": true, + + "loom:injected_interfaces": { + "net/minecraft/class_18": ["net/modificationstation/stationapi/api/celestial/CelestialActivityStateManager"], + "net/minecraft/class_7": ["net/modificationstation/stationapi/api/celestial/WorldPropertiesWithWorld"] + } + } +} \ No newline at end of file diff --git a/station-celestial-events-v0/src/main/resources/station-celestial-events-v0.mixins.json b/station-celestial-events-v0/src/main/resources/station-celestial-events-v0.mixins.json new file mode 100644 index 000000000..ee45f4091 --- /dev/null +++ b/station-celestial-events-v0/src/main/resources/station-celestial-events-v0.mixins.json @@ -0,0 +1,22 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "net.modificationstation.stationapi.mixin.world", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "DimensionFileMixin", + "NbtCompoundAccessor", + "ServerChunkCacheMixin", + "WorldMixin", + "WorldPropertiesMixin" + ], + "client": [ + "client.ChunkCacheMixin" + ], + "injectors": { + "defaultRequire": 1 + }, + "server": [ + "server.class_79Mixin" + ] +} diff --git a/station-world-events-v0/build.gradle.kts b/station-world-events-v0/build.gradle.kts index 254b0113b..70701748b 100644 --- a/station-world-events-v0/build.gradle.kts +++ b/station-world-events-v0/build.gradle.kts @@ -4,5 +4,5 @@ base.archivesName.set("station-world-events-v0") version = getSubprojectVersion(project, "1.0.0") addModuleDependencies(project, - "station-api-base" + "station-api-base", ) \ No newline at end of file diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java deleted file mode 100644 index 49dee6132..000000000 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.modificationstation.stationapi.api.celestial; - -import net.minecraft.nbt.NbtCompound; -import net.minecraft.world.PersistentState; - -/** - * Manages important NBT data to ensure correct saving and loading of active celestial events. - */ -public class CelestialEventActivityState extends PersistentState { - public boolean active; - public boolean attemptedActivation; - - public CelestialEventActivityState(String id) { - super(id); - } - - @Override - public void readNbt(NbtCompound nbt) { - this.active = nbt.getBoolean("active"); - this.attemptedActivation = nbt.getBoolean("attemptedActivation"); - } - - @Override - public void writeNbt(NbtCompound nbt) { - nbt.putBoolean("active", active); - nbt.putBoolean("attemptedActivation", attemptedActivation); - } -} diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialInitializer.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialInitializer.java deleted file mode 100644 index 535d0614e..000000000 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialInitializer.java +++ /dev/null @@ -1,37 +0,0 @@ -package net.modificationstation.stationapi.api.celestial; - -import java.util.LinkedList; -import java.util.List; - -/** - * Automatically handles initialization of celestial events. - * Ensures that all celestial events are loaded correctly. - */ -public class CelestialInitializer { - private static final List ALL_EVENTS = new LinkedList<>(); - - /** - * Called automatically by every celestial event. - * @param celestialEvent The event to be added. - */ - public static void addEvent(CelestialEvent celestialEvent) { - ALL_EVENTS.add(celestialEvent); - } - - /** - * Prevents duplicates when worlds are switched. - */ - public static void clearList() { - ALL_EVENTS.clear(); - } - - /** - * Initializes all events when the world is loaded, ensures correct loading of active events. - */ - public static void initializeEvents() { - for (CelestialEvent celestialEvent : ALL_EVENTS) { - if (celestialEvent == null) continue; - celestialEvent.markForInitialization(); - } - } -} diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java deleted file mode 100644 index 75bdd7b76..000000000 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java +++ /dev/null @@ -1,7 +0,0 @@ -package net.modificationstation.stationapi.api.event.celestial; - -import lombok.experimental.SuperBuilder; -import net.modificationstation.stationapi.api.event.world.WorldEvent; - -@SuperBuilder -public class CelestialRegisterEvent extends WorldEvent {} diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java index d30e1e5b0..36e6fe1ad 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java @@ -1,18 +1,26 @@ package net.modificationstation.stationapi.mixin.world; +import net.minecraft.world.PersistentState; +import net.minecraft.world.PersistentStateManager; import net.minecraft.world.World; import net.modificationstation.stationapi.api.StationAPI; -import net.modificationstation.stationapi.api.celestial.CelestialInitializer; -import net.modificationstation.stationapi.api.celestial.CelestialTimeManager; -import net.modificationstation.stationapi.api.event.celestial.CelestialRegisterEvent; import net.modificationstation.stationapi.api.event.world.WorldEvent; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(World.class) +abstract class WorldMixin { + @Shadow public PersistentStateManager persistentStateManager; + + @Shadow public abstract PersistentState getOrCreateState(Class stateClass, String id); + + @Shadow public abstract void setState(String id, PersistentState state); + @Inject( method = { "(Lnet/minecraft/world/dimension/DimensionData;Ljava/lang/String;Lnet/minecraft/world/dimension/Dimension;J)V", @@ -22,11 +30,7 @@ class WorldMixin { at = @At("RETURN") ) private void stationapi_onCor1(CallbackInfo ci) { - CelestialTimeManager.clearLists(); - CelestialInitializer.clearList(); StationAPI.EVENT_BUS.post(WorldEvent.Init.builder().world(World.class.cast(this)).build()); - StationAPI.EVENT_BUS.post(CelestialRegisterEvent.builder().world(World.class.cast(this)).build()); - CelestialInitializer.initializeEvents(); } @Inject( diff --git a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java index 02a0c25cd..69482e9e4 100644 --- a/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java +++ b/station-world-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java @@ -3,20 +3,14 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.world.WorldProperties; import net.modificationstation.stationapi.api.StationAPI; -import net.modificationstation.stationapi.api.celestial.CelestialTimeManager; -import net.modificationstation.stationapi.api.event.celestial.CelestialRegisterEvent; import net.modificationstation.stationapi.api.event.world.WorldPropertiesEvent; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(WorldProperties.class) public class WorldPropertiesMixin { - @Shadow private long time; - - @Shadow private long lastPlayed; @Inject( method = "(Lnet/minecraft/nbt/NbtCompound;)V", @@ -44,22 +38,4 @@ private void stationapi_onSaveToTag(NbtCompound arg, NbtCompound arg1, CallbackI .build() ); } - - @Inject( - method = "setTime", - at = @At("HEAD") - ) - private void stationapi_celestialEventTimeManager(CallbackInfo ci) { - long daytime = time % 24000; - long currentDay = time / 24000; - if (daytime >= 0 && daytime < 6000) { - CelestialTimeManager.startMorningEvents(time, currentDay); - } else if (daytime >= 6000 && daytime < 12000) { - CelestialTimeManager.startNoonEvents(time, currentDay); - } else if (daytime >= 12000 && daytime < 18000) { - CelestialTimeManager.startEveningEvents(time, currentDay); - } else if (daytime >= 18000) { - CelestialTimeManager.startMidnightEvents(time, currentDay); - } - } } From 455eee5224a06a30f8a58fb544cffcab458309af Mon Sep 17 00:00:00 2001 From: calmilamsy Date: Thu, 7 Nov 2024 18:04:41 +0000 Subject: [PATCH 22/22] Fix registering on world load --- .../sltest/celestial/CelestialListener.java | 19 ++++++-------- .../CelestialEventActivityState.java | 6 ++--- .../api/celestial/CelestialTimeManager.java | 5 +++- .../celestial/CelestialRegisterEvent.java | 4 --- .../NbtCompoundAccessor.java | 4 +-- .../{world => celestial}/WorldMixin.java | 12 ++------- .../WorldPropertiesMixin.java | 2 +- .../celestial/client/MinecraftMixin.java | 20 +++++++++++++++ .../server/MinecraftServerMixin.java | 25 +++++++++++++++++++ .../station-celestial-events-v0.mixins.json | 14 +++++------ 10 files changed, 70 insertions(+), 41 deletions(-) rename station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/{world => celestial}/NbtCompoundAccessor.java (77%) rename station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/{world => celestial}/WorldMixin.java (74%) rename station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/{world => celestial}/WorldPropertiesMixin.java (96%) create mode 100644 station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/celestial/client/MinecraftMixin.java create mode 100644 station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/celestial/server/MinecraftServerMixin.java diff --git a/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java b/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java index acee9e7c1..19b0172cc 100644 --- a/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java +++ b/src/test/java/net/modificationstation/sltest/celestial/CelestialListener.java @@ -1,26 +1,23 @@ package net.modificationstation.sltest.celestial; import net.mine_diver.unsafeevents.listener.EventListener; -import net.modificationstation.sltest.MainTest; import net.modificationstation.sltest.SLTest; import net.modificationstation.stationapi.api.celestial.CelestialActivityStateManager; -import net.modificationstation.stationapi.api.celestial.CelestialEvent; -import net.modificationstation.stationapi.api.celestial.CelestialTimeManager; import net.modificationstation.stationapi.api.celestial.DayQuarter; -import net.modificationstation.stationapi.api.event.celestial.CelestialRegisterEvent; +import net.modificationstation.stationapi.api.event.celestial.CelestialEvent; import net.modificationstation.stationapi.api.util.Identifier; public class CelestialListener { - public static CelestialEvent flyingDimando; - public static CelestialEvent fallingDimando; - public static CelestialEvent crashingDimando; - public static CelestialEvent spinningDimando; - public static CelestialEvent burningDimando; - public static CelestialEvent longDimando; + public static net.modificationstation.stationapi.api.celestial.CelestialEvent flyingDimando; + public static net.modificationstation.stationapi.api.celestial.CelestialEvent fallingDimando; + public static net.modificationstation.stationapi.api.celestial.CelestialEvent crashingDimando; + public static net.modificationstation.stationapi.api.celestial.CelestialEvent spinningDimando; + public static net.modificationstation.stationapi.api.celestial.CelestialEvent burningDimando; + public static net.modificationstation.stationapi.api.celestial.CelestialEvent longDimando; @EventListener - public void registerCelestialEvents(CelestialRegisterEvent event) { + public void registerCelestialEvents(CelestialEvent event) { SLTest.LOGGER.info("Register celestial events for testing"); flyingDimando = new FlyingDimando(4, Identifier.of(SLTest.NAMESPACE, "flying_dimando")); fallingDimando = new DebugCelestialEvent(2, Identifier.of(SLTest.NAMESPACE, "falling_dimando")); diff --git a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java index 02a311ee6..7d811f4f7 100644 --- a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java +++ b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialEventActivityState.java @@ -1,15 +1,13 @@ package net.modificationstation.stationapi.api.celestial; -import it.unimi.dsi.fastutil.objects.Object2BooleanMap; -import it.unimi.dsi.fastutil.objects.Object2BooleanMaps; import net.minecraft.nbt.NbtByte; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; import net.minecraft.world.PersistentState; import net.modificationstation.stationapi.api.util.Identifier; -import net.modificationstation.stationapi.mixin.world.NbtCompoundAccessor; +import net.modificationstation.stationapi.mixin.celestial.NbtCompoundAccessor; -import java.util.*; +import java.util.HashMap; /** * Manages important NBT data to ensure correct saving and loading of active celestial events. diff --git a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java index bd7af3b9e..f3d8113fe 100644 --- a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java +++ b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/celestial/CelestialTimeManager.java @@ -2,7 +2,10 @@ import net.minecraft.world.World; -import java.util.*; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Random; /** * Manages the activation and deactivation of celestial events. diff --git a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java index 91eceae68..57caf7b61 100644 --- a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java +++ b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/api/event/celestial/CelestialRegisterEvent.java @@ -1,10 +1,6 @@ package net.modificationstation.stationapi.api.event.celestial; -import lombok.experimental.SuperBuilder; import net.mine_diver.unsafeevents.Event; -import net.minecraft.world.World; -@SuperBuilder public class CelestialRegisterEvent extends Event { - public final World world; } diff --git a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/NbtCompoundAccessor.java b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/celestial/NbtCompoundAccessor.java similarity index 77% rename from station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/NbtCompoundAccessor.java rename to station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/celestial/NbtCompoundAccessor.java index 5d6bf238a..cd651e53e 100644 --- a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/NbtCompoundAccessor.java +++ b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/celestial/NbtCompoundAccessor.java @@ -1,10 +1,10 @@ -package net.modificationstation.stationapi.mixin.world; +package net.modificationstation.stationapi.mixin.celestial; import net.minecraft.nbt.NbtCompound; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; -import java.util.*; +import java.util.Map; @Mixin(NbtCompound.class) public interface NbtCompoundAccessor { diff --git a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/celestial/WorldMixin.java similarity index 74% rename from station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java rename to station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/celestial/WorldMixin.java index c0f3eda48..67126315b 100644 --- a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldMixin.java +++ b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/celestial/WorldMixin.java @@ -1,16 +1,9 @@ -package net.modificationstation.stationapi.mixin.world; +package net.modificationstation.stationapi.mixin.celestial; import net.minecraft.world.PersistentState; -import net.minecraft.world.PersistentStateManager; import net.minecraft.world.World; import net.minecraft.world.WorldProperties; -import net.modificationstation.stationapi.api.celestial.CelestialActivityStateManager; -import net.modificationstation.stationapi.api.StationAPI; -import net.modificationstation.stationapi.api.celestial.CelestialEventActivityState; -import net.modificationstation.stationapi.api.celestial.CelestialEventRegistry; -import net.modificationstation.stationapi.api.celestial.CelestialTimeManager; -import net.modificationstation.stationapi.api.celestial.WorldPropertiesWithWorld; -import net.modificationstation.stationapi.api.event.celestial.CelestialRegisterEvent; +import net.modificationstation.stationapi.api.celestial.*; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -47,7 +40,6 @@ private void stationapi_onCor1(CallbackInfo ci) { } celestialTimeManager = new CelestialTimeManager((World) (Object) this); setState(CelestialEventActivityState.ID, celestialEventActivityState); - StationAPI.EVENT_BUS.post(CelestialRegisterEvent.builder().world(World.class.cast(this)).build()); CelestialEventRegistry.INSTANCE.initializeEvents((World) (Object) this); } diff --git a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/celestial/WorldPropertiesMixin.java similarity index 96% rename from station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java rename to station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/celestial/WorldPropertiesMixin.java index d598f40d9..09374c4b7 100644 --- a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/world/WorldPropertiesMixin.java +++ b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/celestial/WorldPropertiesMixin.java @@ -1,4 +1,4 @@ -package net.modificationstation.stationapi.mixin.world; +package net.modificationstation.stationapi.mixin.celestial; import net.minecraft.world.World; import net.minecraft.world.WorldProperties; diff --git a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/celestial/client/MinecraftMixin.java b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/celestial/client/MinecraftMixin.java new file mode 100644 index 000000000..fdddcc82e --- /dev/null +++ b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/celestial/client/MinecraftMixin.java @@ -0,0 +1,20 @@ +package net.modificationstation.stationapi.mixin.celestial.client; + +import net.minecraft.client.Minecraft; +import net.modificationstation.stationapi.api.StationAPI; +import net.modificationstation.stationapi.api.event.celestial.CelestialRegisterEvent; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value = Minecraft.class, priority = 799) +class MinecraftMixin { + @Inject( + method = "run", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;init()V", shift = At.Shift.AFTER) + ) + private void stationapi_endInit(CallbackInfo ci) { + StationAPI.EVENT_BUS.post(new CelestialRegisterEvent()); + } +} diff --git a/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/celestial/server/MinecraftServerMixin.java b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/celestial/server/MinecraftServerMixin.java new file mode 100644 index 000000000..ef877bcb9 --- /dev/null +++ b/station-celestial-events-v0/src/main/java/net/modificationstation/stationapi/mixin/celestial/server/MinecraftServerMixin.java @@ -0,0 +1,25 @@ +package net.modificationstation.stationapi.mixin.celestial.server; + +import net.minecraft.server.MinecraftServer; +import net.modificationstation.stationapi.api.StationAPI; +import net.modificationstation.stationapi.api.event.celestial.CelestialRegisterEvent; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(value = MinecraftServer.class, priority = 799) +class MinecraftServerMixin { + @Inject( + method = "method_2166", + at = @At( + value = "INVOKE", + target = "Ljava/util/logging/Logger;info(Ljava/lang/String;)V", + ordinal = 3, + shift = At.Shift.AFTER + ) + ) + private void stationapi_endInit(CallbackInfoReturnable cir) { + StationAPI.EVENT_BUS.post(new CelestialRegisterEvent()); + } +} \ No newline at end of file diff --git a/station-celestial-events-v0/src/main/resources/station-celestial-events-v0.mixins.json b/station-celestial-events-v0/src/main/resources/station-celestial-events-v0.mixins.json index ee45f4091..b8b381412 100644 --- a/station-celestial-events-v0/src/main/resources/station-celestial-events-v0.mixins.json +++ b/station-celestial-events-v0/src/main/resources/station-celestial-events-v0.mixins.json @@ -1,22 +1,20 @@ { "required": true, "minVersion": "0.8", - "package": "net.modificationstation.stationapi.mixin.world", + "package": "net.modificationstation.stationapi.mixin.celestial", "compatibilityLevel": "JAVA_17", "mixins": [ - "DimensionFileMixin", "NbtCompoundAccessor", - "ServerChunkCacheMixin", "WorldMixin", "WorldPropertiesMixin" ], "client": [ - "client.ChunkCacheMixin" + "client.MinecraftMixin" + ], + "server": [ + "server.MinecraftServerMixin" ], "injectors": { "defaultRequire": 1 - }, - "server": [ - "server.class_79Mixin" - ] + } }