transformer) {
if (originalId == null) throw new IllegalArgumentException("original id is null");
if (transformer == null) throw new IllegalArgumentException("transformer is null");
TransformerRegistry.addBlockReplacement(originalId, transformer);
@@ -31,7 +83,7 @@ public class BlockReplacementManager {
/**
* Adds a mapping to remap stacks and block instances of a specific removed block to the given block whilst, whilst
* maintaining its meta value.
- *
+ *
* IMPORTANT: This only works if the world does not have an existing id set for the target block. If you need
* to transform a missing block into something that was previously given an id (e.g.: Transforming a removed block
* into dirt), use {@link #addBlockReplacement(String, Block)} with both meta parameters set to
@@ -49,7 +101,7 @@ public class BlockReplacementManager {
/**
* Suppresses any missing mapping warning for the given id.
- *
+ *
* @param originalId The id of the block or item to suppress the warning for.
*/
@SuppressWarnings("unused")
@@ -97,6 +149,36 @@ public class BlockReplacementManager {
skipStackRemap);
}
+ // block+meta -> block
+
+ /**
+ * Adds a mapping to remap all stacks and block instances of a given block and damage/meta value to another block,
+ * whilst maintaining its meta value. This also adds a matching item stack replacement.
+ *
+ * @param originalId The id of the block to remap.
+ * @param originalMeta The meta of the block to remap. OreDictionary.WILDCARD_VALUE acts as a wildcard.
+ * @param block The block to remap to.
+ */
+ @SuppressWarnings("unused")
+ public static void addBlockReplacement(@Nonnull String originalId, int originalMeta, @Nonnull Block block) {
+ addBlockReplacement(originalId, originalMeta, block, OreDictionary.WILDCARD_VALUE, false);
+ }
+
+ /**
+ * Adds a mapping to remap all stacks and block instances of a given block and damage/meta value to another block,,
+ * whilst maintaining its meta value.
+ *
+ * @param originalId The id of the block to remap.
+ * @param originalMeta The meta of the block to remap. OreDictionary.WILDCARD_VALUE acts as a wildcard.
+ * @param block The block to remap to.
+ * @param skipStackRemap Set to true to skip auto-adding an item stack remapper.
+ */
+ @SuppressWarnings("unused")
+ public static void addBlockReplacement(@Nonnull String originalId, int originalMeta, @Nonnull Block block,
+ boolean skipStackRemap) {
+ addBlockReplacement(originalId, originalMeta, block, OreDictionary.WILDCARD_VALUE, skipStackRemap);
+ }
+
// block -> block+meta
/**
diff --git a/src/main/java/com/gtnewhorizons/postea/api/ItemStackReplacementManager.java b/src/main/java/com/gtnewhorizons/postea/api/ItemStackReplacementManager.java
index c971944..39ddc93 100644
--- a/src/main/java/com/gtnewhorizons/postea/api/ItemStackReplacementManager.java
+++ b/src/main/java/com/gtnewhorizons/postea/api/ItemStackReplacementManager.java
@@ -3,6 +3,7 @@ package com.gtnewhorizons.postea.api;
import java.util.function.Function;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
@@ -17,15 +18,159 @@ public class ItemStackReplacementManager {
// Public API for converting ItemStacks.
+ // spotless:off
+ /**
+ * Fetches the original registration name of a given item id. Use this to get the actual name of an item when migrating
+ * an item that no longer exists.
+ *
+ * @apiNote This only works for items that have been registered for Postea transformations, and should not be used
+ * outside a Postea transformer function.
+ * {@code
+ * public static class Example {
+ * public static void postLoad() {
+ * ItemStackReplacementManager.addTransformationHandler("removedmod:item1", Example::transform);
+ * ItemStackReplacementManager.addTransformationHandler("removedmod:item2", Example::transform);
+ * ItemStackReplacementManager.addTransformationHandler("removedmod:item3", Example::transform);
+ * }
+ *
+ * public static boolean transform(NBTTagCompound tag) {
+ * // consider using the other addItemReplacement functions without a function
+ * // They create very fast transformers that run in constant time
+ * // regardless of how many transformations you register to a single id
+ * short meta = tag.getShort("Damage");
+ * switch (ItemStackReplacementManager.getOriginalItemName(tag)) {
+ * int meta = 0;
+ * case "removedmod:item1":
+ * if (meta != 0) return false;
+ * meta = 1;
+ * break;
+ * case "removedmod:item2":
+ * meta = 2;
+ * break;
+ * }
+ * IDExtenderCompat.setItemStackID(tag, Items.getIdFromItem(MyItems.item1));
+ * tag.setShort("Damage", meta);
+ * return true;
+ * }
+ * }
+ * }
+ *
+ * @param tag The NBT tag that was passed to your handler.
+ * @return The original namespaced name of the item being transformed.
+ */
+ // spotless:on
+ @SuppressWarnings("unused")
+ public static @Nullable String getOriginalItemName(NBTTagCompound tag) {
+ return TransformerRegistry.getMappedItemName(IDExtenderCompat.getItemStackID(tag));
+ }
+
+ // spotless:off
+ /**
+ * Fetches the original registration name of a given item id. Use this to get the actual name of an item when
+ * migrating an item that no longer exists.
+ *
+ * @apiNote This only works for items that have been registered for Postea transformations, and should not be used
+ * outside a Postea transformer function.
+ * {@code
+ * public static class Example {
+ * public static void postLoad() {
+ * ItemStackReplacementManager.addTransformationHandler("removedmod:item1", Example::transform);
+ * ItemStackReplacementManager.addTransformationHandler("removedmod:item2", Example::transform);
+ * ItemStackReplacementManager.addTransformationHandler("removedmod:item3", Example::transform);
+ * }
+ *
+ * public static boolean transform(NBTTagCompound tag) {
+ * // consider using the other addItemReplacement functions without a function
+ * // They create very fast transformers that run in constant time
+ * // regardless of how many transformations you register to a single id
+ * short meta = tag.getShort("Damage");
+ * int id = IDExtenderCompat.getItemStackID(tag);
+ * switch (ItemStackReplacementManager.getOriginalItemName(id)) {
+ * int meta = 0;
+ * case "removedmod:item1":
+ * if (meta != 0) return false;
+ * meta = 1;
+ * break;
+ * case "removedmod:item2":
+ * meta = 2;
+ * break;
+ * }
+ * IDExtenderCompat.setItemStackID(tag, Items.getIdFromItem(MyItems.item1));
+ * tag.setShort("Damage", meta);
+ * return true;
+ * }
+ * }
+ * }
+ *
+ * @param itemId The numeric id of the item that was passed to your transformation handler.
+ * @return The original namespaced name of the item being transformed.
+ */
+ // spotless:on
+ @SuppressWarnings("unused")
+ public static @Nullable String getOriginalItemName(int itemId) {
+ return TransformerRegistry.getMappedItemName(itemId);
+ }
+
/**
* Adds a custom transformer for a given id.
*
+ * @deprecated Use {@link #addTransformationHandler(String, Function)} instead.
+ *
+ * @apiNote When the transformer function passed to this function returns a null, value Postea will assume that
+ * the transformer has failed to identify and run the handler on any other handler function registered
+ * to the given ID.
+ *
+ * If you need to perform a simple transformations consider using the following methods instead:
+ *
+ * - item -> item (with same meta): {@link #addItemReplacement(String, Item)}
+ * - item -> item with specific meta: {@link #addItemReplacement(String, Item, int)}
+ * - item with meta -> item (with same meta): {@link #addItemReplacement(String, int, Item)}
+ * - item with meta -> item with specific meta: {@link #addItemReplacement(String, int, Item, int)}
+ *
+ *
+ * @implNote For performance reasons, Postea assumes that the tag that was passed to the handler hasn't been
+ * modified
+ * if you return a null value. This isn't enforced though since returning a null value after doing some
+ * modifications has a couple niche uses. eg: having separate handlers for different migrations of a
+ * single thing that can be sunset at different times down the line.
+ *
+ * @param originalId The id of the item to transform.
+ * @param transformer The transformer to apply.
+ */
+ @Deprecated
+ @SuppressWarnings("unused")
+ public static void addItemReplacement(@Nonnull String originalId,
+ @Nonnull Function transformer) {
+ addTransformationHandler(originalId, tag -> transformer.apply(tag) != null);
+ }
+
+ /**
+ * Adds a custom transformer for a given id.
+ *
+ * @apiNote When the transformer function passed to this function returns a null, value Postea will assume that
+ * the transformer has failed to identify and run the handler on any other handler function registered
+ * to the given ID.
+ *
+ * If you need to perform a simple transformations consider using the following methods instead:
+ *
+ * - item -> item (with same meta): {@link #addItemReplacement(String, Item)}
+ * - item -> item with specific meta: {@link #addItemReplacement(String, Item, int)}
+ * - item with meta -> item (with same meta): {@link #addItemReplacement(String, int, Item)}
+ * - item with meta -> item with specific meta: {@link #addItemReplacement(String, int, Item, int)}
+ *
+ *
+ * @implNote For performance reasons, Postea assumes that the tag that was passed to the handler hasn't been
+ * modified
+ * if you return a null value. This isn't enforced though since returning a null value after doing some
+ * modifications has a couple niche uses. eg: having separate handlers for different migrations of a
+ * single thing that can be sunset at different times down the line.
+ *
* @param originalId The id of the item to transform.
* @param transformer The transformer to apply.
*/
@SuppressWarnings("unused")
- public static void addItemReplacement(@Nonnull String originalId,
- @Nonnull Function transformer) {
+ public static void addTransformationHandler(@Nonnull String originalId,
+ @Nonnull Function transformer) {
if (originalId == null) throw new IllegalArgumentException("original id is null");
if (transformer == null) throw new IllegalArgumentException("transformer is null");
TransformerRegistry.addItemReplacement(originalId, transformer);
@@ -51,7 +196,7 @@ public class ItemStackReplacementManager {
/**
* Suppresses any missing mapping warning for the given id.
- *
+ *
* @param originalId The id of the block or item to suppress the warning for.
*/
@SuppressWarnings("unused")
@@ -69,6 +214,9 @@ public class ItemStackReplacementManager {
* mappings,
* (e.g.: Transforming a removed item into a stick)
*
+ * @implNote All transformations registered using this handler are executed in constant time regardless of how many
+ * transformations are registered to a single id.
+ *
* @param originalId The id of the item to remap.
* @param item The item to remap to.
*/
@@ -84,6 +232,9 @@ public class ItemStackReplacementManager {
* mappings,
* (e.g.: Transforming a removed item into a stick)
*
+ * @implNote All transformations registered using this handler are executed in constant time regardless of how many
+ * transformations are registered to a single id.
+ *
* @param originalId The id of the item to remap.
* @param item The item to remap to.
* @param skipBlockRemap Set to true to skip auto-adding a block remapper if the item happens to be an ItemBlock.
@@ -104,6 +255,9 @@ public class ItemStackReplacementManager {
* Adds a mapping to remap stacks of a given item to another item with a given damage/meta value. This also adds a
* matching block replacement if this item happens to be an ItemBlock.
*
+ * @implNote All transformations registered using this handler are executed in constant time regardless of how many
+ * transformations are registered to a single id.
+ *
* @param originalId The id of the item to remap.
* @param item The item to remap to.
* @param newMeta The meta of the item to remap to. OreDictionary.WILDCARD_VALUE maintains the existing value.
@@ -116,6 +270,9 @@ public class ItemStackReplacementManager {
/**
* Adds a mapping to remap stacks of a given item to another item with a given damage/meta value.
*
+ * @implNote All transformations registered using this handler are executed in constant time regardless of how many
+ * transformations are registered to a single id.
+ *
* @param originalId The id of the item to remap.
* @param item The item to remap to.
* @param newMeta The meta of the item to remap to. OreDictionary.WILDCARD_VALUE maintains the existing
@@ -134,6 +291,9 @@ public class ItemStackReplacementManager {
* Adds a mapping to remap stacks of a given item to another item with a given damage/meta value. This also adds a
* matching block replacement if this item happens to be an ItemBlock.
*
+ * @implNote All transformations registered using this handler are executed in constant time regardless of how many
+ * transformations are registered to a single id.
+ *
* @param originalId The id of the item to remap.
* @param stack The item to remap to.
*/
@@ -150,6 +310,9 @@ public class ItemStackReplacementManager {
/**
* Adds a mapping to remap stacks of a given item to another item with a given damage/meta value.
*
+ * @implNote All transformations registered using this handler are executed in constant time regardless of how many
+ * transformations are registered to a single id.
+ *
* @param originalId The id of the item to remap.
* @param stack A stack of the item to replace to.
* @param skipBlockRemap Set to true to skip auto-adding a block remapper if the item happens to be an ItemBlock.
@@ -165,12 +328,51 @@ public class ItemStackReplacementManager {
skipBlockRemap);
}
+ // item+meta -> item
+
+ /**
+ * Adds a mapping to remap all stacks of a given item and damage/meta value to another item, whilst maintaining its
+ * damage/meta value. This also adds a matching block replacement if this item happens to be an ItemBlock.
+ *
+ * @implNote All transformations registered using this handler are executed in constant time regardless of how many
+ * transformations are registered to a single id.
+ *
+ * @param originalId The id of the item to remap.
+ * @param originalMeta The meta of the item to remap. OreDictionary.WILDCARD_VALUE acts as a wildcard.
+ * @param item The item to remap to.
+ */
+ @SuppressWarnings("unused")
+ public static void addItemReplacement(@Nonnull String originalId, int originalMeta, @Nonnull Item item) {
+ addItemReplacement(originalId, originalMeta, item, OreDictionary.WILDCARD_VALUE, false);
+ }
+
+ /**
+ * Adds a mapping to remap all stacks of a given item and damage/meta value to another item, whilst maintaining its
+ * damage/meta value.
+ *
+ * @implNote All transformations registered using this handler are executed in constant time regardless of how many
+ * transformations are registered to a single id.
+ *
+ * @param originalId The id of the item to remap.
+ * @param originalMeta The meta of the item to remap. OreDictionary.WILDCARD_VALUE acts as a wildcard.
+ * @param item The item to remap to.
+ * @param skipBlockRemap Set to true to skip auto-adding a item remapper if the .
+ */
+ @SuppressWarnings("unused")
+ public static void addItemReplacement(@Nonnull String originalId, int originalMeta, @Nonnull Item item,
+ boolean skipBlockRemap) {
+ addItemReplacement(originalId, originalMeta, item, OreDictionary.WILDCARD_VALUE, skipBlockRemap);
+ }
+
// item+meta -> stack
/**
* Adds a mapping to remap all stacks of a given item and damage/meta value to another item with a
* given damage/meta value. This also adds a matching block replacement if this item happens to be an ItemBlock.
*
+ * @implNote All transformations registered using this handler are executed in constant time regardless of how many
+ * transformations are registered to a single id.
+ *
* @param originalId The id of the item to remap.
* @param originalMeta The meta of the item to remap. OreDictionary.WILDCARD_VALUE acts as a wildcard.
* @param stack A stack of the item to replace to.
@@ -184,6 +386,9 @@ public class ItemStackReplacementManager {
* Adds a mapping to remap all stacks of a given item and damage/meta value to another item with a
* given damage/meta value.
*
+ * @implNote All transformations registered using this handler are executed in constant time regardless of how many
+ * transformations are registered to a single id.
+ *
* @param originalId The id of the item to remap.
* @param originalMeta The meta of the item to remap. OreDictionary.WILDCARD_VALUE acts as a wildcard.
* @param stack A stack of the item to replace to.
@@ -201,6 +406,9 @@ public class ItemStackReplacementManager {
* Adds a mapping to remap all stacks of a given item and damage/meta value to another item with a
* given damage/meta value. This also adds a matching block replacement if this item happens to be an ItemBlock.
*
+ * @implNote All transformations registered using this handler are executed in constant time regardless of how many
+ * transformations are registered to a single id.
+ *
* @param originalId The id of the item to remap.
* @param originalMeta The meta of the item to remap. OreDictionary.WILDCARD_VALUE acts as a wildcard.
* @param item The item to remap to.
@@ -216,6 +424,9 @@ public class ItemStackReplacementManager {
* Adds a mapping to remap all stacks of a given item and damage/meta value to another item with a
* given damage/meta value.
*
+ * @implNote All transformations registered using this handler are executed in constant time regardless of how many
+ * transformations are registered to a single id.
+ *
* @param originalId The id of the item to remap.
* @param originalMeta The meta of the item to remap. OreDictionary.WILDCARD_VALUE acts as a wildcard.
* @param item The item to remap to.
@@ -224,7 +435,7 @@ public class ItemStackReplacementManager {
* @param skipBlockRemap Set to true to skip auto-adding a item remapper if the .
*/
@SuppressWarnings("unused")
- public static void addItemReplacement(String originalId, int originalMeta, Item item, int newMeta,
+ public static void addItemReplacement(@Nonnull String originalId, int originalMeta, @Nonnull Item item, int newMeta,
boolean skipBlockRemap) {
if (originalId == null) throw new IllegalArgumentException("original id is null");
if (item == null) throw new IllegalArgumentException("item is null");
diff --git a/src/main/java/com/gtnewhorizons/postea/mixins/early/MixinItemStack.java b/src/main/java/com/gtnewhorizons/postea/mixins/early/MixinItemStack.java
index 7ca19d3..bf8a976 100644
--- a/src/main/java/com/gtnewhorizons/postea/mixins/early/MixinItemStack.java
+++ b/src/main/java/com/gtnewhorizons/postea/mixins/early/MixinItemStack.java
@@ -1,7 +1,5 @@
package com.gtnewhorizons.postea.mixins.early;
-import static com.gtnewhorizons.postea.utility.ItemFixerUtility.fixItemStack;
-
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
@@ -10,6 +8,8 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import com.gtnewhorizons.postea.utility.TransformerRegistry;
+
@Mixin(ItemStack.class)
@SuppressWarnings("unused")
public abstract class MixinItemStack {
@@ -17,7 +17,7 @@ public abstract class MixinItemStack {
@Inject(method = "readFromNBT(Lnet/minecraft/nbt/NBTTagCompound;)V", at = @At("HEAD"))
@SuppressWarnings("unused")
private void onReadFromNBTReturn(NBTTagCompound tag, CallbackInfo ci) {
- fixItemStack(tag);
+ TransformerRegistry.transformItem(tag);
}
}
diff --git a/src/main/java/com/gtnewhorizons/postea/utility/BlockConversionInfo.java b/src/main/java/com/gtnewhorizons/postea/utility/BlockConversionInfo.java
index fecfd7c..2b27808 100644
--- a/src/main/java/com/gtnewhorizons/postea/utility/BlockConversionInfo.java
+++ b/src/main/java/com/gtnewhorizons/postea/utility/BlockConversionInfo.java
@@ -1,19 +1,24 @@
package com.gtnewhorizons.postea.utility;
-import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
public final class BlockConversionInfo {
- public int x;
- public int y;
- public int z;
-
+ public final String blockName;
public int blockID;
public int metadata;
+ public final int x;
+ public final int y;
+ public final int z;
+ public final World world;
- public World world;
- public NBTTagCompound tileEntityNBT;
-
- public String blockName;
+ public BlockConversionInfo(String blockName, int blockID, int metadata, int x, int y, int z, World world) {
+ this.blockName = blockName;
+ this.blockID = blockID;
+ this.metadata = metadata;
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.world = world;
+ }
}
diff --git a/src/main/java/com/gtnewhorizons/postea/utility/ChunkFixerUtility.java b/src/main/java/com/gtnewhorizons/postea/utility/ChunkFixerUtility.java
index c65c92a..55dd554 100644
--- a/src/main/java/com/gtnewhorizons/postea/utility/ChunkFixerUtility.java
+++ b/src/main/java/com/gtnewhorizons/postea/utility/ChunkFixerUtility.java
@@ -1,13 +1,12 @@
package com.gtnewhorizons.postea.utility;
import static com.gtnewhorizons.postea.utility.PosteaUtilities.getModListHash;
+import static com.gtnewhorizons.postea.utility.TransformerRegistry.getBlockReplacement;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
-import net.minecraft.block.Block;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.World;
@@ -20,7 +19,6 @@ import com.gtnewhorizons.postea.compat.Compat;
import com.gtnewhorizons.postea.compat.SubChunkAccess;
import akka.japi.Pair;
-import cpw.mods.fml.common.registry.GameRegistry;
public class ChunkFixerUtility {
@@ -28,7 +26,6 @@ public class ChunkFixerUtility {
public static final int POSTEA_UPDATE_CODE = getModListHash();
private static final int AIR_ID = 0;
- private static final HashMap loadedBlocks = new HashMap<>();
public static void transformNormalBlocks(Chunk chunk, ExtendedBlockStorage ebs, World world) {
@@ -47,36 +44,18 @@ public class ChunkFixerUtility {
// Skip air.
if (blockId == AIR_ID) continue;
- // If this block has no registered Postea conversion, skip it.
- if (TransformerRegistry.blockNotConvertible(blockId)) continue;
- // Cache block names to improve performance, as findUniqueIdentifierFor is expensive.
- Block block = Block.getBlockById(blockId);
- String blockName = loadedBlocks.computeIfAbsent(
- block,
- b -> GameRegistry.findUniqueIdentifierFor(b)
- .toString());
-
- BlockConversionInfo blockConversionInfo = new BlockConversionInfo();
- blockConversionInfo.blockName = blockName;
- blockConversionInfo.blockID = blockId;
- blockConversionInfo.metadata = (byte) metadata; // Updated
-
- blockConversionInfo.world = world;
-
- blockConversionInfo.x = x + chunkXPos + 1;
- blockConversionInfo.y = y + sectionY;
- blockConversionInfo.z = z + chunkZPos + 1;
-
- BlockConversionInfo output = TransformerRegistry.getBlockReplacement(blockConversionInfo, world);
+ BlockConversionInfo output = getBlockReplacement(
+ blockId,
+ (byte) metadata,
+ world,
+ x + chunkXPos + 1,
+ y + sectionY,
+ z + chunkZPos + 1);
if (output != null) {
access.setBlockId(x, y, z, output.blockID);
access.setMeta(x, y, z, output.metadata);
- } else if (MissingMappingHandler.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
deleted file mode 100644
index cd2f4ce..0000000
--- a/src/main/java/com/gtnewhorizons/postea/utility/ItemFixerUtility.java
+++ /dev/null
@@ -1,45 +0,0 @@
-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.api.IDExtenderCompat;
-
-import cpw.mods.fml.common.registry.GameRegistry;
-
-public abstract class ItemFixerUtility {
-
- public static void fixItemStack(NBTTagCompound tag) {
-
- if (tag.hasNoTags()) return;
-
- if (tag.hasKey("id")) {
- int id = IDExtenderCompat.getItemStackID(tag);
- Item item = Item.getItemById(id);
- if (item == null) return;
- GameRegistry.UniqueIdentifier uuid = GameRegistry.findUniqueIdentifierFor(item);
- String itemNameInternal = uuid.modId + ":" + uuid.name;
-
- // abort early if no handlers
- Collection> handlers = TransformerRegistry
- .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 (MissingMappingHandler.isDummyItem(item)) {
- tag.removeTag("id");
- tag.removeTag("idExt");
- }
- }
- }
-}
diff --git a/src/main/java/com/gtnewhorizons/postea/utility/MissingMappingHandler.java b/src/main/java/com/gtnewhorizons/postea/utility/MissingMappingHandler.java
index 3e23b0b..156d507 100644
--- a/src/main/java/com/gtnewhorizons/postea/utility/MissingMappingHandler.java
+++ b/src/main/java/com/gtnewhorizons/postea/utility/MissingMappingHandler.java
@@ -17,6 +17,7 @@ import com.gtnewhorizons.postea.compat.Compat;
import cpw.mods.fml.common.event.FMLMissingMappingsEvent;
import cpw.mods.fml.common.registry.GameRegistry;
+import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
public abstract class MissingMappingHandler {
@@ -65,7 +66,10 @@ public abstract class MissingMappingHandler {
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 HashMap DUMMY_ID_TO_ORIGINAL_ID_LOOKUP = new HashMap<>();
+ private static final HashMap ORIGINAL_ID_TO_DUMMY_ID_LOOKUP = new HashMap<>();
+
+ private static final IntOpenHashSet DUMMY_IDS = new IntOpenHashSet();
private static final String DUMMY_ID_PREFIX_START = Postea.MODID + ":";
private static final String DUMMY_ID_PREFIX_END = "d.";
@@ -96,7 +100,8 @@ public abstract class MissingMappingHandler {
MISSING_ITEM_MAPPINGS.put(originalId, dummy);
Compat.hideItemFromNEI(dummy);
}
- REVERSE_DUMMY_ID_LOOKUP.put(mapping.id, originalId);
+ DUMMY_ID_TO_ORIGINAL_ID_LOOKUP.put(mapping.id, originalId);
+ ORIGINAL_ID_TO_DUMMY_ID_LOOKUP.put(originalId, mapping.id);
}
// no longer needed free what ever used to be in there
DUMMY_TARGET_TYPES.clear();
@@ -176,7 +181,11 @@ public abstract class MissingMappingHandler {
}
public static String getOriginalIDIfIDIsDummyID(String originalId) {
- return REVERSE_DUMMY_ID_LOOKUP.getOrDefault(originalId, originalId);
+ return DUMMY_ID_TO_ORIGINAL_ID_LOOKUP.getOrDefault(originalId, originalId);
+ }
+
+ public static String getDummyIdIfMissing(String originalId) {
+ return ORIGINAL_ID_TO_DUMMY_ID_LOOKUP.getOrDefault(originalId, originalId);
}
private static @Nullable String[] splitItemId(String itemId) {
diff --git a/src/main/java/com/gtnewhorizons/postea/utility/SimpleTransformationMap.java b/src/main/java/com/gtnewhorizons/postea/utility/SimpleTransformationMap.java
index 5fd18e5..ffcfebe 100644
--- a/src/main/java/com/gtnewhorizons/postea/utility/SimpleTransformationMap.java
+++ b/src/main/java/com/gtnewhorizons/postea/utility/SimpleTransformationMap.java
@@ -1,6 +1,5 @@
package com.gtnewhorizons.postea.utility;
-import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@@ -8,9 +7,12 @@ import javax.annotation.Nullable;
import net.minecraftforge.oredict.OreDictionary;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
+
public class SimpleTransformationMap {
- private final Map> registry = new HashMap<>();
+ private final Map> registry = new Object2ObjectOpenHashMap<>();
/**
* Puts a mapping in this registry.
@@ -21,7 +23,7 @@ public class SimpleTransformationMap {
*/
public void put(String originalId, int originalMeta, T data) {
if (originalMeta == -1) originalMeta = OreDictionary.WILDCARD_VALUE;
- this.registry.computeIfAbsent(originalId, k -> new HashMap<>())
+ this.registry.computeIfAbsent(originalId, k -> new Int2ObjectOpenHashMap<>())
.put(originalMeta, data);
}
diff --git a/src/main/java/com/gtnewhorizons/postea/utility/TransformerRegistry.java b/src/main/java/com/gtnewhorizons/postea/utility/TransformerRegistry.java
index f3ea427..35240ce 100644
--- a/src/main/java/com/gtnewhorizons/postea/utility/TransformerRegistry.java
+++ b/src/main/java/com/gtnewhorizons/postea/utility/TransformerRegistry.java
@@ -1,8 +1,7 @@
package com.gtnewhorizons.postea.utility;
-import java.util.Collection;
+import java.util.List;
import java.util.Map;
-import java.util.function.BiFunction;
import java.util.function.Function;
import javax.annotation.Nullable;
@@ -19,26 +18,43 @@ import org.apache.commons.lang3.tuple.Pair;
import com.google.common.collect.LinkedListMultimap;
import com.gtnewhorizons.postea.api.IDExtenderCompat;
+import cpw.mods.fml.common.event.FMLModIdMappingEvent;
+import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
public class TransformerRegistry {
- private static final LinkedListMultimap> ITEM_REPLACEMENT_MAP = LinkedListMultimap
+ private static final LinkedListMultimap> ITEM_REPLACEMENT_MAP = LinkedListMultimap
.create();
- public static final LinkedListMultimap> BLOCK_REPLACEMENT_MAP = LinkedListMultimap
+ public static final LinkedListMultimap> BLOCK_REPLACEMENT_MAP = LinkedListMultimap
.create();
- public static final IntOpenHashSet POSTEA_MARKED_IDS = new IntOpenHashSet();
+ private static final Int2ObjectOpenHashMap>>> RUNTIME_ITEM_REPLACEMENT_MAP = new Int2ObjectOpenHashMap<>();
+ private static final Int2ObjectOpenHashMap>>> RUNTIME_BLOCK_REPLACEMENT_MAP = new Int2ObjectOpenHashMap<>();
+ private static final IntOpenHashSet DUMMY_IDS = new IntOpenHashSet();
+ /**
+ * Map of IDs that were remapped by forge in the currently loaded save file. (usually happens due to missing
+ * mappings)
+ * Should be faster than asking block.getIdFromBlock() and Item.getIdFromItem()
+ */
+ public static final Int2IntOpenHashMap REMAPPED_IDS = new Int2IntOpenHashMap();
+
+ /**
+ * Stores simple item transformations (eg if old id is # with meta # then turn into item with id # with meta #.
+ */
public static final SimpleTransformationMap> SIMPLE_ITEM_TRANSFORMATION_MAP = new SimpleTransformationMap<>();
+ /**
+ * Stores simple block transformations (eg if old id is # with meta # then turn into item with id # with meta #.
+ */
public static final SimpleTransformationMap> SIMPLE_BLOCK_TRANSFORMATION_MAP = new SimpleTransformationMap<>();
- public static void addBlockReplacement(String originalId,
- BiFunction transformer) {
+ public static void addBlockReplacement(String originalId, Function transformer) {
MissingMappingHandler.createDummyBlockIfNeeded(originalId);
BLOCK_REPLACEMENT_MAP.put(originalId, transformer);
}
- public static void addItemReplacement(String originalId, Function transformer) {
+ public static void addItemReplacement(String originalId, Function transformer) {
MissingMappingHandler.createDummyItemIfNeeded(originalId);
ITEM_REPLACEMENT_MAP.put(originalId, transformer);
}
@@ -68,74 +84,157 @@ public class TransformerRegistry {
.put(originalId, originalMeta, Pair.of(Item.getIdFromItem(newItem), (short) newMeta));
}
+ private static boolean simpleBlockTransformer(BlockConversionInfo info,
+ Map> metaMap) {
+ Pair mapping = SimpleTransformationMap.getFromSubmap(metaMap, info.metadata);
+ if (mapping == null) return false;
+ int key = mapping.getKey();
+ info.blockID = REMAPPED_IDS.getOrDefault(key, key);
+ if (mapping.getValue() != OreDictionary.WILDCARD_VALUE) {
+ info.metadata = mapping.getValue();
+ }
+ return true;
+ }
+
+ private static boolean simpleItemStackTransformer(NBTTagCompound tag, Map> metaMap) {
+ short meta = tag.getShort("Damage");
+ Pair mapping = SimpleTransformationMap.getFromSubmap(metaMap, meta);
+ if (mapping == null) return false;
+ int key = mapping.getKey();
+ IDExtenderCompat.setItemStackID(tag, REMAPPED_IDS.getOrDefault(key, key));
+ if (mapping.getValue() != OreDictionary.WILDCARD_VALUE) {
+ tag.setShort("Damage", mapping.getValue());
+ }
+ return true;
+ }
+
+ public static boolean isDummyId(int id) {
+ return DUMMY_IDS.contains(id);
+ }
+
+ // region FML Life Cycle handlers
public static void onLoadCompleted() {
+ // add handlers for simple block remaps
for (Map.Entry>> kv : SIMPLE_BLOCK_TRANSFORMATION_MAP.entrySet()) {
MissingMappingHandler.createDummyBlockIfNeeded(kv.getKey());
- BLOCK_REPLACEMENT_MAP.put(kv.getKey(), (info, world) -> simpleBlockTransformer(info, world, kv.getValue()));
+ BLOCK_REPLACEMENT_MAP.put(kv.getKey(), info -> simpleBlockTransformer(info, kv.getValue()));
}
+ // add handlers for simple item remaps
for (Map.Entry>> kv : SIMPLE_ITEM_TRANSFORMATION_MAP.entrySet()) {
MissingMappingHandler.createDummyItemIfNeeded(kv.getKey());
ITEM_REPLACEMENT_MAP.put(kv.getKey(), tag -> simpleItemStackTransformer(tag, kv.getValue()));
}
}
- private static @Nullable BlockConversionInfo simpleBlockTransformer(BlockConversionInfo info, World world,
- Map> metaMap) {
- Pair mapping = SimpleTransformationMap.getFromSubmap(metaMap, info.metadata);
- if (mapping == null) return null;
- info.blockID = mapping.getKey();
- if (mapping.getValue() != OreDictionary.WILDCARD_VALUE) {
- info.metadata = mapping.getValue();
+ public static void onIdMappingsChanged(FMLModIdMappingEvent event) {
+ REMAPPED_IDS.clear();
+ DUMMY_IDS.clear();
+ RUNTIME_BLOCK_REPLACEMENT_MAP.clear();
+ RUNTIME_ITEM_REPLACEMENT_MAP.clear();
+ // Store the remapped ids since the simple transform pivot on ids since it's faster using the block/item.
+ for (FMLModIdMappingEvent.ModRemapping remap : event.remappedIds) {
+ // the remapping type doesn't actually matter, FML doesn't seem to handle it right anyway.
+ REMAPPED_IDS.putIfAbsent(remap.oldId, remap.newId);
}
- return info;
- }
-
- private static @Nullable NBTTagCompound simpleItemStackTransformer(NBTTagCompound tag,
- Map> metaMap) {
- short meta = tag.getShort("Damage");
- Pair mapping = SimpleTransformationMap.getFromSubmap(metaMap, meta);
- if (mapping == null) return null;
- IDExtenderCompat.setItemStackID(tag, mapping.getKey());
- if (mapping.getValue() != OreDictionary.WILDCARD_VALUE) {
- tag.setShort("Damage", mapping.getValue());
- }
- return tag;
- }
-
- public static void onIdMappingsChanged() {
- POSTEA_MARKED_IDS.clear();
- for (String name : BLOCK_REPLACEMENT_MAP.keySet()) {
- Block block = Block.getBlockFromName(name);
- if (block != null) {
+ // create a lookup for source block ids.
+ for (String key : BLOCK_REPLACEMENT_MAP.keys()) {
+ String name = MissingMappingHandler.getDummyIdIfMissing(key);
+ if (Block.blockRegistry.getObject(name) instanceof Block block) {
int id = Block.getIdFromBlock(block);
- POSTEA_MARKED_IDS.add(id);
+ RUNTIME_BLOCK_REPLACEMENT_MAP.put(id, Pair.of(key, BLOCK_REPLACEMENT_MAP.get(key)));
+ // not using .equals() on purpose, I'm looking for instance, not content equality
+ if (key != name) DUMMY_IDS.add(id);
+ }
+ }
+ // create a lookup for source block ids.
+ for (String key : ITEM_REPLACEMENT_MAP.keys()) {
+ String name = MissingMappingHandler.getDummyIdIfMissing(key);
+ if (Item.itemRegistry.getObject(name) instanceof Item item) {
+ int id = Item.getIdFromItem(item);
+ RUNTIME_ITEM_REPLACEMENT_MAP.put(id, Pair.of(key, ITEM_REPLACEMENT_MAP.get(key)));
+ // not using .equals() on purpose, I'm looking for instance, not content equality
+ if (key != name) DUMMY_IDS.add(id);
}
}
}
public static void onServerStopping() {
- POSTEA_MARKED_IDS.clear();
+ RUNTIME_BLOCK_REPLACEMENT_MAP.clear();
+ RUNTIME_ITEM_REPLACEMENT_MAP.clear();
+ REMAPPED_IDS.clear();
+ DUMMY_IDS.clear();
}
+ // endregion FML Life Cycle handlers
- public static Collection> getItemReplacement(String itemNameInternal) {
- return ITEM_REPLACEMENT_MAP.get(MissingMappingHandler.getOriginalIDIfIDIsDummyID(itemNameInternal));
- }
-
- 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 = MissingMappingHandler.getOriginalIDIfIDIsDummyID(blockConversionInfo.blockName);
- blockConversionInfo.blockName = originalName;
- for (BiFunction transformer : BLOCK_REPLACEMENT_MAP
- .get(originalName)) {
- BlockConversionInfo result = transformer.apply(blockConversionInfo, world);
- if (result != null) return result;
+ // region block replacement handler
+ public static @Nullable BlockConversionInfo getBlockReplacement(int blockId, byte metadata, World world, int x,
+ int y, int z) {
+ Pair>> data = RUNTIME_BLOCK_REPLACEMENT_MAP.get(blockId);
+ if (data == null) return null;
+ BlockConversionInfo blockConversionInfo = new BlockConversionInfo(
+ // transparently maps the id to the original id if it's a dummy id
+ data.getKey(),
+ blockId,
+ metadata,
+ x,
+ y,
+ z,
+ world);
+ for (Function transformer : data.getValue()) {
+ if (transformer.apply(blockConversionInfo)) {
+ // Not sure if we want to keep this around since this would affect perf a bit, good for debugging
+ // though.
+ // if (DUMMY_IDS.contains(result.blockID)) FMLLog.warning("returned a success on a non-transformed
+ // block!");
+ return blockConversionInfo;
+ }
+ }
+ // if we're transforming a dummy block from a missing mapping and it wasn't handled, delete the block.
+ if (TransformerRegistry.isDummyId(blockId)) {
+ blockConversionInfo.blockID = 0;
+ blockConversionInfo.metadata = 0;
+ return blockConversionInfo;
}
return null;
}
+ // endregion block replacement handler
- // We need this to save reprocessing blocks.
- public static boolean blockNotConvertible(int blockID) {
- return !POSTEA_MARKED_IDS.contains(blockID);
+ // region item replacement handler
+ public static void transformItem(NBTTagCompound tag) {
+ // abort early if tag is bad.
+ if (tag.hasNoTags() || !tag.hasKey("id")) return;
+ // get handler
+ int id = IDExtenderCompat.getItemStackID(tag);
+ Pair>> data = RUNTIME_ITEM_REPLACEMENT_MAP.get(id);
+ // abort early if handler not found
+ if (data == null || data.getValue()
+ .isEmpty()) return;
+
+ // apply handlers
+ for (Function transformer : data.getValue()) {
+ if (transformer.apply(tag)) {
+ // Not sure if we want to keep this around since this would affect perf a bit, good for debugging
+ // though.
+ // if (DUMMY_IDS.contains(IDExtenderCompat.getItemStackID(tag))) FMLLog.warning("returned a success on a
+ // non-transformed block!");
+ return;
+ }
+ }
+ // if no handler overwrote anything on this stack, and it's a dummy, delete the stack.
+ if (TransformerRegistry.isDummyId(id)) {
+ tag.removeTag("id");
+ tag.removeTag("idExt");
+ }
}
+
+ /**
+ * A method to go from tag -> name since that's not provided to handlers usually.
+ * Could be useful if you have one handler function handling a lot of complex transforms.
+ */
+ public static @Nullable String getMappedItemName(int itemId) {
+ Pair>> data = RUNTIME_ITEM_REPLACEMENT_MAP.get(itemId);
+ if (data == null) return null;
+ return data.getKey();
+ }
+ // endregion item replacement handler
}