diff --git a/src/main/java/org/violetmoon/quark/base/handler/ItemOverrideHandler.java b/src/main/java/org/violetmoon/quark/base/handler/ItemOverrideHandler.java deleted file mode 100644 index e168aa8962..0000000000 --- a/src/main/java/org/violetmoon/quark/base/handler/ItemOverrideHandler.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.violetmoon.quark.base.handler; - -import net.minecraft.world.item.Item; -import net.minecraft.world.level.block.Block; - -import java.util.HashMap; -import java.util.Map; - -public class ItemOverrideHandler { - - private static final Map defaultItemKeys = new HashMap<>(); - private static final Map defaultBlockKeys = new HashMap<>(); - - public static void changeItemLocalizationKey(Item item, String newKey, boolean enabled) { - if(!enabled) { - if(defaultItemKeys.containsKey(item)) - changeItemLocalizationKey(item, defaultItemKeys.get(item)); - } else { - String currKey = item.descriptionId; - if(!defaultItemKeys.containsKey(item)) - defaultItemKeys.put(item, currKey); - - changeItemLocalizationKey(item, newKey); - } - } - - public static void changeBlockLocalizationKey(Block block, String newKey, boolean enabled) { - if(!enabled) { - if(defaultBlockKeys.containsKey(block)) - changeBlockLocalizationKey(block, defaultBlockKeys.get(block)); - } else { - String currKey = block.descriptionId; - if(!defaultBlockKeys.containsKey(block)) - defaultBlockKeys.put(block, currKey); - - changeBlockLocalizationKey(block, newKey); - } - } - - private static void changeItemLocalizationKey(Item item, String newKey) { - item.descriptionId = newKey; - } - - - private static void changeBlockLocalizationKey(Block block, String newKey) { - block.descriptionId = newKey; - } - -} diff --git a/src/main/java/org/violetmoon/quark/content/building/module/VariantBookshelvesModule.java b/src/main/java/org/violetmoon/quark/content/building/module/VariantBookshelvesModule.java index 2a1166b2eb..d2db885673 100644 --- a/src/main/java/org/violetmoon/quark/content/building/module/VariantBookshelvesModule.java +++ b/src/main/java/org/violetmoon/quark/content/building/module/VariantBookshelvesModule.java @@ -1,7 +1,6 @@ package org.violetmoon.quark.content.building.module; import org.violetmoon.quark.base.config.Config; -import org.violetmoon.quark.base.handler.ItemOverrideHandler; import org.violetmoon.quark.base.util.VanillaWoods; import org.violetmoon.quark.base.util.VanillaWoods.Wood; import org.violetmoon.quark.content.building.block.VariantBookshelfBlock; @@ -26,6 +25,6 @@ public final void register(ZRegister event) { @LoadEvent public final void configChanged(ZConfigChanged event) { - ItemOverrideHandler.changeBlockLocalizationKey(Blocks.BOOKSHELF, "block.quark.oak_bookshelf", changeNames && enabled); + zeta.nameChanger.changeBlock(Blocks.BOOKSHELF, "block.quark.oak_bookshelf", changeNames && enabled); } } diff --git a/src/main/java/org/violetmoon/quark/content/building/module/VariantLaddersModule.java b/src/main/java/org/violetmoon/quark/content/building/module/VariantLaddersModule.java index bd51f1fbb3..ff3eb968d7 100644 --- a/src/main/java/org/violetmoon/quark/content/building/module/VariantLaddersModule.java +++ b/src/main/java/org/violetmoon/quark/content/building/module/VariantLaddersModule.java @@ -1,19 +1,13 @@ package org.violetmoon.quark.content.building.module; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.LadderBlock; -import net.minecraft.world.level.block.TrapDoorBlock; -import net.minecraft.world.level.block.state.BlockState; import java.util.LinkedList; import java.util.List; import org.violetmoon.quark.base.config.Config; import org.violetmoon.quark.base.handler.FuelHandler; -import org.violetmoon.quark.base.handler.ItemOverrideHandler; import org.violetmoon.quark.base.util.VanillaWoods; import org.violetmoon.quark.base.util.VanillaWoods.Wood; import org.violetmoon.quark.content.building.block.VariantLadderBlock; @@ -47,21 +41,7 @@ public void loadComplete(ZLoadComplete e) { @LoadEvent public final void configChanged(ZConfigChanged event) { moduleEnabled = this.enabled; - ItemOverrideHandler.changeBlockLocalizationKey(Blocks.LADDER, "block.quark.oak_ladder", changeNames && enabled); - } - - public static boolean isTrapdoorLadder(boolean defaultValue, LevelReader world, BlockPos pos) { - if(defaultValue || !moduleEnabled) - return defaultValue; - - BlockState curr = world.getBlockState(pos); - if(curr.getProperties().contains(TrapDoorBlock.OPEN) && curr.getValue(TrapDoorBlock.OPEN)) { - BlockState down = world.getBlockState(pos.below()); - if(down.getBlock() instanceof LadderBlock) - return down.getValue(LadderBlock.FACING) == curr.getValue(TrapDoorBlock.FACING); - } - - return false; + zeta.nameChanger.changeBlock(Blocks.LADDER, "block.quark.oak_ladder", changeNames && enabled); } } diff --git a/src/main/java/org/violetmoon/zeta/Zeta.java b/src/main/java/org/violetmoon/zeta/Zeta.java index 5fae48c40d..1250e97d00 100644 --- a/src/main/java/org/violetmoon/zeta/Zeta.java +++ b/src/main/java/org/violetmoon/zeta/Zeta.java @@ -8,6 +8,7 @@ import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.Nullable; import org.violetmoon.quark.base.handler.GeneralConfig; +import org.violetmoon.zeta.util.NameChanger; import org.violetmoon.zeta.util.RaytracingUtil; import org.violetmoon.zeta.advancement.AdvancementModifierRegistry; import org.violetmoon.zeta.block.ext.BlockExtensionFactory; @@ -59,6 +60,7 @@ public Zeta(String modid, Logger log, ZetaSide side) { this.capabilityManager = createCapabilityManager(); this.raytracingUtil = createRaytracingUtil(); + this.nameChanger = createNameChanger(); loadBus.subscribe(craftingExtensions) .subscribe(dyeables) @@ -86,6 +88,7 @@ public Zeta(String modid, Logger log, ZetaSide side) { public final ItemExtensionFactory itemExtensions; public final RaytracingUtil raytracingUtil; + public final NameChanger nameChanger; public ConfigManager configManager; //This could do with being split up into various pieces? public IZetaConfigInternals configInternals; @@ -134,6 +137,9 @@ public BlockExtensionFactory createBlockExtensionFactory() { } public abstract ItemExtensionFactory createItemExtensionFactory(); public abstract RaytracingUtil createRaytracingUtil(); + public NameChanger createNameChanger() { + return new NameChanger(); + } public abstract T fireExternalEvent(T impl); diff --git a/src/main/java/org/violetmoon/zeta/util/NameChanger.java b/src/main/java/org/violetmoon/zeta/util/NameChanger.java new file mode 100644 index 0000000000..72b118af33 --- /dev/null +++ b/src/main/java/org/violetmoon/zeta/util/NameChanger.java @@ -0,0 +1,100 @@ +package org.violetmoon.zeta.util; + +import java.util.ArrayList; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; + +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; + +public class NameChanger { + + /** + * Submit or rescind (depending on `enabled`) a request to change the translation key of a block. + *

+ * The most recently submitted name change request will win. If there are no outstanding requests, + * the block will return to its original vanilla name. + */ + public void changeBlock(Block toChange, String newTranslationKey, boolean enabled) { + changeBlockStatic(toChange, newTranslationKey, enabled); + } + + public void changeItem(Item toChange, String newTranslationKey, boolean enabled) { + changeItemStatic(toChange, newTranslationKey, enabled); + } + + // this stuff is implemented statically so that originalBlockNames really does contain the *original* block names. + // if this wasn't static, you could imagine one Zeta mod changes the name of a block, then another mod changes + // the name of the same block; it'd end up thinking the first mod's *changed* name is the *original* name. + + // Most of the complexity of this class is about handling cases like 'mod A changes block name, mod B changes + // the same block name, mod A removes its name-change" -> we should select mod B's name. + + protected static Map originalBlockNames = new IdentityHashMap<>(); + protected static Map changedBlockNames = new IdentityHashMap<>(); + protected static Map originalItemNames = new IdentityHashMap<>(); + protected static Map changedItemNames = new IdentityHashMap<>(); + + // marked "synchronized" cause uhhhh ?? forge??... idk... might be a good idea + protected static synchronized void changeBlockStatic(Block toChange, String newTranslationKey, boolean enabled) { + //keep track of the original name for this block + originalBlockNames.computeIfAbsent(toChange, Block::getDescriptionId); + + //add the changed name onto the pile + NameChangeRequests changeRequests = changedBlockNames.computeIfAbsent(toChange, __ -> new NameChangeRequests()); + if(enabled) + changeRequests.add(newTranslationKey); + else + changeRequests.remove(newTranslationKey); + + //actually change the block's name - if there are any outstanding name-change requests, use the most recent one, + //else use the block's original name + toChange.descriptionId = changeRequests.lastOrElse(originalBlockNames.get(toChange)); + + //save a tiny bit of memory + if(changeRequests.isEmpty()) + changedBlockNames.remove(toChange); + } + + protected static synchronized void changeItemStatic(Item toChange, String newTranslationKey, boolean enabled) { + originalItemNames.computeIfAbsent(toChange, Item::getDescriptionId); + + NameChangeRequests changeRequests = changedItemNames.computeIfAbsent(toChange, __ -> new NameChangeRequests()); + if(enabled) + changeRequests.add(newTranslationKey); + else + changeRequests.remove(newTranslationKey); + toChange.descriptionId = changeRequests.lastOrElse(originalItemNames.get(toChange)); + + if(changeRequests.isEmpty()) + changedItemNames.remove(toChange); + } + + // In practice these collections will contain like, 1 element at-most, *maybe* 2, so the O(n) algorithm choice is intentional + // Bro i,m starting to think i overengineered this class :skull: + protected static class NameChangeRequests { + List list = new ArrayList<>(1); + + public void add(String value) { + // move it to the end, so the most recent requests get prioritized + remove(value); + list.add(value); + } + + public void remove(String value) { + list.remove(value); + } + + public boolean isEmpty() { + return list.isEmpty(); + } + + public String lastOrElse(String orElse) { + if(list.isEmpty()) + return orElse; + else + return list.get(list.size() - 1); + } + } +} diff --git a/zeta-todo/README.md b/zeta-todo/README.md index ccb685b438..31e96c62ec 100644 --- a/zeta-todo/README.md +++ b/zeta-todo/README.md @@ -105,7 +105,7 @@ Bring to zeta: - [ ] "ig the worldgen shim?" - [ ] "pretty much everything in `block` is viable to pull out" - [x] some stuff wrt to module loader - anti overlap -- [ ] ItemOverrideHandler is used by variant bookshelves/ladders but it's pretty standalone +- [x] ItemOverrideHandler is used by variant bookshelves/ladders but it's pretty standalone - [ ] ToolInteractionHandler is "literally only used for waxing" but it's important - [ ] QuarkBlock and QuarkItem are really for "disableable/enablable blocks" - [ ] WoodSetHandler is important, but there are some quark uniques in there