Compat patches for Vanilla/ChunkAPI/EndlessIDs (#8)

This commit is contained in:
FalsePattern authored and GitHub committed 2025-05-01 11:08:07 -04:00
1 parent 0999b44caf
commit 46877823aa
9 files changed
+270 -68

No files matched your search

@@ -0,0 +1,25 @@
package com.gtnewhorizons.postea.api;
import static net.minecraftforge.common.util.Constants.NBT.TAG_INT;
import static net.minecraftforge.common.util.Constants.NBT.TAG_SHORT;
import net.minecraft.nbt.NBTTagCompound;
public class IDExtenderCompat {
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");
else if (tag.hasKey("id", TAG_SHORT)) return tag.getShort("id");
else return 0;
}
public static void setItemStackID(NBTTagCompound tag, int id) {
if (id < 32000) {
tag.setShort("id", (short) id);
} else {
tag.setShort("id", (short) 0);
tag.setInteger("idExt", id);
}
}
}
@@ -0,0 +1,168 @@
package com.gtnewhorizons.postea.compat;
import net.minecraft.launchwrapper.Launch;
import net.minecraft.world.chunk.NibbleArray;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import com.falsepattern.endlessids.mixin.helpers.SubChunkBlockHook;
import com.gtnewhorizons.neid.mixins.interfaces.IExtendedBlockStorageMixin;
public class Compat {
private static Boolean chunkapi = null;
private static Boolean endlessids = null;
private static Boolean neid = null;
public static boolean chunkapiPresent() {
if (chunkapi == null) {
boolean present = false;
try {
present = Launch.classLoader.getClassBytes("com.falsepattern.chunk.internal.core.CoreLoadingPlugin")
!= null;
} catch (Throwable ignored) {}
chunkapi = present;
}
return chunkapi;
}
public static boolean endlessidsPresent() {
if (endlessids == null) {
boolean present = false;
try {
present = Launch.classLoader.getClassBytes("com.falsepattern.endlessids.asm.EndlessIDsCore") != null;
} catch (Throwable ignored) {}
endlessids = present;
}
return endlessids;
}
public static boolean neidPresent() {
if (neid == null) {
boolean present = false;
try {
present = Launch.classLoader.getClassBytes("com.gtnewhorizons.neid.core.NEIDCore") != null;
} catch (Throwable ignored) {}
neid = present;
}
return neid;
}
public static SubChunkAccess getSubChunkAccess(ExtendedBlockStorage subChunk) {
if (endlessidsPresent()) {
return EndlessIDSCompat.getSubChunkAccess(subChunk);
} else if (neidPresent()) {
return NEIDCompat.getSubChunkAccess(subChunk);
} else {
return VanillaCompat.getSubChunkAccess(subChunk);
}
}
private static class VanillaCompat {
public static SubChunkAccess getSubChunkAccess(ExtendedBlockStorage subChunk) {
final byte[] lsb = subChunk.getBlockLSBArray();
return new SubChunkAccess() {
private NibbleArray msb = subChunk.getBlockMSBArray();
@Override
public int getBlockId(int x, int y, int z) {
int i = toIndex(x, y, z);
int id = lsb[i] & 0xFF;
if (msb != null) {
id |= msb.get(x, y, z) << 8;
}
return id;
}
@Override
public void setBlockId(int x, int y, int z, int id) {
int i = toIndex(x, y, z);
int l = id & 0xFF;
int h = (id >>> 8) & 0xF;
lsb[i] = (byte) l;
if (h == 0 && msb == null) return;
if (msb == null) {
msb = new NibbleArray(lsb.length, 4);
subChunk.setBlockMSBArray(msb);
}
msb.set(x, y, z, h);
}
@Override
public int getMeta(int x, int y, int z) {
return subChunk.getExtBlockMetadata(x, y, z);
}
@Override
public void setMeta(int x, int y, int z, int meta) {
subChunk.setExtBlockMetadata(x, y, z, meta);
}
};
}
}
private static class EndlessIDSCompat {
public static SubChunkAccess getSubChunkAccess(ExtendedBlockStorage subChunk) {
final SubChunkBlockHook bh = (SubChunkBlockHook) subChunk;
return new SubChunkAccess() {
@Override
public int getBlockId(int x, int y, int z) {
return bh.eid$getID(x, y, z);
}
@Override
public void setBlockId(int x, int y, int z, int id) {
bh.eid$setID(x, y, z, id);
}
@Override
public int getMeta(int x, int y, int z) {
return bh.eid$getMetadata(x, y, z);
}
@Override
public void setMeta(int x, int y, int z, int meta) {
bh.eid$setMetadata(x, y, z, meta);
}
};
}
}
private static class NEIDCompat {
public static SubChunkAccess getSubChunkAccess(ExtendedBlockStorage subChunk) {
final IExtendedBlockStorageMixin bh = (IExtendedBlockStorageMixin) subChunk;
final short[] blockArray = bh.getBlock16BArray();
final short[] metaArray = bh.getBlock16BMetaArray();
return new SubChunkAccess() {
@Override
public int getBlockId(int x, int y, int z) {
return blockArray[toIndex(x, y, z)];
}
@Override
public void setBlockId(int x, int y, int z, int id) {
blockArray[toIndex(x, y, z)] = (short) id;
}
@Override
public int getMeta(int x, int y, int z) {
return metaArray[toIndex(x, y, z)];
}
@Override
public void setMeta(int x, int y, int z, int meta) {
metaArray[toIndex(x, y, z)] = (short) meta;
}
};
}
}
private static int toIndex(int x, int y, int z) {
return y << 8 | z << 4 | x;
}
}
@@ -0,0 +1,12 @@
package com.gtnewhorizons.postea.compat;
public interface SubChunkAccess {
int getBlockId(int x, int y, int z);
void setBlockId(int x, int y, int z, int id);
int getMeta(int x, int y, int z);
void setMeta(int x, int y, int z, int meta);
}
@@ -16,39 +16,26 @@ import com.gtnewhorizons.postea.mixins.interfaces.IChunkMixin;
import com.gtnewhorizons.postea.utility.ChunkFixerUtility;
import com.llamalad7.mixinextras.sugar.Local;
@Mixin(AnvilChunkLoader.class)
@Mixin(value = AnvilChunkLoader.class, priority = 1100)
public abstract class MixinAnvilChunkLoader {
@Inject(
method = "readChunkFromNBT",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/nbt/NBTTagCompound;getIntArray(Ljava/lang/String;)[I",
ordinal = 0),
require = 1)
private void postea$readPosteaChunkCode(CallbackInfoReturnable<Chunk> cir, @Local Chunk chunk,
@Local(ordinal = 0) NBTTagCompound tag) {
// This hook is compatible with Vanilla/NEID/EIDs
@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"));
}
}
@Inject(
method = "readChunkFromNBT",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;setBlockMetadataArray(Lnet/minecraft/world/chunk/NibbleArray;)V",
shift = At.Shift.AFTER),
require = 1)
private void postea$transformBlocks(CallbackInfoReturnable<Chunk> cir, @Local World world, @Local Chunk chunk,
@Local ExtendedBlockStorage ebs) {
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.transformNormalBlocks(chunk, ebs, world);
for (ExtendedBlockStorage ebs : chunk.getBlockStorageArray()) {
if (ebs == null) {
continue;
}
ChunkFixerUtility.transformNormalBlocks(chunk, ebs, world);
}
}
@Inject(
@@ -16,9 +16,10 @@ import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import com.gtnewhorizons.neid.mixins.interfaces.IExtendedBlockStorageMixin;
import com.gtnewhorizons.postea.api.BlockReplacementManager;
import com.gtnewhorizons.postea.api.TileEntityReplacementManager;
import com.gtnewhorizons.postea.compat.Compat;
import com.gtnewhorizons.postea.compat.SubChunkAccess;
import akka.japi.Pair;
import cpw.mods.fml.common.registry.GameRegistry;
@@ -38,46 +39,45 @@ public class ChunkFixerUtility {
int sectionY = ebs.getYLocation();
IExtendedBlockStorageMixin ebsMixin = (IExtendedBlockStorageMixin) ebs;
short[] blockArray = ebsMixin.getBlock16BArray();
short[] metadataArray = ebsMixin.getBlock16BMetaArray();
SubChunkAccess access = Compat.getSubChunkAccess(ebs);
for (int index = 0; index < blockArray.length; index++) {
int blockId = blockArray[index];
int metadata = metadataArray[index];
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
int blockId = access.getBlockId(x, y, z);
int metadata = access.getMeta(x, y, z);
// Skip air.
if (blockId == AIR_ID) continue;
// If this block has no registered Postea conversion, skip it.
if (blockNotConvertible(blockId)) continue;
// Skip air.
if (blockId == AIR_ID) continue;
// If this block has no registered Postea conversion, skip it.
if (blockNotConvertible(blockId)) continue;
// Cache block names to improve performance, as findUniqueIdentifierFor is expensive.
Block block = Block.getBlockById(blockId);
String blockName = loadedBlocks.computeIfAbsent(
block,
b -> GameRegistry.findUniqueIdentifierFor(b)
.toString());
// Cache block names to improve performance, as findUniqueIdentifierFor is expensive.
Block block = Block.getBlockById(blockId);
String blockName = loadedBlocks.computeIfAbsent(
block,
b -> GameRegistry.findUniqueIdentifierFor(b)
.toString());
BlockConversionInfo blockConversionInfo = new BlockConversionInfo();
blockConversionInfo.blockName = blockName;
blockConversionInfo.blockID = blockId;
blockConversionInfo.metadata = (byte) metadata; // Updated
BlockConversionInfo blockConversionInfo = new BlockConversionInfo();
blockConversionInfo.blockName = blockName;
blockConversionInfo.blockID = blockId;
blockConversionInfo.metadata = (byte) metadata; // Updated
blockConversionInfo.world = world;
blockConversionInfo.world = world;
int x = index % 16;
int y = (index / 256) + sectionY;
int z = (index / 16) % 16;
blockConversionInfo.x = x + chunkXPos + 1;
blockConversionInfo.y = y + sectionY;
blockConversionInfo.z = z + chunkZPos + 1;
blockConversionInfo.x = x + chunkXPos + 1;
blockConversionInfo.y = y;
blockConversionInfo.z = z + chunkZPos + 1;
BlockConversionInfo output = BlockReplacementManager
.getBlockReplacement(blockConversionInfo, world);
BlockConversionInfo output = BlockReplacementManager.getBlockReplacement(blockConversionInfo, world);
if (output != null) {
blockArray[index] = (short) output.blockID;
metadataArray[index] = (short) output.metadata;
if (output != null) {
access.setBlockId(x, y, z, output.blockID);
access.setMeta(x, y, z, output.metadata);
}
}
}
}
}
@@ -95,25 +95,24 @@ public class ChunkFixerUtility {
}
for (ExtendedBlockStorage ebs : chunk.getBlockStorageArray()) {
if (ebs == null) continue;
processSection(ebs, conversionInfoList);
}
}
private static void processSection(ExtendedBlockStorage ebs, List<ConversionInfo> conversionInfoList) {
if (ebs instanceof final IExtendedBlockStorageMixin ebsMixin) {
int sectionY = ebs.getYLocation();
List<ConversionInfo> filteredList = conversionInfoList.stream()
.filter(info -> info.y >= sectionY && info.y < (sectionY + 16))
.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);
}
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);
}
}
@@ -5,6 +5,7 @@ import java.util.function.Function;
import net.minecraft.item.Item;
import net.minecraft.nbt.NBTTagCompound;
import com.gtnewhorizons.postea.api.IDExtenderCompat;
import com.gtnewhorizons.postea.api.ItemStackReplacementManager;
import cpw.mods.fml.common.registry.GameRegistry;
@@ -16,7 +17,7 @@ public abstract class ItemFixerUtility {
if (tag.hasNoTags()) return;
if (tag.hasKey("id")) {
short id = tag.getShort("id");
int id = IDExtenderCompat.getItemStackID(tag);
Item item = Item.getItemById(id);
if (item == null) return;
String itemNameInternal = GameRegistry.findUniqueIdentifierFor(item).modId + ":"