diff --git a/src/main/java/com/gtnewhorizons/postea/api/BlockNameAndMeta.java b/src/main/java/com/gtnewhorizons/postea/api/BlockNameAndMeta.java new file mode 100644 index 0000000..18f02ca --- /dev/null +++ b/src/main/java/com/gtnewhorizons/postea/api/BlockNameAndMeta.java @@ -0,0 +1,22 @@ +package com.gtnewhorizons.postea.api; + +/** + * A block referenced by its namespaced id, together with a meta value. Returned by + * {@link BlockReplacementManager#transformBlock(String, int)}. + */ +public final class BlockNameAndMeta { + + /** + * The namespaced id of the block. + */ + public final String name; + /** + * The meta value of the block. + */ + public final int metadata; + + public BlockNameAndMeta(String name, int metadata) { + this.name = name; + this.metadata = metadata; + } +} diff --git a/src/main/java/com/gtnewhorizons/postea/api/BlockReplacementManager.java b/src/main/java/com/gtnewhorizons/postea/api/BlockReplacementManager.java index 168362d..a25af50 100644 --- a/src/main/java/com/gtnewhorizons/postea/api/BlockReplacementManager.java +++ b/src/main/java/com/gtnewhorizons/postea/api/BlockReplacementManager.java @@ -3,6 +3,7 @@ package com.gtnewhorizons.postea.api; import java.util.function.Consumer; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import net.minecraft.block.Block; import net.minecraftforge.oredict.OreDictionary; @@ -54,6 +55,32 @@ public abstract class BlockReplacementManager { // endregion custom transformer registration + // region lookup + + /** + * Runs the block transformers registered for the given id on a block that isn't placed in the world, and returns + * what it would be transformed into.
+ *
+ * This is meant for mods that store blocks by their namespaced id inside their own NBT (e.g.: blocks that are + * made out of other blocks), which Postea can't reach while converting chunks. Calling this when such a block is + * loaded applies every migration registered to Postea to it. + * + * @apiNote Only call this while a world is loaded, transformers rely on the numeric ids resolved for that world. + * The transformers are given a {@link com.gtnewhorizons.postea.utility.BlockConversionInfo} without a + * world, and with all coordinates set to 0. Tile entity transformers are not run. + * + * @param name The namespaced id of the block. + * @param metadata The meta value of the block. + * @return The namespaced id and meta value of the block to use instead, or null if no transformer applies. + */ + @SuppressWarnings("unused") + public static @Nullable BlockNameAndMeta transformBlock(@Nonnull String name, int metadata) { + if (name == null) throw new NullPointerException("name cannot be null"); + return TransformerRegistry.transformBlock(name, metadata); + } + + // endregion lookup + // region id resolving // spotless:off diff --git a/src/main/java/com/gtnewhorizons/postea/utility/TransformerRegistry.java b/src/main/java/com/gtnewhorizons/postea/utility/TransformerRegistry.java index 8655e7c..1fbd0ae 100644 --- a/src/main/java/com/gtnewhorizons/postea/utility/TransformerRegistry.java +++ b/src/main/java/com/gtnewhorizons/postea/utility/TransformerRegistry.java @@ -6,6 +6,7 @@ import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.block.Block; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; @@ -13,6 +14,7 @@ import net.minecraft.world.chunk.Chunk; import org.apache.commons.lang3.tuple.Pair; import com.google.common.collect.LinkedListMultimap; +import com.gtnewhorizons.postea.api.BlockNameAndMeta; import com.gtnewhorizons.postea.api.IBlockTransformationHandler; import com.gtnewhorizons.postea.api.IDExtenderCompat; import com.gtnewhorizons.postea.api.IItemStackTransformationHandler; @@ -20,6 +22,7 @@ import com.gtnewhorizons.postea.api.TriFunction; import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.LoaderState; +import cpw.mods.fml.common.registry.GameData; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; /** @@ -156,6 +159,32 @@ public class TransformerRegistry { return null; } + public static @Nullable BlockNameAndMeta transformBlock(@Nonnull String name, int metadata) { + List handlers = BLOCK_REPLACEMENT_MAP.get(name); + if (handlers.isEmpty()) return null; + // there is no position nor world, the block isn't placed anywhere + BlockConversionInfo blockConversionInfo = new BlockConversionInfo( + name, + IDRegistry.getBlockId(name), + metadata, + 0, + 0, + 0, + null); + for (IBlockTransformationHandler transformer : handlers) { + if (transformer.apply(blockConversionInfo)) { + Block block = GameData.getBlockRegistry() + .getRaw(blockConversionInfo.blockID); + if (block == null) return null; + return new BlockNameAndMeta( + GameData.getBlockRegistry() + .getNameForObject(block), + blockConversionInfo.metadata); + } + } + return null; + } + public static void transformItem(NBTTagCompound tag) { // abort early if tag is bad. if (tag.hasNoTags() || !tag.hasKey("id")) return;