Initial Commit

This commit is contained in:
James Seibel
2021-02-07 21:32:26 -06:00
parent a08e36f127
commit b22d6345d2
18 changed files with 277 additions and 37 deletions
+4
View File
@@ -0,0 +1,4 @@
[submodule "ASMHelper"]
path = ASMHelper
url = https://github.com/squeek502/ASMHelper.git
branch = 1.12.x
Submodule
+1
Submodule ASMHelper added at 6f5aeda4cc
+5 -1
View File
@@ -18,8 +18,12 @@ Step 3: run the command: "./gradlew eclipse"
Step 4: Import project
Step 5: create a system variable called "JAVA_MC_HOME" with the location of the JDK 1.8.0_251 (This is needed for gradle to work correctly)
And make sure it is used in the build.gradle file.
Step 6: make sure the eclipse has the JDK 1.8.0_251 installed. (This is needed so that eclipse can run minecraft)
Step 6: In the eclipse run configuration add "-Dfml.coreMods.load=backsun.lod.LodMain"
This lets forge know that you have a core mod you want to run.
Step 7: make sure the eclipse has the JDK 1.8.0_251 installed. (This is needed so that eclipse can run minecraft)
Other commands:
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
these are tools needed for looking at obfuscated minecraft code.
+8
View File
@@ -33,6 +33,14 @@ minecraft {
// makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
}
jar {
manifest {
attributes 'FMLCorePlugin': 'backsun.lod.LodMain'
//attributes 'FMLCorePluginContainsMod': 'true'
attributes 'FMLCorePluginContainsFMLMod': 'true'
}
}
dependencies {
// you may put jars on which you depend on in ./libs
// or you may define them like so..
+1
View File
@@ -0,0 +1 @@
include ":ASMHelper"
+8
View File
@@ -0,0 +1,8 @@
package backsun.lod;
// -Dfml.coreMods.load=backsun.lod.LodCore
public class LodCore
{
}
@@ -1,5 +1,8 @@
package backsun.lod;
import java.util.Map;
import backsun.lod.asm.RenderGlobalClassTransformer;
import backsun.lod.proxy.ClientProxy;
import backsun.lod.proxy.CommonProxy;
import backsun.lod.util.Reference;
@@ -12,17 +15,20 @@ import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
/**
*
* @author James Seibel
* @version 08-31-2020
* @version 02-07-2021
*/
@IFMLLoadingPlugin.MCVersion("1.12.2")
@IFMLLoadingPlugin.TransformerExclusions({"backsun.lod.asm"})
@Mod(modid = Reference.MOD_ID, name = Reference.NAME, version = Reference.VERSION)
public class Main
public class LodMain implements IFMLLoadingPlugin
{
@Instance
public static Main instance;
public static LodMain instance;
@SidedProxy(clientSide = Reference.CLIENT_PROXY_CLASS, serverSide = Reference.COMMON_PROXY_CLASS)
public static CommonProxy common_proxy;
@@ -39,7 +45,6 @@ public class Main
{
MinecraftForge.EVENT_BUS.register(common_proxy);
client_proxy = new ClientProxy();
}
@EventHandler
@@ -47,4 +52,39 @@ public class Main
{
}
// required for IFMLLoadingPlugin
@Override
public String[] getASMTransformerClass()
{
return new String[] { RenderGlobalClassTransformer.class.getName() };
}
@Override
public String getModContainerClass()
{
// unneeded since we are also running a normal mod
return null;
}
@Override
public String getSetupClass() {
// TODO Auto-generated method stub
return null;
}
@Override
public void injectData(Map<String, Object> data) {
// TODO Auto-generated method stub
}
@Override
public String getAccessTransformerClass() {
// TODO Auto-generated method stub
return null;
}
}
@@ -0,0 +1,130 @@
package backsun.lod.asm;
import java.util.Arrays;
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.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.VarInsnNode;
import backsun.lod.util.RenderGlobalHook;
import net.minecraft.launchwrapper.IClassTransformer;
public class RenderGlobalClassTransformer implements IClassTransformer
{
private static final String[] classesBeingTransformed = { "net.minecraft.client.renderer.RenderGlobal" };
@Override
public byte[] transform(String name, String transformedName, byte[] classBeingTransformed)
{
int index = Arrays.asList(classesBeingTransformed).indexOf(transformedName);
// do we wan't to transform this class?
if (index != -1)
{
// yes, transform this class
boolean isObfuscated = !name.equals(transformedName);
return transformClass(index, classBeingTransformed, isObfuscated);
}
else
{
// no, just skip this class
return classBeingTransformed;
}
}
private static byte[] transformClass(int index, byte[] classBeingTransformed, boolean isObfuscated)
{
try
{
// convert the byte code into readable ASM code
ClassNode classNode = new ClassNode();
ClassReader classReader = new ClassReader(classBeingTransformed);
classReader.accept(classNode, 0);
transformRenderGlobal(classNode, isObfuscated);
// convert back into byte code
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
classNode.accept(classWriter);
return classWriter.toByteArray();
}
catch(Exception e)
{
e.printStackTrace();
}
return classBeingTransformed;
}
private static void transformRenderGlobal(ClassNode classNode, boolean isObfuscated)
{
final String methodName = isObfuscated ? "a" : "renderBlockLayer";
final String methodDesc = isObfuscated ?
"(Lamk;)V" :
"(Lnet/minecraft/util/BlockRenderLayer;)V";
for (MethodNode method : classNode.methods)
{
if (method.name.equals(methodName) && method.desc.equals(methodDesc))
{
AbstractInsnNode firstLoadNode = null;
AbstractInsnNode firstReturnNode = null;
for (AbstractInsnNode instruction : method.instructions.toArray())
{
if (firstLoadNode == null && instruction.getOpcode() == Opcodes.ALOAD)
{
// look for the first time the RenderGlobal (self)
// variable is loaded, IE the first line of code
// in the unedited method
if (((VarInsnNode) instruction).var == 0)
{
firstLoadNode = instruction;
}
}
if (instruction.getOpcode() == Opcodes.RETURN)
{
// look for the first (and only) return statement
// IE the last line of code in the unedited method
firstReturnNode = instruction;
break;
}
}
if (firstLoadNode != null && firstReturnNode != null)
{
// add the startRenderingStencil method to the beginning of the method
InsnList toInsert = new InsnList();
toInsert.add(new VarInsnNode(Opcodes.ALOAD, 1)); // BlockRenderLayer variable
toInsert.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Type.getInternalName(RenderGlobalHook.class), RenderGlobalHook.START_STENCIL_METHOD_NAME, isObfuscated ? "(Lamk;)V" : "(Lnet/minecraft/util/BlockRenderLayer;)V", false));
toInsert.add(new LabelNode());
method.instructions.insertBefore(firstLoadNode, toInsert);
// add the endRenderingStencil method to the end of the method
toInsert = new InsnList();
toInsert.add(new VarInsnNode(Opcodes.ALOAD, 1)); // BlockRenderLayer variable
toInsert.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Type.getInternalName(RenderGlobalHook.class), RenderGlobalHook.END_STENCIL_METHOD_NAME, isObfuscated ? "(Lamk;)V" : "(Lnet/minecraft/util/BlockRenderLayer;)V", false));
toInsert.add(new LabelNode());
method.instructions.insertBefore(firstReturnNode, toInsert);
}
else
{
System.out.println("Something went wrong transforming RenderGlobal!");
}
}
}
}
}
@@ -20,8 +20,6 @@ import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.event.terraingen.PopulateChunkEvent;
import net.minecraftforge.event.world.ChunkEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.Phase;
import net.minecraftforge.fml.common.gameevent.TickEvent.RenderTickEvent;
/**
* This is used by the client.
@@ -49,34 +47,15 @@ public class ClientProxy extends CommonProxy
// render event //
//==============//
@SubscribeEvent
public void renderTick(RenderTickEvent event)
{
if (event.phase == Phase.START)
{
startRenderingStencil();
}
}
public static void startRenderingStencil()
{
GL11.glClearStencil(0);
GL11.glStencilMask(0xFF); //255
GL11.glClear(GL11.GL_STENCIL_BUFFER_BIT);
GL11.glEnable(GL11.GL_STENCIL_TEST);
GL11.glStencilFunc(GL11.GL_ALWAYS, 1, 0x11111111); // the 2 numbers here don't matter since GL_ALWAYS is being used
GL11.glStencilMask(0b11111111);
GL11.glStencilOp(GL11.GL_KEEP, // this doesn't mater since GL_ALWAYS is being used
GL11.GL_KEEP, // stencil test passes
GL11.GL_INCR); // stencil + depth pass
//GL11.glStencilOp(GL11.GL_INCR, GL11.GL_INCR, GL11.GL_INCR);
}
public static void endRenderingStencil()
{
GL11.glStencilOp(GL11.GL_KEEP, // this doesn't mater since GL_ALWAYS is being used
GL11.GL_KEEP, // stencil test passes
GL11.GL_KEEP); // stencil + depth pass
}
// @SubscribeEvent
// public void renderTick(RenderTickEvent event)
// {
// if (event.phase == Phase.START)
// {
// RenderGlobalHook.startRenderingStencil(null);
// }
// }
@@ -85,9 +64,8 @@ public class ClientProxy extends CommonProxy
@SubscribeEvent
public void renderWorldLast(RenderWorldLastEvent event)
{
endRenderingStencil();
// RenderGlobalHook.endRenderingStencil(null);
GL11.glStencilFunc(GL11.GL_EQUAL, 0, 0xFF);
// GEQUAL 1, once EQUAL 1 doens't render on mountains
renderLods(event.getPartialTicks());
@@ -0,0 +1,65 @@
package backsun.lod.util;
import org.lwjgl.opengl.GL11;
import net.minecraft.util.BlockRenderLayer;
/**
*
* @author James Seibel
* @version 02-07-2021
*/
public class RenderGlobalHook
{
/**
* this variable should be the same as the method name below.
* It is used when transforming the RenderGlobal class'
* renderBlockLayer method.
*/
public static final String START_STENCIL_METHOD_NAME = "startRenderingStencil";
/**
* Start drawing to the stencil
* <br><br>
* called in the order: <br>
* BlockRenderLayer.SOLID <br>
* BlockRenderLayer.CUTOUT_MIPPED <br>
* BlockRenderLayer.CUTOUT <br>
* BlockRenderLayer.TRANSLUCENT <br>
*/
public static void startRenderingStencil(BlockRenderLayer blockLayerIn)
{
// solid is the first layer rendered
// clear the buffer so we can start fresh.
// if this isn't cleared first we will have overlap with the fog
// outside the world
if (blockLayerIn == BlockRenderLayer.SOLID)
{
GL11.glClearStencil(0);
GL11.glStencilMask(0xFF); //255
GL11.glClear(GL11.GL_STENCIL_BUFFER_BIT);
}
GL11.glEnable(GL11.GL_STENCIL_TEST);
GL11.glStencilFunc(GL11.GL_ALWAYS, 1, 0x11111111); // the 2 numbers here don't matter since GL_ALWAYS is being used
GL11.glStencilMask(0b11111111);
GL11.glStencilOp(GL11.GL_KEEP, // this doesn't mater since GL_ALWAYS is being used
GL11.GL_KEEP, // stencil test passes
GL11.GL_REPLACE); // stencil + depth pass
}
/**
* this variable should be the same as the method name below.
* It is used when transforming the RenderGlobal class'
* renderBlockLayer method.
*/
public static final String END_STENCIL_METHOD_NAME = "endRenderingStencil";
public static void endRenderingStencil(BlockRenderLayer blockLayerIn)
{
GL11.glStencilOp(GL11.GL_KEEP, // this doesn't mater since GL_ALWAYS is being used
GL11.GL_KEEP, // stencil test passes
GL11.GL_KEEP); // stencil + depth pass
}
}