mirror of
https://github.com/GTNewHorizons/Postea.git
synced 2026-10-26 14:24:19 +00:00
any mentions of nuke dummies, add new interfaces that better serve good practices.
This commit is contained in:
1 parent
78e3f792b7
commit
3868d131a7
30 files changed
+1218
-487
No files matched your search
@@ -1,5 +1,9 @@
|
||||
package com.gtnewhorizons.postea;
|
||||
|
||||
import net.minecraftforge.event.world.ChunkEvent;
|
||||
|
||||
import com.gtnewhorizons.postea.utility.ChunkFixerUtility;
|
||||
import com.gtnewhorizons.postea.utility.IDRegistry;
|
||||
import com.gtnewhorizons.postea.utility.MissingMappingHandler;
|
||||
import com.gtnewhorizons.postea.utility.SimpleTransformationRegistry;
|
||||
import com.gtnewhorizons.postea.utility.TransformerRegistry;
|
||||
@@ -9,7 +13,6 @@ 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;
|
||||
import cpw.mods.fml.common.event.FMLServerStoppingEvent;
|
||||
|
||||
@Mod(
|
||||
modid = Postea.MODID,
|
||||
@@ -26,10 +29,16 @@ public class Postea {
|
||||
@Mod.EventHandler
|
||||
public void preInit(FMLPreInitializationEvent event) {}
|
||||
|
||||
@Mod.EventHandler
|
||||
public void chunkLoaded(ChunkEvent.Load event) {
|
||||
ChunkFixerUtility.onChunkLoaded(event.getChunk());
|
||||
}
|
||||
|
||||
@Mod.EventHandler
|
||||
public void onIdMappingsChanged(FMLModIdMappingEvent event) {
|
||||
SimpleTransformationRegistry.onIdMappingsChanged();
|
||||
TransformerRegistry.onIdMappingsChanged();
|
||||
IDRegistry.onMappingUpdated();
|
||||
}
|
||||
|
||||
@Mod.EventHandler
|
||||
@@ -40,12 +49,6 @@ public class Postea {
|
||||
@Mod.EventHandler
|
||||
public void onLoadCompleted(FMLLoadCompleteEvent event) {
|
||||
SimpleTransformationRegistry.onLoadCompleted();
|
||||
MissingMappingHandler.onLoadCompleted();
|
||||
}
|
||||
|
||||
@Mod.EventHandler
|
||||
public void onServerStopping(FMLServerStoppingEvent event) {
|
||||
TransformerRegistry.onServerStopping();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.gtnewhorizons.postea.api;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
|
||||
import com.gtnewhorizons.postea.compat.Compat;
|
||||
import com.gtnewhorizons.postea.compat.SubChunkAccess;
|
||||
|
||||
/**
|
||||
* Public API for accessing information related to a block located at the location of a tile entity inside a
|
||||
* tile entity transformer registered via
|
||||
* {@link TileEntityReplacementManager#tileEntityTransformer(String, TriFunction)}
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class BlockAccessCompat {
|
||||
|
||||
/**
|
||||
* Fetches the id of the block that is (or used to be) at the position of the TE stored in the given tag.
|
||||
*
|
||||
* @apiNote This method is intended for use withing TileEntityTransformers declared via
|
||||
* {@link TileEntityReplacementManager#tileEntityTransformer(String, TriFunction)}
|
||||
*
|
||||
* @param tag The tag for the tile entity
|
||||
* @param chunk The chunk containing the tile entity
|
||||
* @return The id of the block that exists (or used to exist) at that location.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static int getBlockIDAtTE(NBTTagCompound tag, Chunk chunk) {
|
||||
// fetch the block accessor
|
||||
ExtendedBlockStorage[] ebsArray = chunk.getBlockStorageArray();
|
||||
// abort if y is oob
|
||||
int y = tag.getInteger("y");
|
||||
if (y >> 4 >= ebsArray.length) return 0;
|
||||
SubChunkAccess access = Compat.getSubChunkAccess(ebsArray[y >> 4]);
|
||||
|
||||
// identify the block
|
||||
int x = tag.getInteger("x") & 0xf;
|
||||
y &= 0xf;
|
||||
int z = tag.getInteger("z") & 0xf;
|
||||
return access.getBlockId(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the meta of the block that is (or used to be) at the position of the TE stored in the given tag.
|
||||
*
|
||||
* @apiNote This method is intended for use withing TileEntityTransformers declared via
|
||||
* {@link TileEntityReplacementManager#tileEntityTransformer(String, TriFunction)}
|
||||
*
|
||||
* @param tag The tag for the tile entity
|
||||
* @param chunk The chunk containing the tile entity
|
||||
* @return The id of the block that exists (or used to exist) at that location.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static int getBlockMetaAtTE(NBTTagCompound tag, Chunk chunk) {
|
||||
// fetch the block accessor
|
||||
ExtendedBlockStorage[] ebsArray = chunk.getBlockStorageArray();
|
||||
// abort if y is oob
|
||||
int y = tag.getInteger("y");
|
||||
if (y >> 4 >= ebsArray.length) return 0;
|
||||
SubChunkAccess access = Compat.getSubChunkAccess(ebsArray[y >> 4]);
|
||||
|
||||
// identify the block
|
||||
int x = tag.getInteger("x") & 0xf;
|
||||
y &= 0xf;
|
||||
int z = tag.getInteger("z") & 0xf;
|
||||
return access.getMeta(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the id and meta of the block that is (or used to be) at the position of the TE stored in the given tag.
|
||||
*
|
||||
* @apiNote This method is intended for use withing TileEntityTransformers declared via
|
||||
* {@link TileEntityReplacementManager#tileEntityTransformer(String, TriFunction)}
|
||||
*
|
||||
* @param tag The tag for the tile entity
|
||||
* @param chunk The chunk containing the tile entity
|
||||
* @return An array with th eid of the block that exists (or used to exist) at that location.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static int[] getBlockIDAndMetaAtTE(NBTTagCompound tag, Chunk chunk) {
|
||||
// fetch the block accessor
|
||||
ExtendedBlockStorage[] ebsArray = chunk.getBlockStorageArray();
|
||||
// abort if y is oob
|
||||
int y = tag.getInteger("y");
|
||||
if (y >> 4 >= ebsArray.length) return new int[] { 0, 0 };
|
||||
SubChunkAccess access = Compat.getSubChunkAccess(ebsArray[y >> 4]);
|
||||
|
||||
// identify the block
|
||||
int x = tag.getInteger("x") & 0xf;
|
||||
y &= 0xf;
|
||||
int z = tag.getInteger("z") & 0xf;
|
||||
return new int[] { access.getBlockId(x, y, z), access.getMeta(x, y, z) };
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.gtnewhorizons.postea.api;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@@ -10,11 +11,19 @@ import net.minecraft.world.World;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
|
||||
import com.gtnewhorizons.postea.utility.BlockConversionInfo;
|
||||
import com.gtnewhorizons.postea.utility.IDRegistry;
|
||||
import com.gtnewhorizons.postea.utility.MissingMappingHandler;
|
||||
import com.gtnewhorizons.postea.utility.SimpleTransformationRegistry;
|
||||
import com.gtnewhorizons.postea.utility.TransformerRegistry;
|
||||
|
||||
public class BlockReplacementManager {
|
||||
/**
|
||||
* Public API used to register block transformers via postea's handler system.<br>
|
||||
* <br>
|
||||
* Block transformers are executed after Tile Entity transformers, when chunks being loading into the world.
|
||||
*/
|
||||
public abstract class BlockReplacementManager {
|
||||
|
||||
// region custom transformer registration
|
||||
|
||||
/**
|
||||
* Adds a custom transformer for a given id.
|
||||
@@ -27,11 +36,11 @@ public class BlockReplacementManager {
|
||||
* <br>
|
||||
* If you need to perform a simple transformations consider using the following methods instead:
|
||||
* <ul>
|
||||
* <li>block -> block (with same meta): {@link #addBlockReplacement(String, Block)}</li>
|
||||
* <li>block -> block with specific meta: {@link #addBlockReplacement(String, Block, int)}</li>
|
||||
* <li>block with meta -> block (with same meta): {@link #addBlockReplacement(String, int, Block)}</li>
|
||||
* <li>block -> block (with same meta): {@link #addSimpleReplacement(String, Block)}</li>
|
||||
* <li>block -> block with specific meta: {@link #addSimpleReplacement(String, Block, int)}</li>
|
||||
* <li>block with meta -> block (with same meta): {@link #addSimpleReplacement(String, int, Block)}</li>
|
||||
* <li>block with meta -> block with specific meta:
|
||||
* {@link #addBlockReplacement(String, int, Block, int)}</li>
|
||||
* {@link #addSimpleReplacement(String, int, Block, int)}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @implNote For performance reasons, Postea assumes that the BlockConversionInfo that was passed to the handler
|
||||
@@ -59,11 +68,11 @@ public class BlockReplacementManager {
|
||||
* <br>
|
||||
* If you need to perform a simple transformations consider using the following methods instead:
|
||||
* <ul>
|
||||
* <li>block -> block (with same meta): {@link #addBlockReplacement(String, Block)}</li>
|
||||
* <li>block -> block with specific meta: {@link #addBlockReplacement(String, Block, int)}</li>
|
||||
* <li>block with meta -> block (with same meta): {@link #addBlockReplacement(String, int, Block)}</li>
|
||||
* <li>block -> block (with same meta): {@link #addSimpleReplacement(String, Block)}</li>
|
||||
* <li>block -> block with specific meta: {@link #addSimpleReplacement(String, Block, int)}</li>
|
||||
* <li>block with meta -> block (with same meta): {@link #addSimpleReplacement(String, int, Block)}</li>
|
||||
* <li>block with meta -> block with specific meta:
|
||||
* {@link #addBlockReplacement(String, int, Block, int)}</li>
|
||||
* {@link #addSimpleReplacement(String, int, Block, int)}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @implNote For performance reasons, Postea assumes that the BlockConversionInfo that was passed to the handler
|
||||
@@ -81,13 +90,179 @@ public class BlockReplacementManager {
|
||||
TransformerRegistry.addBlockTransformer(originalId, transformer);
|
||||
}
|
||||
|
||||
// endregion custom transformer registration
|
||||
|
||||
// region id resolving
|
||||
|
||||
// spotless:off
|
||||
/**
|
||||
* Registers a callback function that will be provided the numeric ID of the given namespaced ID when a world is
|
||||
* first loaded. Since forge doesn't remap missing block IDs to 0 when loading a world for performance reasons,
|
||||
* instead opting to treat any block ID as Air, you can store that value into a static field, and use it to
|
||||
* compare against an id provided to you during the execution of a transformation handler.<br>
|
||||
* <br>
|
||||
* This function is mostly intended to be used in partnership with tile entity transformers, and is intended to
|
||||
* overcome the need to create dummy blocks and items in order to identify blocks inside a custom transformer.<br>
|
||||
* <br>
|
||||
* For compatibility reasons, it's better not to register dummies to take the place of dummy items. If one mod was
|
||||
* to only convert blocks with a specific meta while another handled the rest, the other mod would either need
|
||||
* additional work to detect your own dummy blocks or even worst, fail to identify the original blocks as it's not
|
||||
* aware of your dummy blocks.
|
||||
*
|
||||
* @apiNote Here is an example implementation:
|
||||
* <pre>{@code
|
||||
* import net.minecraft.block.Block;
|
||||
* import net.minecraft.block.material.Material;
|
||||
* import net.minecraft.nbt.NBTTagCompound;
|
||||
* import net.minecraft.world.World;
|
||||
* import net.minecraft.world.chunk.Chunk;
|
||||
*
|
||||
* import com.gtnewhorizons.postea.api.BlockAccessCompat;
|
||||
* import com.gtnewhorizons.postea.api.BlockReplacementManager;
|
||||
* import com.gtnewhorizons.postea.api.TileEntityReplacementManager;
|
||||
* import com.gtnewhorizons.postea.utility.BlockInfo;
|
||||
* import com.gtnewhorizons.postea.utility.PosteaUtilities;
|
||||
*
|
||||
* import cpw.mods.fml.common.Mod;
|
||||
* import cpw.mods.fml.common.event.FMLPostInitializationEvent;
|
||||
* import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
* import cpw.mods.fml.common.registry.GameRegistry;
|
||||
*
|
||||
* @Mod(
|
||||
* modid = "mymod",
|
||||
* version = "1.0.0",
|
||||
* name = "Example Mod",
|
||||
* acceptedMinecraftVersions = "[1.7.10]",
|
||||
* dependencies = " after:otherMod;")
|
||||
* @SuppressWarnings("unused")
|
||||
* public class ExampleMod {
|
||||
*
|
||||
* private static int targetBlock1 = -1;
|
||||
* private static int targetBlock2 = -1;
|
||||
* private static int targetBlock3 = -1;
|
||||
*
|
||||
* private static class MyBlocks {
|
||||
* public static Block block1;
|
||||
* public static Block block2;
|
||||
* public static Block block3;
|
||||
* public static Block block4;
|
||||
* public static Block block5;
|
||||
* public static Block block6;
|
||||
* }
|
||||
*
|
||||
* private static class TestBlock extends Block {
|
||||
* public TestBlock(String id) {
|
||||
* super(Material.ground);
|
||||
* GameRegistry.registerBlock(this, id);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @Mod.EventHandler
|
||||
* @SuppressWarnings("unused")
|
||||
* public static void preInit(FMLPreInitializationEvent event) {
|
||||
* MyBlocks.block1 = new TestBlock("block1");
|
||||
* MyBlocks.block2 = new TestBlock("block2");
|
||||
* MyBlocks.block3 = new TestBlock("block3");
|
||||
* MyBlocks.block4 = new TestBlock("block4");
|
||||
* MyBlocks.block5 = new TestBlock("block5");
|
||||
* MyBlocks.block6 = new TestBlock("block6");
|
||||
* }
|
||||
*
|
||||
* @Mod.EventHandler
|
||||
* @SuppressWarnings("unused")
|
||||
* public static void postLoad(FMLPostInitializationEvent event) {
|
||||
* BlockReplacementManager.registerIDResolver("otherMod:block1", i -> targetBlock1 = i);
|
||||
* BlockReplacementManager.registerIDResolver("otherMod:block2", i -> targetBlock2 = i);
|
||||
* BlockReplacementManager.registerIDResolver("otherMod:block3", i -> targetBlock3 = i);
|
||||
* TileEntityReplacementManager.tileEntityTransformer("otherModTE", ExampleMod::transform);
|
||||
* // If you were to have all of these in one mod,
|
||||
* // the general recommendation would be to merge the handlers,
|
||||
* // but let's pretend that these are set up by other mods
|
||||
* // for the sake of example.
|
||||
* TileEntityReplacementManager.tileEntityTransformer("otherModTE", ExampleMod::transformOther);
|
||||
* BlockReplacementManager.addBlockReplacement("otherMod:block1", 0, MyBlocks.block1, 0);
|
||||
* }
|
||||
*
|
||||
* public static BlockInfo transform(NBTTagCompound tag, World world, Chunk chunk) {
|
||||
* int oldBlock = BlockAccessCompat.getBlockIDAtTE(tag, chunk);
|
||||
* int x = tag.getInteger("x") & 0xF;
|
||||
* int y = tag.getInteger("y");
|
||||
* int z = tag.getInteger("z") & 0xF;
|
||||
* int meta = chunk.getBlockMetadata(x, y, z);
|
||||
* Block newBlock;
|
||||
* String targetType;
|
||||
* if (oldBlock == targetBlock1) {
|
||||
* // block transformer executes after TE transformers
|
||||
* // so we sill need to check for meta 0
|
||||
* if (meta == 0) return null;
|
||||
* newBlock = MyBlocks.block2;
|
||||
* targetType = "stone";
|
||||
* } else if (oldBlock == targetBlock2) {
|
||||
* // another mod would be handling the transformation for 0
|
||||
* if (meta != 1 && meta != 2) return null;
|
||||
* newBlock = meta == 1 ? MyBlocks.block3 : MyBlocks.block4;
|
||||
* targetType = "iron";
|
||||
* } else {
|
||||
* // Return null to tell postea that you can't handle via this transformer.
|
||||
* // Maybe another transformer can handle it.
|
||||
* return null;
|
||||
* }
|
||||
* return new BlockInfo(newBlock, 0, originalNBT -> {
|
||||
* NBTTagCompound newNBT = PosteaUtilities.cleanseNBT("myTE", originalNBT);
|
||||
* newNBT.setString("type", targetType);
|
||||
* newNBT.setInteger("level", meta);
|
||||
* newNBT.setInteger("fuelLevel", originalNBT.getInteger("storage") * 20);
|
||||
* return newNBT;
|
||||
* });
|
||||
* }
|
||||
*
|
||||
* public static BlockInfo transformOther(NBTTagCompound tag, World world, Chunk chunk) {
|
||||
* int oldBlock = BlockAccessCompat.getBlockIDAtTE(tag, chunk);
|
||||
* int x = tag.getInteger("x") & 0xF;
|
||||
* int y = tag.getInteger("y");
|
||||
* int z = tag.getInteger("z") & 0xF;
|
||||
* int meta = chunk.getBlockMetadata(x, y, z);
|
||||
* if (oldBlock == targetBlock2) {
|
||||
* if (meta != 3) return null;
|
||||
* // that doesn't need to be a TE anymore.
|
||||
* return new BlockInfo(MyBlocks.block5, 0, null);
|
||||
* } else if (oldBlock == targetBlock3) {
|
||||
* // transfer the TE correctly
|
||||
* return new BlockInfo(MyBlocks.block6, meta, originalNBT -> {
|
||||
* NBTTagCompound newNBT = PosteaUtilities.cleanseNBT("myOtherTE", originalNBT);
|
||||
* newNBT.setInteger("remaining", originalNBT.getInteger("storage"));
|
||||
* return newNBT;
|
||||
* });
|
||||
* }
|
||||
* // can't handle this
|
||||
* return null;
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
*
|
||||
* @param originalId The namespaced ID of a block you wish to identify in one of your transformers.
|
||||
* @param resolver The callback executed to provide the numeric ID of the given namespaced ID.
|
||||
*/
|
||||
// spotless:on
|
||||
@SuppressWarnings("unused")
|
||||
public static void registerIDResolver(String originalId, Consumer<Integer> resolver) {
|
||||
if (originalId == null) throw new NullPointerException("originalId cannot be null");
|
||||
if (resolver == null) throw new NullPointerException("resolver cannot be null");
|
||||
IDRegistry.registerBlockIDResolver(originalId, resolver);
|
||||
}
|
||||
|
||||
// endregion id resolving
|
||||
|
||||
// region missing mapping replacements
|
||||
|
||||
/**
|
||||
* Adds a mapping to remap stacks and block instances of a specific removed block to the given block whilst, whilst
|
||||
* maintaining its meta value.
|
||||
* maintaining its meta value.<br>
|
||||
* <br>
|
||||
* <b><u>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
|
||||
* into dirt), use {@link #addSimpleReplacement(String, Block)} with both meta parameters set to
|
||||
* OreDictionary.WILDCARD_VALUE.</u></b>
|
||||
*
|
||||
* @param originalId The id of the block to remap.
|
||||
@@ -97,7 +272,7 @@ public class BlockReplacementManager {
|
||||
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);
|
||||
MissingMappingHandler.addBlockMapping(originalId, block);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,6 +285,10 @@ public class BlockReplacementManager {
|
||||
MissingMappingHandler.addIgnore(originalId);
|
||||
}
|
||||
|
||||
// endregion missing mapping replacements
|
||||
|
||||
// region simple replacements
|
||||
|
||||
// block -> block
|
||||
|
||||
/**
|
||||
@@ -124,8 +303,8 @@ public class BlockReplacementManager {
|
||||
* @param block The block to remap to.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void addBlockReplacement(@Nonnull String originalId, @Nonnull Block block) {
|
||||
addBlockReplacement(originalId, OreDictionary.WILDCARD_VALUE, block, OreDictionary.WILDCARD_VALUE, false);
|
||||
public static void addSimpleReplacement(@Nonnull String originalId, @Nonnull Block block) {
|
||||
addSimpleReplacement(originalId, OreDictionary.WILDCARD_VALUE, block, OreDictionary.WILDCARD_VALUE, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,8 +320,8 @@ 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, @Nonnull Block block, boolean skipStackRemap) {
|
||||
addBlockReplacement(
|
||||
public static void addSimpleReplacement(@Nonnull String originalId, @Nonnull Block block, boolean skipStackRemap) {
|
||||
addSimpleReplacement(
|
||||
originalId,
|
||||
OreDictionary.WILDCARD_VALUE,
|
||||
block,
|
||||
@@ -161,8 +340,8 @@ public class BlockReplacementManager {
|
||||
* @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);
|
||||
public static void addSimpleReplacement(@Nonnull String originalId, int originalMeta, @Nonnull Block block) {
|
||||
addSimpleReplacement(originalId, originalMeta, block, OreDictionary.WILDCARD_VALUE, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,9 +354,9 @@ 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,
|
||||
public static void addSimpleReplacement(@Nonnull String originalId, int originalMeta, @Nonnull Block block,
|
||||
boolean skipStackRemap) {
|
||||
addBlockReplacement(originalId, originalMeta, block, OreDictionary.WILDCARD_VALUE, skipStackRemap);
|
||||
addSimpleReplacement(originalId, originalMeta, block, OreDictionary.WILDCARD_VALUE, skipStackRemap);
|
||||
}
|
||||
|
||||
// block -> block+meta
|
||||
@@ -191,8 +370,8 @@ public class BlockReplacementManager {
|
||||
* @param newMeta The meta of the block to remap to. OreDictionary.WILDCARD_VALUE maintains the existing value.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void addBlockReplacement(@Nonnull String originalId, @Nonnull Block block, int newMeta) {
|
||||
addBlockReplacement(originalId, OreDictionary.WILDCARD_VALUE, block, newMeta, false);
|
||||
public static void addSimpleReplacement(@Nonnull String originalId, @Nonnull Block block, int newMeta) {
|
||||
addSimpleReplacement(originalId, OreDictionary.WILDCARD_VALUE, block, newMeta, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,9 +385,9 @@ 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, @Nonnull Block block, int newMeta,
|
||||
public static void addSimpleReplacement(@Nonnull String originalId, @Nonnull Block block, int newMeta,
|
||||
boolean skipStackRemap) {
|
||||
addBlockReplacement(originalId, OreDictionary.WILDCARD_VALUE, block, newMeta, skipStackRemap);
|
||||
addSimpleReplacement(originalId, OreDictionary.WILDCARD_VALUE, block, newMeta, skipStackRemap);
|
||||
}
|
||||
|
||||
// block+meta -> block+meta
|
||||
@@ -223,9 +402,9 @@ public class BlockReplacementManager {
|
||||
* @param newMeta The meta of the block to remap to. OreDictionary.WILDCARD_VALUE maintains the existing value.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void addBlockReplacement(@Nonnull String originalId, int originalMeta, @Nonnull Block block,
|
||||
public static void addSimpleReplacement(@Nonnull String originalId, int originalMeta, @Nonnull Block block,
|
||||
int newMeta) {
|
||||
addBlockReplacement(originalId, originalMeta, block, newMeta, false);
|
||||
addSimpleReplacement(originalId, originalMeta, block, newMeta, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -240,10 +419,13 @@ public class BlockReplacementManager {
|
||||
* @param skipStackRemap Set to true to skip auto-adding an item stack remapper.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void addBlockReplacement(String originalId, int originalMeta, Block block, int newMeta,
|
||||
public static void addSimpleReplacement(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");
|
||||
SimpleTransformationRegistry.addSimpleTransformer(originalId, originalMeta, block, newMeta, skipStackRemap);
|
||||
}
|
||||
|
||||
// endregion simple replacements
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.gtnewhorizons.postea.api;
|
||||
|
||||
import com.gtnewhorizons.postea.utility.BlockConversionInfo;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface IComplexBlockTransformer {
|
||||
|
||||
/**
|
||||
* A custom transformer for blocks.
|
||||
*
|
||||
* @param info The information about the block.
|
||||
* @return True if the block was replaced and no other block transformation handler should be executed for the
|
||||
* associated original id;
|
||||
*/
|
||||
boolean transformBlock(BlockConversionInfo info);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.gtnewhorizons.postea.api;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface IComplexStackTransformer {
|
||||
|
||||
/**
|
||||
* A custom transformer for items.
|
||||
*
|
||||
* @param originalId The namespaced id of the stack being passed to this transformer.
|
||||
* @param tag The raw nbt data of the stack being transformed.
|
||||
* @return A non-null value to prevent any future handlers from executing or if the stack was replaced.
|
||||
*/
|
||||
boolean transformStack(String originalId, NBTTagCompound tag);
|
||||
}
|
||||
@@ -5,8 +5,13 @@ import static net.minecraftforge.common.util.Constants.NBT.TAG_SHORT;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
/**
|
||||
* Public API used to query and update stack item IDs inside Postea transformers.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class IDExtenderCompat {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static int getItemStackID(NBTTagCompound tag) {
|
||||
if (tag.hasKey("idExt", TAG_INT)) return tag.getInteger("idExt");
|
||||
else if (tag.hasKey("id", TAG_INT)) return tag.getInteger("id");
|
||||
@@ -14,6 +19,7 @@ public class IDExtenderCompat {
|
||||
else return 0;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static void setItemStackID(NBTTagCompound tag, int id) {
|
||||
if (id < 32000) {
|
||||
tag.setShort("id", (short) id);
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.gtnewhorizons.postea.api;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
|
||||
public interface ISimpleBlockTransformer {
|
||||
|
||||
Block getTargetBlock();
|
||||
|
||||
int getTargetBlockMeta();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.gtnewhorizons.postea.api;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
|
||||
public interface ISimpleItemTransformer {
|
||||
|
||||
Item getTargetItem();
|
||||
|
||||
int getTargetItemMeta();
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.gtnewhorizons.postea.api;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
public interface ISimpleStackTransformer {
|
||||
|
||||
ItemStack getTargetStack();
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.gtnewhorizons.postea.api;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@@ -11,13 +12,21 @@ import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
|
||||
import com.gtnewhorizons.postea.utility.IDRegistry;
|
||||
import com.gtnewhorizons.postea.utility.MissingMappingHandler;
|
||||
import com.gtnewhorizons.postea.utility.SimpleTransformationRegistry;
|
||||
import com.gtnewhorizons.postea.utility.TransformerRegistry;
|
||||
|
||||
public class ItemStackReplacementManager {
|
||||
/**
|
||||
* Public API used to register item stack transformers via postea's handler system.<br>
|
||||
* <br>
|
||||
* Item stack transformers are applied when something tries to convert any NBT that has an "id" field into an item
|
||||
* stack.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class ItemStackReplacementManager {
|
||||
|
||||
// Public API for converting ItemStacks.
|
||||
// region custom transformer registration
|
||||
|
||||
/**
|
||||
* Adds a custom transformer for a given id.
|
||||
@@ -30,10 +39,11 @@ public class ItemStackReplacementManager {
|
||||
* <p>
|
||||
* If you need to perform a simple transformations consider using the following methods instead:
|
||||
* <ul>
|
||||
* <li>item -> item (with same meta): {@link #addItemReplacement(String, Item)}</li>
|
||||
* <li>item -> item with specific meta: {@link #addItemReplacement(String, Item, int)}</li>
|
||||
* <li>item with meta -> item (with same meta): {@link #addItemReplacement(String, int, Item)}</li>
|
||||
* <li>item with meta -> item with specific meta: {@link #addItemReplacement(String, int, Item, int)}</li>
|
||||
* <li>item -> item (with same meta): {@link #addSimpleReplacement(String, Item)}</li>
|
||||
* <li>item -> item with specific meta: {@link #addSimpleReplacement(String, Item, int)}</li>
|
||||
* <li>item with meta -> item (with same meta): {@link #addSimpleReplacement(String, int, Item)}</li>
|
||||
* <li>item with meta -> item with specific meta:
|
||||
* {@link #addSimpleReplacement(String, int, Item, int)}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @implNote For performance reasons, Postea assumes that the tag that was passed to the handler hasn't been
|
||||
@@ -61,10 +71,11 @@ public class ItemStackReplacementManager {
|
||||
* <p>
|
||||
* If you need to perform a simple transformations consider using the following methods instead:
|
||||
* <ul>
|
||||
* <li>item -> item (with same meta): {@link #addItemReplacement(String, Item)}</li>
|
||||
* <li>item -> item with specific meta: {@link #addItemReplacement(String, Item, int)}</li>
|
||||
* <li>item with meta -> item (with same meta): {@link #addItemReplacement(String, int, Item)}</li>
|
||||
* <li>item with meta -> item with specific meta: {@link #addItemReplacement(String, int, Item, int)}</li>
|
||||
* <li>item -> item (with same meta): {@link #addSimpleReplacement(String, Item)}</li>
|
||||
* <li>item -> item with specific meta: {@link #addSimpleReplacement(String, Item, int)}</li>
|
||||
* <li>item with meta -> item (with same meta): {@link #addSimpleReplacement(String, int, Item)}</li>
|
||||
* <li>item with meta -> item with specific meta:
|
||||
* {@link #addSimpleReplacement(String, int, Item, int)}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @implNote For performance reasons, Postea assumes that the tag that was passed to the handler hasn't been
|
||||
@@ -83,12 +94,47 @@ public class ItemStackReplacementManager {
|
||||
TransformerRegistry.addStackTransformer(originalId, transformer);
|
||||
}
|
||||
|
||||
// endregion custom transformer registration
|
||||
|
||||
// region id resolving
|
||||
|
||||
/**
|
||||
* Adds a mapping to remap stacks of a specific removed item to the given item.
|
||||
* <p>
|
||||
* Registers a callback function that will be provided the numeric ID of the given namespaced ID when a world is
|
||||
* first loaded. Since forge doesn't discard stacks associated with missing IDs when loading a world for
|
||||
* performance reasons, instead opting to null the result of the nbt data read, you can store that value into a
|
||||
* static field, and use it to compare against an id provided to you during the execution of a transformation
|
||||
* handler.<br>
|
||||
* <br>
|
||||
* This function is mostly intended to speed up larger transformer handlers since resolving the string id of a
|
||||
* removed id inside a transformer will be slower than simply matching for it. Regular item transformers are
|
||||
* already provided the string ID of the item they are transforming so, there is no reason not to do a switch case
|
||||
* on those. This also overcomes the need to create dummy blocks and items in order to identify
|
||||
* items inside a custom stack transformer.<br>
|
||||
* <br>
|
||||
* For compatibility reasons, it's better not to register dummies to take the place of dummy items. If one mod was
|
||||
* to only convert blocks with a specific meta while another handled the rest, the other mod would either need
|
||||
* additional work to detect your own dummy blocks or even worst, fail to identify the original blocks as it's not
|
||||
* aware of your dummy blocks.
|
||||
*
|
||||
* @param originalId The namespaced ID of a block you wish to identify in one of your transformers.
|
||||
* @param resolver The callback executed to provide the numeric ID of the given namespaced ID.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void registerIDResolver(String originalId, Consumer<Integer> resolver) {
|
||||
if (originalId == null) throw new NullPointerException("originalId cannot be null");
|
||||
if (resolver == null) throw new NullPointerException("resolver cannot be null");
|
||||
IDRegistry.registerItemIDResolver(originalId, resolver);
|
||||
}
|
||||
|
||||
// endregion id resolving
|
||||
|
||||
// region missing mapping replacements
|
||||
/**
|
||||
* Adds a mapping to remap stacks of a specific removed item to the given item.<br>
|
||||
* <br>
|
||||
* <b><u>IMPORTANT: This only works if the world does not have an existing id set for the target item. If you need
|
||||
* to transform a missing item into something that was previously given an id (e.g.: Transforming a removed item
|
||||
* into a stick), use {@link #addItemReplacement(String, int, Item, int)} with both meta values set to
|
||||
* into a stick), use {@link #addSimpleReplacement(String, int, Item, int)} with both meta values set to
|
||||
* OreDictionary.WILDCARD_VALUE.</u></b>
|
||||
*
|
||||
* @param originalId The id of the item to remap.
|
||||
@@ -98,7 +144,7 @@ public class ItemStackReplacementManager {
|
||||
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);
|
||||
MissingMappingHandler.addItemMapping(originalId, item);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,6 +157,10 @@ public class ItemStackReplacementManager {
|
||||
MissingMappingHandler.addIgnore(originalId);
|
||||
}
|
||||
|
||||
// endregion missing mapping replacements
|
||||
|
||||
// region simple replacements
|
||||
|
||||
// item -> item
|
||||
|
||||
/**
|
||||
@@ -128,8 +178,8 @@ public class ItemStackReplacementManager {
|
||||
* @param item The item to remap to.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void addItemReplacement(@Nonnull String originalId, @Nonnull Item item) {
|
||||
addItemReplacement(originalId, OreDictionary.WILDCARD_VALUE, item, OreDictionary.WILDCARD_VALUE, false);
|
||||
public static void addSimpleReplacement(@Nonnull String originalId, @Nonnull Item item) {
|
||||
addSimpleReplacement(originalId, OreDictionary.WILDCARD_VALUE, item, OreDictionary.WILDCARD_VALUE, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,8 +197,8 @@ public class ItemStackReplacementManager {
|
||||
* @param skipBlockRemap Set to true to skip auto-adding a block remapper if the item happens to be an ItemBlock.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void addItemReplacement(@Nonnull String originalId, @Nonnull Item item, boolean skipBlockRemap) {
|
||||
addItemReplacement(
|
||||
public static void addSimpleReplacement(@Nonnull String originalId, @Nonnull Item item, boolean skipBlockRemap) {
|
||||
addSimpleReplacement(
|
||||
originalId,
|
||||
OreDictionary.WILDCARD_VALUE,
|
||||
item,
|
||||
@@ -170,8 +220,8 @@ public class ItemStackReplacementManager {
|
||||
* @param newMeta The meta of the item to remap to. OreDictionary.WILDCARD_VALUE maintains the existing value.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void addItemReplacement(@Nonnull String originalId, @Nonnull Item item, int newMeta) {
|
||||
addItemReplacement(originalId, OreDictionary.WILDCARD_VALUE, item, newMeta, false);
|
||||
public static void addSimpleReplacement(@Nonnull String originalId, @Nonnull Item item, int newMeta) {
|
||||
addSimpleReplacement(originalId, OreDictionary.WILDCARD_VALUE, item, newMeta, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,9 +237,9 @@ public class ItemStackReplacementManager {
|
||||
* @param skipBlockRemap Set to true to skip auto-adding a block remapper if the item happens to be an ItemBlock.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void addItemReplacement(@Nonnull String originalId, @Nonnull Item item, int newMeta,
|
||||
public static void addSimpleReplacement(@Nonnull String originalId, @Nonnull Item item, int newMeta,
|
||||
boolean skipBlockRemap) {
|
||||
addItemReplacement(originalId, OreDictionary.WILDCARD_VALUE, item, newMeta, skipBlockRemap);
|
||||
addSimpleReplacement(originalId, OreDictionary.WILDCARD_VALUE, item, newMeta, skipBlockRemap);
|
||||
}
|
||||
|
||||
// item -> stack
|
||||
@@ -207,8 +257,8 @@ public class ItemStackReplacementManager {
|
||||
* @param stack The item to remap to.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void addItemReplacement(@Nonnull String originalId, @Nonnull ItemStack stack) {
|
||||
addItemReplacement(
|
||||
public static void addSimpleReplacement(@Nonnull String originalId, @Nonnull ItemStack stack) {
|
||||
addSimpleReplacement(
|
||||
originalId,
|
||||
OreDictionary.WILDCARD_VALUE,
|
||||
stack.getItem(),
|
||||
@@ -229,9 +279,9 @@ public class ItemStackReplacementManager {
|
||||
* @param skipBlockRemap Set to true to skip auto-adding a block remapper if the item happens to be an ItemBlock.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void addItemReplacement(@Nonnull String originalId, @Nonnull ItemStack stack,
|
||||
public static void addSimpleReplacement(@Nonnull String originalId, @Nonnull ItemStack stack,
|
||||
boolean skipBlockRemap) {
|
||||
addItemReplacement(
|
||||
addSimpleReplacement(
|
||||
originalId,
|
||||
OreDictionary.WILDCARD_VALUE,
|
||||
stack.getItem(),
|
||||
@@ -253,8 +303,8 @@ public class ItemStackReplacementManager {
|
||||
* @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);
|
||||
public static void addSimpleReplacement(@Nonnull String originalId, int originalMeta, @Nonnull Item item) {
|
||||
addSimpleReplacement(originalId, originalMeta, item, OreDictionary.WILDCARD_VALUE, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,9 +320,9 @@ 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,
|
||||
public static void addSimpleReplacement(@Nonnull String originalId, int originalMeta, @Nonnull Item item,
|
||||
boolean skipBlockRemap) {
|
||||
addItemReplacement(originalId, originalMeta, item, OreDictionary.WILDCARD_VALUE, skipBlockRemap);
|
||||
addSimpleReplacement(originalId, originalMeta, item, OreDictionary.WILDCARD_VALUE, skipBlockRemap);
|
||||
}
|
||||
|
||||
// item+meta -> stack
|
||||
@@ -291,8 +341,8 @@ public class ItemStackReplacementManager {
|
||||
* @param stack A stack of the item to replace to.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void addItemReplacement(@Nonnull String originalId, int originalMeta, @Nonnull ItemStack stack) {
|
||||
addItemReplacement(originalId, originalMeta, stack, false);
|
||||
public static void addSimpleReplacement(@Nonnull String originalId, int originalMeta, @Nonnull ItemStack stack) {
|
||||
addSimpleReplacement(originalId, originalMeta, stack, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,9 +360,9 @@ public class ItemStackReplacementManager {
|
||||
* @param skipBlockRemap Set to true to skip auto-adding a block remapper if the item happens to be an ItemBlock.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void addItemReplacement(@Nonnull String originalId, int originalMeta, @Nonnull ItemStack stack,
|
||||
public static void addSimpleReplacement(@Nonnull String originalId, int originalMeta, @Nonnull ItemStack stack,
|
||||
boolean skipBlockRemap) {
|
||||
addItemReplacement(originalId, originalMeta, stack.getItem(), Items.feather.getDamage(stack), skipBlockRemap);
|
||||
addSimpleReplacement(originalId, originalMeta, stack.getItem(), Items.feather.getDamage(stack), skipBlockRemap);
|
||||
}
|
||||
|
||||
// item+meta -> item+meta
|
||||
@@ -330,9 +380,9 @@ public class ItemStackReplacementManager {
|
||||
* @param newMeta The meta of the item to remap to. OreDictionary.WILDCARD_VALUE maintains the existing value.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void addItemReplacement(@Nonnull String originalId, int originalMeta, @Nonnull Item item,
|
||||
public static void addSimpleReplacement(@Nonnull String originalId, int originalMeta, @Nonnull Item item,
|
||||
int newMeta) {
|
||||
addItemReplacement(originalId, originalMeta, item, newMeta, false);
|
||||
addSimpleReplacement(originalId, originalMeta, item, newMeta, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -350,10 +400,12 @@ 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 addSimpleReplacement(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");
|
||||
SimpleTransformationRegistry.addSimpleTransformer(originalId, originalMeta, item, newMeta, skipBlockRemap);
|
||||
}
|
||||
|
||||
// endregion simple replacements
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.gtnewhorizons.postea.api;
|
||||
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
|
||||
import com.gtnewhorizons.postea.utility.BlockConversionInfo;
|
||||
|
||||
public abstract class PosteaBlockStackTransformer {
|
||||
|
||||
public String originalId;
|
||||
public int originalMeta;
|
||||
|
||||
public PosteaBlockStackTransformer(String originalId) {
|
||||
this(originalId, OreDictionary.WILDCARD_VALUE);
|
||||
}
|
||||
|
||||
public PosteaBlockStackTransformer(String originalId, int originalMeta) {
|
||||
this.originalId = originalId;
|
||||
this.originalMeta = originalMeta;
|
||||
}
|
||||
|
||||
public void register() {
|
||||
if (this instanceof IComplexStackTransformer cst) {
|
||||
if (this.originalMeta == OreDictionary.WILDCARD_VALUE) {
|
||||
ItemStackReplacementManager.addTransformationHandler(
|
||||
this.originalId,
|
||||
(originalId, tag) -> complexStackTransformerCheckMeta(originalId, tag, cst));
|
||||
} else {
|
||||
ItemStackReplacementManager.addTransformationHandler(this.originalId, cst::transformStack);
|
||||
}
|
||||
}
|
||||
if (this instanceof IComplexBlockTransformer cbt) {
|
||||
if (this.originalMeta == OreDictionary.WILDCARD_VALUE) {
|
||||
BlockReplacementManager
|
||||
.addTransformationHandler(this.originalId, (info) -> complexBlockTransformerCheckMeta(info, cbt));
|
||||
} else {
|
||||
BlockReplacementManager.addTransformationHandler(this.originalId, cbt::transformBlock);
|
||||
}
|
||||
}
|
||||
if (this instanceof ISimpleBlockTransformer sbt) {
|
||||
BlockReplacementManager.addSimpleReplacement(
|
||||
this.originalId,
|
||||
this.originalMeta,
|
||||
sbt.getTargetBlock(),
|
||||
sbt.getTargetBlockMeta(),
|
||||
true);
|
||||
}
|
||||
if (this instanceof ISimpleItemTransformer sit) {
|
||||
ItemStackReplacementManager.addSimpleReplacement(
|
||||
this.originalId,
|
||||
this.originalMeta,
|
||||
sit.getTargetItem(),
|
||||
sit.getTargetItemMeta(),
|
||||
true);
|
||||
}
|
||||
if (this instanceof ISimpleStackTransformer sst) {
|
||||
ItemStack stack = sst.getTargetStack();
|
||||
ItemStackReplacementManager.addSimpleReplacement(
|
||||
this.originalId,
|
||||
this.originalMeta,
|
||||
stack.getItem(),
|
||||
Items.feather.getDamage(stack),
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean complexStackTransformerCheckMeta(String originalId, NBTTagCompound tag,
|
||||
IComplexStackTransformer st) {
|
||||
if (tag.getShort("Damage") != originalMeta) return false;
|
||||
return st.transformStack(originalId, tag);
|
||||
}
|
||||
|
||||
private boolean complexBlockTransformerCheckMeta(BlockConversionInfo info, IComplexBlockTransformer bt) {
|
||||
if (info.metadata != originalMeta) return false;
|
||||
return bt.transformBlock(info);
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,23 @@
|
||||
package com.gtnewhorizons.postea.api;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
|
||||
import com.google.common.collect.LinkedListMultimap;
|
||||
import com.gtnewhorizons.postea.utility.BlockInfo;
|
||||
import com.gtnewhorizons.postea.utility.PosteaUtilities;
|
||||
import com.gtnewhorizons.postea.utility.TransformerRegistry;
|
||||
|
||||
/**
|
||||
* Public API used to register tile entity transformers via postea's handler system.<br>
|
||||
* <br>
|
||||
* Tile entity transformers are executed before any block transformers, when chunks being loading into the world.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class TileEntityReplacementManager {
|
||||
|
||||
private static final LinkedListMultimap<String, TriFunction<NBTTagCompound, World, Chunk, BlockInfo>> tileEntityToNormalBlockTransformer = LinkedListMultimap
|
||||
.create();
|
||||
public abstract class TileEntityReplacementManager {
|
||||
|
||||
/**
|
||||
* @deprecated Superseded by {@link #tileEntityTransformer(String, TriFunction)}.
|
||||
@@ -22,26 +25,57 @@ public class TileEntityReplacementManager {
|
||||
@Deprecated
|
||||
public static void tileEntityTransformer(String tileEntityId,
|
||||
BiFunction<NBTTagCompound, World, BlockInfo> transformerFunction) {
|
||||
tileEntityToNormalBlockTransformer
|
||||
.put(tileEntityId, (tag, world, chunk) -> transformerFunction.apply(tag, world));
|
||||
if (transformerFunction == null) throw new NullPointerException("transformer is null");
|
||||
tileEntityTransformer(tileEntityId, (tag, world, chunk) -> transformerFunction.apply(tag, world));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback function to transform a tile entity before it's loaded.
|
||||
* Callback returns a {@link BlockInfo} which the tile entity will be transformed into.</br>
|
||||
* Note that the callback will be called before the world is fully loaded, and world.getBlock will throw an error.
|
||||
* Use chunk.getBlock(x & 15, y, z & 15) instead.
|
||||
* Callback returns a {@link BlockInfo} which the tile entity will be transformed into.
|
||||
* If you return a null value instead of a block info, Postea will assume that you don't want to replace the block
|
||||
* and/or tile entity and look for any other compatible handlers that may be able to do a replacement.<br>
|
||||
* <br>
|
||||
* Note that the callback will be called before the world is fully loaded, and {@code world.getBlock} will throw an
|
||||
* error. If you need to identify a block, consider using
|
||||
* {@link BlockReplacementManager#registerIDResolver(String, Consumer)}
|
||||
* and {@link BlockAccessCompat#getBlockIDAtTE(NBTTagCompound, Chunk)} instead. If you need to identify the meta
|
||||
* value, consider using {@code Chunk.getBlockMetadata(x & 15, y, z & 15)} or the other functions inside of
|
||||
* {@link BlockReplacementManager}.<br>
|
||||
* <br>
|
||||
* {@code BlockReplacementManager.registerIDResolver} registers a simple callback that will be executed just after
|
||||
* the game resolves all numeric ID conflicts when loading a save. The provided value is the numeric ID of the
|
||||
* block linked provided string ID or -1 if the block has <em>never</em> been registered while the currently
|
||||
* loading world.<br>
|
||||
* <br>
|
||||
* {@code BlockAccessCompat.getBlockIDAtTE} lets you fetch the ID of the block where the current tile entity is
|
||||
* located. Since forge doesn't actually replace the id of missing blocks for performance reasons, opting to treat
|
||||
* them like air instead; You can use the value given to the resolver you registered using
|
||||
* {@code BlockReplacementManager.registerIDResolver} to identify the block directly.<br>
|
||||
* <br>
|
||||
* Using these 2 methods skips the need to register dummy blocks or items to identify blocks when migrating things,
|
||||
* which will improve the overall performance and compatibility of your migrations.
|
||||
*
|
||||
* @param tileEntityId ID of the tile entity to be transformed
|
||||
* @param transformerFunction Callback function to transforms the tile entity
|
||||
*/
|
||||
public static void tileEntityTransformer(String tileEntityId,
|
||||
TriFunction<NBTTagCompound, World, Chunk, BlockInfo> transformerFunction) {
|
||||
tileEntityToNormalBlockTransformer.put(tileEntityId, transformerFunction);
|
||||
if (transformerFunction == null) throw new NullPointerException("transformer is null");
|
||||
if (tileEntityId == null) throw new NullPointerException("transformer is null");
|
||||
TransformerRegistry.addTileEntityTransformer(tileEntityId, transformerFunction);
|
||||
}
|
||||
|
||||
public static Collection<TriFunction<NBTTagCompound, World, Chunk, BlockInfo>> getTileEntityToNormalBlockTransformerFunction(
|
||||
String tileEntityId) {
|
||||
return tileEntityToNormalBlockTransformer.get(tileEntityId);
|
||||
/**
|
||||
* Creates a bare-bones tile entity tag for the provided ID that clones all the positional information of the
|
||||
* provided tile entity NBT Tag. The passed NBT tag is never modified.
|
||||
*
|
||||
* @param tag The tag of the tile entity at the current position.
|
||||
* @param newId The ID of the new tile entity.
|
||||
* @return A bare-bones tile entity tag for the provided id at ths same position as the passed tile entity tag.
|
||||
*/
|
||||
public static NBTTagCompound createTETagAtSamePosition(String newId, NBTTagCompound tag) {
|
||||
if (tag == null) throw new NullPointerException("tag was null");
|
||||
if (newId == null) throw new NullPointerException("tag was null");
|
||||
return PosteaUtilities.cleanseNBT(newId, tag);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,13 @@
|
||||
package com.gtnewhorizons.postea.api;
|
||||
|
||||
/**
|
||||
* A simple function interface for functions with 3 parameters that must return a value.
|
||||
*
|
||||
* @param <T> The first parameter type.
|
||||
* @param <U> The second parameter type.
|
||||
* @param <O> The third parameter type.
|
||||
* @param <R> The return type.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface TriFunction<T, U, O, R> {
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ public final class PosteaLoadingPlugin implements IEarlyMixinLoader, IFMLLoading
|
||||
mixins.add("MixinItemStack");
|
||||
mixins.add("MixinChunk");
|
||||
mixins.add("MixinAnvilChunkLoader");
|
||||
mixins.add("MixinNBTTagList");
|
||||
return mixins;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.gtnewhorizons.postea.mixins;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.spongepowered.asm.lib.tree.ClassNode;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
|
||||
|
||||
public final class PosteaPreInitLoadingPlugin implements IMixinConfigPlugin {
|
||||
|
||||
@Override
|
||||
public void onLoad(String mixinPackage) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRefMapperConfig() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMixins() {
|
||||
List<String> mixins = new ArrayList<>();
|
||||
mixins.add("MixinGameData");
|
||||
return mixins;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preApply(String s, ClassNode classNode, String s1, IMixinInfo iMixinInfo) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postApply(String s, ClassNode classNode, String s1, IMixinInfo iMixinInfo) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.storage.AnvilChunkLoader;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@@ -12,7 +11,6 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import com.gtnewhorizons.postea.mixins.interfaces.IChunkMixin;
|
||||
import com.gtnewhorizons.postea.utility.ChunkFixerUtility;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
|
||||
@@ -23,53 +21,17 @@ public abstract class MixinAnvilChunkLoader {
|
||||
@Inject(method = "readChunkFromNBT", at = @At("RETURN"), require = 1)
|
||||
private void postea$chunkHook(CallbackInfoReturnable<Chunk> cir, @Local Chunk chunk,
|
||||
@Local(argsOnly = true) World world, @Local(ordinal = 0, argsOnly = true) NBTTagCompound tag) {
|
||||
IChunkMixin chunkMixin = (IChunkMixin) chunk;
|
||||
chunkMixin.Postea$setPosteaCode(-1);
|
||||
if (tag.hasKey("POSTEA")) {
|
||||
chunkMixin.Postea$setPosteaCode(tag.getLong("POSTEA"));
|
||||
}
|
||||
// This checks if the chunk has been run with the current POSTEA_UPDATE_CODE and skips it if so.
|
||||
if (chunkMixin.Postea$getPosteaCode() == ChunkFixerUtility.POSTEA_UPDATE_CODE) return;
|
||||
for (ExtendedBlockStorage ebs : chunk.getBlockStorageArray()) {
|
||||
if (ebs == null) {
|
||||
continue;
|
||||
}
|
||||
ChunkFixerUtility.transformNormalBlocks(chunk, ebs, world);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "loadEntities",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/nbt/NBTTagCompound;getTagList(Ljava/lang/String;I)Lnet/minecraft/nbt/NBTTagList;",
|
||||
ordinal = 1),
|
||||
require = 1)
|
||||
private void postea$transformTileEntities(CallbackInfo ci, @Local(ordinal = 0) NBTTagCompound tag,
|
||||
@Local World world, @Local Chunk chunk) {
|
||||
IChunkMixin chunkMixin = (IChunkMixin) chunk;
|
||||
// This checks if the chunk has been run with the current POSTEA_UPDATE_CODE and skips it if so.
|
||||
if (chunkMixin.Postea$getPosteaCode() == ChunkFixerUtility.POSTEA_UPDATE_CODE) return;
|
||||
|
||||
ChunkFixerUtility.transformTileEntities(tag, chunk, world);
|
||||
ChunkFixerUtility.onChunkRead(chunk, world, tag);
|
||||
}
|
||||
|
||||
@Inject(method = "loadChunk", at = @At("RETURN"))
|
||||
private void postea$updatePosteaChunkCode(World world, int i, int j, CallbackInfoReturnable<Chunk> cir) {
|
||||
Chunk chunk = cir.getReturnValue();
|
||||
if (chunk instanceof IChunkMixin iChunkMixin) {
|
||||
if (iChunkMixin.Postea$getPosteaCode() != ChunkFixerUtility.POSTEA_UPDATE_CODE) {
|
||||
iChunkMixin.Postea$setPosteaCode(ChunkFixerUtility.POSTEA_UPDATE_CODE);
|
||||
chunk.setChunkModified();
|
||||
}
|
||||
}
|
||||
ChunkFixerUtility.onChunkLoaded(cir.getReturnValue());
|
||||
}
|
||||
|
||||
@Inject(method = "writeChunkToNBT", at = @At("HEAD"))
|
||||
private void postea$writePosteaChunkCode(Chunk chunk, World world, NBTTagCompound nbtTagCompound, CallbackInfo ci) {
|
||||
if (chunk instanceof IChunkMixin iChunkMixin) {
|
||||
nbtTagCompound.setLong("POSTEA", iChunkMixin.Postea$getPosteaCode());
|
||||
}
|
||||
ChunkFixerUtility.onChunkWrite(chunk, nbtTagCompound);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.gtnewhorizons.postea.mixins.early;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
|
||||
import com.gtnewhorizons.postea.mixins.interfaces.IMixinNBTTagList;
|
||||
|
||||
@Mixin(NBTTagList.class)
|
||||
public class MixinNBTTagList implements IMixinNBTTagList {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private List tagList = new ArrayList();
|
||||
|
||||
@Override
|
||||
@Unique
|
||||
public void Postea$replaceCompoundTagAt(int index, NBTTagCompound tag) {
|
||||
tagList.set(index, tag);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.gtnewhorizons.postea.mixins.interfaces;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
public interface IMixinNBTTagList {
|
||||
|
||||
void Postea$replaceCompoundTagAt(int index, NBTTagCompound tag);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.gtnewhorizons.postea.mixins.preinit;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import com.gtnewhorizons.postea.utility.IDRegistry;
|
||||
|
||||
import cpw.mods.fml.common.registry.GameData;
|
||||
|
||||
@Mixin(value = GameData.class, remap = false)
|
||||
public abstract class MixinGameData {
|
||||
|
||||
@Inject(
|
||||
method = "injectWorldIDMap(Ljava/util/Map;Ljava/util/Set;Ljava/util/Map;Ljava/util/Map;Ljava/util/Set;Ljava/util/Set;ZZ)Ljava/util/List;",
|
||||
at = @At("HEAD"),
|
||||
require = 1)
|
||||
@SuppressWarnings("unused")
|
||||
private static void Postea$injectWorldIDMap(Map<String, Integer> dataList, Set<Integer> blockedIds,
|
||||
Map<String, String> blockAliases, Map<String, String> itemAliases, Set<String> blockSubstitutions,
|
||||
Set<String> itemSubstitutions, boolean injectFrozenData, boolean isLocalWorld,
|
||||
CallbackInfoReturnable<List<String>> cir) {
|
||||
IDRegistry.registerWorldSpecificIDs(dataList);
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,35 @@ import net.minecraft.world.World;
|
||||
|
||||
public final class BlockConversionInfo {
|
||||
|
||||
/**
|
||||
* The namespaced ID of the block being converted.
|
||||
*/
|
||||
public final String blockName;
|
||||
/**
|
||||
* The numeric ID of the block currently being replaced, or of the block you want it replaced with.
|
||||
*/
|
||||
public int blockID;
|
||||
/**
|
||||
* The meta value of the block currently being replaced, or value you want it replaced with.
|
||||
*/
|
||||
public int metadata;
|
||||
/**
|
||||
* The x coordinate of the block being replaced.
|
||||
*/
|
||||
public final int x;
|
||||
/**
|
||||
* The y coordinate of the block being replaced.
|
||||
*/
|
||||
public final int y;
|
||||
/**
|
||||
* The z coordinate of the block being replaced.
|
||||
*/
|
||||
public final int z;
|
||||
|
||||
/**
|
||||
* The world containing the block being replaced. It won't be loaded fully when a block transformer is executed, so
|
||||
* any call to something like world.getBlock() will throw an error.
|
||||
*/
|
||||
public final World world;
|
||||
|
||||
public BlockConversionInfo(String blockName, int blockID, int metadata, int x, int y, int z, World world) {
|
||||
|
||||
@@ -11,12 +11,29 @@ public final class BlockInfo {
|
||||
public final int metadata;
|
||||
public final Function<NBTTagCompound, NBTTagCompound> tileTransformer;
|
||||
|
||||
/**
|
||||
* Used to notify postea that you wish to update a tile entity, and the block situated at that same location.
|
||||
*
|
||||
* @param block The block that should replace the block currently stored at the tile entity's location.
|
||||
* @param metadata The meta value of the block being placed where the tile entity used to exist.
|
||||
* @param tileTransformer A transformer function for the NBT data of the tile entity. (you can just edit the one
|
||||
* passed to the transformer instead, it's executed right after you return this block info,
|
||||
* just make sure to provide a pass though function otherwise we won't know you want to keep
|
||||
* the tile entity alive.)
|
||||
*/
|
||||
public BlockInfo(Block block, int metadata, Function<NBTTagCompound, NBTTagCompound> tileTransformer) {
|
||||
this.block = block;
|
||||
this.metadata = metadata;
|
||||
this.tileTransformer = tileTransformer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to replace a tile entity with a block that does not need any tile entity data. Any existing data will be
|
||||
* erased when returning a block info created with this constructor.
|
||||
*
|
||||
* @param block The block that should replace the block currently stored at the tile entity's location.
|
||||
* @param metadata The meta value of the block being placed where the tile entity used to exist.
|
||||
*/
|
||||
public BlockInfo(Block block, int metadata) {
|
||||
this.block = block;
|
||||
this.metadata = metadata;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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;
|
||||
@@ -13,21 +12,72 @@ import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
|
||||
import com.gtnewhorizons.postea.api.TileEntityReplacementManager;
|
||||
import com.gtnewhorizons.postea.api.TriFunction;
|
||||
import com.gtnewhorizons.postea.compat.Compat;
|
||||
import com.gtnewhorizons.postea.compat.SubChunkAccess;
|
||||
|
||||
import akka.japi.Pair;
|
||||
import com.gtnewhorizons.postea.mixins.interfaces.IChunkMixin;
|
||||
import com.gtnewhorizons.postea.mixins.interfaces.IMixinNBTTagList;
|
||||
|
||||
public class ChunkFixerUtility {
|
||||
|
||||
// This will not change between runs, unless a mod is updated or added.
|
||||
public static final int POSTEA_UPDATE_CODE = getModListHash();
|
||||
public static final int POSTEA_UPDATE_CODE = PosteaUtilities.getModListHash();
|
||||
|
||||
public static boolean hasChunkBeenUpdated(long chunkHash) {
|
||||
// We are in a dev env.
|
||||
if (POSTEA_UPDATE_CODE == -1) return false;
|
||||
return chunkHash == POSTEA_UPDATE_CODE;
|
||||
}
|
||||
|
||||
private static final int AIR_ID = 0;
|
||||
|
||||
public static void transformNormalBlocks(Chunk chunk, ExtendedBlockStorage ebs, World world) {
|
||||
public static void onChunkRead(Chunk chunk, World world, NBTTagCompound tag) {
|
||||
IChunkMixin chunkMixin = (IChunkMixin) chunk;
|
||||
chunkMixin.Postea$setPosteaCode(-1);
|
||||
if (tag.hasKey("POSTEA", 4)) {
|
||||
chunkMixin.Postea$setPosteaCode(tag.getLong("POSTEA"));
|
||||
}
|
||||
// This checks if the chunk has been run with the current POSTEA_UPDATE_CODE and skips it if so.
|
||||
if (hasChunkBeenUpdated(chunkMixin.Postea$getPosteaCode())) return;
|
||||
List<ConversionInfo> conversionInfoList = adjustTileEntities(tag.getTagList("TileEntities", 10), world, chunk);
|
||||
|
||||
for (ExtendedBlockStorage ebs : chunk.getBlockStorageArray()) {
|
||||
if (ebs == null) continue;
|
||||
int sectionY = ebs.getYLocation();
|
||||
|
||||
List<ConversionInfo> filteredList = conversionInfoList.stream()
|
||||
.filter(info -> info.y >= sectionY && info.y < (sectionY + 16))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (ConversionInfo info : filteredList) {
|
||||
int localX = info.x & 15;
|
||||
int localY = info.y & 15;
|
||||
int localZ = info.z & 15;
|
||||
ebs.func_150818_a(localX, localY, localZ, info.blockInfo.block);
|
||||
ebs.setExtBlockMetadata(localX, localY, localZ, info.blockInfo.metadata);
|
||||
}
|
||||
|
||||
transformNormalBlocksInSubChunk(chunk, ebs, world);
|
||||
}
|
||||
chunkMixin.Postea$setPosteaCode(ChunkFixerUtility.POSTEA_UPDATE_CODE);
|
||||
}
|
||||
|
||||
public static void onChunkLoaded(Chunk chunk) {
|
||||
if (chunk instanceof IChunkMixin iChunkMixin) {
|
||||
if (!hasChunkBeenUpdated(iChunkMixin.Postea$getPosteaCode())) {
|
||||
iChunkMixin.Postea$setPosteaCode(ChunkFixerUtility.POSTEA_UPDATE_CODE);
|
||||
chunk.setChunkModified();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void onChunkWrite(Chunk chunk, NBTTagCompound tag) {
|
||||
if (chunk instanceof IChunkMixin iChunkMixin) {
|
||||
tag.setLong("POSTEA", iChunkMixin.Postea$getPosteaCode());
|
||||
}
|
||||
}
|
||||
|
||||
public static void transformNormalBlocksInSubChunk(Chunk chunk, ExtendedBlockStorage ebs, World world) {
|
||||
|
||||
int chunkXPos = chunk.xPosition * 16;
|
||||
int chunkZPos = chunk.zPosition * 16;
|
||||
@@ -62,54 +112,15 @@ public class ChunkFixerUtility {
|
||||
}
|
||||
}
|
||||
|
||||
public static void transformTileEntities(NBTTagCompound levelCompoundTag, Chunk chunk, World world) {
|
||||
|
||||
Pair<List<ConversionInfo>, NBTTagList> output = adjustTileEntities(
|
||||
levelCompoundTag.getTagList("TileEntities", 10),
|
||||
world,
|
||||
chunk);
|
||||
List<ConversionInfo> conversionInfoList = output.first();
|
||||
NBTTagList tileEntities = output.second();
|
||||
|
||||
if (tileEntities.tagCount() > 0) {
|
||||
levelCompoundTag.setTag("TileEntities", tileEntities);
|
||||
}
|
||||
|
||||
for (ExtendedBlockStorage ebs : chunk.getBlockStorageArray()) {
|
||||
if (ebs == null) continue;
|
||||
processSection(ebs, conversionInfoList);
|
||||
}
|
||||
}
|
||||
|
||||
private static void processSection(ExtendedBlockStorage ebs, List<ConversionInfo> conversionInfoList) {
|
||||
int sectionY = ebs.getYLocation();
|
||||
|
||||
List<ConversionInfo> filteredList = conversionInfoList.stream()
|
||||
.filter(info -> info.y >= sectionY && info.y < (sectionY + 16))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (ConversionInfo info : filteredList) {
|
||||
int localX = info.x & 15;
|
||||
int localY = info.y & 15;
|
||||
int localZ = info.z & 15;
|
||||
ebs.func_150818_a(localX, localY, localZ, info.blockInfo.block);
|
||||
ebs.setExtBlockMetadata(localX, localY, localZ, info.blockInfo.metadata);
|
||||
}
|
||||
}
|
||||
|
||||
private static Pair<List<ConversionInfo>, NBTTagList> adjustTileEntities(NBTTagList tileEntities, World world,
|
||||
Chunk chunk) {
|
||||
private static List<ConversionInfo> adjustTileEntities(NBTTagList tileEntities, World world, Chunk chunk) {
|
||||
List<ConversionInfo> conversionInfo = new ArrayList<>();
|
||||
|
||||
NBTTagList tileEntitiesCopy = new NBTTagList();
|
||||
|
||||
for (int i = 0; i < tileEntities.tagCount(); i++) {
|
||||
NBTTagCompound tileEntity = tileEntities.getCompoundTagAt(i);
|
||||
String tileEntityId = tileEntity.getString("id");
|
||||
|
||||
// Check if we have a transformer registered for this tile entity ID
|
||||
boolean found = false;
|
||||
for (TriFunction<NBTTagCompound, World, Chunk, BlockInfo> transformationFunction : TileEntityReplacementManager
|
||||
for (TriFunction<NBTTagCompound, World, Chunk, BlockInfo> transformationFunction : TransformerRegistry
|
||||
.getTileEntityToNormalBlockTransformerFunction(tileEntityId)) {
|
||||
|
||||
int x = tileEntity.getInteger("x");
|
||||
@@ -119,21 +130,18 @@ public class ChunkFixerUtility {
|
||||
BlockInfo blockInfo = transformationFunction.apply(tileEntity, world, chunk);
|
||||
if (blockInfo == null) continue;
|
||||
|
||||
if (blockInfo.tileTransformer != null) {
|
||||
tileEntitiesCopy.appendTag(blockInfo.tileTransformer.apply(tileEntity));
|
||||
} // Otherwise they are removed, therefore not appended.
|
||||
if (blockInfo.tileTransformer == null) {
|
||||
tileEntities.removeTag(i--);
|
||||
} else {
|
||||
((IMixinNBTTagList) tileEntities)
|
||||
.Postea$replaceCompoundTagAt(i, blockInfo.tileTransformer.apply(tileEntity));
|
||||
}
|
||||
|
||||
conversionInfo.add(new ConversionInfo(x, y, z, blockInfo));
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (!found) {
|
||||
// Do nothing.
|
||||
tileEntitiesCopy.appendTag(tileEntity);
|
||||
}
|
||||
}
|
||||
|
||||
return new Pair<>(conversionInfo, tileEntitiesCopy);
|
||||
return conversionInfo;
|
||||
}
|
||||
|
||||
private static class ConversionInfo {
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
package com.gtnewhorizons.postea.utility;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.LoaderState;
|
||||
import cpw.mods.fml.common.registry.GameData;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
|
||||
/**
|
||||
* A simple utility to resolve the IDs of any namepsaced ID that has ever been registered to an active world's id list.
|
||||
*/
|
||||
public abstract class IDRegistry {
|
||||
|
||||
// Part of a bi-map for lookups between block namespaced ids and numeric ids
|
||||
private static final Object2IntOpenHashMap<String> BLOCK_NAME_TO_ID = new Object2IntOpenHashMap<>();
|
||||
|
||||
// Part of a bi-map for lookups between item namespaced ids and numeric ids
|
||||
private static final Object2IntOpenHashMap<String> ITEM_NAME_TO_ID = new Object2IntOpenHashMap<>();
|
||||
|
||||
private static final LinkedHashMultimap<String, Consumer<Integer>> BLOCK_ID_RESOLVERS = LinkedHashMultimap.create();
|
||||
private static final LinkedHashMultimap<String, Consumer<Integer>> ITEM_ID_RESOLVERS = LinkedHashMultimap.create();
|
||||
|
||||
/**
|
||||
* Triggers all the callbacks registered by other mods that wish to identify a block that may no longer exist.
|
||||
* These callbacks effectively remove the need for dummies, and should help improve performance at runtime.
|
||||
*/
|
||||
public static void onMappingUpdated() {
|
||||
// this event is fired on server startup and shutdown. On shutdown, we just need to clear the mappings to save
|
||||
// some space memory we can just ignore adding stuff safely.
|
||||
if (!Loader.instance()
|
||||
.isInState(LoaderState.SERVER_ABOUT_TO_START)) return;
|
||||
// we should be fine to execute those in parallel I think?
|
||||
BLOCK_ID_RESOLVERS.asMap()
|
||||
.entrySet()
|
||||
.parallelStream()
|
||||
.forEach(kv -> {
|
||||
int id = getItemId(kv.getKey());
|
||||
for (Consumer<Integer> resolver : kv.getValue()) {
|
||||
resolver.accept(id);
|
||||
}
|
||||
});
|
||||
ITEM_ID_RESOLVERS.asMap()
|
||||
.entrySet()
|
||||
.parallelStream()
|
||||
.forEach(kv -> {
|
||||
int id = getItemId(kv.getKey());
|
||||
for (Consumer<Integer> resolver : kv.getValue()) {
|
||||
resolver.accept(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by {@link com.gtnewhorizons.postea.mixins.preinit.MixinGameData}, this function is used to register all
|
||||
* the previously registered namespaced to numeric id mappings that have ever been seen into a world.<br>
|
||||
* <br>
|
||||
* This function executes before the game starts remapping it's own internal IDs, so we can be sure that any
|
||||
* existing will remain while the world is loaded.
|
||||
*/
|
||||
public static void registerWorldSpecificIDs(Map<String, Integer> map) {
|
||||
BLOCK_NAME_TO_ID.clear();
|
||||
ITEM_NAME_TO_ID.clear();
|
||||
for (Map.Entry<String, Integer> kv : map.entrySet()) {
|
||||
String name = kv.getKey()
|
||||
.substring(1);
|
||||
int id = kv.getValue();
|
||||
if (kv.getKey()
|
||||
.charAt(0) == '\u0001') {
|
||||
BLOCK_NAME_TO_ID.put(name, id);
|
||||
} else {
|
||||
ITEM_NAME_TO_ID.put(name, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the block numeric ID associated with the namespaced ID.
|
||||
*
|
||||
* @param name the namespaced id of the block.
|
||||
* @return The ID of the block, or -1 if the namespaced ID has never been registered while the current world was
|
||||
* loaded.
|
||||
*/
|
||||
public static int getBlockId(String name) {
|
||||
int id = BLOCK_NAME_TO_ID.getOrDefault(name, -1);
|
||||
if (id < 0) {
|
||||
id = GameData.getBlockRegistry()
|
||||
.getId(name);
|
||||
if (id >= 0) BLOCK_NAME_TO_ID.put(name, id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the item numeric ID associated with the namespaced ID.
|
||||
*
|
||||
* @param name the namespaced id of the block.
|
||||
* @return The ID of the block, or -1 if the namespaced ID has never been registered while the current world was
|
||||
* loaded.
|
||||
*/
|
||||
public static int getItemId(String name) {
|
||||
int id = ITEM_NAME_TO_ID.getOrDefault(name, -1);
|
||||
if (id < 0) {
|
||||
id = GameData.getItemRegistry()
|
||||
.getId(name);
|
||||
if (id >= 0) ITEM_NAME_TO_ID.put(name, id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a callback used by mods to identify the numeric ID of a namespaced ID when a world is loaded.
|
||||
*
|
||||
* @param name The namespaced ID to resolve.
|
||||
* @param resolver The callback to call just after forge adjusts the ID mappings to prevent collisions.
|
||||
*/
|
||||
public static void registerBlockIDResolver(String name, Consumer<Integer> resolver) {
|
||||
BLOCK_ID_RESOLVERS.put(name, resolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a callback used by mods to identify the numeric ID of a namespaced ID when a world is loaded.
|
||||
*
|
||||
* @param name The namespaced ID to resolve.
|
||||
* @param resolver The callback to call just after forge adjusts the ID mappings to prevent collisions.
|
||||
*/
|
||||
public static void registerItemIDResolver(String name, Consumer<Integer> resolver) {
|
||||
ITEM_ID_RESOLVERS.put(name, resolver);
|
||||
}
|
||||
}
|
||||
@@ -1,116 +1,40 @@
|
||||
package com.gtnewhorizons.postea.utility;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
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.Postea;
|
||||
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;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
|
||||
/**
|
||||
* A simple utility used to allow mods to register simple missing mapping migrations without having to set up a whole
|
||||
* system themselves.
|
||||
*/
|
||||
public abstract class MissingMappingHandler {
|
||||
|
||||
enum MappingType {
|
||||
/** Tells the mapping logic to register an Item. */
|
||||
Item,
|
||||
/** Tells the mapping logic to register a Block (and ItemBlock). */
|
||||
Block
|
||||
}
|
||||
|
||||
static class DummyMapping {
|
||||
|
||||
/** 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;
|
||||
}
|
||||
}
|
||||
|
||||
// because we're using reflection to quickly identify our stuff at runtime.
|
||||
public static class DummyBlock extends Block {
|
||||
|
||||
public DummyBlock() {
|
||||
super(Material.ground);
|
||||
}
|
||||
}
|
||||
|
||||
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 Set<String> MISSING_IDS_TO_IGNORE = new HashSet<>();
|
||||
private static final HashMap<String, Item> MISSING_ITEM_MAPPINGS = new HashMap<>();
|
||||
private static final HashMap<String, Block> MISSING_BLOCK_MAPPINGS = new HashMap<>();
|
||||
private static final HashMap<String, DummyMapping> DUMMY_TARGET_TYPES = new HashMap<>();
|
||||
private static final HashMap<String, String> DUMMY_ID_TO_ORIGINAL_ID_LOOKUP = new HashMap<>();
|
||||
private static final HashMap<String, String> 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.";
|
||||
private static final String DUMMY_ID_PREFIX = DUMMY_ID_PREFIX_START + DUMMY_ID_PREFIX_END;
|
||||
|
||||
public static void onLoadCompleted() {
|
||||
for (Map.Entry<String, DummyMapping> 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);
|
||||
}
|
||||
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();
|
||||
}
|
||||
/**
|
||||
* A set of String IDs that can safely be ignored.
|
||||
*/
|
||||
private static final Set<String> MISSING_IDS_TO_IGNORE = new ObjectOpenHashSet<>();
|
||||
/**
|
||||
* A set of string IDs and items they should map to.
|
||||
*/
|
||||
private static final Map<String, Item> MISSING_ITEM_MAPPINGS = new Object2ObjectOpenHashMap<>();
|
||||
/**
|
||||
* A set of string IDs and items they should map to.
|
||||
*/
|
||||
private static final Map<String, Block> MISSING_BLOCK_MAPPINGS = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
// region FML Life Cycle handlers
|
||||
public static void onMissingMapping(FMLMissingMappingsEvent event) {
|
||||
for (FMLMissingMappingsEvent.MissingMapping mapping : event.getAll()) {
|
||||
// ignore things that can be ignored safely, and our own dummy items for when a handler is removed.
|
||||
if (MISSING_IDS_TO_IGNORE.contains(mapping.name) || mapping.name.startsWith(DUMMY_ID_PREFIX)) {
|
||||
if (MISSING_IDS_TO_IGNORE.contains(mapping.name)) {
|
||||
mapping.ignore();
|
||||
continue;
|
||||
}
|
||||
@@ -135,70 +59,35 @@ public abstract class MissingMappingHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
// endregion FML Life Cycle handlers
|
||||
|
||||
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 addSimpleReplacement(String originalId, Item item) {
|
||||
/**
|
||||
* Adds a direct mapping for a missing item mapping.
|
||||
*
|
||||
* @param originalId The namespaced id of the missing item.
|
||||
* @param item The item it should be replaced with.
|
||||
*/
|
||||
public static void addItemMapping(String originalId, Item item) {
|
||||
MISSING_ITEM_MAPPINGS.put(originalId, item);
|
||||
}
|
||||
|
||||
public static void addSimpleReplacement(String originalId, Block block) {
|
||||
/**
|
||||
* Adds a direct mapping for a missing block mapping.
|
||||
*
|
||||
* @param originalId The namespaced id of the missing block.
|
||||
* @param block The block it should be replaced with.
|
||||
*/
|
||||
public static void addBlockMapping(String originalId, Block block) {
|
||||
MISSING_BLOCK_MAPPINGS.put(originalId, block);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a notice that FML should silence any warning when loading a world telling the player that an ID
|
||||
* is now missing.
|
||||
*
|
||||
* @param originalId The namespace ID to ignore.
|
||||
*/
|
||||
public static void addIgnore(String originalId) {
|
||||
MISSING_IDS_TO_IGNORE.add(originalId);
|
||||
}
|
||||
|
||||
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 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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package com.gtnewhorizons.postea.utility;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
@@ -30,6 +31,9 @@ public abstract class PosteaUtilities {
|
||||
}
|
||||
|
||||
public static int getModListHash() {
|
||||
// when in a dev env allow mutations to happen every time a chunk is loaded for testing purposes.
|
||||
final Object deobfEnv = Launch.blackboard != null ? Launch.blackboard.get("fml.deobfuscatedEnvironment") : null;
|
||||
if (deobfEnv != null && (boolean) deobfEnv) return -1;
|
||||
|
||||
// We iterate over every mod, get its version and put it into a giant list.
|
||||
// This is done so we can see if our mods have actually changed, if so, we
|
||||
|
||||
@@ -10,55 +10,97 @@ import net.minecraftforge.oredict.OreDictionary;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
|
||||
public class SimpleTransformationMap<T> {
|
||||
/**
|
||||
* A simple mapping registry for quick access to simple transformations.<br>
|
||||
* <br>
|
||||
* It's essentially a 2 layer map.
|
||||
* The first layer contains the namespaced ID of the thing that needs to be replaced.
|
||||
* The second layer contains mappings for each meta/damage value of the namespaced ID.<br>
|
||||
* <br>
|
||||
* When registering something to the second/meta layer, Using {@link OreDictionary#WILDCARD_VALUE}
|
||||
* will register a fallback for all meta/damage value of the namespaced ID.<br>
|
||||
* <br>
|
||||
* Here is an example of the typical structure of this map
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* ┌─ mod:name_one ─┬─ 1 -> {Stone, 0} : Transforms all mod:name_one with meta 1 into stone with meta 0
|
||||
* │ └─ wildcard -> {Plank, Wildcard} : Transforms all other mod:name_one to planks of the same meta.
|
||||
* │
|
||||
* ├─ mod:name_two ─── 2 -> {Clay, 0} : transforms all mod:name_two with meta 2 to clay with meta 0
|
||||
* │
|
||||
* └─ mod:name_three ─┬─ 0 -> {Air, 0} : transforms all mod:name_three with meta 0 to air with meta 0
|
||||
* ├─ 1 -> {Sand, 1} : transforms all mod:name_three with meta 1 to sand with meta 1
|
||||
* └─ 5 -> {SandStone, Wildcard} : transforms all mod:name_three to sandstone with the same meta.
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param <T> Either {@link net.minecraft.block.Block} or {@link net.minecraft.item.Item}
|
||||
*/
|
||||
class SimpleTransformationMap<T> {
|
||||
|
||||
private final Map<String, Map<Integer, T>> registry = new Object2ObjectOpenHashMap<>();
|
||||
public static class Value<T> {
|
||||
|
||||
/**
|
||||
* The target block or item for the simple transformation
|
||||
*/
|
||||
public final T target;
|
||||
/**
|
||||
* The target meta/damage value for the transformation.
|
||||
* If the value is {@link OreDictionary#WILDCARD_VALUE}, It maintains the old meta/damage value.
|
||||
*/
|
||||
public final short targetMeta;
|
||||
/**
|
||||
* The numeric id of the target block, updated during the FMLMappingUpdate event
|
||||
*/
|
||||
public int targetRuntimeId;
|
||||
|
||||
public Value(T target, short targetMeta) {
|
||||
this.target = target;
|
||||
this.targetMeta = targetMeta;
|
||||
this.targetRuntimeId = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<String, Map<Integer, Value<T>>> registry = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
/**
|
||||
* Puts a mapping in this registry.
|
||||
*
|
||||
* @param originalId The original id of the item/block to replace.
|
||||
* @param originalMeta The metadata of the item/block to replace. OreDictionary.WILDCARD_VALUE can be used as a
|
||||
* wildcard.
|
||||
* @param originalId The namespaced ID of the item or block to replace.
|
||||
* @param originalMeta The meta or damage value of the item or block to replace.
|
||||
* {@link OreDictionary#WILDCARD_VALUE} can be used as a wildcard/fallback value.
|
||||
* When querying, the value will be replaced, which will
|
||||
* be used when ever no other specific meta match is found.
|
||||
*/
|
||||
public void put(String originalId, int originalMeta, T data) {
|
||||
public void put(String originalId, int originalMeta, T target, short targetMeta) {
|
||||
if (originalMeta == -1) originalMeta = OreDictionary.WILDCARD_VALUE;
|
||||
this.registry.computeIfAbsent(originalId, k -> new Int2ObjectOpenHashMap<>())
|
||||
.put(originalMeta, data);
|
||||
.put(originalMeta, new Value<>(target, targetMeta));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mapping from the registry.
|
||||
* Used to query sub-maps at runtime since we capture the relevant sub-map into the transformation handler that is
|
||||
* registered for simple transformations. This allows us to not re-query the first layer of this map while
|
||||
* performing simple transformations, which should hopefully increase performance.
|
||||
*
|
||||
* @param id The id of the item/block to replace.
|
||||
* @param meta The meta of the item/block to replace.
|
||||
* @return The new id and meta for the item/block if found.
|
||||
* @param subMap The sub-map to query.
|
||||
* @param meta The meta/damage value of the block/item being transformed.
|
||||
* @return The mapping if found, else null.
|
||||
* @param <T> The type of the sub-map,
|
||||
*/
|
||||
public @Nullable T get(String id, int meta) {
|
||||
Map<Integer, T> metaMap = this.registry.get(id);
|
||||
if (metaMap == null) return null;
|
||||
T mapping = metaMap.get(meta);
|
||||
public static <T> @Nullable Value<T> getFromSubMap(Map<Integer, Value<T>> subMap, int meta) {
|
||||
Value<T> mapping = subMap.get(meta);
|
||||
if (mapping != null) return mapping;
|
||||
return metaMap.get(OreDictionary.WILDCARD_VALUE);
|
||||
}
|
||||
|
||||
public static <T> @Nullable T getFromSubmap(Map<Integer, T> metaMap, int meta) {
|
||||
T mapping = metaMap.get(meta);
|
||||
if (mapping != null) return mapping;
|
||||
return metaMap.get(OreDictionary.WILDCARD_VALUE);
|
||||
return subMap.get(OreDictionary.WILDCARD_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the set of all registered item ids.
|
||||
* Used to update runtime IDs during the MappingUpdate event.
|
||||
*
|
||||
* @return The set of all registered item ids
|
||||
*/
|
||||
public Set<String> keySet() {
|
||||
return this.registry.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the set of all registered item ids.
|
||||
*/
|
||||
public Set<Map.Entry<String, Map<Integer, T>>> entrySet() {
|
||||
public Set<Map.Entry<String, Map<Integer, Value<T>>>> entrySet() {
|
||||
return this.registry.entrySet();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.gtnewhorizons.postea.utility;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.item.Item;
|
||||
@@ -8,12 +10,8 @@ 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
|
||||
@@ -30,49 +28,47 @@ 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<>();
|
||||
private static final SimpleTransformationMap<Block> SIMPLE_BLOCK_TRANSFORMATION_MAP = new SimpleTransformationMap<>();
|
||||
/**
|
||||
* 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<>();
|
||||
private static final SimpleTransformationMap<Item> SIMPLE_ITEM_TRANSFORMATION_MAP = new SimpleTransformationMap<>();
|
||||
|
||||
// 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.
|
||||
* the execution time of the handlers. This is done at the load completed to hopefully always register these
|
||||
* handlers last, allowing all other user made transformers to execute first.
|
||||
*/
|
||||
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.addBlockTransformer(kv.getKey(), info -> simpleBlockTransformer(info, subMap));
|
||||
for (Map.Entry<String, Map<Integer, SimpleTransformationMap.Value<Block>>> kv : SIMPLE_BLOCK_TRANSFORMATION_MAP
|
||||
.entrySet()) {
|
||||
TransformerRegistry.addBlockTransformer(kv.getKey(), new SimpleBlockTransformationHandler(kv.getValue()));
|
||||
}
|
||||
// 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
|
||||
.addStackTransformer(kv.getKey(), (originalId, tag) -> simpleItemStackTransformer(tag, subMap));
|
||||
for (Map.Entry<String, Map<Integer, SimpleTransformationMap.Value<Item>>> kv : SIMPLE_ITEM_TRANSFORMATION_MAP
|
||||
.entrySet()) {
|
||||
TransformerRegistry.addStackTransformer(kv.getKey(), new SimpleItemTransformationHandler(kv.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-caches updated block and item IDs for any simple transformation to speed-up the handlers.
|
||||
* Pre-caches updated block and item numeric 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()
|
||||
for (Map.Entry<String, Map<Integer, SimpleTransformationMap.Value<Block>>> kv : SIMPLE_BLOCK_TRANSFORMATION_MAP
|
||||
.entrySet()) {
|
||||
for (SimpleTransformationMap.Value<Block> mapping : kv.getValue()
|
||||
.values()) {
|
||||
RUNTIME_BLOCK_ID_LOOKUP.computeIfAbsent(mapping.getKey(), Block::getIdFromBlock);
|
||||
mapping.targetRuntimeId = Block.getIdFromBlock(mapping.target);
|
||||
}
|
||||
}
|
||||
for (Map.Entry<String, Map<Integer, Pair<Item, Short>>> kv : SIMPLE_ITEM_TRANSFORMATION_MAP.entrySet()) {
|
||||
for (Pair<Item, Short> mapping : kv.getValue()
|
||||
for (Map.Entry<String, Map<Integer, SimpleTransformationMap.Value<Item>>> kv : SIMPLE_ITEM_TRANSFORMATION_MAP
|
||||
.entrySet()) {
|
||||
for (SimpleTransformationMap.Value<Item> mapping : kv.getValue()
|
||||
.values()) {
|
||||
RUNTIME_ITEM_ID_LOOKUP.computeIfAbsent(mapping.getKey(), Item::getIdFromItem);
|
||||
mapping.targetRuntimeId = Item.getIdFromItem(mapping.target);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,11 +100,11 @@ public class SimpleTransformationRegistry {
|
||||
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));
|
||||
SIMPLE_BLOCK_TRANSFORMATION_MAP.put(originalId, originalMeta, 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));
|
||||
SIMPLE_ITEM_TRANSFORMATION_MAP.put(originalId, originalMeta, item, (short) newMeta);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,14 +114,25 @@ public class SimpleTransformationRegistry {
|
||||
*
|
||||
* @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();
|
||||
private static class SimpleBlockTransformationHandler implements Function<BlockConversionInfo, Boolean> {
|
||||
|
||||
private final Map<Integer, SimpleTransformationMap.Value<Block>> metaMap;
|
||||
|
||||
SimpleBlockTransformationHandler(Map<Integer, SimpleTransformationMap.Value<Block>> metaMap) {
|
||||
this.metaMap = metaMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean apply(BlockConversionInfo info) {
|
||||
SimpleTransformationMap.Value<Block> mapping = SimpleTransformationMap
|
||||
.getFromSubMap(metaMap, info.metadata);
|
||||
if (mapping == null || mapping.targetRuntimeId <= -1) return false;
|
||||
info.blockID = mapping.targetRuntimeId;
|
||||
if (mapping.targetMeta != OreDictionary.WILDCARD_VALUE) {
|
||||
info.metadata = mapping.targetMeta;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// endregion block transformations
|
||||
|
||||
@@ -159,9 +166,9 @@ public class SimpleTransformationRegistry {
|
||||
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_BLOCK_TRANSFORMATION_MAP.put(originalId, originalMeta, ib.field_150939_a, (short) newMeta);
|
||||
}
|
||||
SIMPLE_ITEM_TRANSFORMATION_MAP.put(originalId, originalMeta, Pair.of(newItem, (short) newMeta));
|
||||
SIMPLE_ITEM_TRANSFORMATION_MAP.put(originalId, originalMeta, newItem, (short) newMeta);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,16 +176,25 @@ public class SimpleTransformationRegistry {
|
||||
*
|
||||
* @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());
|
||||
private static class SimpleItemTransformationHandler implements BiFunction<String, NBTTagCompound, Boolean> {
|
||||
|
||||
private final Map<Integer, SimpleTransformationMap.Value<Item>> metaMap;
|
||||
|
||||
SimpleItemTransformationHandler(Map<Integer, SimpleTransformationMap.Value<Item>> metaMap) {
|
||||
this.metaMap = metaMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean apply(String originalId, NBTTagCompound tag) {
|
||||
short meta = tag.getShort("Damage");
|
||||
SimpleTransformationMap.Value<Item> mapping = SimpleTransformationMap.getFromSubMap(metaMap, meta);
|
||||
if (mapping == null || mapping.targetRuntimeId <= -1) return false;
|
||||
IDExtenderCompat.setItemStackID(tag, mapping.targetRuntimeId);
|
||||
if (mapping.targetMeta != OreDictionary.WILDCARD_VALUE) {
|
||||
tag.setShort("Damage", mapping.targetMeta);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// endregion item transformations
|
||||
}
|
||||
@@ -1,23 +1,26 @@
|
||||
package com.gtnewhorizons.postea.utility;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.collect.LinkedListMultimap;
|
||||
import com.gtnewhorizons.postea.api.IDExtenderCompat;
|
||||
import com.gtnewhorizons.postea.api.TriFunction;
|
||||
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.LoaderState;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
|
||||
/**
|
||||
* A registry for all transformer functions
|
||||
@@ -28,7 +31,8 @@ public class TransformerRegistry {
|
||||
.create();
|
||||
public static final LinkedListMultimap<String, Function<BlockConversionInfo, Boolean>> BLOCK_REPLACEMENT_MAP = LinkedListMultimap
|
||||
.create();
|
||||
|
||||
private static final LinkedListMultimap<String, TriFunction<NBTTagCompound, World, Chunk, BlockInfo>> TILE_ENTITY_REPLACEMENT_MAP = LinkedListMultimap
|
||||
.create();
|
||||
/**
|
||||
* Map of itemID -> originalName+transformationHandler.
|
||||
* Pivoting on the id is faster than pivoting on the strings so this should help with perf a bit.
|
||||
@@ -41,11 +45,40 @@ public class TransformerRegistry {
|
||||
* 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<>();
|
||||
|
||||
// region FML Life Cycle handlers
|
||||
/**
|
||||
* List of ids used by dummy items and blocks generated by Postea.
|
||||
* Generated during the mapping update event whilst entering/loading a world.
|
||||
* When FML loads a world, it remaps certain IDs if the IDs it registered during the load period do not match the
|
||||
* IDs that were previously registered when the world was last loaded.
|
||||
* <br>
|
||||
* We use this opportunity to fetch the "world specific" IDs of all the blocks and items that have a
|
||||
* transformation registered to them so we can pivot using the numeric IDs when we're doing replacements.
|
||||
* <br>
|
||||
* This is because pivoting on the numeric ids is significantly faster than pivoting on string or object hashes.
|
||||
*/
|
||||
public static final IntOpenHashSet DUMMY_IDS = new IntOpenHashSet();
|
||||
public static void onIdMappingsChanged() {
|
||||
RUNTIME_BLOCK_REPLACEMENT_MAP.clear();
|
||||
RUNTIME_ITEM_REPLACEMENT_MAP.clear();
|
||||
// this event is fired on server startup and shutdown. On shutdown, we just need to clear the mappings to save
|
||||
// some space memory we can just ignore adding stuff safely.
|
||||
if (!Loader.instance()
|
||||
.isInState(LoaderState.SERVER_ABOUT_TO_START)) return;
|
||||
// create a lookup for source block ids.
|
||||
for (String key : BLOCK_REPLACEMENT_MAP.keys()) {
|
||||
int id = IDRegistry.getBlockId(key);
|
||||
if (id >= 0) {
|
||||
RUNTIME_BLOCK_REPLACEMENT_MAP.put(id, Pair.of(key, BLOCK_REPLACEMENT_MAP.get(key)));
|
||||
}
|
||||
}
|
||||
// create a lookup for source block ids.
|
||||
for (String key : ITEM_REPLACEMENT_MAP.keys()) {
|
||||
int id = IDRegistry.getItemId(key);
|
||||
if (id >= 0) {
|
||||
RUNTIME_ITEM_REPLACEMENT_MAP.put(id, Pair.of(key, ITEM_REPLACEMENT_MAP.get(key)));
|
||||
}
|
||||
}
|
||||
}
|
||||
// endregion FML Life Cycle handlers
|
||||
|
||||
/**
|
||||
* Registers a block transformation handler function for the given id.
|
||||
@@ -60,8 +93,8 @@ public class TransformerRegistry {
|
||||
* @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 addBlockTransformer(String originalId, Function<BlockConversionInfo, Boolean> transformer) {
|
||||
MissingMappingHandler.createDummyBlockIfNeeded(originalId);
|
||||
public static void addBlockTransformer(@Nonnull String originalId,
|
||||
@Nonnull Function<BlockConversionInfo, Boolean> transformer) {
|
||||
BLOCK_REPLACEMENT_MAP.put(originalId, transformer);
|
||||
}
|
||||
|
||||
@@ -78,50 +111,30 @@ public class TransformerRegistry {
|
||||
* @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 addStackTransformer(String originalId, BiFunction<String, NBTTagCompound, Boolean> transformer) {
|
||||
MissingMappingHandler.createDummyItemIfNeeded(originalId);
|
||||
public static void addStackTransformer(@Nonnull String originalId,
|
||||
@Nonnull BiFunction<String, NBTTagCompound, Boolean> transformer) {
|
||||
ITEM_REPLACEMENT_MAP.put(originalId, transformer);
|
||||
}
|
||||
|
||||
// region FML Life Cycle handlers
|
||||
public static void onIdMappingsChanged() {
|
||||
DUMMY_IDS.clear();
|
||||
RUNTIME_BLOCK_REPLACEMENT_MAP.clear();
|
||||
RUNTIME_ITEM_REPLACEMENT_MAP.clear();
|
||||
// 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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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 addTileEntityTransformer(@Nonnull String originalId,
|
||||
@Nonnull TriFunction<NBTTagCompound, World, Chunk, BlockInfo> transformer) {
|
||||
TILE_ENTITY_REPLACEMENT_MAP.put(originalId, transformer);
|
||||
}
|
||||
|
||||
public static void onServerStopping() {
|
||||
RUNTIME_BLOCK_REPLACEMENT_MAP.clear();
|
||||
RUNTIME_ITEM_REPLACEMENT_MAP.clear();
|
||||
DUMMY_IDS.clear();
|
||||
}
|
||||
// endregion FML Life Cycle handlers
|
||||
|
||||
// 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);
|
||||
@@ -137,19 +150,9 @@ public class TransformerRegistry {
|
||||
world);
|
||||
for (Function<BlockConversionInfo, Boolean> 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;
|
||||
}
|
||||
|
||||
@@ -160,24 +163,20 @@ public class TransformerRegistry {
|
||||
int id = IDExtenderCompat.getItemStackID(tag);
|
||||
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 (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
|
||||
// non-transformed block!");
|
||||
return;
|
||||
if (data != null && !data.getValue()
|
||||
.isEmpty()) {
|
||||
// apply handlers
|
||||
for (BiFunction<String, NBTTagCompound, Boolean> transformer : data.getValue()) {
|
||||
if (transformer.apply(data.getKey(), tag)) {
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
public static Collection<TriFunction<NBTTagCompound, World, Chunk, BlockInfo>> getTileEntityToNormalBlockTransformerFunction(
|
||||
String tileEntityId) {
|
||||
return TILE_ENTITY_REPLACEMENT_MAP.get(tileEntityId);
|
||||
}
|
||||
// endregion transformation handlers
|
||||
}
|
||||
@@ -8,7 +8,8 @@
|
||||
"mixins": [
|
||||
"MixinAnvilChunkLoader",
|
||||
"MixinChunk",
|
||||
"MixinItemStack"
|
||||
"MixinItemStack",
|
||||
"MixinNBTTagList"
|
||||
],
|
||||
"client": [],
|
||||
"server": []
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
{
|
||||
"required": true,
|
||||
"minVersion": "0.8.5-GTNH",
|
||||
"package": "com.gtnewhorizons.postea.mixins.preinit",
|
||||
"plugin": "com.gtnewhorizons.postea.mixins.PosteaPreInitLoadingPlugin",
|
||||
"refmap": "mixins.postea.refmap.json",
|
||||
"target": "@env(DEFAULT)",
|
||||
"target": "@env(PREINIT)",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"mixins": [],
|
||||
"client": [],
|
||||
|
||||
Reference in new issue
Block a user