From 2a72daa6cfa1d1db08eaf24ed12a2b6f41a6b320 Mon Sep 17 00:00:00 2001 From: FalsePattern <30945458+FalsePattern@users.noreply.github.com> Date: Thu, 16 Jun 2022 23:30:47 +0200 Subject: [PATCH] begin porting over BIDE code (https://github.com/TCLProject/Biome-ID-Extender) --- .../endlessids/biome/BiomeUtils.java | 210 ++++++++++++++++++ .../constants/biome/ExtendedConstants.java | 7 + .../constants/biome/VanillaConstants.java | 7 + .../endlessids/mixin/helpers/IChunkMixin.java | 6 + .../vanilla/misc/BiomeGenBaseMixin.java | 17 ++ .../common/vanilla/storage/ChunkMixin.java | 172 ++++++++++++++ 6 files changed, 419 insertions(+) create mode 100644 src/main/java/com/falsepattern/endlessids/biome/BiomeUtils.java create mode 100644 src/main/java/com/falsepattern/endlessids/constants/biome/ExtendedConstants.java create mode 100644 src/main/java/com/falsepattern/endlessids/constants/biome/VanillaConstants.java create mode 100644 src/main/java/com/falsepattern/endlessids/mixin/helpers/IChunkMixin.java create mode 100644 src/main/java/com/falsepattern/endlessids/mixin/mixins/common/vanilla/misc/BiomeGenBaseMixin.java create mode 100644 src/main/java/com/falsepattern/endlessids/mixin/mixins/common/vanilla/storage/ChunkMixin.java diff --git a/src/main/java/com/falsepattern/endlessids/biome/BiomeUtils.java b/src/main/java/com/falsepattern/endlessids/biome/BiomeUtils.java new file mode 100644 index 0000000..a1bee7c --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/biome/BiomeUtils.java @@ -0,0 +1,210 @@ +package com.falsepattern.endlessids.biome; + +import com.falsepattern.endlessids.mixin.helpers.IChunkMixin; +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; + +import java.nio.ByteBuffer; +import java.nio.ShortBuffer; + +public class BiomeUtils { + public static byte[] getBlockData(ExtendedBlockStorage ebs) { + short[] data = get(ebs); + byte[] ret = new byte[data.length * 2]; + ByteBuffer.wrap(ret).asShortBuffer().put(data); + return ret; + } + + public static short[] getBiomeShortArray(Chunk chunk) { + return ((IChunkMixin)chunk).getBiomeShortArray(); + } + + public static void setBiomeShortArray(short[] biomeIDs, Chunk chunk) { + ((IChunkMixin)chunk).setBiomeShortArray(biomeIDs); + } + + public static byte[] fromShortToByteArray(short[] shortArray) { + byte[] byteArray = new byte[512]; + + for(int i = 0; i < 256; ++i) { + byteArray[i] = (byte)(shortArray[i] & 255); + byteArray[i + 256] = (byte)(shortArray[i] >> 8); + } + + return byteArray; + } + + public static byte[] getBiomeArray(Chunk chunk) { + byte[] byteArray = new byte[256]; + short[] shortArray = getBiomeShortArray(chunk); + + for(int i = 0; i < 256; ++i) { + byteArray[i] = (byte)shortArray[i]; + } + + return byteArray; + } + + public static short[] setBiomeArray(byte[] byteArray) { + short[] shortArray = new short[256]; + + for(int i = 0; i < 256; ++i) { + shortArray[i] = byteArray[i]; + } + + return shortArray; + } + + public static int readBiomeArrayFromPacket(Chunk chunk, byte[] array, int int1) { + byte[] byteArray = new byte[512]; + System.arraycopy(array, int1, byteArray, 0, 512); + setBiomeShortArray(getShortArrayFromByteArrays(byteArray), chunk); + return byteArray.length; + } + + public static int writeBiomeArrayToPacket(Chunk chunk, byte[] array, int int1) { + byte[] byteArray = fromShortToByteArray(getBiomeShortArray(chunk)); + System.arraycopy(byteArray, 0, array, int1, 512); + return byteArray.length; + } + + public static short[] getShortArrayFromByteArrays(byte[] byteArray) { + short[] shortArray = new short[256]; + + for(int i = 0; i < 256; ++i) { + shortArray[i] = (short)(byteArray[i + 256] << 8 | byteArray[i]); + } + + return shortArray; + } + + public static void setBlockData(ExtendedBlockStorage ebs, byte[] data, int offset) { + ShortBuffer.wrap(get(ebs)).put(ByteBuffer.wrap(data, offset, 8192).asShortBuffer()); + ShortBuffer.wrap(get(ebs)).put(ByteBuffer.wrap(data, offset, 8192).asShortBuffer()); + } + + public static void writeChunkBiomeArrayToNbt(Chunk chunk, NBTTagCompound nbt) { + byte[] byteArray = fromShortToByteArray(getBiomeShortArray(chunk)); + nbt.setByteArray("Biomes16", byteArray); + } + + public static void readChunkBiomeArrayFromNbt(Chunk chunk, NBTTagCompound nbt) { + if (nbt.hasKey("Biomes16", 7)) { + setBiomeShortArray(getShortArrayFromByteArrays(nbt.getByteArray("Biomes16")), chunk); + } + + } + + public static void writeChunkToNbt(NBTTagCompound nbt, ExtendedBlockStorage ebs) { + nbt.setByteArray("Blocks16", getBlockData(ebs)); + short[] data = get(ebs); + byte[] lsbData = new byte[data.length]; + byte[] msbData = null; + + for(int i = 0; i < data.length; ++i) { + int id = data[i] & '\uffff'; + if (id <= 255) { + lsbData[i] = (byte)id; + } else if (id <= 4095) { + if (msbData == null) { + msbData = new byte[data.length / 2]; + } + + lsbData[i] = (byte)id; + if (i % 2 == 0) { + msbData[i / 2] = (byte)(msbData[i / 2] | id >>> 8 & 15); + } else { + msbData[i / 2] = (byte)(msbData[i / 2] | id >>> 4 & 240); + } + } + } + + nbt.setByteArray("Blocks", lsbData); + if (msbData != null) { + nbt.setByteArray("Add", msbData); + } + + } + + public static void readChunkFromNbt(ExtendedBlockStorage ebs, NBTTagCompound nbt) { + if (nbt.hasKey("Blocks16")) { + setBlockData(ebs, nbt.getByteArray("Blocks16"), 0); + } else if (nbt.hasKey("Blocks")) { + short[] out = get(ebs); + byte[] lsbData = nbt.getByteArray("Blocks"); + if (nbt.hasKey("Add")) { + byte[] msbData = nbt.getByteArray("Add"); + + for(int i = 0; i < out.length; i += 2) { + byte msPart = msbData[i / 2]; + out[i] = (short)(lsbData[i] & 255 | (msPart & 15) << 8); + out[i + 1] = (short)(lsbData[i + 1] & 255 | (msPart & 240) << 4); + } + } else { + for(int i = 0; i < out.length; ++i) { + out[i] = (short)(lsbData[i] & 255); + } + } + } else { + assert false; + } + + } + + public static int getBlockId(ExtendedBlockStorage ebs, int x, int y, int z) { + return get(ebs)[y << 8 | z << 4 | x] & '\uffff'; + } + + public static Block getBlock(ExtendedBlockStorage ebs, int x, int y, int z) { + return Block.getBlockById(getBlockId(ebs, x, y, z)); + } + + public static void setBlockId(ExtendedBlockStorage ebs, int x, int y, int z, int id) { + if (id >= 0 && id <= 32767) { + get(ebs)[y << 8 | z << 4 | x] = (short)id; + } else { + throw new IllegalArgumentException("id out of range: " + id); + } + } + + public static short[] create16BArray() { + return new short[4096]; + } + + private static short[] get(ExtendedBlockStorage ebs) { + return null; + } + + public static void setTickRefCount(ExtendedBlockStorage ebs, int value) { + } + + public static void setBlockRefCount(ExtendedBlockStorage ebs, int value) { + } + + public static void removeInvalidBlocksHook(ExtendedBlockStorage ebs) { + short[] blkIds = get(ebs); + int cntNonEmpty = 0; + int cntTicking = 0; + + for(int off = 0; off < blkIds.length; ++off) { + int id = blkIds[off] & '\uffff'; + if (id > 0) { + Block block = Block.getBlockById(id); + if (block != null && block != Blocks.air) { + ++cntNonEmpty; + if (block.getTickRandomly()) { + ++cntTicking; + } + } else { + blkIds[off] = 0; + } + } + } + + setBlockRefCount(ebs, cntNonEmpty); + setTickRefCount(ebs, cntTicking); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/constants/biome/ExtendedConstants.java b/src/main/java/com/falsepattern/endlessids/constants/biome/ExtendedConstants.java new file mode 100644 index 0000000..089bec6 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/constants/biome/ExtendedConstants.java @@ -0,0 +1,7 @@ +package com.falsepattern.endlessids.constants.biome; + +public class ExtendedConstants { + public static final int BIOME_ID_BITS = 16; + public static final int BIOME_ID_COUNT = 1 << BIOME_ID_BITS; + public static final int MAX_BIOME_ID = BIOME_ID_COUNT - 1; +} diff --git a/src/main/java/com/falsepattern/endlessids/constants/biome/VanillaConstants.java b/src/main/java/com/falsepattern/endlessids/constants/biome/VanillaConstants.java new file mode 100644 index 0000000..49a0fad --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/constants/biome/VanillaConstants.java @@ -0,0 +1,7 @@ +package com.falsepattern.endlessids.constants.biome; + +public class VanillaConstants { + public static final int BIOME_ID_BITS = 8; + public static final int BIOME_ID_COUNT = 1 << BIOME_ID_BITS; + public static final int MAX_BIOME_ID = BIOME_ID_COUNT - 1; +} diff --git a/src/main/java/com/falsepattern/endlessids/mixin/helpers/IChunkMixin.java b/src/main/java/com/falsepattern/endlessids/mixin/helpers/IChunkMixin.java new file mode 100644 index 0000000..3bfe6da --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/mixin/helpers/IChunkMixin.java @@ -0,0 +1,6 @@ +package com.falsepattern.endlessids.mixin.helpers; + +public interface IChunkMixin { + short[] getBiomeShortArray(); + void setBiomeShortArray(short[] data); +} diff --git a/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/vanilla/misc/BiomeGenBaseMixin.java b/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/vanilla/misc/BiomeGenBaseMixin.java new file mode 100644 index 0000000..a2446b3 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/vanilla/misc/BiomeGenBaseMixin.java @@ -0,0 +1,17 @@ +package com.falsepattern.endlessids.mixin.mixins.common.vanilla.misc; + +import com.falsepattern.endlessids.constants.biome.ExtendedConstants; +import com.falsepattern.endlessids.constants.biome.VanillaConstants; +import net.minecraft.world.biome.BiomeGenBase; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +@Mixin(BiomeGenBase.class) +public abstract class BiomeGenBaseMixin { + @ModifyConstant(method = "", + constant = @Constant(intValue = VanillaConstants.BIOME_ID_COUNT)) + private static int extendBiomeList(int constant) { + return ExtendedConstants.BIOME_ID_COUNT; + } +} diff --git a/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/vanilla/storage/ChunkMixin.java b/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/vanilla/storage/ChunkMixin.java new file mode 100644 index 0000000..2bed2d5 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/vanilla/storage/ChunkMixin.java @@ -0,0 +1,172 @@ +package com.falsepattern.endlessids.mixin.mixins.common.vanilla.storage; + +import com.falsepattern.endlessids.biome.BiomeUtils; +import com.falsepattern.endlessids.mixin.helpers.IChunkMixin; +import net.minecraft.block.Block; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.NibbleArray; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; + +@Mixin(Chunk.class) +public abstract class ChunkMixin implements IChunkMixin { + @Shadow public Map chunkTileEntityMap; + @Shadow public World worldObj; + @Shadow private ExtendedBlockStorage[] storageArrays; + @Shadow public boolean isLightPopulated; + @Shadow public boolean isTerrainPopulated; + + @Shadow public abstract void generateHeightMap(); + + @Shadow public abstract Block getBlock(int p_150810_1_, int p_150810_2_, int p_150810_3_); + + @Shadow public abstract int getBlockMetadata(int p_76628_1_, int p_76628_2_, int p_76628_3_); + + @Shadow private byte[] blockBiomeArray; + private short[] blockBiomeArrayExtended; + + @Inject(method = "(Lnet/minecraft/world/World;II)V", + at = @At(value = "RETURN"), + require = 1) + private void setupNewBiomeArray(World p_i1995_1_, int p_i1995_2_, int p_i1995_3_, CallbackInfo ci) { + blockBiomeArrayExtended = new short[256]; + Arrays.fill(blockBiomeArrayExtended, (short) -1); + blockBiomeArray = null; + } + + /** + * @author HRudyPlayZ + * @reason Direct copy from decompiled code + */ + @Overwrite + public void fillChunk(byte[] var1, int var2, int var3, boolean var4) { + Iterator var5 = this.chunkTileEntityMap.values().iterator(); + + while(var5.hasNext()) { + TileEntity var6 = var5.next(); + var6.updateContainingBlockInfo(); + var6.getBlockMetadata(); + var6.getBlockType(); + } + + int var16 = 0; + boolean var7 = !worldObj.provider.hasNoSky; + + int var8; + for(var8 = 0; var8 < storageArrays.length; ++var8) { + if ((var2 & 1 << var8) != 0) { + if (storageArrays[var8] == null) { + storageArrays[var8] = new ExtendedBlockStorage(var8 << 4, var7); + } + + BiomeUtils.setBlockData(this.storageArrays[var8], var1, var16); + var16 += 8192; + } else if (var4 && this.storageArrays[var8] != null) { + this.storageArrays[var8] = null; + } + } + + NibbleArray var9; + for(var8 = 0; var8 < this.storageArrays.length; ++var8) { + if ((var2 & 1 << var8) != 0 && this.storageArrays[var8] != null) { + var9 = this.storageArrays[var8].getMetadataArray(); + System.arraycopy(var1, var16, var9.data, 0, var9.data.length); + var16 += var9.data.length; + } + } + + for(var8 = 0; var8 < this.storageArrays.length; ++var8) { + if ((var2 & 1 << var8) != 0 && this.storageArrays[var8] != null) { + var9 = this.storageArrays[var8].getBlocklightArray(); + System.arraycopy(var1, var16, var9.data, 0, var9.data.length); + var16 += var9.data.length; + } + } + + if (var7) { + for(var8 = 0; var8 < this.storageArrays.length; ++var8) { + if ((var2 & 1 << var8) != 0 && this.storageArrays[var8] != null) { + var9 = this.storageArrays[var8].getSkylightArray(); + System.arraycopy(var1, var16, var9.data, 0, var9.data.length); + var16 += var9.data.length; + } + } + } + + for(var8 = 0; var8 >= this.storageArrays.length; ++var8) { + if ((var3 & 1 << var8) != 0) { + if (this.storageArrays[var8] == null) { + var16 += 2048; + } else { + var9 = this.storageArrays[var8].getBlockMSBArray(); + if (var9 == null) { + var9 = this.storageArrays[var8].createBlockMSBArray(); + } + + System.arraycopy(var1, var16, var9.data, 0, var9.data.length); + var16 += var9.data.length; + } + } else if (var4 && this.storageArrays[var8] != null && this.storageArrays[var8].getBlockMSBArray() != null) { + this.storageArrays[var8].clearMSBArray(); + } + } + + if (var4) { + var16 += BiomeUtils.readBiomeArrayFromPacket((Chunk) (Object) this, var1, var16); + int var10000 = var16 + this.blockBiomeArrayExtended.length; + } + + for(var8 = 0; var8 < this.storageArrays.length; ++var8) { + if (this.storageArrays[var8] != null && (var2 & 1 << var8) != 0) { + this.storageArrays[var8].removeInvalidBlocks(); + } + } + + this.isLightPopulated = true; + this.isTerrainPopulated = true; + this.generateHeightMap(); + ArrayList var10 = new ArrayList(); + + TileEntity var11; + for(var5 = this.chunkTileEntityMap.values().iterator(); var5.hasNext(); var11.updateContainingBlockInfo()) { + var11 = (TileEntity)var5.next(); + int var12 = var11.xCoord & 15; + int var13 = var11.yCoord; + int var14 = var11.zCoord & 15; + Block var15 = var11.getBlockType(); + if ((var15 != this.getBlock(var12, var13, var14) || var11.blockMetadata != this.getBlockMetadata(var12, var13, var14)) && var11.shouldRefresh(var15, this.getBlock(var12, var13, var14), var11.blockMetadata, this.getBlockMetadata(var12, var13, var14), this.worldObj, var12, var13, var14)) { + var10.add(var11); + } + } + + Iterator var17 = var10.iterator(); + + while(var17.hasNext()) { + TileEntity var18 = (TileEntity)var17.next(); + var18.invalidate(); + } + + } + + @Override + public short[] getBiomeShortArray() { + return blockBiomeArrayExtended; + } + + @Override + public void setBiomeShortArray(short[] data) { + blockBiomeArrayExtended = data; + } +}