Kajetan Johannes Hammerle 5 years ago
commit
5aeb072d7b

+ 9 - 0
.gitignore

@@ -0,0 +1,9 @@
+/run
+/build
+/gradle
+build.gradle
+gradle.properties
+gradlew
+/.gradle
+/.nb-gradle
+.nb-gradle-properties

+ 36 - 0
src/main/java/me/ktcm/KajetansLoadingPlugin.java

@@ -0,0 +1,36 @@
+package me.ktcm;
+
+import java.util.Map;
+import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
+
+public class KajetansLoadingPlugin implements IFMLLoadingPlugin
+{        
+    @Override
+    public String[] getASMTransformerClass() 
+    {
+        return new String[] {KajetansTransformer.class.getName()};
+    }
+
+    @Override
+    public String getModContainerClass() 
+    {
+        return null; //KajetansModContainer.class.getName();
+    }
+
+    @Override
+    public String getSetupClass() 
+    {
+        return null;//KajetansHooks.class.getName();
+    }
+
+    @Override
+    public void injectData(Map<String, Object> data) 
+    {
+    }
+
+    @Override
+    public String getAccessTransformerClass() 
+    {
+        return null;
+    }
+}

+ 30 - 0
src/main/java/me/ktcm/KajetansTextCoreMod.java

@@ -0,0 +1,30 @@
+package me.ktcm;
+
+import net.minecraftforge.fml.common.Mod;
+import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
+
+@Mod(modid = KajetansTextCoreMod.MODID, version = KajetansTextCoreMod.VERSION, name = KajetansTextCoreMod.NAME, acceptableRemoteVersions = "*")
+public class KajetansTextCoreMod 
+{
+    public static final String MODID = "ktcm";
+    public static final String NAME = "Kajetans Text Core Mod";
+    public static final String VERSION = "0.0.1";
+    
+    @Mod.EventHandler
+    public void preInit(FMLPreInitializationEvent e) 
+    {
+        System.out.println(NAME + " is loading!");
+        /*net.minecraftforge.common.MinecraftForge.EVENT_BUS.register(new Object()
+            {
+                @net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+                public void wusi(ServerChatEvent e) 
+                {
+                    e.setComponent(new TextComponentString(
+                            "§0█§1█§2█§3█§4█§5█§6█§7█§8█§9█§a█§b█§c█§d█§e█§f█" + 
+                            "§g█§h█§i█§j█§p█§q█§s█§t█§u█§v█§w█§x█§y█§z█" + 
+                            "§0D§1a§2s §3i§4s§5t §6e§7i§8n §9S§ac§bh§cr§di§ef§ft" + 
+                            "§gt§he§is§jt §pH§qa§sl§tl§uo§vo§wo§xo§yo§zo"));
+                }
+            });*/
+    }
+}

+ 198 - 0
src/main/java/me/ktcm/KajetansTransformer.java

@@ -0,0 +1,198 @@
+package me.ktcm;
+
+import net.minecraft.launchwrapper.IClassTransformer;
+import net.minecraft.launchwrapper.Launch;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.FieldInsnNode;
+import org.objectweb.asm.tree.FrameNode;
+import org.objectweb.asm.tree.InsnList;
+import org.objectweb.asm.tree.InsnNode;
+import org.objectweb.asm.tree.LineNumberNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.VarInsnNode;
+
+public class KajetansTransformer implements IClassTransformer
+{
+    private final boolean obfuscated;
+    
+    public KajetansTransformer() 
+    {
+        Boolean ldev = (Boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment");
+        if(ldev == null)
+        {
+            obfuscated = true;
+        }
+        else
+        {
+            obfuscated = !ldev;
+        }
+    }
+    
+    @Override
+    public byte[] transform(String old, String searge, byte[] bytes)
+    {
+        if(searge.equals("net.minecraft.client.gui.FontRenderer"))
+        {
+            //net.minecraft.client.gui.FontRenderer;
+            System.out.println("|‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾");
+            System.out.println("| Patching net.minecraft.client.gui.FontRenderer");
+            System.out.println("|___________________________________________________");
+            return patchColorHook(old, bytes);
+        }
+        return bytes;
+    }
+
+    public byte[] patchColorHook(String c, byte[] bytes)
+    {
+        try
+        {
+            ClassNode classNode = new ClassNode();
+            ClassReader classReader = new ClassReader(bytes);
+            classReader.accept(classNode, 0);
+            
+            // net/minecraft/client/gui/FontRenderer bip
+            // func_78255_a renderStringAtPos  Render a single line string at the current (posX,posY) and update posX
+            // MD: net/minecraft/client/gui/FontRenderer/renderStringAtPos (Ljava/lang/String;Z)V bip/a (Ljava/lang/String;Z)V
+            MethodNode mn;
+            if(obfuscated)
+            {
+                mn = classNode.methods.stream().filter(me -> me.name.equals("a")).filter(me -> "(Ljava/lang/String;Z)V".equals(me.desc)).findAny().get();
+            }
+            else
+            {
+                mn = classNode.methods.stream().filter(me -> me.name.equals("renderStringAtPos")).findAny().get();
+            }
+            
+            InsnList ins = mn.instructions;
+            int index = 0; 
+            boolean found = false;
+            AbstractInsnNode next;
+            while(index < ins.size())
+            {
+                next = ins.get(index);
+                if(next instanceof MethodInsnNode)
+                {
+                    MethodInsnNode mnode = (MethodInsnNode) next;
+                    if(mnode.name.equals("valueOf") && mnode.desc.equals("(C)Ljava/lang/String;"))
+                    {
+                        found = true;
+            
+                        // LdcInsnNode  18  9  - loading of string constant "0123456789abcdefklmnor", must be removed
+                        // VarInsnNode  25  2  1
+                        // VarInsnNode  21  2  3
+                        // InsnNode  4  0  
+                        // InsnNode  96  0  
+                        // MethodInsnNode  182  5  (I)C false charAt java/lang/String
+                        // insert new instruction here
+                        // MethodInsnNode  184  5  (C)Ljava/lang/String; false valueOf java/lang/String - search for this instruction, its not obfuscated
+                        // FieldInsnNode  178  4  Ljava/util/Locale; ROOT java/util/Locale - must be removed
+                        // MethodInsnNode  182  5  (Ljava/util/Locale;)Ljava/lang/String; false toLowerCase java/lang/String - must be removed
+                        // InsnNode  3  0  - must be removed
+                        // MethodInsnNode  182  5  (I)C false charAt java/lang/String - must be removed
+                        // MethodInsnNode  182  5  (I)I false indexOf java/lang/String - must be removed
+                        // VarInsnNode  54  2  5
+                        // LabelNode  -1  8  
+            
+                        index--;
+                        ins.remove(ins.get(index - 5)); // remove "0123456789abcdefklmnor"
+                        ins.remove(ins.get(index));
+                        ins.remove(ins.get(index));
+                        ins.remove(ins.get(index));
+                        ins.remove(ins.get(index));
+                        ins.remove(ins.get(index));
+                        ins.remove(ins.get(index));
+                        ins.insert(ins.get(index - 1), new MethodInsnNode(Opcodes.INVOKESTATIC, "me/ktcm/events/Hooks", "onColorCodeChosen", "(CZ)I", false));
+                        ins.insert(ins.get(index - 1), new VarInsnNode(Opcodes.ILOAD, 2)); // push boolean shadow on the stack, inverted order
+                        break;
+                    }
+                }
+                index++;
+            }
+            
+            if(!found)
+            {
+                System.out.println("Start of color hook was not found");
+                return bytes;
+            }
+            
+            /*java.util.ListIterator<AbstractInsnNode> list = ins.iterator();
+            while(list.hasNext())
+            {
+                System.out.println(getString(list.next()));
+            }*/
+
+            ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
+            classNode.accept(writer);
+            return writer.toByteArray();
+        }
+        catch(Exception ex)
+        {
+            ex.printStackTrace();
+        }       
+        return bytes;
+    }
+    
+    public String getString(AbstractInsnNode node)
+    {
+        StringBuilder sb = new StringBuilder();
+        sb.append(node.getClass().getSimpleName());
+        sb.append("  ");
+        sb.append(node.getOpcode());
+        sb.append("  ");
+        sb.append(node.getType());
+        sb.append("  ");
+        if(node instanceof LineNumberNode)
+        {
+            LineNumberNode n = (LineNumberNode) node;
+            sb.append(n.line);
+            sb.append(" ");
+            sb.append(n.start);
+        }
+        else if(node instanceof VarInsnNode)
+        {
+            VarInsnNode n = (VarInsnNode) node;
+            sb.append(n.var);
+        }
+        else if(node instanceof MethodInsnNode)
+        {
+            MethodInsnNode n = (MethodInsnNode) node;
+            sb.append(n.desc);
+            sb.append(" ");
+            sb.append(n.itf);
+            sb.append(" ");
+            sb.append(n.name);
+            sb.append(" ");
+            sb.append(n.owner);
+        }
+        else if(node instanceof FrameNode)
+        {
+            FrameNode n = (FrameNode) node;
+            if(n.local != null)
+            {
+                n.local.forEach(s -> {sb.append(s); sb.append(" ");});
+            }
+            if(n.stack != null)
+            {
+                n.stack.forEach(s -> {sb.append(s); sb.append(" ");});
+            }
+        }
+        else if(node instanceof InsnNode)
+        {
+        }
+        else if(node instanceof FieldInsnNode)
+        {
+            FieldInsnNode n = (FieldInsnNode) node;
+            sb.append(n.desc);
+            sb.append(" ");
+            sb.append(n.name);
+            sb.append(" ");
+            sb.append(n.owner);
+        }
+        return sb.toString();
+    }
+}

+ 165 - 0
src/main/java/me/ktcm/events/Hooks.java

@@ -0,0 +1,165 @@
+package me.ktcm.events;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import net.minecraft.client.Minecraft;
+import net.minecraftforge.fml.relauncher.ReflectionHelper;
+import net.minecraft.client.gui.FontRenderer;
+
+public class Hooks 
+{
+    public static int onColorCodeChosen(char c, boolean shadow)
+    {
+        switch(c)
+        {
+            case '0': return 0;
+            case '1': return 1;
+            case '2': return 2;
+            case '3': return 3;
+            case '4': return 4;
+            case '5': return 5;
+            case '6': return 6;
+            case '7': return 7;
+            case '8': return 8;
+            case '9': return 9;
+            case 'a': return 10;
+            case 'b': return 11;
+            case 'c': return 12;
+            case 'd': return 13;
+            case 'e': return 14;
+            case 'f': return 15;
+            case 'k': return 16;
+            case 'l': return 17;
+            case 'm': return 18;
+            case 'n': return 19;
+            case 'o': return 20;
+            case 'r': return 21;
+            case 'A': return 10;
+            case 'B': return 11;
+            case 'C': return 12;
+            case 'D': return 13;
+            case 'E': return 14;
+            case 'F': return 15;
+            case 'K': return 16;
+            case 'L': return 17;
+            case 'M': return 18;
+            case 'N': return 19;
+            case 'O': return 20;
+            case 'R': return 21;
+            
+            // brown
+            case 'g': 
+            case 'G': setColor(shadow, 0.4f, 0.2f, 0.0f, 0.1f, 0.05f, 0.0f); return 22;
+            case 'h': 
+            case 'H': setColor(shadow, 0.6f, 0.4f, 0.2f, 0.15f, 0.1f, 0.05f); return 22;
+            
+            // blue
+            case 'i': 
+            case 'I': setColor(shadow, 0.0f, 0.2f, 0.4f, 0.0f, 0.05f, 0.1f); return 22;
+            case 'j': 
+            case 'J': setColor(shadow, 0.0f, 0.4f, 0.6f, 0.0f, 0.1f, 0.15f); return 22;
+            
+            // green
+            case 'p': 
+            case 'P': setColor(shadow, 0.4f, 0.6f, 0.0f, 0.1f, 0.15f, 0.0f); return 22;
+            case 'q': 
+            case 'Q': setColor(shadow, 0.6f, 0.8f, 0.0f, 0.15f, 0.2f, 0.0f); return 22;
+            
+            // cyan
+            case 's': 
+            case 'S': setColor(shadow, 0.0f, 0.6f, 1.0f, 0.0f, 0.15f, 0.25f); return 22;
+            case 't': 
+            case 'T': setColor(shadow, 0.4f, 0.8f, 1.0f, 0.1f, 0.2f, 0.25f); return 22;
+            
+            // red
+            case 'u': 
+            case 'U': setColor(shadow, 0.6f, 0.2f, 0.0f, 0.15f, 0.05f, 0.0f); return 22;
+            case 'v': 
+            case 'V': setColor(shadow, 0.8f, 0.4f, 0.0f, 0.2f, 0.1f, 0.0f); return 22;
+            
+            
+            // violet
+            case 'w': 
+            case 'W': setColor(shadow, 0.4f, 0.0f, 0.4f, 0.1f, 0.0f, 0.1f); return 22;
+            case 'x': 
+            case 'X': setColor(shadow, 0.6f, 0.0f, 0.8f, 0.15f, 0.0f, 0.2f); return 22;
+            
+            // yellow
+            case 'y': 
+            case 'Y': setColor(shadow, 0.8f, 0.6f, 0.0f, 0.2f, 0.15f, 0.0f); return 22;
+            case 'z': 
+            case 'Z': setColor(shadow, 1.0f, 0.8f, 0.0f, 0.25f, 0.2f, 0.0f); return 22;
+        }
+        return -1;
+    }
+    
+    private static void setColor(boolean shadow, float r, float g, float b, float dr, float dg, float db)
+    {
+        if(shadow)
+        {
+            setColor(dr, dg, db);
+        }
+        else
+        {
+            setColor(r, g, b);
+        }
+    }
+    
+    private static Method getMethod(Class c, String name, String oName, Class... classes)
+    {
+        try
+        {
+            return ReflectionHelper.findMethod(c, name, oName, classes);
+        }
+        catch(SecurityException | ReflectionHelper.UnableToFindFieldException ex)
+        {
+            System.out.println(name + " - " + oName + " - " + ex);
+        }
+        return null;
+    }
+    
+    private static Field getField(Class c, String... field)
+    {
+        try
+        {
+            return ReflectionHelper.findField(c, field);
+        }
+        catch(SecurityException | ReflectionHelper.UnableToFindFieldException ex)
+        {
+            System.out.println(String.join(" - ", field) + " - " + ex);
+        }
+        return null;
+    }
+    
+    private final static FontRenderer FONT = Minecraft.getMinecraft().fontRenderer;
+    // /home/kajetan/.gradle/caches/minecraft/de/oceanlabs/mcp/mcp_snapshot/20171003/1.12.2/srgs/mcp-srg.srg
+    // FD: net/minecraft/client/gui/FontRenderer/alpha net/minecraft/client/gui/FontRenderer/field_78305_q
+    private final static Field ALPHA = getField(FontRenderer.class, "field_78305_q", "alpha");
+    
+    public static float getAlpha()
+    {
+        try
+        {
+            return ALPHA.getFloat(FONT);
+        }
+        catch(SecurityException | IllegalAccessException | IllegalArgumentException ex)
+        {
+            return 1;
+        }
+    }
+    
+    private final static Method SET_COLOR = getMethod(FontRenderer.class, "setColor", null, float.class, float.class, float.class, float.class);
+    
+    public static void setColor(float r, float g, float b)
+    {
+        try
+        {
+            SET_COLOR.invoke(FONT, r, g, b, getAlpha());
+        }
+        catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException ex)
+        {
+            ex.printStackTrace();
+        }
+    }
+}

+ 16 - 0
src/main/resources/mcmod.info

@@ -0,0 +1,16 @@
+[
+{
+  "modid": "kcm",
+  "name": "Kajetans Core Mod",
+  "description": "Kajetans Core Mod für Mundus Crassus",
+  "version": "${version}",
+  "mcversion": "${mcversion}",
+  "url": "",
+  "updateUrl": "",
+  "authorList": ["kajetanjohannes"],
+  "credits": "kajetanjohannes",
+  "logoFile": "",
+  "screenshots": [],
+  "dependencies": []
+}
+]