mirror of
https://github.com/GTNewHorizons/Postea.git
synced 2026-11-13 00:47:53 +00:00
isolate simple transformations to own file + more doc + cleanup
This commit is contained in:
1 parent
d20a5fe43f
commit
9672270b1e
5 files changed
+272
-224
No files matched your search
@@ -1,6 +1,7 @@
|
||||
package com.gtnewhorizons.postea;
|
||||
|
||||
import com.gtnewhorizons.postea.utility.MissingMappingHandler;
|
||||
import com.gtnewhorizons.postea.utility.SimpleTransformationRegistry;
|
||||
import com.gtnewhorizons.postea.utility.TransformerRegistry;
|
||||
|
||||
import cpw.mods.fml.common.Mod;
|
||||
@@ -27,7 +28,8 @@ public class Postea {
|
||||
|
||||
@Mod.EventHandler
|
||||
public void onIdMappingsChanged(FMLModIdMappingEvent event) {
|
||||
TransformerRegistry.onIdMappingsChanged(event);
|
||||
SimpleTransformationRegistry.onIdMappingsChanged();
|
||||
TransformerRegistry.onIdMappingsChanged();
|
||||
}
|
||||
|
||||
@Mod.EventHandler
|
||||
@@ -37,7 +39,7 @@ public class Postea {
|
||||
|
||||
@Mod.EventHandler
|
||||
public void onLoadCompleted(FMLLoadCompleteEvent event) {
|
||||
TransformerRegistry.onLoadCompleted();
|
||||
SimpleTransformationRegistry.onLoadCompleted();
|
||||
MissingMappingHandler.onLoadCompleted();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import net.minecraftforge.oredict.OreDictionary;
|
||||
|
||||
import com.gtnewhorizons.postea.utility.BlockConversionInfo;
|
||||
import com.gtnewhorizons.postea.utility.MissingMappingHandler;
|
||||
import com.gtnewhorizons.postea.utility.SimpleTransformationRegistry;
|
||||
import com.gtnewhorizons.postea.utility.TransformerRegistry;
|
||||
|
||||
public class BlockReplacementManager {
|
||||
@@ -43,8 +44,9 @@ public class BlockReplacementManager {
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("unused")
|
||||
public static void addBlockReplacement(@Nonnull String originalId,
|
||||
@Nonnull BiFunction<BlockConversionInfo, World, BlockConversionInfo> transformer) {
|
||||
public static void addBlockReplacement(String originalId,
|
||||
BiFunction<BlockConversionInfo, World, BlockConversionInfo> transformer) {
|
||||
if (transformer == null) throw new IllegalArgumentException("transformer is null");
|
||||
addTransformationHandler(originalId, info -> transformer.apply(info, info.world) != null);
|
||||
}
|
||||
|
||||
@@ -73,8 +75,7 @@ public class BlockReplacementManager {
|
||||
* @param transformer The transformer to apply.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void addTransformationHandler(@Nonnull String originalId,
|
||||
@Nonnull Function<BlockConversionInfo, Boolean> transformer) {
|
||||
public static void addTransformationHandler(String originalId, Function<BlockConversionInfo, Boolean> transformer) {
|
||||
if (originalId == null) throw new IllegalArgumentException("original id is null");
|
||||
if (transformer == null) throw new IllegalArgumentException("transformer is null");
|
||||
TransformerRegistry.addBlockReplacement(originalId, transformer);
|
||||
@@ -93,7 +94,7 @@ public class BlockReplacementManager {
|
||||
* @param block The block to remap to.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void replaceMissingBlockWithNewBlock(@Nonnull String originalId, @Nonnull Block block) {
|
||||
public static void replaceMissingBlockWithNewBlock(String originalId, Block block) {
|
||||
if (originalId == null) throw new IllegalArgumentException("original id is null");
|
||||
if (block == null) throw new IllegalArgumentException("block is null");
|
||||
MissingMappingHandler.addSimpleReplacement(originalId, block);
|
||||
@@ -239,10 +240,10 @@ public class BlockReplacementManager {
|
||||
* @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,
|
||||
int newMeta, boolean skipStackRemap) {
|
||||
public static void addBlockReplacement(String originalId, int originalMeta, Block block, int newMeta,
|
||||
boolean skipStackRemap) {
|
||||
if (originalId == null) throw new IllegalArgumentException("original id is null");
|
||||
if (block == null) throw new IllegalArgumentException("block is null");
|
||||
TransformerRegistry.addSimpleTransformer(originalId, originalMeta, block, newMeta, skipStackRemap);
|
||||
SimpleTransformationRegistry.addSimpleTransformer(originalId, originalMeta, block, newMeta, skipStackRemap);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.gtnewhorizons.postea.api;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.Item;
|
||||
@@ -12,109 +12,17 @@ import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
|
||||
import com.gtnewhorizons.postea.utility.MissingMappingHandler;
|
||||
import com.gtnewhorizons.postea.utility.SimpleTransformationRegistry;
|
||||
import com.gtnewhorizons.postea.utility.TransformerRegistry;
|
||||
|
||||
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.
|
||||
* <pre>{@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;
|
||||
* }
|
||||
* }
|
||||
* }<pre/>
|
||||
*
|
||||
* @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.
|
||||
* <pre>{@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;
|
||||
* }
|
||||
* }
|
||||
* }<pre/>
|
||||
*
|
||||
* @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.
|
||||
* @deprecated Use {@link #addTransformationHandler(String, BiFunction)} 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
|
||||
@@ -139,9 +47,9 @@ public class ItemStackReplacementManager {
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("unused")
|
||||
public static void addItemReplacement(@Nonnull String originalId,
|
||||
@Nonnull Function<NBTTagCompound, NBTTagCompound> transformer) {
|
||||
addTransformationHandler(originalId, tag -> transformer.apply(tag) != null);
|
||||
public static void addItemReplacement(String originalId, Function<NBTTagCompound, NBTTagCompound> transformer) {
|
||||
if (transformer == null) throw new IllegalArgumentException("transformer is null");
|
||||
addTransformationHandler(originalId, (_originalId, tag) -> transformer.apply(tag) != null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,8 +76,8 @@ public class ItemStackReplacementManager {
|
||||
* @param transformer The transformer to apply.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void addTransformationHandler(@Nonnull String originalId,
|
||||
@Nonnull Function<NBTTagCompound, Boolean> transformer) {
|
||||
public static void addTransformationHandler(String originalId,
|
||||
BiFunction<String, NBTTagCompound, Boolean> transformer) {
|
||||
if (originalId == null) throw new IllegalArgumentException("original id is null");
|
||||
if (transformer == null) throw new IllegalArgumentException("transformer is null");
|
||||
TransformerRegistry.addItemReplacement(originalId, transformer);
|
||||
@@ -187,7 +95,7 @@ public class ItemStackReplacementManager {
|
||||
* @param item The item to remap to.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void replaceMissingItemWithNewItem(@Nonnull String originalId, @Nonnull Item item) {
|
||||
public static void replaceMissingItemWithNewItem(String originalId, Item item) {
|
||||
if (originalId == null) throw new IllegalArgumentException("original id is null");
|
||||
if (item == null) throw new IllegalArgumentException("item is null");
|
||||
MissingMappingHandler.addSimpleReplacement(originalId, item);
|
||||
@@ -289,6 +197,8 @@ 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.
|
||||
* <br>
|
||||
* DOES NOT COPY NBT FROM STACK.
|
||||
*
|
||||
* @implNote All transformations registered using this handler are executed in constant time regardless of how many
|
||||
* transformations are registered to a single id.
|
||||
@@ -308,6 +218,8 @@ public class ItemStackReplacementManager {
|
||||
|
||||
/**
|
||||
* Adds a mapping to remap stacks of a given item to another item with a given damage/meta value.
|
||||
* <br>
|
||||
* DOES NOT COPY NBT FROM STACK.
|
||||
*
|
||||
* @implNote All transformations registered using this handler are executed in constant time regardless of how many
|
||||
* transformations are registered to a single id.
|
||||
@@ -368,6 +280,8 @@ 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.
|
||||
* <br>
|
||||
* DOES NOT COPY NBT FROM STACK.
|
||||
*
|
||||
* @implNote All transformations registered using this handler are executed in constant time regardless of how many
|
||||
* transformations are registered to a single id.
|
||||
@@ -384,6 +298,8 @@ 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.
|
||||
* <br>
|
||||
* DOES NOT COPY NBT FROM STACK.
|
||||
*
|
||||
* @implNote All transformations registered using this handler are executed in constant time regardless of how many
|
||||
* transformations are registered to a single id.
|
||||
@@ -434,10 +350,10 @@ public class ItemStackReplacementManager {
|
||||
* @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, int newMeta,
|
||||
public static void addItemReplacement(String originalId, int originalMeta, 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");
|
||||
TransformerRegistry.addSimpleTransformer(originalId, originalMeta, item, newMeta, skipBlockRemap);
|
||||
SimpleTransformationRegistry.addSimpleTransformer(originalId, originalMeta, item, newMeta, skipBlockRemap);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
package com.gtnewhorizons.postea.utility;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemBlock;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.gtnewhorizons.postea.api.IDExtenderCompat;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
|
||||
/**
|
||||
* A registry for simple item and block transformations. A common use case is mod removal, replacements or deprecations.
|
||||
* When replacing one mod with another in GTNH, we have to migrate most if not all the mod's items and this often means
|
||||
* having to migrate almost every block and item from the original mod.
|
||||
* <hr>
|
||||
* If a mod uses metas to differentiate items (eg: GT5u) that will end up being migrated to separate items, this would
|
||||
* usually result in potentially multiple handlers per item if they are destined to be split into separate mods,
|
||||
* which increases the execution time linearly. The simple transformations uses a better algorithm for these
|
||||
* which is executed in constant time regardless of how many transformations have been assigned to a given id. (mostly
|
||||
* at the cost of higher memory usage due to caching)
|
||||
*/
|
||||
public class SimpleTransformationRegistry {
|
||||
|
||||
/**
|
||||
* Stores simple block transformations (eg: if old id is # with meta # then turn into item with id # with meta #.)
|
||||
*/
|
||||
public static final SimpleTransformationMap<Pair<Block, Short>> SIMPLE_BLOCK_TRANSFORMATION_MAP = new SimpleTransformationMap<>();
|
||||
public static final Object2IntOpenHashMap<Block> RUNTIME_BLOCK_ID_LOOKUP = new Object2IntOpenHashMap<>();
|
||||
/**
|
||||
* Stores simple item transformations (eg: if old id is # with meta # then turn into item with id # with meta #.)
|
||||
*/
|
||||
public static final SimpleTransformationMap<Pair<Item, Short>> SIMPLE_ITEM_TRANSFORMATION_MAP = new SimpleTransformationMap<>();
|
||||
public static final Object2IntOpenHashMap<Item> RUNTIME_ITEM_ID_LOOKUP = new Object2IntOpenHashMap<>();
|
||||
|
||||
// region FML Life Cycle handlers
|
||||
/**
|
||||
* Registers 1 handler per targeted ID to minimize the number of handlers. The meta-map is captured to reduce
|
||||
* the execution time of the handlers.
|
||||
*/
|
||||
public static void onLoadCompleted() {
|
||||
// add handlers for simple block remaps
|
||||
for (Map.Entry<String, Map<Integer, Pair<Block, Short>>> kv : SIMPLE_BLOCK_TRANSFORMATION_MAP.entrySet()) {
|
||||
Map<Integer, Pair<Block, Short>> subMap = kv.getValue();
|
||||
TransformerRegistry.addBlockReplacement(kv.getKey(), info -> simpleBlockTransformer(info, subMap));
|
||||
}
|
||||
// add handlers for simple item remaps
|
||||
for (Map.Entry<String, Map<Integer, Pair<Item, Short>>> kv : SIMPLE_ITEM_TRANSFORMATION_MAP.entrySet()) {
|
||||
Map<Integer, Pair<Item, Short>> subMap = kv.getValue();
|
||||
TransformerRegistry
|
||||
.addItemReplacement(kv.getKey(), (originalId, tag) -> simpleItemStackTransformer(tag, subMap));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-caches updated block and item IDs for any simple transformation to speed-up the handlers.
|
||||
*/
|
||||
public static void onIdMappingsChanged() {
|
||||
RUNTIME_ITEM_ID_LOOKUP.clear();
|
||||
RUNTIME_BLOCK_ID_LOOKUP.clear();
|
||||
for (Map.Entry<String, Map<Integer, Pair<Block, Short>>> kv : SIMPLE_BLOCK_TRANSFORMATION_MAP.entrySet()) {
|
||||
for (Pair<Block, Short> mapping : kv.getValue()
|
||||
.values()) {
|
||||
RUNTIME_BLOCK_ID_LOOKUP.computeIfAbsent(mapping.getKey(), Block::getIdFromBlock);
|
||||
}
|
||||
}
|
||||
for (Map.Entry<String, Map<Integer, Pair<Item, Short>>> kv : SIMPLE_ITEM_TRANSFORMATION_MAP.entrySet()) {
|
||||
for (Pair<Item, Short> mapping : kv.getValue()
|
||||
.values()) {
|
||||
RUNTIME_ITEM_ID_LOOKUP.computeIfAbsent(mapping.getKey(), Item::getIdFromItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
// endregion FML Life Cycle handlers
|
||||
|
||||
// region block transformations
|
||||
/**
|
||||
* Registers a simple Block transformation for a simple 1:1 transformation:
|
||||
* <ul>
|
||||
* <li>block -> block (with same meta)</li>
|
||||
* <li>block -> block with specific meta</li>
|
||||
* <li>block with meta -> block (with same meta)</li>
|
||||
* <li>block with meta -> block with specific meta</li>
|
||||
* </ul>
|
||||
*
|
||||
* @implNote With these simple transformers, it doesn't matter how many transformations are registered to a single
|
||||
* id, only a single handler will be registered per id during the FMLLoadCompleted event. Replacements
|
||||
* are by using hash-table lookups so the execution of the transformation should be constant-time
|
||||
* regardless
|
||||
* of how many handlers were registered to a single id.
|
||||
*
|
||||
* @param originalId The original namespaced id of the block to replace.
|
||||
* @param originalMeta The meta value of the block to replace. OreDictionary.WILDCARD_VALUE acts as a wildcard
|
||||
* and fallback if there isn't simple transformation registered for a given meta.
|
||||
* @param newBlock What block to replace with.
|
||||
* @param newMeta The meta value of the transformed block. OreDictionary.WILDCARD_VALUE preserves the
|
||||
* existing value.
|
||||
* @param skipStackRemap Set to true to skip registering an identical simple item transformation.
|
||||
*/
|
||||
public static void addSimpleTransformer(String originalId, int originalMeta, Block newBlock, int newMeta,
|
||||
boolean skipStackRemap) {
|
||||
if (newMeta == -1) newMeta = OreDictionary.WILDCARD_VALUE;
|
||||
SIMPLE_BLOCK_TRANSFORMATION_MAP.put(originalId, originalMeta, Pair.of(newBlock, (short) newMeta));
|
||||
if (!skipStackRemap) {
|
||||
Item item = Item.getItemFromBlock(newBlock);
|
||||
if (item != null) {
|
||||
SIMPLE_ITEM_TRANSFORMATION_MAP.put(originalId, originalMeta, Pair.of(item, (short) newMeta));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The handler for the simple block transformation.
|
||||
*
|
||||
* @implNote This implementation has constant-time runtime.
|
||||
*/
|
||||
private static boolean simpleBlockTransformer(BlockConversionInfo info, Map<Integer, Pair<Block, Short>> metaMap) {
|
||||
Pair<Block, Short> mapping = SimpleTransformationMap.getFromSubmap(metaMap, info.metadata);
|
||||
if (mapping == null) return false;
|
||||
info.blockID = RUNTIME_BLOCK_ID_LOOKUP.computeIfAbsent(mapping.getKey(), Block::getIdFromBlock);
|
||||
if (mapping.getValue() != OreDictionary.WILDCARD_VALUE) {
|
||||
info.metadata = mapping.getValue();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// endregion block transformations
|
||||
|
||||
// region item transformations
|
||||
/**
|
||||
* Registers a simple Block transformation for a simple 1:1 transformation:
|
||||
* <ul>
|
||||
* <li>item -> item (with same meta)</li>
|
||||
* <li>item -> item with specific meta</li>
|
||||
* <li>item with meta/damage -> item (with same meta/damage)</li>
|
||||
* <li>item with meta/damage -> item with specific meta/damage</li>
|
||||
* </ul>
|
||||
*
|
||||
* @implNote With these simple transformers, it doesn't matter how many transformations are registered to a single
|
||||
* id, only a single handler will be registered per id during the FMLLoadCompleted event. Replacements
|
||||
* are by using hash-table lookups so the execution of the transformation should be constant-time
|
||||
* regardless
|
||||
* of how many handlers were registered to a single id.
|
||||
*
|
||||
* @param originalId The original namespaced id of the item to replace.
|
||||
* @param originalMeta The meta/damage value of the item to replace. OreDictionary.WILDCARD_VALUE acts as a
|
||||
* wildcard
|
||||
* and fallback if there isn't simple transformation registered for a given meta.
|
||||
* @param newItem What item to replace with.
|
||||
* @param newMeta The meta/damage value of the transformed item. OreDictionary.WILDCARD_VALUE preserves the
|
||||
* existing
|
||||
* value.
|
||||
* @param skipBlockRemap Set to true to skip registering an identical block transformation if the item is an
|
||||
* ItemBlock.
|
||||
*/
|
||||
public static void addSimpleTransformer(String originalId, int originalMeta, Item newItem, int newMeta,
|
||||
boolean skipBlockRemap) {
|
||||
if (newMeta == -1) newMeta = OreDictionary.WILDCARD_VALUE;
|
||||
if (!skipBlockRemap && newItem instanceof ItemBlock ib) {
|
||||
SIMPLE_BLOCK_TRANSFORMATION_MAP.put(originalId, originalMeta, Pair.of(ib.field_150939_a, (short) newMeta));
|
||||
}
|
||||
SIMPLE_ITEM_TRANSFORMATION_MAP.put(originalId, originalMeta, Pair.of(newItem, (short) newMeta));
|
||||
}
|
||||
|
||||
/**
|
||||
* The handler for the simple item transformation.
|
||||
*
|
||||
* @implNote This implementation has constant-time runtime.
|
||||
*/
|
||||
private static boolean simpleItemStackTransformer(NBTTagCompound tag, Map<Integer, Pair<Item, Short>> metaMap) {
|
||||
short meta = tag.getShort("Damage");
|
||||
Pair<Item, Short> mapping = SimpleTransformationMap.getFromSubmap(metaMap, meta);
|
||||
if (mapping == null) return false;
|
||||
IDExtenderCompat
|
||||
.setItemStackID(tag, RUNTIME_ITEM_ID_LOOKUP.computeIfAbsent(mapping.getKey(), Item::getIdFromItem));
|
||||
if (mapping.getValue() != OreDictionary.WILDCARD_VALUE) {
|
||||
tag.setShort("Damage", mapping.getValue());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// endregion item transformations
|
||||
}
|
||||
@@ -1,141 +1,93 @@
|
||||
package com.gtnewhorizons.postea.utility;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemBlock;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* A registry for all transformer functions
|
||||
*/
|
||||
public class TransformerRegistry {
|
||||
|
||||
private static final LinkedListMultimap<String, Function<NBTTagCompound, Boolean>> ITEM_REPLACEMENT_MAP = LinkedListMultimap
|
||||
private static final LinkedListMultimap<String, BiFunction<String, NBTTagCompound, Boolean>> ITEM_REPLACEMENT_MAP = LinkedListMultimap
|
||||
.create();
|
||||
public static final LinkedListMultimap<String, Function<BlockConversionInfo, Boolean>> BLOCK_REPLACEMENT_MAP = LinkedListMultimap
|
||||
.create();
|
||||
|
||||
private static final Int2ObjectOpenHashMap<Pair<String, List<Function<NBTTagCompound, Boolean>>>> RUNTIME_ITEM_REPLACEMENT_MAP = new Int2ObjectOpenHashMap<>();
|
||||
/**
|
||||
* Map of itemID -> originalName+transformationHandler.
|
||||
* Pivoting on the id is faster than pivoting on the strings so this should help with perf a bit.
|
||||
* Generated during the mapping update event whilst entering/loading a world.
|
||||
*/
|
||||
private static final Int2ObjectOpenHashMap<Pair<String, List<BiFunction<String, NBTTagCompound, Boolean>>>> RUNTIME_ITEM_REPLACEMENT_MAP = new Int2ObjectOpenHashMap<>();
|
||||
/**
|
||||
* Map of blockIO -> originalName+transformationHandler.
|
||||
* Pivoting on the id is faster than pivoting on the strings so this should help with perf a bit.
|
||||
* Generated during the mapping update event whilst entering/loading a world.
|
||||
*/
|
||||
private static final Int2ObjectOpenHashMap<Pair<String, List<Function<BlockConversionInfo, Boolean>>>> 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()
|
||||
* List of ids used by dummy items and blocks generated by Postea.
|
||||
* Generated during the mapping update event whilst entering/loading a world.
|
||||
*/
|
||||
public static final Int2IntOpenHashMap REMAPPED_IDS = new Int2IntOpenHashMap();
|
||||
public static final IntOpenHashSet DUMMY_IDS = new IntOpenHashSet();
|
||||
|
||||
/**
|
||||
* Stores simple item transformations (eg if old id is # with meta # then turn into item with id # with meta #.)
|
||||
* Registers a block transformation handler function for the given id.
|
||||
*
|
||||
* @implNote It doesn't matter if the id doesn't belong to an existing block, a dummy block will be created when
|
||||
* Postea detects that the id isn't associated to a block during the FMLLoadCompleted event. Dependent
|
||||
* mods don't need to worry about this as the block name in the BlockConversionInfo is automatically
|
||||
* updated to the original id when attempting to transform a dummy block. When Postea runs a
|
||||
* transformation on a dummy block and no handler return true, Postea will automatically convert it to
|
||||
* air.
|
||||
*
|
||||
* @param originalId The namespaced id of the block to transform.
|
||||
* @param transformer The transformation handler that will execute a transformation on the block.
|
||||
*/
|
||||
public static final SimpleTransformationMap<Pair<Integer, Short>> 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<Pair<Integer, Short>> SIMPLE_BLOCK_TRANSFORMATION_MAP = new SimpleTransformationMap<>();
|
||||
|
||||
public static void addBlockReplacement(String originalId, Function<BlockConversionInfo, Boolean> transformer) {
|
||||
MissingMappingHandler.createDummyBlockIfNeeded(originalId);
|
||||
BLOCK_REPLACEMENT_MAP.put(originalId, transformer);
|
||||
}
|
||||
|
||||
public static void addItemReplacement(String originalId, Function<NBTTagCompound, Boolean> transformer) {
|
||||
/**
|
||||
* Registers an item transformation handler function for the given id.
|
||||
*
|
||||
* @implNote It doesn't matter if the id doesn't belong to an existing item, a dummy item will be created when
|
||||
* Postea detects that the id isn't associated to an item during the FMLLoadCompleted event. Dependent
|
||||
* mods don't need to worry about this as transformation handlers are given the original id associated
|
||||
* with the nbt they are provided when the handler is executed. When Postea runs a transformation on a
|
||||
* dummy item and no handler returns true, Postea will automatically invalidate the stack by removing
|
||||
* its id and idExt fields.
|
||||
*
|
||||
* @param originalId The namespaced id of the block to transform.
|
||||
* @param transformer The transformation handler that will execute a transformation on the block.
|
||||
*/
|
||||
public static void addItemReplacement(String originalId, BiFunction<String, NBTTagCompound, Boolean> transformer) {
|
||||
MissingMappingHandler.createDummyItemIfNeeded(originalId);
|
||||
ITEM_REPLACEMENT_MAP.put(originalId, transformer);
|
||||
}
|
||||
|
||||
public static void addSimpleTransformer(String originalId, int originalMeta, Block newBlock, int newMeta,
|
||||
boolean skipStackRemap) {
|
||||
if (newMeta == -1) newMeta = OreDictionary.WILDCARD_VALUE;
|
||||
SIMPLE_BLOCK_TRANSFORMATION_MAP
|
||||
.put(originalId, originalMeta, Pair.of(Block.getIdFromBlock(newBlock), (short) newMeta));
|
||||
if (!skipStackRemap) {
|
||||
Item item = Item.getItemFromBlock(newBlock);
|
||||
if (item != null) {
|
||||
SIMPLE_ITEM_TRANSFORMATION_MAP
|
||||
.put(originalId, originalMeta, Pair.of(Item.getIdFromItem(item), (short) newMeta));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void addSimpleTransformer(String originalId, int originalMeta, Item newItem, int newMeta,
|
||||
boolean skipBlockRemap) {
|
||||
if (newMeta == -1) newMeta = OreDictionary.WILDCARD_VALUE;
|
||||
if (!skipBlockRemap && newItem instanceof ItemBlock ib) {
|
||||
SIMPLE_BLOCK_TRANSFORMATION_MAP
|
||||
.put(originalId, originalMeta, Pair.of(Block.getIdFromBlock(ib.field_150939_a), (short) newMeta));
|
||||
}
|
||||
SIMPLE_ITEM_TRANSFORMATION_MAP
|
||||
.put(originalId, originalMeta, Pair.of(Item.getIdFromItem(newItem), (short) newMeta));
|
||||
}
|
||||
|
||||
private static boolean simpleBlockTransformer(BlockConversionInfo info,
|
||||
Map<Integer, Pair<Integer, Short>> metaMap) {
|
||||
Pair<Integer, Short> 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<Integer, Pair<Integer, Short>> metaMap) {
|
||||
short meta = tag.getShort("Damage");
|
||||
Pair<Integer, Short> 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<String, Map<Integer, Pair<Integer, Short>>> kv : SIMPLE_BLOCK_TRANSFORMATION_MAP.entrySet()) {
|
||||
MissingMappingHandler.createDummyBlockIfNeeded(kv.getKey());
|
||||
BLOCK_REPLACEMENT_MAP.put(kv.getKey(), info -> simpleBlockTransformer(info, kv.getValue()));
|
||||
}
|
||||
// add handlers for simple item remaps
|
||||
for (Map.Entry<String, Map<Integer, Pair<Integer, Short>>> kv : SIMPLE_ITEM_TRANSFORMATION_MAP.entrySet()) {
|
||||
MissingMappingHandler.createDummyItemIfNeeded(kv.getKey());
|
||||
ITEM_REPLACEMENT_MAP.put(kv.getKey(), tag -> simpleItemStackTransformer(tag, kv.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
public static void onIdMappingsChanged(FMLModIdMappingEvent event) {
|
||||
REMAPPED_IDS.clear();
|
||||
public static void onIdMappingsChanged() {
|
||||
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);
|
||||
}
|
||||
// create a lookup for source block ids.
|
||||
for (String key : BLOCK_REPLACEMENT_MAP.keys()) {
|
||||
String name = MissingMappingHandler.getDummyIdIfMissing(key);
|
||||
@@ -161,12 +113,15 @@ public class TransformerRegistry {
|
||||
public static void onServerStopping() {
|
||||
RUNTIME_BLOCK_REPLACEMENT_MAP.clear();
|
||||
RUNTIME_ITEM_REPLACEMENT_MAP.clear();
|
||||
REMAPPED_IDS.clear();
|
||||
DUMMY_IDS.clear();
|
||||
}
|
||||
// endregion FML Life Cycle handlers
|
||||
|
||||
// region block replacement handler
|
||||
// region transformation handlers
|
||||
public static boolean isDummyId(int id) {
|
||||
return TransformerRegistry.DUMMY_IDS.contains(id);
|
||||
}
|
||||
|
||||
public static @Nullable BlockConversionInfo getBlockReplacement(int blockId, byte metadata, World world, int x,
|
||||
int y, int z) {
|
||||
Pair<String, List<Function<BlockConversionInfo, Boolean>>> data = RUNTIME_BLOCK_REPLACEMENT_MAP.get(blockId);
|
||||
@@ -197,22 +152,20 @@ public class TransformerRegistry {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// endregion block replacement handler
|
||||
|
||||
// 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<String, List<Function<NBTTagCompound, Boolean>>> data = RUNTIME_ITEM_REPLACEMENT_MAP.get(id);
|
||||
Pair<String, List<BiFunction<String, NBTTagCompound, Boolean>>> data = RUNTIME_ITEM_REPLACEMENT_MAP.get(id);
|
||||
// abort early if handler not found
|
||||
if (data == null || data.getValue()
|
||||
.isEmpty()) return;
|
||||
|
||||
// apply handlers
|
||||
for (Function<NBTTagCompound, Boolean> transformer : data.getValue()) {
|
||||
if (transformer.apply(tag)) {
|
||||
for (BiFunction<String, NBTTagCompound, Boolean> transformer : data.getValue()) {
|
||||
if (transformer.apply(data.getKey(), 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
|
||||
@@ -226,15 +179,5 @@ public class TransformerRegistry {
|
||||
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<String, List<Function<NBTTagCompound, Boolean>>> data = RUNTIME_ITEM_REPLACEMENT_MAP.get(itemId);
|
||||
if (data == null) return null;
|
||||
return data.getKey();
|
||||
}
|
||||
// endregion item replacement handler
|
||||
// endregion transformation handlers
|
||||
}
|
||||
Reference in new issue
Block a user