From 36de68e5ab62d89d9686a7a7838569a7fade1047 Mon Sep 17 00:00:00 2001 From: Guillaume Mercier <10gui-gui10@live.ca> Date: Tue, 20 Jan 2026 11:00:33 -0500 Subject: [PATCH] add dummy item auto-creation --- .../java/com/gtnewhorizons/postea/Postea.java | 11 ++ .../postea/PosteaMissingMappingHandler.java | 129 ++++++++++++++++++ .../postea/api/BlockReplacementManager.java | 17 ++- .../api/ItemStackReplacementManager.java | 4 +- .../postea/utility/ChunkFixerUtility.java | 5 + .../postea/utility/ItemFixerUtility.java | 25 +++- 6 files changed, 182 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/postea/PosteaMissingMappingHandler.java diff --git a/src/main/java/com/gtnewhorizons/postea/Postea.java b/src/main/java/com/gtnewhorizons/postea/Postea.java index 6e357b1..49cac85 100644 --- a/src/main/java/com/gtnewhorizons/postea/Postea.java +++ b/src/main/java/com/gtnewhorizons/postea/Postea.java @@ -3,9 +3,11 @@ package com.gtnewhorizons.postea; import static com.gtnewhorizons.postea.api.BlockReplacementManager.blockReplacementMap; import static com.gtnewhorizons.postea.api.BlockReplacementManager.posteaMarkedIDs; +import cpw.mods.fml.common.event.FMLLoadCompleteEvent; import net.minecraft.block.Block; import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.event.FMLMissingMappingsEvent; import cpw.mods.fml.common.event.FMLModIdMappingEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; import cpw.mods.fml.common.event.FMLServerStoppingEvent; @@ -37,6 +39,15 @@ public class Postea { } } + @Mod.EventHandler + public void onMissingMapping(FMLMissingMappingsEvent event) { + PosteaMissingMappingHandler.onMissingMapping(event); + } + + public void onLoadCompleted(FMLLoadCompleteEvent event) { + PosteaMissingMappingHandler.onLoadCompleted(); + } + @Mod.EventHandler public void onServerStopping(FMLServerStoppingEvent event) { posteaMarkedIDs.clear(); diff --git a/src/main/java/com/gtnewhorizons/postea/PosteaMissingMappingHandler.java b/src/main/java/com/gtnewhorizons/postea/PosteaMissingMappingHandler.java new file mode 100644 index 0000000..2191eae --- /dev/null +++ b/src/main/java/com/gtnewhorizons/postea/PosteaMissingMappingHandler.java @@ -0,0 +1,129 @@ +package com.gtnewhorizons.postea; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Supplier; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.item.Item; +import net.minecraft.item.ItemBlock; + +import cpw.mods.fml.common.event.FMLMissingMappingsEvent; +import cpw.mods.fml.common.registry.GameRegistry; + +public abstract class PosteaMissingMappingHandler { + + private static final HashMap missingItemMappings = new HashMap<>(); + private static final HashMap missingBlockMappings = new HashMap<>(); + private static final HashMap remappedBlocks = new HashMap<>(); + private static final HashSet remappedItems = new HashSet<>(); + + private static final String DUMMY_ID_PREFIX_START = Postea.MODID + ":"; + private static final String DUMMY_ID_PREFIX_END = "d."; + private static final String DUMMY_ID_PREFIX = DUMMY_ID_PREFIX_START + DUMMY_ID_PREFIX_END; + + public static String createDummyBlockIfNeeded(String originalId) { + if (remappedItems.contains(originalId)) + throw new IllegalArgumentException("block mappings must be declared before the item remapping"); + String newId = onMappingAdded( + originalId, + GameRegistry::findBlock, + missingBlockMappings, + DummyBlock::new, + GameRegistry::registerBlock); + // don't let it register an item jic + if (!newId.equals(originalId)) { + remappedBlocks.put(originalId, newId); + } + return newId; + } + + public static String createDummyItemIfNeeded(String originalId) { + if (remappedBlocks.containsKey(originalId)) return remappedBlocks.get(originalId); + String newId = onMappingAdded( + originalId, + GameRegistry::findItem, + missingItemMappings, + DummyItem::new, + GameRegistry::registerItem); + if (!newId.equals(originalId)) remappedItems.add(newId); + return newId; + } + + private static String onMappingAdded(String originalId, BiFunction registryCheck, + HashMap dummyLookup, Supplier dummySupplier, BiConsumer registryConsumer) { + // split name into parts + int pos = originalId.indexOf(':'); + if (pos < 1) return originalId; + final String modId = originalId.substring(0, pos); + final String name = originalId.substring(pos + 1); + // check if it exists + if (registryCheck.apply(modId, name) != null) return originalId; + // else register a fake item + final String registerAs = DUMMY_ID_PREFIX_END + modId + "." + name; + final String dummyFullId = DUMMY_ID_PREFIX_START + registerAs; + // abort early if we've already registered a dummy handler for this item. + if (dummyLookup.containsKey(dummyFullId)) return dummyFullId; + T dummy = dummySupplier.get(); + dummyLookup.put(dummyFullId, dummy); + dummyLookup.put(originalId, dummy); + registryConsumer.accept(dummy, registerAs); + return dummyFullId; + } + + public static boolean isDummyItem(Item item) { + return item instanceof DummyItem || item instanceof ItemBlock ib && ib.field_150939_a instanceof DummyBlock; + } + + public static boolean isDummyBlock(Block block) { + return block instanceof DummyBlock; + } + + public static void onLoadCompleted() { + for ( + } + + // we're using reflection to identify dummies quickly. + public static class DummyBlock extends Block { + + public DummyBlock() { + super(Material.ground); + } + } + + // because we're using reflection to quickly identify our items + public static class DummyItem extends Item { + } + + static void onMissingMapping(FMLMissingMappingsEvent event) { + for (FMLMissingMappingsEvent.MissingMapping mapping : event.getAll()) { + if (mapping.name.startsWith(DUMMY_ID_PREFIX)) { + // for when a migrator ceases being registered, likely due to a removal. + mapping.ignore(); + continue; + } + + if (mapping.type == GameRegistry.Type.BLOCK) { + Block remappedBlock = missingBlockMappings.get(mapping.name); + if (remappedBlock != null) { + mapping.remap(remappedBlock); + continue; + } + } else if (mapping.type == GameRegistry.Type.ITEM) { + Block remappedBlock = missingBlockMappings.get(mapping.name); + if (remappedBlock != null) { + mapping.remap(Item.getItemFromBlock(remappedBlock)); + continue; + } + Item remappedItem = missingItemMappings.get(mapping.name); + if (remappedItem != null) { + mapping.remap(missingItemMappings.get(mapping.name)); + continue; + } + } + } + } +} diff --git a/src/main/java/com/gtnewhorizons/postea/api/BlockReplacementManager.java b/src/main/java/com/gtnewhorizons/postea/api/BlockReplacementManager.java index 21ec216..66dd356 100644 --- a/src/main/java/com/gtnewhorizons/postea/api/BlockReplacementManager.java +++ b/src/main/java/com/gtnewhorizons/postea/api/BlockReplacementManager.java @@ -1,16 +1,19 @@ package com.gtnewhorizons.postea.api; +import java.util.HashMap; import java.util.function.BiFunction; import net.minecraft.world.World; import com.google.common.collect.LinkedListMultimap; +import com.gtnewhorizons.postea.PosteaMissingMappingHandler; import com.gtnewhorizons.postea.utility.BlockConversionInfo; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; public class BlockReplacementManager { + private static final HashMap dummyMap = new HashMap<>(); public static final LinkedListMultimap> blockReplacementMap = LinkedListMultimap .create(); public static final IntOpenHashSet posteaMarkedIDs = new IntOpenHashSet(); @@ -18,12 +21,21 @@ public class BlockReplacementManager { @SuppressWarnings("unused") public static void addBlockReplacement(String blockNameIn, BiFunction transformer) { - blockReplacementMap.put(blockNameIn, transformer); + String newName = PosteaMissingMappingHandler.createDummyBlockIfNeeded(blockNameIn); + if (!newName.equals(blockNameIn)) { + dummyMap.put(newName, blockNameIn); + } + blockReplacementMap.put(newName, transformer); } public static BlockConversionInfo getBlockReplacement(BlockConversionInfo blockConversionInfo, World world) { + // auto change the value in case a handler check it, we can't do anything about the block id + // but hopefully that's never going to be an issue + String originalName = blockConversionInfo.blockName; + blockConversionInfo.blockName = dummyMap + .getOrDefault(blockConversionInfo.blockName, blockConversionInfo.blockName); for (BiFunction transformer : blockReplacementMap - .get(blockConversionInfo.blockName)) { + .get(originalName)) { BlockConversionInfo result = transformer.apply(blockConversionInfo, world); if (result != null) return result; } @@ -34,5 +46,4 @@ public class BlockReplacementManager { public static boolean blockNotConvertible(int blockID) { return !posteaMarkedIDs.contains(blockID); } - } diff --git a/src/main/java/com/gtnewhorizons/postea/api/ItemStackReplacementManager.java b/src/main/java/com/gtnewhorizons/postea/api/ItemStackReplacementManager.java index 6f207c4..a7031dc 100644 --- a/src/main/java/com/gtnewhorizons/postea/api/ItemStackReplacementManager.java +++ b/src/main/java/com/gtnewhorizons/postea/api/ItemStackReplacementManager.java @@ -6,6 +6,7 @@ import java.util.function.Function; import net.minecraft.nbt.NBTTagCompound; import com.google.common.collect.LinkedListMultimap; +import com.gtnewhorizons.postea.PosteaMissingMappingHandler; public class ItemStackReplacementManager { @@ -16,11 +17,12 @@ public class ItemStackReplacementManager { @SuppressWarnings("unused") public static void addItemReplacement(String itemName, Function transformer) { - replacementMap.put(itemName, transformer); + replacementMap.put(PosteaMissingMappingHandler.createDummyItemIfNeeded(itemName), transformer); } @SuppressWarnings("unused") public static Collection> getItemReplacement(String itemNameInternal) { return replacementMap.get(itemNameInternal); } + } diff --git a/src/main/java/com/gtnewhorizons/postea/utility/ChunkFixerUtility.java b/src/main/java/com/gtnewhorizons/postea/utility/ChunkFixerUtility.java index 8f56fde..d0c157c 100644 --- a/src/main/java/com/gtnewhorizons/postea/utility/ChunkFixerUtility.java +++ b/src/main/java/com/gtnewhorizons/postea/utility/ChunkFixerUtility.java @@ -15,6 +15,7 @@ import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; +import com.gtnewhorizons.postea.PosteaMissingMappingHandler; import com.gtnewhorizons.postea.api.BlockReplacementManager; import com.gtnewhorizons.postea.api.TileEntityReplacementManager; import com.gtnewhorizons.postea.api.TriFunction; @@ -76,6 +77,10 @@ public class ChunkFixerUtility { if (output != null) { access.setBlockId(x, y, z, output.blockID); access.setMeta(x, y, z, output.metadata); + } else if (PosteaMissingMappingHandler.isDummyBlock(block)) { + // clear out the slot if this is an unhandled dummy item. + access.setBlockId(x, y, z, 0); + access.setMeta(x, y, z, 0); } } } diff --git a/src/main/java/com/gtnewhorizons/postea/utility/ItemFixerUtility.java b/src/main/java/com/gtnewhorizons/postea/utility/ItemFixerUtility.java index c50d824..c6ca17a 100644 --- a/src/main/java/com/gtnewhorizons/postea/utility/ItemFixerUtility.java +++ b/src/main/java/com/gtnewhorizons/postea/utility/ItemFixerUtility.java @@ -1,10 +1,12 @@ package com.gtnewhorizons.postea.utility; +import java.util.Collection; import java.util.function.Function; import net.minecraft.item.Item; import net.minecraft.nbt.NBTTagCompound; +import com.gtnewhorizons.postea.PosteaMissingMappingHandler; import com.gtnewhorizons.postea.api.IDExtenderCompat; import com.gtnewhorizons.postea.api.ItemStackReplacementManager; @@ -20,12 +22,25 @@ public abstract class ItemFixerUtility { int id = IDExtenderCompat.getItemStackID(tag); Item item = Item.getItemById(id); if (item == null) return; - String itemNameInternal = GameRegistry.findUniqueIdentifierFor(item).modId + ":" - + GameRegistry.findUniqueIdentifierFor(item).name; + GameRegistry.UniqueIdentifier uuid = GameRegistry.findUniqueIdentifierFor(item); + String itemNameInternal = uuid.modId + ":" + uuid.name; - for (Function transformer : ItemStackReplacementManager - .getItemReplacement(itemNameInternal)) { - if (transformer.apply(tag) != null) break; + // abort early if no handlers + Collection> handlers = ItemStackReplacementManager + .getItemReplacement(itemNameInternal); + if (handlers.isEmpty()) return; + + // apply handlers + for (Function transformer : handlers) { + if (transformer.apply(tag) != null) { + return; + } + } + + // if no handler overwrote anything on this stack, and it's a dummy, delete the stack. + if (PosteaMissingMappingHandler.isDummyItem(item)) { + tag.removeTag("id"); + tag.removeTag("idExt"); } } }