Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.0.2 #36

Merged
merged 2 commits into from
Oct 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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