Files
Postea/src/main/java/com/gtnewhorizons/postea/ExampleMigrators.java
T

350 lines
16 KiB
Java
Raw Normal View History

2026-01-30 20:06:37 -05:00
package com.gtnewhorizons.postea;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraftforge.oredict.OreDictionary;
import com.gtnewhorizons.postea.api.BlockAccessCompat;
import com.gtnewhorizons.postea.api.BlockReplacementManager;
import com.gtnewhorizons.postea.api.IDExtenderCompat;
import com.gtnewhorizons.postea.api.ItemStackReplacementManager;
import com.gtnewhorizons.postea.api.TileEntityReplacementManager;
import com.gtnewhorizons.postea.utility.BlockConversionInfo;
import com.gtnewhorizons.postea.utility.BlockInfo;
import cpw.mods.fml.common.registry.GameRegistry;
abstract class ExampleMigrators {
static void postLoad() {
TEToBlockExample.postLoad();
TEModifyExample.postLoad();
TEFullReplacementExample.postLoad();
SimpleTransformationExample.postLoad();
ComplexBlockTransformer.postLoad();
ComplexItemTransformer.postLoad();
FMLReMappingExample.postLoad();
}
public static abstract class TEToBlockExample {
public static void postLoad() {
// it's with great shame that we do admit that gregtech ores used to be tile entities.
TileEntityReplacementManager.tileEntityTransformer("GT_TileEntity_Ores", (tag, world, chunk) -> {
if (world.provider.dimensionId == -1) {
// nether gets orange wool
return new BlockInfo(Blocks.wool, 1);
}
if (world.provider.dimensionId == 1) {
// the end gets magenta wool
return new BlockInfo(Blocks.wool, 2);
}
// all other dimensions get light blue wool
return new BlockInfo(Blocks.wool, 3);
});
}
}
public static abstract class TEModifyExample {
private static int reedsId = -1;
private static int diamondId = -1;
private static int stoneId = -1;
private static int record11Id = -1;
public static void postLoad() {
// pre caching ids like this will lead to faster transformers
ItemStackReplacementManager.registerIDResolver("minecraft:reeds", i -> reedsId = i);
ItemStackReplacementManager.registerIDResolver("minecraft:diamond", i -> diamondId = i);
ItemStackReplacementManager.registerIDResolver("minecraft:stone", i -> stoneId = i);
TileEntityReplacementManager.tileEntityTransformer("Chest", (tag, world, chunk) -> {
// This transformer replaces all sugar cane stacks inside a chest with
// stone, unless it's in the 13th slot at which point it's replaced with
// diamonds. All transformations are done without affecting the stack size.
NBTTagList slots = tag.getTagList("Items", 10);
for (int i = 0; i < slots.tagCount(); i++) {
NBTTagCompound slot = slots.getCompoundTagAt(i);
// only target the removed item
if (IDExtenderCompat.getItemStackID(slot) != reedsId) continue;
if (slot.getByte("Slot") == 13) {
// replace it with diamonds if it's in slot 13
IDExtenderCompat.setItemStackID(slot, diamondId);
} else {
// else replace it with stone.
IDExtenderCompat.setItemStackID(slot, stoneId);
}
}
return null;
});
// this tile entity transformer also executes because the other transformer returned null
ItemStackReplacementManager.registerIDResolver("minecraft:record_11", i -> record11Id = i);
byte targetSLot = (byte) 12;
TileEntityReplacementManager.tileEntityTransformer("Chest", (tag, world, chunk) -> {
// This transformer looks for the 12th slot of the chest and replaces
// or sets it's content to a new stack of record 11 with a stack size of 1.
NBTTagList slots = tag.getTagList("Items", 10);
NBTTagCompound toEdit = null;
for (int i = 0; i < slots.tagCount(); i++) {
NBTTagCompound slot = slots.getCompoundTagAt(i);
if (slot.getByte("Slot") != targetSLot) continue;
toEdit = slot;
break;
}
if (toEdit == null) {
toEdit = new NBTTagCompound();
toEdit.setByte("Slot", targetSLot);
slots.appendTag(toEdit);
}
toEdit.setByte("Count", (byte) 1);
toEdit.setShort("Damage", (short) 0);
IDExtenderCompat.setItemStackID(toEdit, record11Id);
return null;
});
}
}
public static abstract class TEFullReplacementExample {
public static int litFurnaceId = -1;
public static int unlitFurnaceId = -1;
public static int fireChargeId = -1;
public static void postLoad() {
BlockReplacementManager.registerIDResolver("minecraft:lit_furnace", i -> litFurnaceId = i);
BlockReplacementManager.registerIDResolver("minecraft:furnace", i -> unlitFurnaceId = i);
ItemStackReplacementManager.registerIDResolver("minecraft:fire_charge", i -> fireChargeId = i);
TileEntityReplacementManager.tileEntityTransformer("Furnace", TEFullReplacementExample::transformFurnace);
}
/**
* This transformer transforms a furnace into a chest, and adds a fire charge in the 4th slot of the chest if
* the block where the tile entity once stood was a lit furnace. If it's not either a lit or unlit furnace,
* the block is simply transformed into air.
*
* @param tag The NBT data of the tile entity being transformed.
* @param world The world in which the tile entity is located.
* @param chunk The chunk in which the tile entity is located.
* @return Null if we didn't update the block, else a BlockInfo with the transformation data you wish to
* execute.
*/
private static BlockInfo transformFurnace(NBTTagCompound tag, World world, Chunk chunk) {
int[] blockIdAndMeta = BlockAccessCompat.getBlockIDAndMetaAtTE(tag, chunk);
int blockId = blockIdAndMeta[0];
int meta = blockIdAndMeta[1];
// we return a value this time because we are actually replacing the block and tile entity.
// we copy the meta value since that preserves the orientation for these blocks.
return new BlockInfo(Blocks.chest, meta, oldTag -> transformFurnaceNBT(oldTag, blockId));
}
/**
* Moves the content of the furnace to the chest and adds a fire charge in the 4th slot if the furnace was lit.
*
* @param oldTag The current NBT data ofthe tile entity being transformed.
* @return null if we want the tile entity to be erased.
*/
private static NBTTagCompound transformFurnaceNBT(NBTTagCompound oldTag, int blockId) {
// if the block wasn't a furnace, clear the current tile entity and let the chest spawn a new one.
if (blockId != litFurnaceId && blockId != unlitFurnaceId) {
return null;
}
// use this function to create a new tile entity tag with the same positional data as the old one.
NBTTagCompound newTag = TileEntityReplacementManager.createTETagAtSamePosition("Chest", oldTag);
NBTTagList newSlots = (NBTTagList) oldTag.getTagList("Items", 10)
.copy();
// if the block used to be a lit furnace add a fire charge in the 4th slot.
if (blockId == litFurnaceId) {
NBTTagCompound fireChargeStack = new NBTTagCompound();
IDExtenderCompat.setItemStackID(fireChargeStack, fireChargeId);
fireChargeStack.setByte("Slot", (byte) 4);
fireChargeStack.setByte("Count", (byte) 1);
fireChargeStack.setShort("Damage", (short) 0);
newSlots.appendTag(fireChargeStack);
}
newTag.setTag("Items", newSlots);
return newTag;
}
}
public static abstract class SimpleTransformationExample {
public static void postLoad() {
// item/block -> item/block, preserving the Meta/Damage value.
//
// remap all block and items of colored stone blocks with wool of the same color
BlockReplacementManager.addSimpleReplacement("ExtraUtilities:colorStoneBrick", Blocks.wool);
// Item/Block with meta -> Item/Block, meta preserved
//
// angel ring:3 to disk 11
ItemStackReplacementManager
.addSimpleReplacement("ExtraUtilities:angelRing", 3, new ItemStack(Items.record_11));
ItemStackReplacementManager
.addSimpleReplacement("ExtraUtilities:angelRing", 4, new ItemStack(Items.record_13));
// Item/Block with meta -> Item/Block with specific meta
//
// remap all compressed cobble to oak planks
//
// When using a stack as a target the passed stack size is ignored, only the contained item and meta value
// are kept.
ItemStackReplacementManager
.addSimpleReplacement("ExtraUtilities:cobblestone_compressed", 0, new ItemStack(Blocks.planks, 0, 0));
// block only with meta -> block with specific meta value.
//
// remap blocks of double compressed cobble to cobble.
BlockReplacementManager
.addSimpleReplacement("ExtraUtilities:cobblestone_compressed", 1, Blocks.cobblestone, 0, true);
// item only with damage -> item only with specific damage value.
//
// remap stacks of double compressed cobble to oak saplings.
ItemStackReplacementManager.addSimpleReplacement(
"ExtraUtilities:cobblestone_compressed",
1,
new ItemStack(Blocks.sapling, 1, 0),
true);
// Block/Item with any Meta/Damage -> Block/Item with specific Meta/Damage value.
//
// Using OreDictionary.WILDCARD_VALUE will tell postea to use this mapping as a fallback when there is no
// transformer targeting the specific meta/damage value of the block/item.
//
// remap all other instances of compressed blocks to endstone
BlockReplacementManager.addSimpleReplacement(
"ExtraUtilities:cobblestone_compressed",
OreDictionary.WILDCARD_VALUE,
Blocks.end_stone,
0);
// Block/Item with any Meta/Damage -> Block/Item, preserving the Meta/Damage value.
//
// When passing OreDictionary.WILDCARD_VALUE as the target Meta/Damage value, Postea will preserve any
// existing
// Meta/Damage value. This is also the default value when you don't specify a target meta value.
//
// remap all other instances of compressed blocks to endstone
BlockReplacementManager.addSimpleReplacement(
"ExtraUtilities:cobblestone_compressed",
OreDictionary.WILDCARD_VALUE,
Blocks.end_stone,
OreDictionary.WILDCARD_VALUE);
}
}
public static abstract class ComplexBlockTransformer {
private static int woolId = -1;
public static void postLoad() {
// This transformer replaces all grass blocks with even x-coordinates with orange wool.
BlockReplacementManager.registerIDResolver("minecraft:wool", i -> woolId = i);
BlockReplacementManager
.addTransformationHandler("minecraft:grass", ComplexBlockTransformer::transformGrass);
}
private static boolean transformGrass(BlockConversionInfo info) {
// only affect blocks that are on even x coordinates
if (info.x % 2 != 0) return false;
// transform all these blocks into orange wool.
info.blockID = woolId;
info.metadata = 1;
return true;
}
}
public static abstract class ComplexItemTransformer {
private static int writableBookId = -1;
private static int woolId = -1;
private static void postLoad() {
ItemStackReplacementManager.registerIDResolver("minecraft:writable_book", i -> writableBookId = i);
ItemStackReplacementManager.registerIDResolver("minecraft:wool", i -> woolId = i);
ItemStackReplacementManager
.addTransformationHandler("minecraft:written_book", ComplexItemTransformer::unsignBook);
}
/**
* This transformer transforms a written book into either an unsigned book or orange wool depending on it's
* title.
*
* @param name The name of the item being transformed, even if that item doesn't exist anymore.
* @param nbt The NBT data of the stack item being transformed.
* @return True if we've actually transformed the item.
*/
private static boolean unsignBook(String name, NBTTagCompound nbt) {
// check if the book has a title.
if (!nbt.hasKey("tag", 10)) return false;
NBTTagCompound tag = nbt.getCompoundTag("tag");
if (!tag.hasKey("title", 8)) return false;
String title = tag.getString("title");
if (title.equalsIgnoreCase("unsign me")) {
// unsign the book
IDExtenderCompat.setItemStackID(nbt, writableBookId);
nbt.setShort("Damage", (short) 0);
nbt.setByte("Count", (byte) 1);
// clear the signed book nbt
tag.removeTag("title");
tag.removeTag("author");
return true;
} else if (title.equalsIgnoreCase("orange wool")) {
// Transform it into orange wool.
IDExtenderCompat.setItemStackID(nbt, woolId);
nbt.setShort("Damage", (short) 1);
nbt.setByte("Count", (byte) 1);
// removes the NBT tag from the stack.
nbt.removeTag("tag");
return true;
}
return false;
}
}
public static abstract class FMLReMappingExample {
// You have to make your own block class since the block constructor is protected.
public static class MyBlock extends Block {
protected MyBlock() {
super(Material.ground);
}
}
public static void postLoad() {
// this only works when the thing you're replacing with has never been registered to a world's
// id map. If you try to run this with a block that already exists (eg good old dirt), FML error out and
// you that your world is corrupted beyond repair, and advise you to undo what ever you just did.
//
// Postea Simple Transformers don't have that issue and are more lag friendly in the long term. Consider
// using them when ever possible, instead of FML mappings.
Item item = new Item();
GameRegistry.registerItem(item, "my_item");
ItemStackReplacementManager.replaceMissingMapping("IC2:itemFertilizer", item);
Block block = new MyBlock();
GameRegistry.registerBlock(block, "my_block");
BlockReplacementManager.replaceMissingMapping("IC2:blockCrop", block);
}
}
public static abstract class FMLIgnoreMissingMappingExample {
public static void postLoad() {
// It doesn't really matter which one you use, they both do the same thing under the hood.
ItemStackReplacementManager.ignoreMissingMapping("IC2:itemFertilizer");
BlockReplacementManager.ignoreMissingMapping("IC2:blockCrop");
}
}
}