• Recently Browsing

    No registered users viewing this page.

  • Posts

    • So... it's generating a renderer class at runtime. Why? What is the purpose of this? I'm not going to decypher all that ASM code.
    • I'm not even sure whether this code from 1.12.2 will work (if not work, i will have to learn bci, which would be terrible) package com.github.patrick.customentity.renderer.asm; import com.github.patrick.customentity.client.CustomEntity; import com.github.patrick.customentity.client.CustomEntityEvent; import com.github.patrick.customentity.renderer.CustomRenderer; import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.client.renderer.entity.EntityRendererManager; import net.minecraft.client.renderer.entity.GiantZombieRenderer; import net.minecraft.client.renderer.entity.LivingRenderer; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.FieldVisitor; import net.minecraft.client.Minecraft; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashSet; @SuppressWarnings("rawtypes") public class ASMRenderer implements Opcodes { private static final Field SHADOW_SIZE; private static final Method PRE_RENDER_CALL_BACK; private static final ASMClassLoader CLASS_LOADER; private static int count; static { CLASS_LOADER = new ASMClassLoader(); PRE_RENDER_CALL_BACK = getPreRenderCallback(); SHADOW_SIZE = getShadowSize(); } public static LivingRenderer createRenderClass(final Class<? extends Entity> entityClass, final LivingRenderer render) throws Exception { final Class<?> superClass = render.getClass(); final String className = "com/github/patrick/customentity/renderer/" + superClass.getSimpleName() + "Custom" + count++; final ClassWriter writer = new ClassWriter(0); writer.visit(V1_6, ACC_PUBLIC + ACC_SUPER, className, null, Type.getInternalName(superClass), new String[] { Type.getInternalName(CustomRenderer.class) }); writer.visitSource(".dynamic", null); final FieldVisitor fv = writer.visitField(ACC_PRIVATE + ACC_FINAL, "defaultShadowSize", "F", null, null); fv.visitEnd(); int stack = 0; Constructor<?> con; if (GiantZombieRenderer.class.isAssignableFrom(superClass)) { con = findConstructor(superClass, EntityRendererManager.class, Float.TYPE); stack = 1; } else con = findConstructor(superClass, EntityRendererManager.class); if (con == null) return null; MethodVisitor visitor = writer.visitMethod(ACC_PUBLIC, "<init>", "(" + Type.getDescriptor(EntityRendererManager.class) + ")V", null, null); visitor.visitCode(); visitor.visitVarInsn(ALOAD, 0); visitor.visitVarInsn(ALOAD, 1); if (stack == 1) visitor.visitLdcInsn(6F); visitor.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(superClass), "<init>", Type.getConstructorDescriptor(con), false); visitor.visitVarInsn(ALOAD, 0); visitor.visitVarInsn(ALOAD, 0); visitor.visitFieldInsn(GETFIELD, Type.getInternalName(superClass), SHADOW_SIZE.getName(), "F"); visitor.visitFieldInsn(PUTFIELD, className, "defaultShadowSize", "F"); visitor.visitInsn(RETURN); visitor.visitMaxs(2 + stack, 2); visitor.visitEnd(); final Label ifLabel = new Label(); final Method preRenderCallback = findPreRenderCallback(entityClass, superClass); if (preRenderCallback == null) return null; visitor = writer.visitMethod(ACC_PUBLIC, preRenderCallback.getName(), "(" + Type.getDescriptor(entityClass) + "F)V", null, null); visitor.visitCode(); if (preRenderCallback.getDeclaringClass() != LivingRenderer.class) { visitor.visitVarInsn(ALOAD, 0); visitor.visitVarInsn(ALOAD, 1); visitor.visitVarInsn(FLOAD, 2); visitor.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(superClass), preRenderCallback.getName(), Type.getMethodDescriptor(preRenderCallback), false); } visitor.visitFieldInsn(GETSTATIC, Type.getInternalName(CustomEntityEvent.class), "rendering", Type.getDescriptor(CustomEntity.class)); visitor.visitVarInsn(ASTORE, 3); visitor.visitVarInsn(ALOAD, 0); visitor.visitFieldInsn(GETFIELD, className, "defaultShadowSize", "F"); visitor.visitVarInsn(FSTORE, 4); visitor.visitVarInsn(ALOAD, 3); visitor.visitJumpInsn(IFNULL, ifLabel); visitor.visitVarInsn(FLOAD, 4); visitor.visitVarInsn(ALOAD, 3); visitor.visitVarInsn(ALOAD, 1); visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(CustomEntity.class), "applyGraphic", "(" + Type.getDescriptor(LivingEntity.class) + ")F", false); visitor.visitInsn(FMUL); visitor.visitVarInsn(FSTORE, 4); visitor.visitLabel(ifLabel); visitor.visitLineNumber(33, ifLabel); visitor.visitFrame(1, 2, new Object[] { Type.getInternalName(CustomEntity.class), FLOAT }, 0, null); visitor.visitVarInsn(ALOAD, 0); visitor.visitVarInsn(FLOAD, 4); visitor.visitFieldInsn(PUTFIELD, className, SHADOW_SIZE.getName(), "F"); visitor.visitInsn(RETURN); visitor.visitMaxs(3, 5); visitor.visitEnd(); visitor = writer.visitMethod(ACC_PUBLIC, "setShadowSize", "(F)V", null, null); visitor.visitCode(); visitor.visitVarInsn(ALOAD, 0); visitor.visitVarInsn(FLOAD, 1); visitor.visitFieldInsn(PUTFIELD, className, SHADOW_SIZE.getName(), "F"); visitor.visitInsn(RETURN); visitor.visitMaxs(2, 2); visitor.visitEnd(); if (preRenderCallback.getParameterTypes()[0] != entityClass) { visitor = writer.visitMethod(ACC_PROTECTED + ACC_VOLATILE + ACC_SYNTHETIC, PRE_RENDER_CALL_BACK.getName(), Type.getMethodDescriptor(preRenderCallback), null, null); visitor.visitCode(); visitor.visitVarInsn(ALOAD, 0); visitor.visitVarInsn(ALOAD, 1); visitor.visitTypeInsn(CHECKCAST, Type.getInternalName(entityClass)); visitor.visitVarInsn(FLOAD, 2); visitor.visitMethodInsn(INVOKEVIRTUAL, className, PRE_RENDER_CALL_BACK.getName(), "(" + Type.getDescriptor(entityClass) + "F)V", false); visitor.visitInsn(RETURN); visitor.visitMaxs(3, 3); visitor.visitEnd(); } writer.visitEnd(); return (LivingRenderer) CLASS_LOADER.define(className.replace('/', '.'), writer.toByteArray()).getConstructor(EntityRendererManager.class).newInstance(Minecraft.getInstance().getRenderManager()); } private static Constructor<?> findConstructor(final Class<?> c, final Class... parameterTypes) { try { return c.getConstructor((Class<?>[])parameterTypes); } catch (Exception e) { return null; } } private static Method findPreRenderCallback(final Class<? extends Entity> entityClass, Class<?> renderClass) { while (LivingRenderer.class.isAssignableFrom(renderClass)) { Class<?> superEntityClass = entityClass; while (LivingEntity.class.isAssignableFrom(superEntityClass)) { try { return renderClass.getDeclaredMethod(PRE_RENDER_CALL_BACK.getName(), superEntityClass, Float.TYPE); } catch (Exception ex) { superEntityClass = superEntityClass.getSuperclass(); } } renderClass = renderClass.getSuperclass(); } return null; } private static Field getShadowSize() throws RuntimeException { Exception failed = null; for (String fieldName : new HashSet<>(Arrays.asList("shadowSize", "field_76989_e"))) try { Field field = EntityRenderer.class.getDeclaredField(fieldName); field.setAccessible(true); return field; } catch (Exception e) { failed = e; } throw new RuntimeException(failed); } private static Method getPreRenderCallback() throws RuntimeException { Exception failed = null; for (String fieldName : new HashSet<>(Arrays.asList("func_77041_b", "preRenderCallback"))) try { Method method = LivingRenderer.class.getDeclaredMethod(fieldName, LivingEntity.class, Float.TYPE); method.setAccessible(true); return method; } catch (Exception e) { failed = e; } throw new RuntimeException(failed); } }  
    • No, an EntityType does not know about it's entity class.  Can you please show the code where the class is needed?
    • What i'm trying to do, is injecting the original rendering class. The part of this code is not written by me, so i'm not sure about how to inject (ASM Library). To do this, i need an original class extending Entity, and the original Renderer. Is it not possible at all?
    • Thanks man, I'm really happy about your answer
  • Topics

  • Who's Online (See full list)