diff --git a/README.md b/README.md index f7dcfca..1de8bfe 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,8 @@ BlockReplacementManager.addBlockReplacement("minecraft:grass", blockTransformer) ```java Function itemTransformer = (tag) -> { - tag.setShort("id", (short) Item.getIdFromItem(Items.gold_ingot)); + // Use the utility method for compatibility with NEID/EndlessIDs + IDExtenderCompat.setItemStackID(tag, Item.getIdFromItem(Items.gold_ingot)); return tag; }; diff --git a/dependencies.gradle b/dependencies.gradle index 37d47bb..860ceac 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -1,5 +1,7 @@ dependencies { - api('com.github.GTNewHorizons:NotEnoughIds:2.1.6:dev') api("com.github.GTNewHorizons:GTNHLib:0.6.21:dev") + compileOnly('com.github.GTNewHorizons:NotEnoughIds:2.1.6:dev') + compileOnly('com.falsepattern:chunkapi-mc1.7.10:0.6.0:dev') + compileOnly('com.falsepattern:endlessids-mc1.7.10:1.6.0:dev') } diff --git a/repositories.gradle b/repositories.gradle index 033d07f..5a81f49 100644 --- a/repositories.gradle +++ b/repositories.gradle @@ -1,5 +1,12 @@ // Add any additional repositories for your dependencies here repositories { + maven { + name = "mavenpattern" + url = "https://mvn.falsepattern.com/releases" + content { + group("com.falsepattern") + } + } mavenLocal() } diff --git a/src/main/java/com/gtnewhorizons/postea/api/IDExtenderCompat.java b/src/main/java/com/gtnewhorizons/postea/api/IDExtenderCompat.java new file mode 100644 index 0000000..41f756b --- /dev/null +++ b/src/main/java/com/gtnewhorizons/postea/api/IDExtenderCompat.java @@ -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); + } + } +} diff --git a/src/main/java/com/gtnewhorizons/postea/compat/Compat.java b/src/main/java/com/gtnewhorizons/postea/compat/Compat.java new file mode 100644 index 0000000..f025da4 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/postea/compat/Compat.java @@ -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; + } +} diff --git a/src/main/java/com/gtnewhorizons/postea/compat/SubChunkAccess.java b/src/main/java/com/gtnewhorizons/postea/compat/SubChunkAccess.java new file mode 100644 index 0000000..a5b9e03 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/postea/compat/SubChunkAccess.java @@ -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); +} diff --git a/src/main/java/com/gtnewhorizons/postea/mixins/early/MixinAnvilChunkLoader.java b/src/main/java/com/gtnewhorizons/postea/mixins/early/MixinAnvilChunkLoader.java index 32860de..927356d 100644 --- a/src/main/java/com/gtnewhorizons/postea/mixins/early/MixinAnvilChunkLoader.java +++ b/src/main/java/com/gtnewhorizons/postea/mixins/early/MixinAnvilChunkLoader.java @@ -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 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 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 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( diff --git a/src/main/java/com/gtnewhorizons/postea/utility/ChunkFixerUtility.java b/src/main/java/com/gtnewhorizons/postea/utility/ChunkFixerUtility.java index 36fd694..04a414b 100644 --- a/src/main/java/com/gtnewhorizons/postea/utility/ChunkFixerUtility.java +++ b/src/main/java/com/gtnewhorizons/postea/utility/ChunkFixerUtility.java @@ -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 conversionInfoList) { - if (ebs instanceof final IExtendedBlockStorageMixin ebsMixin) { int sectionY = ebs.getYLocation(); List 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); } } diff --git a/src/main/java/com/gtnewhorizons/postea/utility/ItemFixerUtility.java b/src/main/java/com/gtnewhorizons/postea/utility/ItemFixerUtility.java index 0699f23..e8cb46b 100644 --- a/src/main/java/com/gtnewhorizons/postea/utility/ItemFixerUtility.java +++ b/src/main/java/com/gtnewhorizons/postea/utility/ItemFixerUtility.java @@ -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 + ":"