Skip to content

Commit

Permalink
Merge pull request #36 from DimensionalDevelopment/1.0.2
Browse files Browse the repository at this point in the history
1.0.2
  • Loading branch information
ZombieHDGaming authored Oct 2, 2018
2 parents 92a54da + cb5a961 commit 49419cf
Show file tree
Hide file tree
Showing 16 changed files with 477 additions and 17 deletions.
5 changes: 3 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ apply plugin: "org.spongepowered.mixin"

repositories {
maven { url "http://repo.spongepowered.org/maven" }
maven { url "http://www.dimdev.org/maven" }
ivy {
url "https://google.com/404"
ivyPattern("https://google.com/404") // Workaround for https://github.com/gradle/gradle/issues/4107
Expand All @@ -26,7 +27,7 @@ repositories {
}

dependencies {
implementation("org.spongepowered:mixin:0.7.8-SNAPSHOT") {
implementation("org.dimdev:mixin:0.7.11-SNAPSHOT") {
exclude module: "asm-commons"
exclude module: "asm-tree"
exclude module: "launchwrapper"
Expand Down Expand Up @@ -60,7 +61,7 @@ targetCompatibility = 1.8
minecraft {
version "1.12.2-14.23.4.2703"
runDir "run"
mappings "snapshot_20180607"
mappings "stable_39"
makeObfSourceJar false

def args = [
Expand Down
41 changes: 39 additions & 2 deletions src/main/java/org/dimdev/jeid/JEID.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionEffect;
import net.minecraft.potion.PotionType;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeVoid;
Expand All @@ -14,13 +17,16 @@
import net.minecraftforge.registries.IForgeRegistry;
import org.dimdev.jeid.network.MessageManager;

import java.util.Random;

@Mod(modid = "jeid",
name = "JustEnoughIDs",
updateJSON = "https://gist.githubusercontent.com/Runemoro/67b1d8d31af58e9d35410ef60b2017c3/raw/1fe08a6c45a1f481a8a2a8c71e52d4245dcb7713/jeid_update.json")
public class JEID {
private static final boolean DEBUG_BLOCK_IDS = false;
private static final boolean DEBUG_ITEM_IDS = false;
private static final boolean DEBUG_BIOME_IDS = false;
private static final boolean DEBUG_POTION_IDS = true;
public static final Biome errorBiome = new BiomeVoid(new Biome.BiomeProperties("A mod doesn't support extended biome IDs -- report to JEID"))
.setRegistryName("jeid:error_biome");

Expand All @@ -36,7 +42,7 @@ public void onPreInit(FMLPreInitializationEvent event) {
for (int i = 0; i < 5000; i++) {
Block block = new Block(Material.GROUND)
.setCreativeTab(CreativeTabs.BUILDING_BLOCKS)
.setUnlocalizedName("block_" + i)
.setRegistryName("block_" + i)
.setRegistryName(new ResourceLocation("jeid:block_" + i));

blockRegistry.register(block);
Expand All @@ -49,7 +55,7 @@ public void onPreInit(FMLPreInitializationEvent event) {
for (int i = 0; i < 40000; i++) {
Item item = new Item()
.setCreativeTab(CreativeTabs.FOOD)
.setUnlocalizedName("item_" + i)
.setRegistryName("item_" + i)
.setRegistryName(new ResourceLocation("jeid:item_" + i));

itemRegistry.register(item);
Expand All @@ -67,5 +73,36 @@ public void onPreInit(FMLPreInitializationEvent event) {
}

GameRegistry.findRegistry(Biome.class).register(errorBiome);

if (DEBUG_POTION_IDS) {
IForgeRegistry<Potion> potionRegistry = GameRegistry.findRegistry(Potion.class);
IForgeRegistry<PotionType> potionTypeRegistry = GameRegistry.findRegistry(PotionType.class);
for (int i = 0; i < 300; i++) {
Potion potion = new PotionTest(i).setRegistryName(new ResourceLocation("jeid:potion_" + i));
potionRegistry.register(potion);
}

for (int i = 0; i < 300; i++) {
PotionType pt = new PotionType(new PotionEffect(Potion.REGISTRY.getObject(new ResourceLocation("jeid:potion_" + i)), 2000, 0, false, true));
pt.setRegistryName(new ResourceLocation("jeid:potiontype_"+i));
potionTypeRegistry.register(pt);
}
}
}

public static class PotionTest extends Potion {

private static final Random r = new Random();
private String nm = "";

protected PotionTest(int id) {
super(false, 0xFFFFFF & r.nextInt(Integer.MAX_VALUE));
nm = "Test Potion #"+id;
}

@Override
public String getName() {
return nm;
}
}
}
4 changes: 2 additions & 2 deletions src/main/java/org/dimdev/jeid/JEIDLoadingPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

@IFMLLoadingPlugin.MCVersion(ForgeVersion.mcVersion)
@IFMLLoadingPlugin.SortingIndex(-7500)
@IFMLLoadingPlugin.TransformerExclusions("org.dimdev.jeid.")
//@IFMLLoadingPlugin.TransformerExclusions("org.dimdev.jeid.")
public class JEIDLoadingPlugin implements IFMLLoadingPlugin {

public JEIDLoadingPlugin() {
Expand All @@ -19,7 +19,7 @@ public JEIDLoadingPlugin() {
Mixins.addConfiguration("mixins.jeid.init.json");
}

@Override public String[] getASMTransformerClass() { return new String[0]; }
@Override public String[] getASMTransformerClass() { Obf.loadData(); return new String[]{ "org.dimdev.jeid.PotionTransformer" }; }
@Override public String getModContainerClass() { return null; }
@Nullable @Override public String getSetupClass() { return null; }
@Override public void injectData(Map<String, Object> data) {}
Expand Down
206 changes: 206 additions & 0 deletions src/main/java/org/dimdev/jeid/PotionTransformer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
package org.dimdev.jeid;

import net.minecraft.launchwrapper.IClassTransformer;
import net.minecraft.launchwrapper.Launch;
import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionEffect;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.*;

import java.util.Iterator;
import java.util.function.Predicate;

/**
* This class was borrowed from Zabi94's MaxPotionIDExtender
* until we can figure out the issue with two of our Mixin
* classes with mappings. All credit in this class goes to Zabi
* and his incredible work on figuring out how to make this work.
*
* https://github.com/zabi94/MaxPotionIDExtender
*/
public class PotionTransformer implements IClassTransformer {

@Override
public byte[] transform(String name, String transformedName, byte[] basicClass) {
if (transformedName.equals("net.minecraft.network.play.server.SPacketEntityEffect")) {
return transformSPacketEntityEffect(basicClass);
}
if (transformedName.equals("net.minecraft.network.play.server.SPacketRemoveEntityEffect")) {
return transformSPacketRemoveEntityEffect(basicClass);
}
if (transformedName.equals("net.minecraft.nbt.NBTTagCompound")) {
ClassReader cr = new ClassReader(basicClass);
ClassNode cn = new ClassNode();
cr.accept(cn, 0);
if (!cn.name.equals(Obf.NBTTagCompound)) {
throw new RuntimeException("The class NBTTagCompound has broken mappings, should be "+cn.name);
}
}
if (transformedName.equals("net.minecraft.network.PacketBuffer")) {
ClassReader cr = new ClassReader(basicClass);
ClassNode cn = new ClassNode();
cr.accept(cn, 0);
if (!cn.name.equals(Obf.PacketBuffer)) {
throw new RuntimeException("The class PacketBuffer has broken mappings, should be "+cn.name);
}
}
return basicClass;
}

private static MethodNode locateMethod(ClassNode cn, String desc, String nameIn, String deobfNameIn) {
return cn.methods.parallelStream()
.filter(n -> n.desc.equals(desc) && (n.name.equals(nameIn) || n.name.equals(deobfNameIn)))
.findAny().orElseThrow(() -> new RuntimeException((nameIn +" ("+deobfNameIn+"): "+desc+" cannot be found in "+cn.name)));
}

private static AbstractInsnNode locateTargetInsn(MethodNode mn, Predicate<AbstractInsnNode> filter) {
AbstractInsnNode target = null;
Iterator<AbstractInsnNode> i = mn.instructions.iterator();
while (i.hasNext() && target == null) {
AbstractInsnNode n = i.next();
if (filter.test(n)) {
target = n;
}
}
if (target==null) {
//throw new ASMException("Can't locate target instruction in "+mn.name, mn);
}
return target;
}

private byte[] transformSPacketRemoveEntityEffect(byte[] basicClass) {
//Log.i("Patching SPacketRemoveEntityEffect");
ClassReader cr = new ClassReader(basicClass);
ClassNode cn = new ClassNode();
cr.accept(cn, 0);
String descriptors = "(L"+Obf.PacketBuffer+";)V";
MethodNode rpd = locateMethod(cn, descriptors, "readPacketData", "a");
AbstractInsnNode target = locateTargetInsn(rpd, n -> n.getOpcode() == Opcodes.INVOKEVIRTUAL && ((MethodInsnNode)n).name.equals("readUnsignedByte"));
rpd.instructions.insert(target, new MethodInsnNode(Opcodes.INVOKEVIRTUAL, Obf.PacketBuffer, "readInt", "()I", false));
rpd.instructions.remove(target);

MethodNode wpd = locateMethod(cn, descriptors, "writePacketData", "b");
target = locateTargetInsn(wpd, n -> n.getOpcode() == Opcodes.INVOKEVIRTUAL && ((MethodInsnNode)n).name.equals("writeByte"));
wpd.instructions.insert(target, new MethodInsnNode(Opcodes.INVOKEVIRTUAL, Obf.PacketBuffer, "writeInt", "(I)Lio/netty/buffer/ByteBuf;", false));
wpd.instructions.remove(target);

ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
cn.accept(cw);
//Log.i("Patch Successful");
return cw.toByteArray();
}

private byte[] transformSPacketEntityEffect(byte[] basicClass) {
//Log.i("Patching SPacketEntityEffect");
ClassReader cr = new ClassReader(basicClass);
ClassNode cn = new ClassNode();
cr.accept(cn, 0);

if (!Obf.SPacketEntityEffect.equals(cn.name)) {
//throw new ASMException("Mapping mismatch! SPacketEntityEffect is "+cn.name+", not "+Obf.SPacketEntityEffect);
}

//Adding a new field, int effectInt
cn.fields.add(new FieldNode(Opcodes.ACC_PUBLIC, "effectInt", "I", null, 0));

//Initialize this field in the constructor
MethodNode mn_init = locateMethod(cn, "(IL"+Obf.PotionEffect+";)V", "<init>", "<init>");
Iterator<AbstractInsnNode> i = mn_init.instructions.iterator();
AbstractInsnNode targetNode = null;
int line = 0;
while (i.hasNext() && targetNode == null) {
AbstractInsnNode node = i.next();
if (node instanceof LineNumberNode) {
if (line == 1) {
targetNode = node;
}
line++;
}
}

if (targetNode == null) {
//throw new ASMException("Can't find target node for SPacketEntityEffect constructor");
}

//These are reversed, they get pushed down the stack
mn_init.instructions.insert(targetNode, new FieldInsnNode(Opcodes.PUTFIELD, Obf.SPacketEntityEffect, "effectInt", "I"));
mn_init.instructions.insert(targetNode, new MethodInsnNode(Opcodes.INVOKESTATIC, Type.getInternalName(this.getClass()), "getIdFromPotEffect", "(L"+Obf.PotionEffect+";)I", false));
mn_init.instructions.insert(targetNode, new VarInsnNode(Opcodes.ALOAD, 2));
mn_init.instructions.insert(targetNode, new VarInsnNode(Opcodes.ALOAD, 0));

MethodNode mn_empty_init = locateMethod(cn, "()V", "<init>", "<init>");

AbstractInsnNode tgt = locateTargetInsn(mn_empty_init, n -> n.getOpcode()==Opcodes.RETURN);
mn_empty_init.instructions.insertBefore(tgt, new VarInsnNode(Opcodes.ALOAD, 0));
mn_empty_init.instructions.insertBefore(tgt, new LdcInsnNode(0));
mn_empty_init.instructions.insertBefore(tgt, new FieldInsnNode(Opcodes.PUTFIELD, Obf.SPacketEntityEffect, "effectInt", "I"));

//Patch readPacketData
MethodNode mn_readPacket = locateMethod(cn, "(L"+Obf.PacketBuffer+";)V", "readPacketData", "a");
String readVarInt_name = (Obf.isDeobf()?"readVarInt":"g");

AbstractInsnNode target = locateTargetInsn(mn_readPacket, n -> n.getOpcode()==Opcodes.RETURN).getPrevious().getPrevious();
mn_readPacket.instructions.insertBefore(target, new VarInsnNode(Opcodes.ALOAD, 0));
mn_readPacket.instructions.insertBefore(target, new VarInsnNode(Opcodes.ALOAD, 1));
mn_readPacket.instructions.insertBefore(target, new MethodInsnNode(Opcodes.INVOKEVIRTUAL, Obf.PacketBuffer, readVarInt_name, "()I", false));
mn_readPacket.instructions.insertBefore(target, new FieldInsnNode(Opcodes.PUTFIELD, Obf.SPacketEntityEffect, "effectInt", "I"));

//Patch writePacketData
MethodNode mn_writePacket = locateMethod(cn, "(L"+Obf.PacketBuffer+";)V", "writePacketData", "b");
String writeVarInt_name = (Obf.isDeobf()?"writeVarInt":"d");
AbstractInsnNode wp_target = locateTargetInsn(mn_writePacket, n -> n.getOpcode()==Opcodes.RETURN).getPrevious().getPrevious();

mn_writePacket.instructions.insertBefore(wp_target, new VarInsnNode(Opcodes.ALOAD, 1));
mn_writePacket.instructions.insertBefore(wp_target, new VarInsnNode(Opcodes.ALOAD, 0));
mn_writePacket.instructions.insertBefore(wp_target, new FieldInsnNode(Opcodes.GETFIELD, Obf.SPacketEntityEffect, "effectInt", "I"));
mn_writePacket.instructions.insertBefore(wp_target, new MethodInsnNode(Opcodes.INVOKEVIRTUAL, Obf.PacketBuffer, writeVarInt_name, "(I)L"+Obf.PacketBuffer+";", false));
mn_writePacket.instructions.insertBefore(wp_target, new InsnNode(Opcodes.POP));

ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
cn.accept(cw);
//Log.i("Patch Successful");
return cw.toByteArray();
}

public int getIdFromPotEffect(PotionEffect pe) {
return Potion.getIdFromPotion(pe.getPotion());
}

}

class Obf {


public static boolean isPotionClass(String s) {
if (s.endsWith(";")) {
s = s.substring(1, s.length()-1);
}
return s.equals(Type.getInternalName(Potion.class)) || s.equals("uz");
}

public static boolean isDeobf() {
return (boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment");
}

public static void loadData() {
if ((boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment")) {
NBTTagCompound = "net/minecraft/nbt/NBTTagCompound";
PotionEffect ="net/minecraft/potion/PotionEffect";
SPacketEntityEffect = "net/minecraft/network/play/server/SPacketEntityEffect";
PacketBuffer = "net/minecraft/network/PacketBuffer";
} else {
NBTTagCompound = "fy";
PotionEffect = "va";
SPacketEntityEffect = "kw";
PacketBuffer = "gy";
}
}

public static String NBTTagCompound;
public static String PotionEffect;
public static String SPacketEntityEffect;
public static String PacketBuffer;
}
10 changes: 7 additions & 3 deletions src/main/java/org/dimdev/jeid/mixin/core/MixinGameData.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ private static int getItemIDLimit(int value) {
return Integer.MAX_VALUE - 1;
}

/** @reason Removes the biome ID limit. */
@ModifyConstant(method = "init", constant = @Constant(intValue = 255, ordinal = 1), remap = false)
private static int getBiomeIDLimit(int value) {
/** @reason Removes the potion ID limit. */
@ModifyConstant(method = "init", constant = @Constant(intValue = 255, ordinal = 0), remap = false)
private static int getPotionIDLimit(int value) {
return Integer.MAX_VALUE - 1;
}

/** @reason Removes the biome ID limit. */
@ModifyConstant(method = "init", constant = @Constant(intValue = 255, ordinal = 1), remap = false)
private static int getBiomeIDLimit(int value) { return Integer.MAX_VALUE - 1; }
}
Loading

0 comments on commit 49419cf

Please sign in to comment.