diff --git a/dependencies.gradle b/dependencies.gradle index 865b291..918e6e2 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -4,4 +4,5 @@ dependencies { compileOnly('com.github.GTNewHorizons:NotEnoughIds:2.1.10:dev') compileOnly('com.falsepattern:chunkapi-mc1.7.10:0.6.0:dev') compileOnly('com.falsepattern:endlessids-mc1.7.10:1.6.0:dev') + compileOnly("com.github.GTNewHorizons:NotEnoughItems:2.8.48-GTNH:dev") { transitive = false } } diff --git a/src/main/java/com/gtnewhorizons/postea/Postea.java b/src/main/java/com/gtnewhorizons/postea/Postea.java index 49cac85..fa4c8f8 100644 --- a/src/main/java/com/gtnewhorizons/postea/Postea.java +++ b/src/main/java/com/gtnewhorizons/postea/Postea.java @@ -3,10 +3,10 @@ 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.FMLLoadCompleteEvent; import cpw.mods.fml.common.event.FMLMissingMappingsEvent; import cpw.mods.fml.common.event.FMLModIdMappingEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; @@ -44,6 +44,7 @@ public class Postea { PosteaMissingMappingHandler.onMissingMapping(event); } + @Mod.EventHandler public void onLoadCompleted(FMLLoadCompleteEvent event) { PosteaMissingMappingHandler.onLoadCompleted(); } diff --git a/src/main/java/com/gtnewhorizons/postea/PosteaMissingMappingHandler.java b/src/main/java/com/gtnewhorizons/postea/PosteaMissingMappingHandler.java index 2191eae..8edd233 100644 --- a/src/main/java/com/gtnewhorizons/postea/PosteaMissingMappingHandler.java +++ b/src/main/java/com/gtnewhorizons/postea/PosteaMissingMappingHandler.java @@ -1,92 +1,46 @@ 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 java.util.Map; + +import javax.annotation.Nullable; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; +import com.gtnewhorizons.postea.compat.Compat; + 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<>(); + enum MappingType { + /** Tells the mapping logic to register an Item. */ + Item, + /** Tells the mapping logic to register a Block (and ItemBlock). */ + Block + } - 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; + static class DummyMapping { - 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); + /** The type of thing that should be registered for this dummy */ + public MappingType type; + /** The id under which the dummy should be registered */ + public String registerAs; + /** The full id of the dummy, including mod prefix */ + public String id; + + public DummyMapping(MappingType type, String registerAs, String id) { + this.type = type; + this.registerAs = registerAs; + this.id = id; } - 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. + // because we're using reflection to quickly identify our stuff at runtime. public static class DummyBlock extends Block { public DummyBlock() { @@ -94,10 +48,56 @@ public abstract class PosteaMissingMappingHandler { } } - // because we're using reflection to quickly identify our items public static class DummyItem extends Item { } + public static class DummyItemBlock extends ItemBlock { + + public DummyItemBlock(Block p_i45328_1_) { + super(p_i45328_1_); + } + } + + private static final HashMap MISSING_ITEM_MAPPINGS = new HashMap<>(); + private static final HashMap MISSING_BLOCK_MAPPINGS = new HashMap<>(); + private static final HashMap DUMMY_TARGET_TYPES = new HashMap<>(); + private static final HashMap REVERSE_DUMMY_ID_LOOKUP = new HashMap<>(); + + 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; + + static void onLoadCompleted() { + for (Map.Entry kv : DUMMY_TARGET_TYPES.entrySet()) { + DummyMapping mapping = kv.getValue(); + String originalId = kv.getKey(); + // split the original id into parts to query for the original's existance. + String[] splitId = splitItemId(originalId); + if (splitId == null) continue; + // ensure nothing else is registered under that id. + if (GameRegistry.findBlock(splitId[0], splitId[1]) != null) continue; + if (GameRegistry.findItem(splitId[0], splitId[1]) != null) continue; + // remap if not found + if (mapping.type == MappingType.Block) { + // check if the block was since registered. + Block dummy = new DummyBlock(); + GameRegistry.registerBlock(dummy, DummyItemBlock.class, mapping.registerAs); + // register both for when we're remapping from ourselves to ourselves because something wasn't loaded + // and transformed. + MISSING_BLOCK_MAPPINGS.put(originalId, dummy); + Compat.hideItemFromNEI(Item.getItemFromBlock(dummy)); + } else { + Item dummy = new DummyItem(); + GameRegistry.registerItem(dummy, mapping.registerAs); + MISSING_ITEM_MAPPINGS.put(originalId, dummy); + Compat.hideItemFromNEI(dummy); + } + REVERSE_DUMMY_ID_LOOKUP.put(mapping.id, originalId); + } + // no longer needed free what ever used to be in there + DUMMY_TARGET_TYPES.clear(); + } + static void onMissingMapping(FMLMissingMappingsEvent event) { for (FMLMissingMappingsEvent.MissingMapping mapping : event.getAll()) { if (mapping.name.startsWith(DUMMY_ID_PREFIX)) { @@ -107,23 +107,76 @@ public abstract class PosteaMissingMappingHandler { } if (mapping.type == GameRegistry.Type.BLOCK) { - Block remappedBlock = missingBlockMappings.get(mapping.name); + Block remappedBlock = MISSING_BLOCK_MAPPINGS.get(mapping.name); if (remappedBlock != null) { mapping.remap(remappedBlock); continue; } } else if (mapping.type == GameRegistry.Type.ITEM) { - Block remappedBlock = missingBlockMappings.get(mapping.name); + Block remappedBlock = MISSING_BLOCK_MAPPINGS.get(mapping.name); if (remappedBlock != null) { mapping.remap(Item.getItemFromBlock(remappedBlock)); continue; } - Item remappedItem = missingItemMappings.get(mapping.name); + Item remappedItem = MISSING_ITEM_MAPPINGS.get(mapping.name); if (remappedItem != null) { - mapping.remap(missingItemMappings.get(mapping.name)); + mapping.remap(MISSING_ITEM_MAPPINGS.get(mapping.name)); continue; } } } + // no longer needed free what ever used to be in there + MISSING_BLOCK_MAPPINGS.clear(); + MISSING_ITEM_MAPPINGS.clear(); + } + + private static void onMappingAdded(String originalId, MappingType mappingType) { + // split name into parts + String[] splitId = splitItemId(originalId); + if (splitId == null) return; + // else register a fake item + final String registerAs = DUMMY_ID_PREFIX_END + splitId[0] + "." + splitId[1]; + final String dummyFullId = DUMMY_ID_PREFIX_START + registerAs; + if (mappingType == MappingType.Item) { + DUMMY_TARGET_TYPES.putIfAbsent(originalId, new DummyMapping(mappingType, registerAs, dummyFullId)); + } else { + DummyMapping existing = DUMMY_TARGET_TYPES.getOrDefault(originalId, null); + if (existing != null) { + existing.type = mappingType; + } else { + DUMMY_TARGET_TYPES.put(originalId, new DummyMapping(mappingType, registerAs, dummyFullId)); + } + } + } + + public static void createDummyBlockIfNeeded(String originalId) { + DummyMapping existing = DUMMY_TARGET_TYPES.get(originalId); + // item mappings should be over-written + if (existing != null && existing.type == MappingType.Block) return; + onMappingAdded(originalId, MappingType.Block); + } + + public static void createDummyItemIfNeeded(String originalId) { + DummyMapping existing = DUMMY_TARGET_TYPES.get(originalId); + if (existing != null) return; + onMappingAdded(originalId, MappingType.Item); + } + + public static String getOriginalIDIfIDIsDummyID(String originalId) { + return REVERSE_DUMMY_ID_LOOKUP.getOrDefault(originalId, originalId); + } + + private static @Nullable String[] splitItemId(String itemId) { + int pos = itemId.indexOf(':'); + if (pos < 1) return null; + return new String[] { itemId.substring(0, pos), itemId.substring(pos + 1) }; + } + + public static boolean isDummyItem(Item item) { + return item instanceof DummyItem || item instanceof DummyItemBlock; + } + + public static boolean isDummyBlock(Block block) { + return block instanceof DummyBlock; } } diff --git a/src/main/java/com/gtnewhorizons/postea/api/BlockReplacementManager.java b/src/main/java/com/gtnewhorizons/postea/api/BlockReplacementManager.java index 66dd356..3671394 100644 --- a/src/main/java/com/gtnewhorizons/postea/api/BlockReplacementManager.java +++ b/src/main/java/com/gtnewhorizons/postea/api/BlockReplacementManager.java @@ -1,6 +1,5 @@ package com.gtnewhorizons.postea.api; -import java.util.HashMap; import java.util.function.BiFunction; import net.minecraft.world.World; @@ -13,7 +12,6 @@ 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(); @@ -21,19 +19,15 @@ public class BlockReplacementManager { @SuppressWarnings("unused") public static void addBlockReplacement(String blockNameIn, BiFunction transformer) { - String newName = PosteaMissingMappingHandler.createDummyBlockIfNeeded(blockNameIn); - if (!newName.equals(blockNameIn)) { - dummyMap.put(newName, blockNameIn); - } - blockReplacementMap.put(newName, transformer); + PosteaMissingMappingHandler.createDummyBlockIfNeeded(blockNameIn); + blockReplacementMap.put(blockNameIn, 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); + String originalName = PosteaMissingMappingHandler.getOriginalIDIfIDIsDummyID(blockConversionInfo.blockName); + blockConversionInfo.blockName = originalName; for (BiFunction transformer : blockReplacementMap .get(originalName)) { BlockConversionInfo result = transformer.apply(blockConversionInfo, world); diff --git a/src/main/java/com/gtnewhorizons/postea/api/ItemStackReplacementManager.java b/src/main/java/com/gtnewhorizons/postea/api/ItemStackReplacementManager.java index a7031dc..58505da 100644 --- a/src/main/java/com/gtnewhorizons/postea/api/ItemStackReplacementManager.java +++ b/src/main/java/com/gtnewhorizons/postea/api/ItemStackReplacementManager.java @@ -17,12 +17,12 @@ public class ItemStackReplacementManager { @SuppressWarnings("unused") public static void addItemReplacement(String itemName, Function transformer) { - replacementMap.put(PosteaMissingMappingHandler.createDummyItemIfNeeded(itemName), transformer); + PosteaMissingMappingHandler.createDummyItemIfNeeded(itemName); + replacementMap.put(itemName, transformer); } @SuppressWarnings("unused") public static Collection> getItemReplacement(String itemNameInternal) { - return replacementMap.get(itemNameInternal); + return replacementMap.get(PosteaMissingMappingHandler.getOriginalIDIfIDIsDummyID(itemNameInternal)); } - } diff --git a/src/main/java/com/gtnewhorizons/postea/compat/Compat.java b/src/main/java/com/gtnewhorizons/postea/compat/Compat.java index f025da4..7c5d6c8 100644 --- a/src/main/java/com/gtnewhorizons/postea/compat/Compat.java +++ b/src/main/java/com/gtnewhorizons/postea/compat/Compat.java @@ -1,17 +1,23 @@ package com.gtnewhorizons.postea.compat; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; import net.minecraft.launchwrapper.Launch; import net.minecraft.world.chunk.NibbleArray; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; +import net.minecraftforge.oredict.OreDictionary; import com.falsepattern.endlessids.mixin.helpers.SubChunkBlockHook; import com.gtnewhorizons.neid.mixins.interfaces.IExtendedBlockStorageMixin; +import codechicken.nei.api.API; + public class Compat { private static Boolean chunkapi = null; private static Boolean endlessids = null; private static Boolean neid = null; + private static Boolean nei = null; public static boolean chunkapiPresent() { if (chunkapi == null) { @@ -47,6 +53,17 @@ public class Compat { return neid; } + public static boolean neiPresent() { + if (nei == null) { + boolean present = false; + try { + present = Launch.classLoader.getClassBytes("codechicken.nei.api.API") != null; + } catch (Throwable ignored) {} + nei = present; + } + return nei; + } + public static SubChunkAccess getSubChunkAccess(ExtendedBlockStorage subChunk) { if (endlessidsPresent()) { return EndlessIDSCompat.getSubChunkAccess(subChunk); @@ -162,6 +179,18 @@ public class Compat { } } + public static void hideItemFromNEI(Item item) { + if (!neiPresent()) return; + NEICompat.hideItem(item); + } + + private static class NEICompat { + + public static void hideItem(Item item) { + API.hideItem(new ItemStack(item, 1, OreDictionary.WILDCARD_VALUE)); + } + } + private static int toIndex(int x, int y, int z) { return y << 8 | z << 4 | x; }