diff --git a/src/main/java/com/falsepattern/endlessids/EndlessIDs.java b/src/main/java/com/falsepattern/endlessids/EndlessIDs.java index 5889254..6fa105c 100644 --- a/src/main/java/com/falsepattern/endlessids/EndlessIDs.java +++ b/src/main/java/com/falsepattern/endlessids/EndlessIDs.java @@ -1,10 +1,14 @@ package com.falsepattern.endlessids; import cpw.mods.fml.common.Mod; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; @Mod(modid = Tags.MODID, version = Tags.VERSION, name = Tags.MODNAME, acceptedMinecraftVersions = "[1.7.10]", dependencies = "required-after:falsepatternlib@[0.8.2,);") -public class EndlessIDs {} +public class EndlessIDs { + public static final Logger LOG = LogManager.getLogger(Tags.MODNAME); +} diff --git a/src/main/java/com/falsepattern/endlessids/constants/ExtendedConstants.java b/src/main/java/com/falsepattern/endlessids/constants/ExtendedConstants.java index 5ecebfd..3092ae7 100644 --- a/src/main/java/com/falsepattern/endlessids/constants/ExtendedConstants.java +++ b/src/main/java/com/falsepattern/endlessids/constants/ExtendedConstants.java @@ -29,7 +29,8 @@ public class ExtendedConstants { //BiomeIDs public static final int biomeIDCount = 1 << bitsPerBiome; - public static final int maxBiomeID = biomeIDCount - 1; + public static final int biomeIDMask = biomeIDCount - 1; + public static final int biomeIDNull = biomeIDMask; public static final int bytesPerBiome = (bitsPerBiome + 7) / 8; //DataWatcher diff --git a/src/main/java/com/falsepattern/endlessids/constants/VanillaConstants.java b/src/main/java/com/falsepattern/endlessids/constants/VanillaConstants.java index 80bdc0b..2207aff 100644 --- a/src/main/java/com/falsepattern/endlessids/constants/VanillaConstants.java +++ b/src/main/java/com/falsepattern/endlessids/constants/VanillaConstants.java @@ -27,7 +27,8 @@ public class VanillaConstants { //BiomeIDs public static final int biomeIDCount = 1 << bitsPerBiome; - public static final int maxBiomeID = biomeIDCount - 1; + public static final int biomeIDMask = biomeIDCount - 1; + public static final int biomeIDNull = biomeIDMask; public static final int bytesPerBiome = (bitsPerBiome + 7) / 8; //DataWatcher diff --git a/src/main/java/com/falsepattern/endlessids/mixin/helpers/IChunkMixin.java b/src/main/java/com/falsepattern/endlessids/mixin/helpers/IChunkMixin.java index 3bfe6da..5a53f68 100644 --- a/src/main/java/com/falsepattern/endlessids/mixin/helpers/IChunkMixin.java +++ b/src/main/java/com/falsepattern/endlessids/mixin/helpers/IChunkMixin.java @@ -1,6 +1,9 @@ package com.falsepattern.endlessids.mixin.helpers; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; + public interface IChunkMixin { short[] getBiomeShortArray(); void setBiomeShortArray(short[] data); + ExtendedBlockStorage _getBlockStorageArray(int index); } 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..404e191 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/vanilla/storage/ChunkMixin.java @@ -0,0 +1,76 @@ +package com.falsepattern.endlessids.mixin.mixins.common.vanilla.storage; + +import com.falsepattern.endlessids.EndlessIDs; +import com.falsepattern.endlessids.Tags; +import com.falsepattern.endlessids.constants.ExtendedConstants; +import com.falsepattern.endlessids.mixin.helpers.IChunkMixin; +import lombok.val; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraft.world.biome.WorldChunkManager; +import net.minecraft.world.chunk.Chunk; +import org.spongepowered.asm.mixin.Final; +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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.Arrays; + +@Mixin(Chunk.class) +public abstract class ChunkMixin implements IChunkMixin { + @Shadow private byte[] blockBiomeArray; + @Shadow @Final public int xPosition; + @Shadow @Final public int zPosition; + private short[] blockBiomeShortArray; + + @Inject(method = "(Lnet/minecraft/world/World;II)V", + at = @At(value = "RETURN"), + require = 1) + private void initShortArray(World p_i1995_1_, int p_i1995_2_, int p_i1995_3_, CallbackInfo ci) { + blockBiomeArray = null; + blockBiomeShortArray = new short[16 * 16]; + Arrays.fill(blockBiomeShortArray, (short)-1); + } + + private void emergencyCrash() { + val crashMSG = "A mod that is incompatible with " + Tags.MODNAME + " has tried to access the biome array of a" + + " chunk like in vanilla! Crashing in fear of potential world corruption!\n" + + "Please report this issue on https://github.com/FalsePattern/EndlessIDs ASAP!"; + EndlessIDs.LOG.fatal(crashMSG); + throw new UnsupportedOperationException(crashMSG); + } + + @Inject(method = "setBiomeArray", + at = @At(value = "HEAD"), + require = 1) + private void crashSetBiomeArray(byte[] p_76616_1_, CallbackInfo ci) { + emergencyCrash(); + } + + @Inject(method = "getBiomeArray", + at = @At(value = "HEAD"), + require = 1) + private void crashGetBiomeArray(CallbackInfoReturnable cir) { + emergencyCrash(); + } + + /** + * @author FalsePattern + * @reason Direct port from dumped code + */ + @Overwrite + public BiomeGenBase getBiomeGenForWorldCoords(int x, int z, WorldChunkManager manager) { + int id = this.blockBiomeShortArray[z << 4 | x] & ExtendedConstants.biomeIDMask; + if (id == ExtendedConstants.biomeIDNull) { + BiomeGenBase gen = manager.getBiomeGenAt((this.xPosition << 4) + x, (this.zPosition << 4) + z); + id = gen.biomeID; + this.blockBiomeShortArray[z << 4 | x] = (short) (id & ExtendedConstants.biomeIDMask); + } + + return BiomeGenBase.getBiome(id) == null ? BiomeGenBase.plains : BiomeGenBase.getBiome(id); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/vanilla/worldgen/ChunkProviderEndMixin.java b/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/vanilla/worldgen/ChunkProviderEndMixin.java new file mode 100644 index 0000000..591f819 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/vanilla/worldgen/ChunkProviderEndMixin.java @@ -0,0 +1,52 @@ +package com.falsepattern.endlessids.mixin.mixins.common.vanilla.worldgen; + +import com.falsepattern.endlessids.mixin.helpers.IChunkMixin; +import net.minecraft.block.Block; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.gen.ChunkProviderEnd; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.Iterator; +import java.util.Random; + +@Mixin(ChunkProviderEnd.class) +public abstract class ChunkProviderEndMixin { + + @Shadow private Random endRNG; + + @Shadow private BiomeGenBase[] biomesForGeneration; + + @Shadow private World endWorld; + + @Shadow public abstract void func_147420_a(int p_147420_1_, int p_147420_2_, Block[] p_147420_3_, BiomeGenBase[] p_147420_4_); + + @Shadow public abstract void replaceBiomeBlocks(int p_147421_1_, int p_147421_2_, Block[] p_147421_3_, BiomeGenBase[] p_147421_4_, byte[] meta); + + /** + * @author FalsePattern + * @reason Direct port from decompiled code + */ + @Overwrite + public Chunk provideChunk(int p_73154_1_, int p_73154_2_) { + this.endRNG.setSeed((long)p_73154_1_ * 341873128712L + (long)p_73154_2_ * 132897987541L); + Block[] var3 = new Block[32768]; + byte[] var4 = new byte[var3.length]; + this.biomesForGeneration = this.endWorld.getWorldChunkManager().loadBlockGeneratorData(this.biomesForGeneration, p_73154_1_ * 16, p_73154_2_ * 16, 16, 16); + this.func_147420_a(p_73154_1_, p_73154_2_, var3, this.biomesForGeneration); + this.replaceBiomeBlocks(p_73154_1_, p_73154_2_, var3, this.biomesForGeneration, var4); + Chunk var5 = new Chunk(this.endWorld, var3, var4, p_73154_1_, p_73154_2_); + @SuppressWarnings("ConstantConditions") //Mixin moment + short[] var6 = ((IChunkMixin)var5).getBiomeShortArray(); + + for(int var7 = 0; var7 < var6.length; ++var7) { + var6[var7] = (short)this.biomesForGeneration[var7].biomeID; + } + + var5.generateSkylightMap(); + return var5; + } +} diff --git a/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/vanilla/worldgen/ChunkProviderFlatMixin.java b/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/vanilla/worldgen/ChunkProviderFlatMixin.java new file mode 100644 index 0000000..b15e69c --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/vanilla/worldgen/ChunkProviderFlatMixin.java @@ -0,0 +1,64 @@ +package com.falsepattern.endlessids.mixin.mixins.common.vanilla.worldgen; + +import com.sk89q.worldedit.world.chunk.Chunk; +import net.minecraft.block.Block; +import net.minecraft.world.World; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; +import net.minecraft.world.gen.ChunkProviderFlat; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.Iterator; + +@Mixin(ChunkProviderFlat.class) +public abstract class ChunkProviderFlatMixin { + @Shadow private World worldObj; + + @Shadow @Final private Block[] cachedBlockIDs; + + @Overwrite + public Chunk provideChunk(int var1, int var2) { + Chunk var3 = new Chunk(this.worldObj, var1, var2); + + int var6; + for(int var4 = 0; var4 < this.cachedBlockIDs.length; ++var4) { + Block var5 = this.cachedBlockIDs[var4]; + if (var5 != null) { + var6 = var4 >> 4; + ExtendedBlockStorage var7 = var3.getBlockStorageArray()[var6]; + if (var7 == null) { + var7 = new ExtendedBlockStorage(var4, !this.worldObj.provider.hasNoSky); + var3.getBlockStorageArray()[var6] = var7; + } + + for(int var8 = 0; var8 < 16; ++var8) { + for(int var9 = 0; var9 < 16; ++var9) { + var7.setExtBlockID(var8, var4 & 15, var9, var5); + var7.setExtBlockMetadata(var8, var4 & 15, var9, this.cachedBlockMetadata[var4]); + } + } + } + } + + var3.generateSkylightMap(); + BiomeGenBase[] var10 = this.worldObj.getWorldChunkManager().loadBlockGeneratorData((BiomeGenBase[])null, var1 * 16, var2 * 16, 16, 16); + short[] var11 = var3.getBiomeShortArray(); + + for(var6 = 0; var6 < var11.length; ++var6) { + var11[var6] = (short)var10[var6].biomeID; + } + + Iterator var12 = this.structureGenerators.iterator(); + + while(var12.hasNext()) { + MapGenBase var13 = (MapGenBase)var12.next(); + var13.generate(this, this.worldObj, var1, var2, (Block[])null); + } + + var3.generateSkylightMap(); + return var3; + } + +}