Initial Commit
This commit is contained in:
@@ -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
@@ -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.
@@ -0,0 +1 @@
|
||||
these are tools needed for looking at obfuscated minecraft code.
|
||||
@@ -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..
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
include ":ASMHelper"
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user