diff --git a/.gitignore b/.gitignore index 382cb21..5b704fa 100644 --- a/.gitignore +++ b/.gitignore @@ -144,3 +144,5 @@ gradle-app.setting .classpath # End of https://www.toptal.com/developers/gitignore/api/intellij+all,gradle,forgegradle,java + +srgmap.cfg \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 7a5b9f3..a740809 100644 --- a/gradle.properties +++ b/gradle.properties @@ -71,7 +71,7 @@ mixinsPackage = mixin.mixins # Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin! # This parameter is for legacy compatibility only # Example value: coreModClass = asm.FMLPlugin + modGroup = com.myname.mymodid -> com.myname.mymodid.asm.FMLPlugin -coreModClass = +coreModClass = IEPlugin # If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod ( = some class # that is annotated with @Mod) you want this to be true. When in doubt: leave it on false! containsMixinsAndOrCoreModOnly = false diff --git a/src/main/java/com/falsepattern/endlessids/Hooks.java b/src/main/java/com/falsepattern/endlessids/Hooks.java new file mode 100644 index 0000000..968de1c --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/Hooks.java @@ -0,0 +1,144 @@ +package com.falsepattern.endlessids; + +import com.falsepattern.endlessids.mixin.helpers.IExtendedBlockStorageMixin; +import net.minecraft.init.Blocks; +import net.minecraft.block.Block; +import net.minecraft.nbt.NBTTagCompound; +import java.nio.ShortBuffer; +import java.nio.ByteBuffer; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; + +public class Hooks +{ + public Hooks() { + super(); + } + + public static byte[] getBlockData(final IExtendedBlockStorageMixin ebs) { + final short[] data = ebs.get16B(); + final byte[] ret = new byte[data.length * 2]; + ByteBuffer.wrap(ret).asShortBuffer().put(data); + return ret; + } + + public static void setBlockData(final IExtendedBlockStorageMixin ebs, final byte[] data, final int offset) { + ShortBuffer.wrap(ebs.get16B()).put(ByteBuffer.wrap(data, offset, 8192).asShortBuffer()); + } + + public static void writeChunkToNbt(final NBTTagCompound nbt, final IExtendedBlockStorageMixin ebs) { + nbt.setByteArray("Blocks16", getBlockData(ebs)); + if (IEConfig.postNeidWorldsSupport) { + final short[] data = ebs.get16B(); + final byte[] lsbData = new byte[data.length]; + byte[] msbData = null; + for (int i = 0; i < data.length; ++i) { + final int id = data[i] & 0xFFFF; + 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) { + final byte[] array = msbData; + final int n = i / 2; + array[n] |= (byte)(id >>> 8 & 0xF); + } + else { + final byte[] array2 = msbData; + final int n2 = i / 2; + array2[n2] |= (byte)(id >>> 4 & 0xF0); + } + } + } + nbt.setByteArray("Blocks", lsbData); + if (msbData != null) { + nbt.setByteArray("Add", msbData); + } + } + } + + public static void readChunkFromNbt(final IExtendedBlockStorageMixin ebs, final NBTTagCompound nbt) { + if (nbt.hasKey("Blocks16")) { + setBlockData(ebs, nbt.getByteArray("Blocks16"), 0); + } + else if (nbt.hasKey("Blocks")) { + final short[] out = ebs.get16B(); + final byte[] lsbData = nbt.getByteArray("Blocks"); + if (nbt.hasKey("Add")) { + final byte[] msbData = nbt.getByteArray("Add"); + for (int i = 0; i < out.length; i += 2) { + final byte msPart = msbData[i / 2]; + out[i] = (short)((lsbData[i] & 0xFF) | (msPart & 0xF) << 8); + out[i + 1] = (short)((lsbData[i + 1] & 0xFF) | (msPart & 0xF0) << 4); + } + } + else { + for (int j = 0; j < out.length; ++j) { + out[j] = (short)(lsbData[j] & 0xFF); + } + } + } + else { + assert false; + } + } + + public static int getBlockId(final IExtendedBlockStorageMixin ebs, final int x, final int y, final int z) { + return ebs.get16B()[y << 8 | z << 4 | x] & 0xFFFF; + } + + public static Block getBlock(final IExtendedBlockStorageMixin ebs, final int x, final int y, final int z) { + return Block.getBlockById(getBlockId(ebs, x, y, z)); + } + + public static void setBlockId(final IExtendedBlockStorageMixin ebs, final int x, final int y, final int z, final int id) { + ebs.get16B()[y << 8 | z << 4 | x] = (short)id; + } + + public static short[] create16BArray() { + return new short[4096]; + } + + public static void removeInvalidBlocksHook(final IExtendedBlockStorageMixin ebs) { + final short[] blkIds = ebs.get16B(); + int cntNonEmpty = 0; + int cntTicking = 0; + for (int off = 0; off < blkIds.length; ++off) { + final int id = blkIds[off] & 0xFFFF; + if (id > 0) { + final Block block = (Block)Block.blockRegistry.getObjectById(id); + if (block == null) { + if (IEConfig.removeInvalidBlocks) { + blkIds[off] = 0; + } + } + else if (block != Blocks.air) { + ++cntNonEmpty; + if (block.getTickRandomly()) { + ++cntTicking; + } + } + } + } + ebs.setBlockRefCount(cntNonEmpty); + ebs.setTickRefCount(cntTicking); + } + + public static int getIdFromBlockWithCheck(final Block block, final Block oldBlock) { + final int id = Block.getIdFromBlock(block); + if (IEConfig.catchUnregisteredBlocks && id == -1) { + throw new IllegalArgumentException("Block " + block + " is not registered. <-- Say about this to the author of this mod, or you can try to enable \"RemoveInvalidBlocks\" option in NEID config."); + } + if (id >= 0 && id <= 32767) { + return id; + } + if (id == -1) { + return Block.getIdFromBlock(oldBlock); + } + throw new IllegalArgumentException("id out of range: " + id); + } + +} diff --git a/src/main/java/com/falsepattern/endlessids/IDExtender.java b/src/main/java/com/falsepattern/endlessids/IDExtender.java new file mode 100644 index 0000000..eb0f8da --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/IDExtender.java @@ -0,0 +1,25 @@ +package com.falsepattern.endlessids; + +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.registry.GameRegistry; +import net.minecraft.block.Block; +import net.minecraft.block.BlockIce; +import net.minecraft.creativetab.CreativeTabs; + +@Mod(modid = "notenoughIDs", name = "NotEnoughIDs", version = "1.4.3.4") +public class IDExtender +{ + public IDExtender() { + super(); + } + + @Mod.EventHandler + public void test(final FMLPreInitializationEvent event) { + for(int i = 0; i < 31658; i++){ + Block shield = new BlockIce().setBlockName(".shield" + i); + GameRegistry.registerBlock(shield, i + "ShieldBlock"); + shield.setCreativeTab(CreativeTabs.tabFood); + } + } +} diff --git a/src/main/java/com/falsepattern/endlessids/IEConfig.java b/src/main/java/com/falsepattern/endlessids/IEConfig.java new file mode 100644 index 0000000..ce56dfc --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/IEConfig.java @@ -0,0 +1,40 @@ +package com.falsepattern.endlessids; + +import java.io.File; +import net.minecraftforge.common.config.Configuration; + +public class IEConfig +{ + static Configuration config; + public static boolean catchUnregisteredBlocks; + public static boolean removeInvalidBlocks; + public static boolean postNeidWorldsSupport; + public static boolean extendDataWatcher; + + public IEConfig() { + super(); + } + + public static void init(final File file) { + File newFile; + if (file.getPath().contains("bin")) { + newFile = new File(file.getParent() + "/eclipse/config", "NEID.cfg"); + } + else { + newFile = new File(file.getParentFile().getParent() + "/config", "NEID.cfg"); + } + IEConfig.config = new Configuration(newFile); + IEConfig.catchUnregisteredBlocks = IEConfig.config.getBoolean("CatchUnregisteredBlocks", "NEID", false, ""); + IEConfig.removeInvalidBlocks = IEConfig.config.getBoolean("RemoveInvalidBlocks", "NEID", false, "Remove invalid (corrupted) blocks from the game."); + IEConfig.postNeidWorldsSupport = IEConfig.config.getBoolean("PostNeidWorldsSupport", "NEID", true, "If true, only blocks with IDs > 4095 will disappear after removing NEID."); + IEConfig.extendDataWatcher = IEConfig.config.getBoolean("ExtendDataWatcher", "NEID", false, "Extend DataWatcher IDs. Vanilla limit is 31, new limit is 127."); + IEConfig.config.save(); + } + + static { + IEConfig.catchUnregisteredBlocks = false; + IEConfig.removeInvalidBlocks = false; + IEConfig.postNeidWorldsSupport = true; + IEConfig.extendDataWatcher = false; + } +} diff --git a/src/main/java/com/falsepattern/endlessids/IEPlugin.java b/src/main/java/com/falsepattern/endlessids/IEPlugin.java new file mode 100644 index 0000000..1a97593 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/IEPlugin.java @@ -0,0 +1,37 @@ +package com.falsepattern.endlessids; + +import java.io.File; +import java.util.Map; + +import com.falsepattern.endlessids.asm.IETransformer; +import cpw.mods.fml.relauncher.IFMLLoadingPlugin; + +@IFMLLoadingPlugin.MCVersion("1.7.10") +@IFMLLoadingPlugin.TransformerExclusions({ "com.falsepattern.endlessids.asm" }) +public class IEPlugin implements IFMLLoadingPlugin +{ + public IEPlugin() { + super(); + } + + public String[] getASMTransformerClass() { + return new String[] { IETransformer.class.getName() }; + } + + public String getModContainerClass() { + return null; + } + + public String getSetupClass() { + return null; + } + + public void injectData(final Map data) { + IEConfig.init((File) data.get("coremodLocation")); + IETransformer.isObfuscated = (Boolean) data.get("runtimeDeobfuscationEnabled"); + } + + public String getAccessTransformerClass() { + return null; + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/AsmTransformException.java b/src/main/java/com/falsepattern/endlessids/asm/AsmTransformException.java new file mode 100644 index 0000000..6f396f6 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/AsmTransformException.java @@ -0,0 +1,18 @@ +package com.falsepattern.endlessids.asm; + +public class AsmTransformException extends RuntimeException +{ + private static final long serialVersionUID = 5128914670008752449L; + + public AsmTransformException(final String message) { + super(message); + } + + public AsmTransformException(final Throwable cause) { + super(cause); + } + + public AsmTransformException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/AsmUtil.java b/src/main/java/com/falsepattern/endlessids/asm/AsmUtil.java new file mode 100644 index 0000000..f3c613f --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/AsmUtil.java @@ -0,0 +1,183 @@ +package com.falsepattern.endlessids.asm; + +import java.io.PrintWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.util.Printer; +import org.objectweb.asm.util.TraceMethodVisitor; +import org.objectweb.asm.util.Textifier; +import org.objectweb.asm.tree.InsnList; +import java.util.ListIterator; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.IntInsnNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.ClassNode; + +public class AsmUtil +{ + public AsmUtil() { + super(); + } + + public static MethodNode findMethod(final ClassNode cn, final String name) { + return findMethod(cn, name, false); + } + + public static MethodNode findMethod(final ClassNode cn, final String name, final boolean optional) { + for (final MethodNode ret : cn.methods) { + if (ret.name.equals(name)) { + return ret; + } + } + if (optional) { + return null; + } + throw new MethodNotFoundException(name); + } + + public static MethodNode findMethod(final ClassNode cn, final Name name) { + return findMethod(cn, name, false); + } + + public static MethodNode findMethod(final ClassNode cn, final Name name, final boolean optional) { + for (final MethodNode ret : cn.methods) { + if (name.matches(ret)) { + return ret; + } + } + if (optional) { + return null; + } + throw new MethodNotFoundException(name.deobf); + } + + public static FieldNode findField(final ClassNode cn, final String name) { + return findField(cn, name, false); + } + + public static FieldNode findField(final ClassNode cn, final String name, final boolean optional) { + for (final FieldNode ret : cn.fields) { + if (name.equals(ret.name)) { + return ret; + } + } + if (optional) { + return null; + } + throw new FieldNotFoundException(name); + } + + public static FieldNode findField(final ClassNode cn, final Name name) { + return findField(cn, name, false); + } + + public static FieldNode findField(final ClassNode cn, final Name name, final boolean optional) { + for (final FieldNode ret : cn.fields) { + if (name.matches(ret)) { + return ret; + } + } + if (optional) { + return null; + } + throw new FieldNotFoundException(name.deobf); + } + + public static void makePublic(final MethodNode x) { + x.access = ((x.access & 0xFFFFFFF9) | 0x1); + } + + public static void makePublic(final FieldNode x) { + x.access = ((x.access & 0xFFFFFFF9) | 0x1); + } + + public static boolean transformInlinedSizeMethod(final ClassNode cn, final MethodNode method, final int oldValue, final int newValue) { + return transformInlinedSizeMethod(cn, method, oldValue, newValue, false); + } + + public static boolean transformInlinedSizeMethod(final ClassNode cn, final MethodNode method, final int oldValue, final int newValue, final boolean optional) { + boolean found = false; + boolean foundOnce = false; + final int i = 0; + final ListIterator it = (ListIterator)method.instructions.iterator(); + while (it.hasNext()) { + final AbstractInsnNode insn = it.next(); + if (insn.getOpcode() == 3 && oldValue == 0) { + found = true; + } + else if (insn.getOpcode() == 4 && oldValue == 1) { + found = true; + } + else if (insn.getOpcode() == 5 && oldValue == 2) { + found = true; + } + else if (insn.getOpcode() == 6 && oldValue == 3) { + found = true; + } + else if (insn.getOpcode() == 7 && oldValue == 4) { + found = true; + } + else if (insn.getOpcode() == 8 && oldValue == 5) { + found = true; + } + else if (insn.getOpcode() == 18) { + final LdcInsnNode node = (LdcInsnNode)insn; + if (node.cst instanceof Integer && (int)node.cst == oldValue) { + found = true; + } + } + else if (insn.getOpcode() == 17 || insn.getOpcode() == 16) { + final IntInsnNode node2 = (IntInsnNode)insn; + if (node2.operand == oldValue) { + found = true; + } + } + if (found) { + foundOnce = true; + if (newValue == 0) { + it.set(new InsnNode(3)); + } + else if (newValue == 1) { + it.set(new InsnNode(4)); + } + else if (newValue == 2) { + it.set(new InsnNode(5)); + } + else if (newValue == 3) { + it.set(new InsnNode(6)); + } + else if (newValue == 4) { + it.set(new InsnNode(7)); + } + else if (newValue == 5) { + it.set(new InsnNode(8)); + } + else if (newValue >= -128 && newValue <= 127) { + it.set(new IntInsnNode(16, newValue)); + } + else if (newValue >= -32768 && newValue <= 32767) { + it.set(new IntInsnNode(17, newValue)); + } + else { + it.set(new LdcInsnNode((Object)Integer.valueOf(newValue))); + } + found = false; + } + } + if (!foundOnce && !optional) { + throw new AsmTransformException("can't find constant value " + oldValue + " in method " + method.name); + } + return foundOnce; + } + + public static void dump(final InsnList list) { + final Textifier textifier = new Textifier(); + final TraceMethodVisitor visitor = new TraceMethodVisitor((Printer)textifier); + list.accept((MethodVisitor)visitor); + final PrintWriter writer = new PrintWriter(System.out); + textifier.print(writer); + writer.flush(); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/ClassEdit.java b/src/main/java/com/falsepattern/endlessids/asm/ClassEdit.java new file mode 100644 index 0000000..70c65f9 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/ClassEdit.java @@ -0,0 +1,82 @@ +package com.falsepattern.endlessids.asm; + +import java.util.HashMap; +import com.falsepattern.endlessids.asm.transformer.WorldEditBaseBlock; +import com.falsepattern.endlessids.asm.transformer.MFQM; +import com.falsepattern.endlessids.asm.transformer.UndergroundBiomesBiomeUndergroundDecorator; +import com.falsepattern.endlessids.asm.transformer.UndergroundBiomesOreUBifier; +import com.falsepattern.endlessids.asm.transformer.CofhBlockHelper; +import com.falsepattern.endlessids.asm.transformer.FmlRegistry; +import com.falsepattern.endlessids.asm.transformer.VanillaWorld; +import com.falsepattern.endlessids.asm.transformer.VanillaItemInWorldManager; +import com.falsepattern.endlessids.asm.transformer.VanillaPlayerControllerMP; +import com.falsepattern.endlessids.asm.transformer.VanillaRenderGlobal; +import com.falsepattern.endlessids.asm.transformer.VanillaS26PacketMapChunkBulk; +import com.falsepattern.endlessids.asm.transformer.VanillaS24PacketBlockActivation; +import com.falsepattern.endlessids.asm.transformer.VanillaS22PacketMultiBlockChange; +import com.falsepattern.endlessids.asm.transformer.VanillaS21PacketChunkData; +import com.falsepattern.endlessids.asm.transformer.VanillaNetHandlerPlayClient; +import com.falsepattern.endlessids.asm.transformer.VanillaDataWatcher; +import com.falsepattern.endlessids.asm.transformer.VanillaExtendedBlockStorage; +import com.falsepattern.endlessids.asm.transformer.VanillaChunk; +import com.falsepattern.endlessids.asm.transformer.VanillaAnvilChunkLoader; +import com.falsepattern.endlessids.asm.transformer.VanillaStatList; +import com.falsepattern.endlessids.asm.transformer.VanillaBlockFire; +import com.falsepattern.endlessids.asm.transformer.SelfHooks; +import java.util.Map; + +public enum ClassEdit +{ + //SelfHooks(new SelfHooks(), new String[] { "com.falsepattern.endlessids.Hooks" }), + VanillaBlockFire(new VanillaBlockFire(), new String[] { "net.minecraft.block.BlockFire" }), + VanillaStatList(new VanillaStatList(), new String[] { "net.minecraft.stats.StatList" }), + //VanillaAnvilChunkLoader(new VanillaAnvilChunkLoader(), new String[] { "net.minecraft.world.chunk.storage.AnvilChunkLoader" }), + //VanillaChunk(new VanillaChunk(), new String[] { "net.minecraft.world.chunk.Chunk" }), + //VanillaExtendedBlockStorage(new VanillaExtendedBlockStorage(), new String[] { "net.minecraft.world.chunk.storage.ExtendedBlockStorage" }), + VanillaDataWatcher(new VanillaDataWatcher(), new String[] { "net.minecraft.entity.DataWatcher" }), + VanillaNetHandlerPlayClient(new VanillaNetHandlerPlayClient(), new String[] { "net.minecraft.client.network.NetHandlerPlayClient" }), + //VanillaS21PacketChunkData(new VanillaS21PacketChunkData(), new String[] { "net.minecraft.network.play.server.S21PacketChunkData" }), + VanillaS22PacketMultiBlockChange(new VanillaS22PacketMultiBlockChange(), new String[] { "net.minecraft.network.play.server.S22PacketMultiBlockChange" }), + VanillaS24PacketBlockActivation(new VanillaS24PacketBlockActivation(), new String[] { "net.minecraft.network.play.server.S24PacketBlockAction" }), + VanillaS26PacketMapChunkBulk(new VanillaS26PacketMapChunkBulk(), new String[] { "net.minecraft.network.play.server.S26PacketMapChunkBulk" }), + VanillaRenderGlobal(new VanillaRenderGlobal(), new String[] { "net.minecraft.client.renderer.RenderGlobal" }), + VanillaPlayerControllerMP(new VanillaPlayerControllerMP(), new String[] { "net.minecraft.client.multiplayer.PlayerControllerMP" }), + VanillaItemInWorldManager(new VanillaItemInWorldManager(), new String[] { "net.minecraft.server.management.ItemInWorldManager" }), + //VanillaWorld(new VanillaWorld(), new String[] { "net.minecraft.world.World" }), + FmlRegistry(new FmlRegistry(), new String[] { "cpw.mods.fml.common.registry.GameData", "cpw.mods.fml.common.registry.FMLControlledNamespacedRegistry" }), + CofhBlockHelper(new CofhBlockHelper(), new String[] { "cofh.lib.util.helpers.BlockHelper" }), + UndergroundBiomesOreUBifier(new UndergroundBiomesOreUBifier(), new String[] { "exterminatorJeff.undergroundBiomes.worldGen.OreUBifier" }), + UndergroundBiomesBiomeUndergroundDecorator(new UndergroundBiomesBiomeUndergroundDecorator(), new String[] { "exterminatorJeff.undergroundBiomes.worldGen.BiomeUndergroundDecorator" }), + MFQM(new MFQM(), new String[] { "MoreFunQuicksandMod.main.MFQM" }), + WorldEditBaseBlock(new WorldEditBaseBlock(), new String[] { "com.sk89q.worldedit.blocks.BaseBlock" }); + + private static final Map editMap; + private final IClassNodeTransformer transformer; + private final String[] classNames; + + ClassEdit(final IClassNodeTransformer transformer, final String[] classNames) { + this.transformer = transformer; + this.classNames = classNames; + } + + public static ClassEdit get(final String className) { + return ClassEdit.editMap.get(className); + } + + public String getName() { + return this.name(); + } + + public IClassNodeTransformer getTransformer() { + return this.transformer; + } + + static { + editMap = new HashMap<>(); + for (final ClassEdit edit : values()) { + for (final String name : edit.classNames) { + ClassEdit.editMap.put(name, edit); + } + } + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/Constants.java b/src/main/java/com/falsepattern/endlessids/asm/Constants.java new file mode 100644 index 0000000..a3718ce --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/Constants.java @@ -0,0 +1,18 @@ +package com.falsepattern.endlessids.asm; + +public class Constants +{ + public static final int maxBlockId = 32767; + public static final int blockIdMask = 65535; + public static final int ebsIdArrayLength = 4096; + public static final int ebsIdArraySize = 8192; + public static final int vanillaEbsSize = 12288; + public static final int vanillaSize = 196864; + public static final int newEbsSize = 14336; + public static final int newSize = 229632; + public static final int maxDataWatcherId = 127; + + public Constants() { + super(); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/FieldNotFoundException.java b/src/main/java/com/falsepattern/endlessids/asm/FieldNotFoundException.java new file mode 100644 index 0000000..bc7f6c2 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/FieldNotFoundException.java @@ -0,0 +1,8 @@ +package com.falsepattern.endlessids.asm; + +public class FieldNotFoundException extends AsmTransformException +{ + public FieldNotFoundException(final String field) { + super("can't find field " + field); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/IClassNodeTransformer.java b/src/main/java/com/falsepattern/endlessids/asm/IClassNodeTransformer.java new file mode 100644 index 0000000..0b14ad5 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/IClassNodeTransformer.java @@ -0,0 +1,8 @@ +package com.falsepattern.endlessids.asm; + +import org.objectweb.asm.tree.ClassNode; + +public interface IClassNodeTransformer +{ + void transform(final ClassNode p0, final boolean p1); +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/IETransformer.java b/src/main/java/com/falsepattern/endlessids/asm/IETransformer.java new file mode 100644 index 0000000..9cbeac5 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/IETransformer.java @@ -0,0 +1,72 @@ +package com.falsepattern.endlessids.asm; + +import org.apache.logging.log4j.LogManager; +import org.objectweb.asm.util.CheckClassAdapter; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.ClassNode; +import org.apache.logging.log4j.Logger; +import net.minecraft.launchwrapper.IClassTransformer; + +public class IETransformer implements IClassTransformer +{ + private static final boolean enablePreVerification = false; + private static final boolean enablePostVerification = true; + public static final Logger logger; + public static boolean isObfuscated; + private static Boolean isClient; + + public IETransformer() { + super(); + } + + public byte[] transform(final String name, final String transformedName, final byte[] bytes) { + if (bytes == null) { + return bytes; + } + final ClassEdit edit = ClassEdit.get(transformedName); + if (edit == null) { + return bytes; + } + IETransformer.logger.debug("Patching {} with {}...", new Object[] { transformedName, edit.getName() }); + final ClassNode cn = new ClassNode(327680); + final ClassReader reader = new ClassReader(bytes); + final int readFlags = 0; + reader.accept((ClassVisitor)cn, 0); + try { + edit.getTransformer().transform(cn, IETransformer.isObfuscated); + } + catch (AsmTransformException t) { + IETransformer.logger.error("Error transforming {} with {}: {}", new Object[] { transformedName, edit.getName(), t.getMessage() }); + throw t; + } + catch (Throwable t2) { + IETransformer.logger.error("Error transforming {} with {}: {}", new Object[] { transformedName, edit.getName(), t2.getMessage() }); + throw new RuntimeException(t2); + } + final ClassWriter writer = new ClassWriter(0); + try { + final ClassVisitor check = (ClassVisitor)new CheckClassAdapter((ClassVisitor)writer); + cn.accept(check); + } + catch (Throwable t3) { + IETransformer.logger.error("Error verifying {} transformed with {}: {}", new Object[] { transformedName, edit.getName(), t3.getMessage() }); + throw new RuntimeException(t3); + } + IETransformer.logger.debug("Patched {} successfully.", new Object[] { edit.getName() }); + return writer.toByteArray(); + } + + public static boolean isClient() { + if (IETransformer.isClient == null) { + IETransformer.isClient = Boolean.valueOf(IETransformer.class.getResource("/net/minecraft/client/main/Main.class") != null); + } + return IETransformer.isClient; + } + + static { + logger = LogManager.getLogger("NEID"); + IETransformer.isClient = null; + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/MethodNotFoundException.java b/src/main/java/com/falsepattern/endlessids/asm/MethodNotFoundException.java new file mode 100644 index 0000000..31946b6 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/MethodNotFoundException.java @@ -0,0 +1,8 @@ +package com.falsepattern.endlessids.asm; + +public class MethodNotFoundException extends AsmTransformException +{ + public MethodNotFoundException(final String method) { + super("can't find method " + method); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/Name.java b/src/main/java/com/falsepattern/endlessids/asm/Name.java new file mode 100644 index 0000000..fc2dc6d --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/Name.java @@ -0,0 +1,205 @@ +package com.falsepattern.endlessids.asm; + +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.MethodNode; + +public enum Name +{ + hooks("com/falsepattern/endlessids/Hooks"), + hooks_create16BArray(Name.hooks, "create16BArray", null, null, "()[S"), + hooks_getBlockData(Name.hooks, "getBlockData", null, null, "(Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;)[B"), + hooks_setBlockData(Name.hooks, "setBlockData", null, null, "(Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;[BI)V"), + hooks_writeChunkToNbt(Name.hooks, "writeChunkToNbt", null, null, "(Lnet/minecraft/nbt/NBTTagCompound;Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;)V"), + hooks_readChunkFromNbt(Name.hooks, "readChunkFromNbt", null, null, "(Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;Lnet/minecraft/nbt/NBTTagCompound;)V"), + hooks_getBlockId(Name.hooks, "getBlockId", null, null, "(Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;III)I"), + hooks_getBlockById(Name.hooks, "getBlock", null, null, "(Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;III)Lnet/minecraft/block/Block;"), + hooks_setBlockId(Name.hooks, "setBlockId", null, null, "(Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;IIII)V"), + hooks_getIdFromBlockWithCheck(Name.hooks, "getIdFromBlockWithCheck", null, null, "(Lnet/minecraft/block/Block;Lnet/minecraft/block/Block;)I"), + acl("net/minecraft/world/chunk/storage/AnvilChunkLoader", "aqk"), + block("net/minecraft/block/Block", "aji"), + chunk("net/minecraft/world/chunk/Chunk", "apx"), + extendedBlockStorage("net/minecraft/world/chunk/storage/ExtendedBlockStorage", "apz"), + iChunkProvider("net/minecraft/world/chunk/IChunkProvider", "apu"), + nbtTagCompound("net/minecraft/nbt/NBTTagCompound", "dh"), + nhpc("net/minecraft/client/network/NetHandlerPlayClient", "bjb"), + nibbleArray("net/minecraft/world/chunk/NibbleArray", "apv"), + packet("net/minecraft/network/Packet", "ft"), + packetBuffer("net/minecraft/network/PacketBuffer", "et"), + s22("net/minecraft/network/play/server/S22PacketMultiBlockChange", "gk"), + s21("net/minecraft/network/play/server/S21PacketChunkData", "gx"), + s21_extracted("net/minecraft/network/play/server/S21PacketChunkData$Extracted", "gy"), + world("net/minecraft/world/World", "ahb"), + dataWatcher("net/minecraft/entity/DataWatcher", "te"), + dataWatcher_watchableObject("net/minecraft/entity/DataWatcher$WatchableObject", "tf"), + renderGlobal("net/minecraft/client/renderer/RenderGlobal", "bma"), + playerControllerMP("net/minecraft/client/multiplayer/PlayerControllerMP", "bje"), + itemInWorldManager("net/minecraft/server/management/ItemInWorldManager", "mx"), + entityPlayer("net/minecraft/entity/player/EntityPlayer", "yz"), + ebs_getBlock(Name.extendedBlockStorage, "getBlockByExtId", "a", "func_150819_a", "(III)Lnet/minecraft/block/Block;"), + ebs_setBlock(Name.extendedBlockStorage, "func_150818_a", "a", null, "(IIILnet/minecraft/block/Block;)V"), + ebs_getBlockLSBArray(Name.extendedBlockStorage, "getBlockLSBArray", "g", "func_76658_g", "()[B"), + ebs_getBlockMSBArray(Name.extendedBlockStorage, "getBlockMSBArray", "i", "func_76660_i", "()Lnet/minecraft/world/chunk/NibbleArray;"), + ebs_setBlockMSBArray(Name.extendedBlockStorage, "setBlockMSBArray", "a", "func_76673_a", "(Lnet/minecraft/world/chunk/NibbleArray;)V"), + ebs_isEmpty(Name.extendedBlockStorage, "isEmpty", "a", "func_76663_a", "()Z"), + ebs_removeInvalidBlocks(Name.extendedBlockStorage, "removeInvalidBlocks", "e", "func_76672_e", "()V"), + dataWatcher_addObject(Name.dataWatcher, "addObject", "a", "func_75682_a", "(ILjava/lang/Object;)V"), + dataWatcher_writeWatchableObjectToPacketBuffer(Name.dataWatcher, "writeWatchableObjectToPacketBuffer", "a", "func_151510_a", "(Lnet/minecraft/network/PacketBuffer;Lnet/minecraft/entity/DataWatcher$WatchableObject;)V"), + dataWatcher_readWatchedListFromPacketBuffer(Name.dataWatcher, "readWatchedListFromPacketBuffer", "b", "func_151508_b", "(Lnet/minecraft/network/PacketBuffer;)Ljava/util/List;"), + dataWatcher_writeWatchedListToPacketBuffer(Name.dataWatcher, "writeWatchedListToPacketBuffer", "a", "func_151507_a", "(Ljava/util/List;Lnet/minecraft/network/PacketBuffer;)V"), + dataWatcher_func_151509_a(Name.dataWatcher, "func_151509_a", "a", "func_151509_a", "(Lnet/minecraft/network/PacketBuffer;)V"), + ebs_blockRefCount(Name.extendedBlockStorage, "blockRefCount", "b", "field_76682_b", "I"), + ebs_tickRefCount(Name.extendedBlockStorage, "tickRefCount", "c", "field_76683_c", "I"), + acl_writeChunkToNBT(Name.acl, "writeChunkToNBT", "a", "func_75820_a", "(Lnet/minecraft/world/chunk/Chunk;Lnet/minecraft/world/World;Lnet/minecraft/nbt/NBTTagCompound;)V"), + acl_readChunkFromNBT(Name.acl, "readChunkFromNBT", "a", "func_75823_a", "(Lnet/minecraft/world/World;Lnet/minecraft/nbt/NBTTagCompound;)Lnet/minecraft/world/chunk/Chunk;"), + block_getIdFromBlock(Name.block, "getIdFromBlock", "b", "func_149682_b", "(Lnet/minecraft/block/Block;)I"), + chunk_fillChunk(Name.chunk, "fillChunk", "a", "func_76607_a", "([BIIZ)V"), + packet_readPacketData(Name.packet, "readPacketData", "a", "func_148837_a", "(Lnet/minecraft/network/PacketBuffer;)V"), + packet_writePacketData(Name.packet, "writePacketData", "b", "func_148840_b", "(Lnet/minecraft/network/PacketBuffer;)V"), + nhpc_handleMultiBlockChange(Name.nhpc, "handleMultiBlockChange", "a", "func_147287_a", "(Lnet/minecraft/network/play/server/S22PacketMultiBlockChange;)V"), + s22_init_server(Name.s22, "", null, null, "(I[SLnet/minecraft/world/chunk/Chunk;)V"), + s21_undefined1(Name.s21, "func_149275_c", "c", null, "()I"), + s21_undefined2(Name.s21, "func_149269_a", "a", null, "(Lnet/minecraft/world/chunk/Chunk;ZI)Lnet/minecraft/network/play/server/S21PacketChunkData$Extracted;"), + renderGlobal_playAuxSFX(Name.renderGlobal, "playAuxSFX", "a", "func_72706_a", "(Lnet/minecraft/entity/player/EntityPlayer;IIIII)V"), + playerControllerMP_onPlayerDestroyBlock(Name.playerControllerMP, "onPlayerDestroyBlock", "a", "func_78751_a", "(IIII)Z"), + itemInWorldManager_tryHarvestBlock(Name.itemInWorldManager, "tryHarvestBlock", "b", "func_73084_b", "(III)Z"), + world_breakBlock(Name.world, "func_147480_a", "a", null, "(IIIZ)Z"), + ub_bud("exterminatorJeff/undergroundBiomes/worldGen/BiomeUndergroundDecorator"), + ub_bud_replaceChunkOres_world(Name.ub_bud, "replaceChunkOres", null, null, "(IILnet/minecraft/world/World;)V"), + ub_bud_replaceChunkOres_iChunkProvider(Name.ub_bud, "replaceChunkOres", null, null, "(Lnet/minecraft/world/chunk/IChunkProvider;II)V"), + MFQM("MoreFunQuicksandMod/main/MFQM"), + MFQM_preInit(Name.MFQM, "preInit", null, null, "(Lcpw/mods/fml/common/event/FMLPreInitializationEvent;)V"); + + public final Name clazz; + public final String deobf; + public final String obf; + public final String srg; + public final String desc; + public String obfDesc; + + Name(final String deobf) { + this(deobf, deobf); + } + + Name(final String deobf, final String obf) { + this.clazz = null; + this.deobf = deobf; + this.obf = obf; + this.srg = deobf; + this.desc = null; + } + + Name(final Name clazz, final String deobf, final String obf, final String srg, final String desc) { + this.clazz = clazz; + this.deobf = deobf; + this.obf = ((obf != null) ? obf : deobf); + this.srg = ((srg != null) ? srg : deobf); + this.desc = desc; + } + + public boolean matches(final MethodNode x) { + assert this.desc.startsWith("("); + return (this.obf.equals(x.name) && this.obfDesc.equals(x.desc)) || (this.srg.equals(x.name) && this.desc.equals(x.desc)) || (this.deobf.equals(x.name) && this.desc.equals(x.desc)); + } + + public boolean matches(final FieldNode x) { + assert !this.desc.startsWith("("); + return (this.obf.equals(x.name) && this.obfDesc.equals(x.desc)) || (this.srg.equals(x.name) && this.desc.equals(x.desc)) || (this.deobf.equals(x.name) && this.desc.equals(x.desc)); + } + + public boolean matches(final MethodInsnNode x, final boolean obfuscated) { + assert this.desc.startsWith("("); + if (obfuscated) { + return (this.clazz.obf.equals(x.owner) && this.obf.equals(x.name) && this.obfDesc.equals(x.desc)) || (this.clazz.srg.equals(x.owner) && this.srg.equals(x.name) && this.desc.equals(x.desc)); + } + return this.clazz.deobf.equals(x.owner) && this.deobf.equals(x.name) && this.desc.equals(x.desc); + } + + public boolean matches(final FieldInsnNode x, final boolean obfuscated) { + assert !this.desc.startsWith("("); + if (obfuscated) { + return (this.clazz.obf.equals(x.owner) && this.obf.equals(x.name) && this.obfDesc.equals(x.desc)) || (this.clazz.srg.equals(x.owner) && this.srg.equals(x.name) && this.desc.equals(x.desc)); + } + return this.clazz.deobf.equals(x.owner) && this.deobf.equals(x.name) && this.desc.equals(x.desc); + } + + public MethodInsnNode staticInvocation(final boolean obfuscated) { + assert this.desc.startsWith("("); + if (obfuscated) { + return new MethodInsnNode(184, this.clazz.srg, this.srg, this.desc, false); + } + return new MethodInsnNode(184, this.clazz.deobf, this.deobf, this.desc, false); + } + + public MethodInsnNode virtualInvocation(final boolean obfuscated) { + assert this.desc.startsWith("("); + if (obfuscated) { + return new MethodInsnNode(182, this.clazz.srg, this.srg, this.desc, false); + } + return new MethodInsnNode(182, this.clazz.deobf, this.deobf, this.desc, false); + } + + public FieldInsnNode staticGet(final boolean obfuscated) { + assert !this.desc.startsWith("("); + if (obfuscated) { + return new FieldInsnNode(178, this.clazz.srg, this.srg, this.desc); + } + return new FieldInsnNode(178, this.clazz.deobf, this.deobf, this.desc); + } + + public FieldInsnNode virtualGet(final boolean obfuscated) { + assert !this.desc.startsWith("("); + if (obfuscated) { + return new FieldInsnNode(180, this.clazz.srg, this.srg, this.desc); + } + return new FieldInsnNode(180, this.clazz.deobf, this.deobf, this.desc); + } + + public FieldInsnNode staticSet(final boolean obfuscated) { + assert !this.desc.startsWith("("); + if (obfuscated) { + return new FieldInsnNode(179, this.clazz.srg, this.srg, this.desc); + } + return new FieldInsnNode(179, this.clazz.deobf, this.deobf, this.desc); + } + + public FieldInsnNode virtualSet(final boolean obfuscated) { + assert !this.desc.startsWith("("); + if (obfuscated) { + return new FieldInsnNode(181, this.clazz.srg, this.srg, this.desc); + } + return new FieldInsnNode(181, this.clazz.deobf, this.deobf, this.desc); + } + + private static void translateDescs() { + final StringBuilder sb = new StringBuilder(); + for (final Name name : values()) { + if (name.desc != null) { + int pos; + int endPos; + for (pos = 0, endPos = -1; (pos = name.desc.indexOf(76, pos)) != -1; pos = endPos + 1) { + sb.append(name.desc, endPos + 1, pos); + endPos = name.desc.indexOf(59, pos + 1); + String cName = name.desc.substring(pos + 1, endPos); + for (final Name name2 : values()) { + if (name2.deobf.equals(cName)) { + cName = name2.obf; + break; + } + } + sb.append('L'); + sb.append(cName); + sb.append(';'); + } + sb.append(name.desc, endPos + 1, name.desc.length()); + name.obfDesc = sb.toString(); + sb.setLength(0); + } + } + } + + static { + translateDescs(); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/CofhBlockHelper.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/CofhBlockHelper.java new file mode 100644 index 0000000..41d3c51 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/CofhBlockHelper.java @@ -0,0 +1,21 @@ +package com.falsepattern.endlessids.asm.transformer; + +import org.objectweb.asm.tree.MethodNode; +import com.falsepattern.endlessids.asm.AsmUtil; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class CofhBlockHelper implements IClassNodeTransformer +{ + public CofhBlockHelper() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + final MethodNode method = AsmUtil.findMethod(cn, ""); + if (!AsmUtil.transformInlinedSizeMethod(cn, method, 4096, 32768, true)) { + AsmUtil.transformInlinedSizeMethod(cn, method, 1024, 32768); + } + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/FmlRegistry.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/FmlRegistry.java new file mode 100644 index 0000000..a6a46c4 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/FmlRegistry.java @@ -0,0 +1,32 @@ +package com.falsepattern.endlessids.asm.transformer; + +import org.objectweb.asm.tree.FieldNode; +import com.falsepattern.endlessids.asm.AsmTransformException; +import org.objectweb.asm.tree.MethodNode; +import com.falsepattern.endlessids.asm.AsmUtil; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class FmlRegistry implements IClassNodeTransformer +{ + public FmlRegistry() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + final FieldNode field = AsmUtil.findField(cn, "MAX_BLOCK_ID", true); + if (field != null) { + field.value = Integer.valueOf(32767); + } + boolean found = false; + for (final MethodNode method : cn.methods) { + if (AsmUtil.transformInlinedSizeMethod(cn, method, 4095, 32767, true)) { + found = true; + } + } + if (!found) { + throw new AsmTransformException("can't find 4095 constant in any method"); + } + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/MFQM.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/MFQM.java new file mode 100644 index 0000000..45e16b6 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/MFQM.java @@ -0,0 +1,23 @@ +package com.falsepattern.endlessids.asm.transformer; + +import org.objectweb.asm.tree.MethodNode; +import com.falsepattern.endlessids.asm.AsmUtil; +import com.falsepattern.endlessids.asm.Name; +import com.falsepattern.endlessids.IEConfig; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class MFQM implements IClassNodeTransformer +{ + public MFQM() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + if (IEConfig.extendDataWatcher) { + final MethodNode method = AsmUtil.findMethod(cn, Name.MFQM_preInit); + AsmUtil.transformInlinedSizeMethod(cn, method, 31, 127); + } + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/SelfHooks.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/SelfHooks.java new file mode 100644 index 0000000..d8e2c26 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/SelfHooks.java @@ -0,0 +1,62 @@ +package com.falsepattern.endlessids.asm.transformer; + +import com.falsepattern.endlessids.asm.Name; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.VarInsnNode; +import org.objectweb.asm.tree.MethodNode; +import com.falsepattern.endlessids.asm.AsmUtil; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class SelfHooks implements IClassNodeTransformer +{ + public SelfHooks() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + MethodNode method = AsmUtil.findMethod(cn, "get"); + this.transformGet(cn, method); + method = AsmUtil.findMethod(cn, "setBlockRefCount"); + this.transformSetBlockRefCount(cn, method, obfuscated); + method = AsmUtil.findMethod(cn, "setTickRefCount"); + this.transformSetTickRefCount(cn, method, obfuscated); + } + + private void transformGet(final ClassNode cn, final MethodNode method) { + final InsnList code = method.instructions; + code.clear(); + code.add((AbstractInsnNode)new VarInsnNode(25, 0)); + code.add((AbstractInsnNode)new FieldInsnNode(180, Type.getArgumentTypes(method.desc)[0].getInternalName(), "block16BArray", "[S")); + code.add((AbstractInsnNode)new InsnNode(176)); + method.localVariables = null; + method.maxStack = 1; + } + + private void transformSetBlockRefCount(final ClassNode cn, final MethodNode method, final boolean isObf) { + final InsnList code = method.instructions; + code.clear(); + code.add((AbstractInsnNode)new VarInsnNode(25, 0)); + code.add((AbstractInsnNode)new VarInsnNode(21, 1)); + code.add((AbstractInsnNode)Name.ebs_blockRefCount.virtualSet(isObf)); + code.add((AbstractInsnNode)new InsnNode(177)); + method.localVariables = null; + method.maxStack = 2; + } + + private void transformSetTickRefCount(final ClassNode cn, final MethodNode method, final boolean isObf) { + final InsnList code = method.instructions; + code.clear(); + code.add((AbstractInsnNode)new VarInsnNode(25, 0)); + code.add((AbstractInsnNode)new VarInsnNode(21, 1)); + code.add((AbstractInsnNode)Name.ebs_tickRefCount.virtualSet(isObf)); + code.add((AbstractInsnNode)new InsnNode(177)); + method.localVariables = null; + method.maxStack = 2; + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/UndergroundBiomesBiomeUndergroundDecorator.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/UndergroundBiomesBiomeUndergroundDecorator.java new file mode 100644 index 0000000..9ea7d07 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/UndergroundBiomesBiomeUndergroundDecorator.java @@ -0,0 +1,46 @@ +package com.falsepattern.endlessids.asm.transformer; + +import java.util.ListIterator; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.VarInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; +import com.falsepattern.endlessids.asm.AsmUtil; +import com.falsepattern.endlessids.asm.Name; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class UndergroundBiomesBiomeUndergroundDecorator implements IClassNodeTransformer +{ + public UndergroundBiomesBiomeUndergroundDecorator() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + MethodNode method = AsmUtil.findMethod(cn, Name.ub_bud_replaceChunkOres_world); + this.transformReplaceChunkOres(cn, method, obfuscated, 1); + method = AsmUtil.findMethod(cn, Name.ub_bud_replaceChunkOres_iChunkProvider); + this.transformReplaceChunkOres(cn, method, obfuscated, 0); + } + + private void transformReplaceChunkOres(final ClassNode cn, final MethodNode method, final boolean obfuscated, final int varOffset) { + final InsnList code = method.instructions; + final ListIterator iterator = (ListIterator)code.iterator(); + while (iterator.hasNext()) { + final AbstractInsnNode insn = (AbstractInsnNode)iterator.next(); + if (insn.getOpcode() == 182 && Name.ebs_getBlockLSBArray.matches((MethodInsnNode)insn, obfuscated)) { + iterator.remove(); + iterator.add((AbstractInsnNode)new VarInsnNode(21, 9 + varOffset)); + iterator.add((AbstractInsnNode)new VarInsnNode(21, 18 + varOffset)); + iterator.add((AbstractInsnNode)new VarInsnNode(21, 10 + varOffset)); + iterator.add((AbstractInsnNode)Name.hooks_getBlockId.staticInvocation(obfuscated)); + while (((AbstractInsnNode)iterator.next()).getOpcode() != 54) { + iterator.remove(); + } + break; + } + } + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/UndergroundBiomesOreUBifier.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/UndergroundBiomesOreUBifier.java new file mode 100644 index 0000000..e4858be --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/UndergroundBiomesOreUBifier.java @@ -0,0 +1,19 @@ +package com.falsepattern.endlessids.asm.transformer; + +import org.objectweb.asm.tree.MethodNode; +import com.falsepattern.endlessids.asm.AsmUtil; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class UndergroundBiomesOreUBifier implements IClassNodeTransformer +{ + public UndergroundBiomesOreUBifier() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + final MethodNode method = AsmUtil.findMethod(cn, "renewBlockReplacers"); + AsmUtil.transformInlinedSizeMethod(cn, method, 4096, 32768, false); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaAnvilChunkLoader.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaAnvilChunkLoader.java new file mode 100644 index 0000000..340de7d --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaAnvilChunkLoader.java @@ -0,0 +1,85 @@ +package com.falsepattern.endlessids.asm.transformer; + +import org.objectweb.asm.tree.MethodInsnNode; +import java.util.ListIterator; +import org.objectweb.asm.tree.InsnList; +import com.falsepattern.endlessids.asm.AsmTransformException; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; +import com.falsepattern.endlessids.asm.AsmUtil; +import com.falsepattern.endlessids.asm.Name; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class VanillaAnvilChunkLoader implements IClassNodeTransformer +{ + public VanillaAnvilChunkLoader() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + MethodNode method = AsmUtil.findMethod(cn, Name.acl_writeChunkToNBT); + this.transformWriteChunkToNBT(cn, method, obfuscated); + method = AsmUtil.findMethod(cn, Name.acl_readChunkFromNBT); + this.transformReadChunkFromNBT(cn, method, obfuscated); + } + + private void transformWriteChunkToNBT(final ClassNode cn, final MethodNode method, final boolean obfuscated) { + final InsnList code = method.instructions; + final ListIterator iterator = (ListIterator)code.iterator(); + while (iterator.hasNext()) { + final AbstractInsnNode insn = (AbstractInsnNode)iterator.next(); + if (insn.getOpcode() == 18 && ((LdcInsnNode)insn).cst.equals("Blocks")) { + iterator.remove(); + iterator.next(); + iterator.next(); + iterator.remove(); + iterator.next(); + iterator.remove(); + iterator.add((AbstractInsnNode)Name.hooks_writeChunkToNbt.staticInvocation(obfuscated)); + return; + } + } + throw new AsmTransformException("can't find Blocks LDC"); + } + + private void transformReadChunkFromNBT(final ClassNode cn, final MethodNode method, final boolean obfuscated) { + final InsnList code = method.instructions; + int part = 0; + final ListIterator iterator = (ListIterator)code.iterator(); + while (iterator.hasNext()) { + final AbstractInsnNode insn = (AbstractInsnNode)iterator.next(); + if (part == 0) { + if (insn.getOpcode() != 18 || !((LdcInsnNode)insn).cst.equals("Blocks")) { + continue; + } + iterator.set((AbstractInsnNode)Name.hooks_readChunkFromNbt.staticInvocation(obfuscated)); + ++part; + } + else if (part == 1) { + iterator.remove(); + if (insn.getOpcode() != 182) { + continue; + } + final MethodInsnNode node = (MethodInsnNode)insn; + if (!Name.ebs_setBlockMSBArray.matches(node, obfuscated)) { + continue; + } + ++part; + } + else { + if (insn.getType() == 14) { + iterator.remove(); + ++part; + break; + } + continue; + } + } + if (part != 3) { + throw new AsmTransformException("no match for part " + part); + } + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaBlockFire.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaBlockFire.java new file mode 100644 index 0000000..ebfd5d6 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaBlockFire.java @@ -0,0 +1,27 @@ +package com.falsepattern.endlessids.asm.transformer; + +import com.falsepattern.endlessids.asm.AsmTransformException; +import com.falsepattern.endlessids.asm.AsmUtil; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class VanillaBlockFire implements IClassNodeTransformer +{ + public VanillaBlockFire() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + boolean found = false; + for (final MethodNode method : cn.methods) { + if (AsmUtil.transformInlinedSizeMethod(cn, method, 4096, 32768, true)) { + found = true; + } + } + if (!found) { + throw new AsmTransformException("can't find 4096 constant in any method"); + } + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaChunk.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaChunk.java new file mode 100644 index 0000000..2af827e --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaChunk.java @@ -0,0 +1,69 @@ +package com.falsepattern.endlessids.asm.transformer; + +import java.util.ListIterator; +import org.objectweb.asm.tree.MethodNode; +import com.falsepattern.endlessids.asm.AsmTransformException; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.VarInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.AbstractInsnNode; +import com.falsepattern.endlessids.asm.AsmUtil; +import com.falsepattern.endlessids.asm.Name; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class VanillaChunk implements IClassNodeTransformer +{ + public VanillaChunk() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + final MethodNode method = AsmUtil.findMethod(cn, Name.chunk_fillChunk, true); + if (method == null) { + return; + } + method.localVariables = null; + int part = 0; + final ListIterator it = (ListIterator)method.instructions.iterator(); + while (it.hasNext()) { + AbstractInsnNode insn = (AbstractInsnNode)it.next(); + if (part == 0) { + if (insn.getOpcode() != 182 || !Name.ebs_getBlockLSBArray.matches((MethodInsnNode)insn, obfuscated)) { + continue; + } + it.set((AbstractInsnNode)new VarInsnNode(25, 1)); + it.add((AbstractInsnNode)new VarInsnNode(21, 6)); + it.add((AbstractInsnNode)Name.hooks_setBlockData.staticInvocation(obfuscated)); + ++part; + } + else if (part == 1) { + if (insn.getOpcode() == 96) { + it.set((AbstractInsnNode)new VarInsnNode(21, 6)); + it.add((AbstractInsnNode)new LdcInsnNode((Object)Integer.valueOf(8192))); + it.add((AbstractInsnNode)new InsnNode(96)); + ++part; + } + else { + it.remove(); + } + } + else { + if (part == 2 && insn.getOpcode() == 182 && Name.ebs_getBlockMSBArray.matches((MethodInsnNode)insn, obfuscated)) { + while (((AbstractInsnNode)it.previous()).getOpcode() != 3) {} + while (((AbstractInsnNode)it.previous()).getType() != 8) {} + do { + insn = it.next(); + } while (insn.getOpcode() != 161 && insn.getOpcode() != 162); + it.set((AbstractInsnNode)new JumpInsnNode((insn.getOpcode() == 161) ? 163 : 161, ((JumpInsnNode)insn).label)); + return; + } + continue; + } + } + throw new AsmTransformException("no match for part " + part); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaDataWatcher.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaDataWatcher.java new file mode 100644 index 0000000..64eb3f8 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaDataWatcher.java @@ -0,0 +1,78 @@ +package com.falsepattern.endlessids.asm.transformer; + +import java.util.ListIterator; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.AbstractInsnNode; +import com.falsepattern.endlessids.asm.AsmUtil; +import com.falsepattern.endlessids.asm.Name; +import com.falsepattern.endlessids.IEConfig; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class VanillaDataWatcher implements IClassNodeTransformer +{ + public VanillaDataWatcher() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + if (IEConfig.extendDataWatcher) { + MethodNode method = AsmUtil.findMethod(cn, Name.dataWatcher_addObject); + AsmUtil.transformInlinedSizeMethod(cn, method, 31, 127); + method = AsmUtil.findMethod(cn, Name.dataWatcher_writeWatchableObjectToPacketBuffer); + AsmUtil.transformInlinedSizeMethod(cn, method, 31, 127); + AsmUtil.transformInlinedSizeMethod(cn, method, 255, 1023); + AsmUtil.transformInlinedSizeMethod(cn, method, 5, 7); + final ListIterator it = (ListIterator)method.instructions.iterator(); + while (it.hasNext()) { + final AbstractInsnNode insn = (AbstractInsnNode)it.next(); + if (insn.getOpcode() == 182 && ((MethodInsnNode)insn).name.equals("writeByte")) { + it.set((AbstractInsnNode)new MethodInsnNode(182, "net/minecraft/network/PacketBuffer", "writeShort", "(I)Lio/netty/buffer/ByteBuf;", false)); + break; + } + } + method = AsmUtil.findMethod(cn, Name.dataWatcher_readWatchedListFromPacketBuffer); + AsmUtil.transformInlinedSizeMethod(cn, method, 127, 32767); + AsmUtil.transformInlinedSizeMethod(cn, method, 224, 896); + AsmUtil.transformInlinedSizeMethod(cn, method, 31, 127); + AsmUtil.transformInlinedSizeMethod(cn, method, 5, 7); + int num = 0; + ListIterator it2 = (ListIterator)method.instructions.iterator(); + while (it2.hasNext()) { + final AbstractInsnNode insn2 = (AbstractInsnNode)it2.next(); + if (insn2.getOpcode() == 182 && ((MethodInsnNode)insn2).name.equals("readByte")) { + if (++num == 2) { + continue; + } + it2.set((AbstractInsnNode)new MethodInsnNode(182, "net/minecraft/network/PacketBuffer", "readShort", "()S", false)); + if (num == 3) { + break; + } + continue; + } + } + method = AsmUtil.findMethod(cn, Name.dataWatcher_writeWatchedListToPacketBuffer); + AsmUtil.transformInlinedSizeMethod(cn, method, 127, 32767); + it2 = (ListIterator)method.instructions.iterator(); + while (it2.hasNext()) { + final AbstractInsnNode insn2 = (AbstractInsnNode)it2.next(); + if (insn2.getOpcode() == 182 && ((MethodInsnNode)insn2).name.equals("writeByte")) { + it2.set((AbstractInsnNode)new MethodInsnNode(182, "net/minecraft/network/PacketBuffer", "writeShort", "(I)Lio/netty/buffer/ByteBuf;", false)); + break; + } + } + method = AsmUtil.findMethod(cn, Name.dataWatcher_func_151509_a); + AsmUtil.transformInlinedSizeMethod(cn, method, 127, 32767); + it2 = (ListIterator)method.instructions.iterator(); + while (it2.hasNext()) { + final AbstractInsnNode insn2 = (AbstractInsnNode)it2.next(); + if (insn2.getOpcode() == 182 && ((MethodInsnNode)insn2).name.equals("writeByte")) { + it2.set((AbstractInsnNode)new MethodInsnNode(182, "net/minecraft/network/PacketBuffer", "writeShort", "(I)Lio/netty/buffer/ByteBuf;", false)); + break; + } + } + } + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaExtendedBlockStorage.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaExtendedBlockStorage.java new file mode 100644 index 0000000..00f7f1d --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaExtendedBlockStorage.java @@ -0,0 +1,133 @@ +package com.falsepattern.endlessids.asm.transformer; + +import org.objectweb.asm.tree.MethodInsnNode; +import com.falsepattern.endlessids.asm.AsmTransformException; +import org.objectweb.asm.tree.InsnNode; +import java.util.ListIterator; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.VarInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; +import com.falsepattern.endlessids.asm.AsmUtil; +import com.falsepattern.endlessids.asm.Name; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class VanillaExtendedBlockStorage implements IClassNodeTransformer +{ + public VanillaExtendedBlockStorage() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + cn.fields.add(new FieldNode(1, "block16BArray", "[S", (String)null, (Object)null)); + AsmUtil.makePublic(AsmUtil.findField(cn, Name.ebs_blockRefCount)); + AsmUtil.makePublic(AsmUtil.findField(cn, Name.ebs_tickRefCount)); + MethodNode method = AsmUtil.findMethod(cn, ""); + this.transformConstructor(cn, method, obfuscated); + method = AsmUtil.findMethod(cn, Name.ebs_getBlock); + this.transformGetBlock(cn, method, obfuscated); + method = AsmUtil.findMethod(cn, Name.ebs_setBlock); + this.transformSetBlock(cn, method, obfuscated); + method = AsmUtil.findMethod(cn, Name.ebs_getBlockMSBArray); + this.transformGetBlockMSBArray(cn, method); + method = AsmUtil.findMethod(cn, Name.ebs_removeInvalidBlocks); + this.transformRemoveInvalidBlocks(cn, method); + } + + private void transformConstructor(final ClassNode cn, final MethodNode method, final boolean obfuscated) { + final InsnList code = method.instructions; + final ListIterator iterator = (ListIterator)code.iterator(); + if (iterator.hasNext()) { + AbstractInsnNode insn = (AbstractInsnNode)iterator.next(); + insn = insn.getNext().getNext(); + final InsnList toInsert = new InsnList(); + toInsert.add((AbstractInsnNode)new VarInsnNode(25, 0)); + toInsert.add((AbstractInsnNode)Name.hooks_create16BArray.staticInvocation(obfuscated)); + toInsert.add((AbstractInsnNode)new FieldInsnNode(181, cn.name, "block16BArray", "[S")); + method.instructions.insert(insn, toInsert); + } + method.maxStack = Math.max(method.maxStack, 2); + } + + private void transformGetBlock(final ClassNode cn, final MethodNode method, final boolean obfuscated) { + final InsnList code = method.instructions; + code.clear(); + code.add((AbstractInsnNode)new VarInsnNode(25, 0)); + code.add((AbstractInsnNode)new VarInsnNode(21, 1)); + code.add((AbstractInsnNode)new VarInsnNode(21, 2)); + code.add((AbstractInsnNode)new VarInsnNode(21, 3)); + code.add((AbstractInsnNode)Name.hooks_getBlockById.staticInvocation(obfuscated)); + code.add((AbstractInsnNode)new InsnNode(176)); + method.localVariables = null; + method.maxStack = 4; + } + + private void transformSetBlock(final ClassNode cn, final MethodNode method, final boolean obfuscated) { + final InsnList code = method.instructions; + int part = 0; + final ListIterator iterator = (ListIterator)code.iterator(); + while (iterator.hasNext()) { + final AbstractInsnNode insn = (AbstractInsnNode)iterator.next(); + if (part == 0) { + iterator.remove(); + if (insn.getOpcode() != 184) { + continue; + } + ++part; + iterator.add((AbstractInsnNode)new VarInsnNode(25, 0)); + iterator.add((AbstractInsnNode)new VarInsnNode(21, 1)); + iterator.add((AbstractInsnNode)new VarInsnNode(21, 2)); + iterator.add((AbstractInsnNode)new VarInsnNode(21, 3)); + iterator.add((AbstractInsnNode)Name.ebs_getBlock.virtualInvocation(obfuscated)); + } + else if (part == 1) { + if (insn.getOpcode() != 184) { + continue; + } + iterator.set((AbstractInsnNode)new VarInsnNode(25, 6)); + iterator.add((AbstractInsnNode)Name.hooks_getIdFromBlockWithCheck.staticInvocation(obfuscated)); + ++part; + } + else { + iterator.remove(); + } + } + if (part != 2) { + throw new AsmTransformException("no match for part " + part); + } + code.add((AbstractInsnNode)new VarInsnNode(54, 5)); + code.add((AbstractInsnNode)new VarInsnNode(25, 0)); + code.add((AbstractInsnNode)new VarInsnNode(21, 1)); + code.add((AbstractInsnNode)new VarInsnNode(21, 2)); + code.add((AbstractInsnNode)new VarInsnNode(21, 3)); + code.add((AbstractInsnNode)new VarInsnNode(21, 5)); + code.add((AbstractInsnNode)Name.hooks_setBlockId.staticInvocation(obfuscated)); + code.add((AbstractInsnNode)new InsnNode(177)); + method.localVariables = null; + --method.maxLocals; + method.maxStack = Math.max(method.maxStack, 5); + } + + private void transformGetBlockMSBArray(final ClassNode cn, final MethodNode method) { + final InsnList code = method.instructions; + code.clear(); + code.add((AbstractInsnNode)new InsnNode(1)); + code.add((AbstractInsnNode)new InsnNode(176)); + method.localVariables = null; + method.maxStack = 1; + } + + private void transformRemoveInvalidBlocks(final ClassNode cn, final MethodNode method) { + final InsnList code = method.instructions; + code.clear(); + code.add((AbstractInsnNode)new VarInsnNode(25, 0)); + code.add((AbstractInsnNode)new MethodInsnNode(184, "com/falsepattern/endlessids/Hooks", "removeInvalidBlocksHook", "(L" + cn.name + ";)V", false)); + code.add((AbstractInsnNode)new InsnNode(177)); + method.localVariables = null; + method.maxStack = 1; + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaItemInWorldManager.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaItemInWorldManager.java new file mode 100644 index 0000000..f2f732c --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaItemInWorldManager.java @@ -0,0 +1,20 @@ +package com.falsepattern.endlessids.asm.transformer; + +import org.objectweb.asm.tree.MethodNode; +import com.falsepattern.endlessids.asm.AsmUtil; +import com.falsepattern.endlessids.asm.Name; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class VanillaItemInWorldManager implements IClassNodeTransformer +{ + public VanillaItemInWorldManager() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + final MethodNode method = AsmUtil.findMethod(cn, Name.itemInWorldManager_tryHarvestBlock); + AsmUtil.transformInlinedSizeMethod(cn, method, 12, 16); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaNetHandlerPlayClient.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaNetHandlerPlayClient.java new file mode 100644 index 0000000..5f602a8 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaNetHandlerPlayClient.java @@ -0,0 +1,84 @@ +package com.falsepattern.endlessids.asm.transformer; + +import java.util.ListIterator; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.MethodNode; +import com.falsepattern.endlessids.asm.AsmTransformException; +import org.objectweb.asm.tree.IntInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.VarInsnNode; +import org.objectweb.asm.tree.AbstractInsnNode; +import com.falsepattern.endlessids.asm.AsmUtil; +import com.falsepattern.endlessids.asm.Name; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class VanillaNetHandlerPlayClient implements IClassNodeTransformer +{ + public VanillaNetHandlerPlayClient() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + final MethodNode method = AsmUtil.findMethod(cn, Name.nhpc_handleMultiBlockChange); + final InsnList code = method.instructions; + int part = 0; + final ListIterator iterator = (ListIterator)code.iterator(); + while (iterator.hasNext()) { + AbstractInsnNode insn = (AbstractInsnNode)iterator.next(); + if (part == 0) { + if (insn.getOpcode() != 25 || ((VarInsnNode)insn).var != 4) { + continue; + } + ++part; + } + else if (part == 1) { + if (insn.getOpcode() != 25 || ((VarInsnNode)insn).var != 4) { + continue; + } + iterator.remove(); + insn = iterator.next(); + iterator.set((AbstractInsnNode)new InsnNode(3)); + ++part; + } + else if (part == 2) { + if (insn.getOpcode() != 21 || ((VarInsnNode)insn).var != 7) { + continue; + } + iterator.set((AbstractInsnNode)new VarInsnNode(25, 4)); + iterator.add((AbstractInsnNode)new MethodInsnNode(182, "java/io/DataInputStream", "readShort", "()S", false)); + ++part; + } + else if (part == 3) { + if (insn.getOpcode() == 54) { + ++part; + } + else { + iterator.remove(); + } + } + else if (part == 4) { + if (insn.getOpcode() != 21 || ((VarInsnNode)insn).var != 7) { + continue; + } + iterator.set((AbstractInsnNode)new VarInsnNode(25, 4)); + iterator.add((AbstractInsnNode)new MethodInsnNode(182, "java/io/DataInputStream", "readByte", "()B", false)); + iterator.add((AbstractInsnNode)new IntInsnNode(16, 15)); + iterator.add((AbstractInsnNode)new InsnNode(126)); + ++part; + } + else { + if (part != 5) { + continue; + } + if (insn.getOpcode() == 54) { + return; + } + iterator.remove(); + } + } + throw new AsmTransformException("no match for part " + part); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaPlayerControllerMP.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaPlayerControllerMP.java new file mode 100644 index 0000000..ac6d714 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaPlayerControllerMP.java @@ -0,0 +1,20 @@ +package com.falsepattern.endlessids.asm.transformer; + +import org.objectweb.asm.tree.MethodNode; +import com.falsepattern.endlessids.asm.AsmUtil; +import com.falsepattern.endlessids.asm.Name; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class VanillaPlayerControllerMP implements IClassNodeTransformer +{ + public VanillaPlayerControllerMP() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + final MethodNode method = AsmUtil.findMethod(cn, Name.playerControllerMP_onPlayerDestroyBlock); + AsmUtil.transformInlinedSizeMethod(cn, method, 12, 16); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaRenderGlobal.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaRenderGlobal.java new file mode 100644 index 0000000..2741e8c --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaRenderGlobal.java @@ -0,0 +1,21 @@ +package com.falsepattern.endlessids.asm.transformer; + +import org.objectweb.asm.tree.MethodNode; +import com.falsepattern.endlessids.asm.AsmUtil; +import com.falsepattern.endlessids.asm.Name; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class VanillaRenderGlobal implements IClassNodeTransformer +{ + public VanillaRenderGlobal() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + final MethodNode method = AsmUtil.findMethod(cn, Name.renderGlobal_playAuxSFX); + AsmUtil.transformInlinedSizeMethod(cn, method, 4095, 65535); + AsmUtil.transformInlinedSizeMethod(cn, method, 12, 16); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaS21PacketChunkData.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaS21PacketChunkData.java new file mode 100644 index 0000000..48a37b1 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaS21PacketChunkData.java @@ -0,0 +1,48 @@ +package com.falsepattern.endlessids.asm.transformer; + +import java.util.ListIterator; +import org.objectweb.asm.tree.InsnList; +import com.falsepattern.endlessids.asm.AsmTransformException; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; +import com.falsepattern.endlessids.asm.Name; +import com.falsepattern.endlessids.asm.AsmUtil; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class VanillaS21PacketChunkData implements IClassNodeTransformer +{ + public VanillaS21PacketChunkData() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + MethodNode method = AsmUtil.findMethod(cn, ""); + AsmUtil.transformInlinedSizeMethod(cn, method, 196864, 229632, false); + method = AsmUtil.findMethod(cn, Name.s21_undefined1); + AsmUtil.transformInlinedSizeMethod(cn, method, 196864, 229632, false); + method = AsmUtil.findMethod(cn, Name.packet_readPacketData); + AsmUtil.transformInlinedSizeMethod(cn, method, 12288, 14336, false); + method = AsmUtil.findMethod(cn, Name.s21_undefined2); + this.transformCreateData(cn, method, obfuscated); + } + + private void transformCreateData(final ClassNode cn, final MethodNode method, final boolean obfuscated) { + final InsnList code = method.instructions; + final ListIterator iterator = (ListIterator)code.iterator(); + while (iterator.hasNext()) { + final AbstractInsnNode insn = (AbstractInsnNode)iterator.next(); + if (insn.getOpcode() == 182) { + final MethodInsnNode node = (MethodInsnNode)insn; + if (Name.ebs_getBlockLSBArray.matches(node, obfuscated)) { + iterator.set((AbstractInsnNode)Name.hooks_getBlockData.staticInvocation(obfuscated)); + return; + } + continue; + } + } + throw new AsmTransformException("can't find getBlockLSBArray INVOKEVIRTUAL"); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaS22PacketMultiBlockChange.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaS22PacketMultiBlockChange.java new file mode 100644 index 0000000..1bf2707 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaS22PacketMultiBlockChange.java @@ -0,0 +1,75 @@ +package com.falsepattern.endlessids.asm.transformer; + +import java.util.ListIterator; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.MethodNode; +import com.falsepattern.endlessids.asm.AsmTransformException; +import org.objectweb.asm.tree.VarInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.AbstractInsnNode; +import com.falsepattern.endlessids.asm.AsmUtil; +import com.falsepattern.endlessids.asm.Name; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class VanillaS22PacketMultiBlockChange implements IClassNodeTransformer +{ + public VanillaS22PacketMultiBlockChange() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + final MethodNode method = AsmUtil.findMethod(cn, Name.s22_init_server); + final InsnList code = method.instructions; + int part = 0; + final ListIterator iterator = (ListIterator)code.iterator(); + while (iterator.hasNext()) { + final AbstractInsnNode insn = (AbstractInsnNode)iterator.next(); + if (part == 0) { + if (insn.getOpcode() != 7) { + continue; + } + iterator.set((AbstractInsnNode)new InsnNode(8)); + ++part; + } + else if (part == 1) { + if (insn.getOpcode() != 184) { + continue; + } + final MethodInsnNode node = (MethodInsnNode)insn; + if (!Name.block_getIdFromBlock.matches(node, obfuscated)) { + continue; + } + iterator.add((AbstractInsnNode)new MethodInsnNode(182, "java/io/DataOutputStream", "writeShort", "(I)V", false)); + ++part; + } + else if (part == 2) { + if (insn.getOpcode() == 25) { + ++part; + } + else { + iterator.remove(); + } + } + else if (part == 3) { + if (insn.getOpcode() != 182) { + continue; + } + iterator.add((AbstractInsnNode)new VarInsnNode(25, 6)); + iterator.add((AbstractInsnNode)new InsnNode(95)); + iterator.add((AbstractInsnNode)new MethodInsnNode(182, "java/io/DataOutputStream", "writeByte", "(I)V", false)); + ++part; + } + else { + iterator.remove(); + if (insn.getOpcode() == 182) { + return; + } + continue; + } + } + throw new AsmTransformException("no match for part " + part); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaS24PacketBlockActivation.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaS24PacketBlockActivation.java new file mode 100644 index 0000000..6e796fa --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaS24PacketBlockActivation.java @@ -0,0 +1,22 @@ +package com.falsepattern.endlessids.asm.transformer; + +import org.objectweb.asm.tree.MethodNode; +import com.falsepattern.endlessids.asm.AsmUtil; +import com.falsepattern.endlessids.asm.Name; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class VanillaS24PacketBlockActivation implements IClassNodeTransformer +{ + public VanillaS24PacketBlockActivation() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + MethodNode method = AsmUtil.findMethod(cn, Name.packet_readPacketData); + AsmUtil.transformInlinedSizeMethod(cn, method, 4095, 65535); + method = AsmUtil.findMethod(cn, Name.packet_writePacketData); + AsmUtil.transformInlinedSizeMethod(cn, method, 4095, 65535); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaS26PacketMapChunkBulk.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaS26PacketMapChunkBulk.java new file mode 100644 index 0000000..d2dba36 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaS26PacketMapChunkBulk.java @@ -0,0 +1,20 @@ +package com.falsepattern.endlessids.asm.transformer; + +import org.objectweb.asm.tree.MethodNode; +import com.falsepattern.endlessids.asm.AsmUtil; +import com.falsepattern.endlessids.asm.Name; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class VanillaS26PacketMapChunkBulk implements IClassNodeTransformer +{ + public VanillaS26PacketMapChunkBulk() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + final MethodNode method = AsmUtil.findMethod(cn, Name.packet_readPacketData); + AsmUtil.transformInlinedSizeMethod(cn, method, 8192, 12288, false); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaStatList.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaStatList.java new file mode 100644 index 0000000..6b1fb2a --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaStatList.java @@ -0,0 +1,19 @@ +package com.falsepattern.endlessids.asm.transformer; + +import org.objectweb.asm.tree.MethodNode; +import com.falsepattern.endlessids.asm.AsmUtil; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class VanillaStatList implements IClassNodeTransformer +{ + public VanillaStatList() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + final MethodNode method = AsmUtil.findMethod(cn, ""); + AsmUtil.transformInlinedSizeMethod(cn, method, 4096, 32768, false); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaWorld.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaWorld.java new file mode 100644 index 0000000..1093e3d --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/VanillaWorld.java @@ -0,0 +1,20 @@ +package com.falsepattern.endlessids.asm.transformer; + +import org.objectweb.asm.tree.MethodNode; +import com.falsepattern.endlessids.asm.AsmUtil; +import com.falsepattern.endlessids.asm.Name; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class VanillaWorld implements IClassNodeTransformer +{ + public VanillaWorld() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + final MethodNode method = AsmUtil.findMethod(cn, Name.world_breakBlock); + AsmUtil.transformInlinedSizeMethod(cn, method, 12, 16); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/asm/transformer/WorldEditBaseBlock.java b/src/main/java/com/falsepattern/endlessids/asm/transformer/WorldEditBaseBlock.java new file mode 100644 index 0000000..84e527c --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/asm/transformer/WorldEditBaseBlock.java @@ -0,0 +1,37 @@ +package com.falsepattern.endlessids.asm.transformer; + +import lombok.val; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.LdcInsnNode; +import com.falsepattern.endlessids.asm.AsmUtil; +import org.objectweb.asm.tree.ClassNode; +import com.falsepattern.endlessids.asm.IClassNodeTransformer; + +public class WorldEditBaseBlock implements IClassNodeTransformer +{ + public WorldEditBaseBlock() { + super(); + } + + @Override + public void transform(final ClassNode cn, final boolean obfuscated) { + final MethodNode method = AsmUtil.findMethod(cn, "internalSetId", true); + if (method == null) { + return; + } + AsmUtil.transformInlinedSizeMethod(cn, method, 4095, 32767); + final InsnList code = method.instructions; + val iter = code.iterator(); + while (iter.hasNext()) { + val insn = iter.next(); + if (insn.getType() == 9 && ((LdcInsnNode)insn).cst instanceof String) { + final String string = (String)((LdcInsnNode)insn).cst; + if (string.contains("4095")) { + ((LdcInsnNode)insn).cst = string.replace("4095", Integer.toString(32767)); + break; + } + } + } + } +} diff --git a/src/main/java/com/falsepattern/endlessids/mixin/helpers/IExtendedBlockStorageMixin.java b/src/main/java/com/falsepattern/endlessids/mixin/helpers/IExtendedBlockStorageMixin.java new file mode 100644 index 0000000..ad53e2e --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/mixin/helpers/IExtendedBlockStorageMixin.java @@ -0,0 +1,7 @@ +package com.falsepattern.endlessids.mixin.helpers; + +public interface IExtendedBlockStorageMixin { + void setBlockRefCount(int value); + void setTickRefCount(int value); + short[] get16B(); +} diff --git a/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/AnvilChunkLoaderMixin.java b/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/AnvilChunkLoaderMixin.java new file mode 100644 index 0000000..666ebb2 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/AnvilChunkLoaderMixin.java @@ -0,0 +1,162 @@ +package com.falsepattern.endlessids.mixin.mixins.common; + +import com.falsepattern.endlessids.Hooks; +import com.falsepattern.endlessids.mixin.helpers.IExtendedBlockStorageMixin; +import net.minecraft.block.Block; +import net.minecraft.entity.Entity; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.NextTickListEntry; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.NibbleArray; +import net.minecraft.world.chunk.storage.AnvilChunkLoader; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +import java.util.Iterator; +import java.util.List; + +@Mixin(AnvilChunkLoader.class) +public abstract class AnvilChunkLoaderMixin { + + /** + * @author FalsePattern + * @reason Direct port from dumped code + */ + @Overwrite + private void writeChunkToNBT(Chunk p_75820_1_, World p_75820_2_, NBTTagCompound p_75820_3_) { + p_75820_3_.setByte("V", (byte)1); + p_75820_3_.setInteger("xPos", p_75820_1_.xPosition); + p_75820_3_.setInteger("zPos", p_75820_1_.zPosition); + p_75820_3_.setLong("LastUpdate", p_75820_2_.getTotalWorldTime()); + p_75820_3_.setIntArray("HeightMap", p_75820_1_.heightMap); + p_75820_3_.setBoolean("TerrainPopulated", p_75820_1_.isTerrainPopulated); + p_75820_3_.setBoolean("LightPopulated", p_75820_1_.isLightPopulated); + p_75820_3_.setLong("InhabitedTime", p_75820_1_.inhabitedTime); + ExtendedBlockStorage[] var4 = p_75820_1_.getBlockStorageArray(); + NBTTagList var5 = new NBTTagList(); + boolean var6 = !p_75820_2_.provider.hasNoSky; + ExtendedBlockStorage[] var7 = var4; + int var8 = var4.length; + + NBTTagCompound var11; + for(int var9 = 0; var9 < var8; ++var9) { + ExtendedBlockStorage var10 = var7[var9]; + if (var10 != null) { + var11 = new NBTTagCompound(); + var11.setByte("Y", (byte)(var10.getYLocation() >> 4 & 255)); + Hooks.writeChunkToNbt(var11, (IExtendedBlockStorageMixin) var10); + if (var10.getBlockMSBArray() != null) { + var11.setByteArray("Add", var10.getBlockMSBArray().data); + } + + var11.setByteArray("Data", var10.getMetadataArray().data); + var11.setByteArray("BlockLight", var10.getBlocklightArray().data); + if (var6) { + var11.setByteArray("SkyLight", var10.getSkylightArray().data); + } else { + var11.setByteArray("SkyLight", new byte[var10.getBlocklightArray().data.length]); + } + + var5.appendTag(var11); + } + } + + p_75820_3_.setTag("Sections", var5); + p_75820_3_.setByteArray("Biomes", p_75820_1_.getBiomeArray()); + p_75820_1_.hasEntities = false; + NBTTagList var21 = new NBTTagList(); + + Iterator var22; + for(var8 = 0; var8 < p_75820_1_.entityLists.length; ++var8) { + var22 = p_75820_1_.entityLists[var8].iterator(); + + while(var22.hasNext()) { + Entity var12 = (Entity)var22.next(); + var11 = new NBTTagCompound(); + if (var12.writeToNBTOptional(var11)) { + p_75820_1_.hasEntities = true; + var21.appendTag(var11); + } + } + } + + p_75820_3_.setTag("Entities", var21); + NBTTagList var23 = new NBTTagList(); + var22 = p_75820_1_.chunkTileEntityMap.values().iterator(); + + while(var22.hasNext()) { + TileEntity var13 = (TileEntity)var22.next(); + var11 = new NBTTagCompound(); + var13.writeToNBT(var11); + var23.appendTag(var11); + } + + p_75820_3_.setTag("TileEntities", var23); + List var24 = p_75820_2_.getPendingBlockUpdates(p_75820_1_, false); + if (var24 != null) { + long var15 = p_75820_2_.getTotalWorldTime(); + NBTTagList var17 = new NBTTagList(); + Iterator var18 = var24.iterator(); + + while(var18.hasNext()) { + NextTickListEntry var19 = (NextTickListEntry)var18.next(); + NBTTagCompound var20 = new NBTTagCompound(); + var20.setInteger("i", Block.getIdFromBlock(var19.func_151351_a())); + var20.setInteger("x", var19.xCoord); + var20.setInteger("y", var19.yCoord); + var20.setInteger("z", var19.zCoord); + var20.setInteger("t", (int)(var19.scheduledTime - var15)); + var20.setInteger("p", var19.priority); + var17.appendTag(var20); + } + + p_75820_3_.setTag("TileTicks", var17); + } + + } + + /** + * @author FalsePattern + * @reason Direct port from dumped code + */ + @Overwrite + private Chunk readChunkFromNBT(World p_75823_1_, NBTTagCompound p_75823_2_) { + int var3 = p_75823_2_.getInteger("xPos"); + int var4 = p_75823_2_.getInteger("zPos"); + Chunk var5 = new Chunk(p_75823_1_, var3, var4); + var5.heightMap = p_75823_2_.getIntArray("HeightMap"); + var5.isTerrainPopulated = p_75823_2_.getBoolean("TerrainPopulated"); + var5.isLightPopulated = p_75823_2_.getBoolean("LightPopulated"); + var5.inhabitedTime = p_75823_2_.getLong("InhabitedTime"); + NBTTagList var6 = p_75823_2_.getTagList("Sections", 10); + byte var7 = 16; + ExtendedBlockStorage[] var8 = new ExtendedBlockStorage[var7]; + boolean var9 = !p_75823_1_.provider.hasNoSky; + + for(int var10 = 0; var10 < var6.tagCount(); ++var10) { + NBTTagCompound var11 = var6.getCompoundTagAt(var10); + byte var12 = var11.getByte("Y"); + ExtendedBlockStorage var13 = new ExtendedBlockStorage(var12 << 4, var9); + Hooks.readChunkFromNbt((IExtendedBlockStorageMixin) var13, var11); + var13.setBlockMetadataArray(new NibbleArray(var11.getByteArray("Data"), 4)); + var13.setBlocklightArray(new NibbleArray(var11.getByteArray("BlockLight"), 4)); + if (var9) { + var13.setSkylightArray(new NibbleArray(var11.getByteArray("SkyLight"), 4)); + } + + var13.removeInvalidBlocks(); + var8[var12] = var13; + } + + var5.setStorageArrays(var8); + if (p_75823_2_.hasKey("Biomes", 7)) { + var5.setBiomeArray(p_75823_2_.getByteArray("Biomes")); + } + + return var5; + } +} diff --git a/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/ChunkMixin.java b/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/ChunkMixin.java new file mode 100644 index 0000000..34cd642 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/ChunkMixin.java @@ -0,0 +1,152 @@ +package com.falsepattern.endlessids.mixin.mixins.common; + +import com.falsepattern.endlessids.Hooks; +import com.falsepattern.endlessids.mixin.helpers.IExtendedBlockStorageMixin; +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 java.util.ArrayList; +import java.util.Iterator; +import java.util.Map; + +@Mixin(Chunk.class) +public abstract class ChunkMixin { + @Shadow public Map chunkTileEntityMap; + + @Shadow public World worldObj; + + @Shadow private ExtendedBlockStorage[] storageArrays; + + @Shadow private byte[] blockBiomeArray; + + @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_); + + /** + * @author FalsePattern + * @reason Direct port from dumped code + */ + @Overwrite + public void fillChunk(byte[] var1, int var2, int var3, boolean var4) { + Iterator var5 = this.chunkTileEntityMap.values().iterator(); + + while(var5.hasNext()) { + TileEntity var6 = (TileEntity)var5.next(); + var6.updateContainingBlockInfo(); + var6.getBlockMetadata(); + var6.getBlockType(); + } + + int var16 = 0; + boolean var7 = !this.worldObj.provider.hasNoSky; + + int var8; + for(var8 = 0; var8 < this.storageArrays.length; ++var8) { + if ((var2 & 1 << var8) != 0) { + if (this.storageArrays[var8] == null) { + this.storageArrays[var8] = new ExtendedBlockStorage(var8 << 4, var7); + } + + Hooks.setBlockData((IExtendedBlockStorageMixin) 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) { + System.arraycopy(var1, var16, this.blockBiomeArray, 0, this.blockBiomeArray.length); + int var10000 = var16 + this.blockBiomeArray.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(); + } + + } +} diff --git a/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/ExtendedBlockStorageMixin.java b/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/ExtendedBlockStorageMixin.java new file mode 100644 index 0000000..053cb9b --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/ExtendedBlockStorageMixin.java @@ -0,0 +1,85 @@ +package com.falsepattern.endlessids.mixin.mixins.common; + +import com.falsepattern.endlessids.Hooks; +import com.falsepattern.endlessids.mixin.helpers.IExtendedBlockStorageMixin; +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +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; + +@Mixin(ExtendedBlockStorage.class) +public abstract class ExtendedBlockStorageMixin implements IExtendedBlockStorageMixin { + @Shadow private int blockRefCount; + @Shadow private int tickRefCount; + private short[] block16BArray; + + @Override + public void setBlockRefCount(int value) { + blockRefCount = value; + } + + @Override + public void setTickRefCount(int value) { + tickRefCount = value; + } + + @Override + public short[] get16B() { + return block16BArray; + } + + @Inject(method = "", + at = @At(value = "RETURN"), + require = 1) + private void init(CallbackInfo ci) { + block16BArray = Hooks.create16BArray(); + } + + /** + * @author FalsePattern + * @reason Direct port from dumped code + */ + @Overwrite + public Block getBlockByExtId(int var1, int var2, int var3) { + return Hooks.getBlock(this, var1, var2, var3); + } + + /** + * @author FalsePattern + * @reason Direct port from dumped code + */ + @Overwrite + public void func_150818_a(int var1, int var2, int var3, Block var4) { + Block var5 = this.getBlockByExtId(var1, var2, var3); + if (var5 != Blocks.air) { + --this.blockRefCount; + if (var5.getTickRandomly()) { + --this.tickRefCount; + } + } + + if (var4 != Blocks.air) { + ++this.blockRefCount; + if (var4.getTickRandomly()) { + ++this.tickRefCount; + } + } + + int var6 = Hooks.getIdFromBlockWithCheck(var4, var5); + Hooks.setBlockId(this, var1, var2, var3, var6); + } + + /** + * @author FalsePattern + * @reason Direct port from dumped code + */ + @Overwrite + public void removeInvalidBlocks() { + Hooks.removeInvalidBlocksHook(this); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/S21PacketChunkDataMixin.java b/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/S21PacketChunkDataMixin.java new file mode 100644 index 0000000..10ea435 --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/S21PacketChunkDataMixin.java @@ -0,0 +1,36 @@ +package com.falsepattern.endlessids.mixin.mixins.common; + +import com.falsepattern.endlessids.Hooks; +import com.falsepattern.endlessids.mixin.helpers.IExtendedBlockStorageMixin; +import net.minecraft.network.play.server.S21PacketChunkData; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(S21PacketChunkData.class) +public abstract class S21PacketChunkDataMixin { + @ModifyConstant(method = {"", "func_149275_c"}, + constant = @Constant(intValue = 0x30100), + require = 1) + private static int increasePacketSize(int constant) { + return constant + 0x8000; + } + + @ModifyConstant(method = "readPacketData", + constant = @Constant(intValue = 0x3000), + require = 1) + private int increaseReadSize(int constant) { + return constant + 0x800; + } + + @Redirect(method = "func_149269_a", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;getBlockLSBArray()[B"), + require = 1) + private static byte[] hookGetBlockData(ExtendedBlockStorage instance) { + return Hooks.getBlockData((IExtendedBlockStorageMixin) instance); + } +} diff --git a/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/WorldMixin.java b/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/WorldMixin.java new file mode 100644 index 0000000..6e2dedd --- /dev/null +++ b/src/main/java/com/falsepattern/endlessids/mixin/mixins/common/WorldMixin.java @@ -0,0 +1,16 @@ +package com.falsepattern.endlessids.mixin.mixins.common; + +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +@Mixin(World.class) +public abstract class WorldMixin { + @ModifyConstant(method = "func_147480_a", + constant = @Constant(intValue = 12), + require = 1) + private int modifySoundShift(int original) { + return 16; + } +} diff --git a/src/main/java/com/falsepattern/endlessids/mixin/plugin/Mixin.java b/src/main/java/com/falsepattern/endlessids/mixin/plugin/Mixin.java index 817f4dd..85e05ed 100644 --- a/src/main/java/com/falsepattern/endlessids/mixin/plugin/Mixin.java +++ b/src/main/java/com/falsepattern/endlessids/mixin/plugin/Mixin.java @@ -7,6 +7,11 @@ import java.util.List; import java.util.Set; public enum Mixin { + AnvilChunkLoaderMixin(builder(Side.COMMON).mixin("AnvilChunkLoaderMixin")), + ChunkMixin(builder(Side.COMMON).mixin("ChunkMixin")), + WorldMixin(builder(Side.COMMON).mixin("WorldMixin")), + ExtendedBlockStorageMixin(builder(Side.COMMON).mixin("ExtendedBlockStorageMixin")), + S21PacketChunkDataMixin(builder(Side.COMMON).mixin("S21PacketChunkDataMixin")), ; public final String mixin;