Skip to content

Instantly share code, notes, and snippets.

@Ivorforce
Created March 27, 2015 13:37
Show Gist options
  • Save Ivorforce/07a7d717d0d6b3578cea to your computer and use it in GitHub Desktop.
Save Ivorforce/07a7d717d0d6b3578cea to your computer and use it in GitHub Desktop.
/*
* Copyright (c) 2014, Lukas Tenbrink.
* * http://lukas.axxim.net
*/
package ivorius.reccomplex.worldgen.villages;
import ivorius.reccomplex.RecurrentComplex;
import net.minecraft.world.gen.structure.StructureVillagePieces;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
import javax.annotation.Nullable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static org.objectweb.asm.Opcodes.*;
/**
* Created by lukas on 26.03.15.
*/
public class VanillaGenerationClassFactory extends ClassLoader
{
private static final VanillaGenerationClassFactory INSTANCE = new VanillaGenerationClassFactory();
protected Map<String, Class<?>> loaded = new HashMap<>();
protected Set<String> failed = new HashSet<>();
public VanillaGenerationClassFactory()
{
super(VanillaGenerationClassFactory.class.getClassLoader());
}
public static VanillaGenerationClassFactory instance()
{
return INSTANCE;
}
@Nullable
public GenericVillagePiece create(String structureID, String generationID)
{
Class<? extends GenericVillagePiece> aClass = getClass(structureID, generationID);
try
{
return aClass != null ? aClass.newInstance() : null;
}
catch (InstantiationException | IllegalAccessException e)
{
e.printStackTrace();
}
return null;
}
@Nullable
public GenericVillagePiece create(String structureID, String generationID, StructureVillagePieces.Start start, int generationDepth)
{
Class<? extends GenericVillagePiece> aClass = getClass(structureID, generationID);
if (aClass != null)
{
try
{
Constructor<? extends GenericVillagePiece> constructor;
constructor = aClass.getConstructor(StructureVillagePieces.class, Integer.TYPE);
constructor.newInstance(start, generationDepth);
}
catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | InstantiationException e)
{
e.printStackTrace();
}
}
return null;
}
public Class<? extends GenericVillagePiece> getClass(String structureID, String generationID)
{
try
{
return (Class<? extends GenericVillagePiece>) findClass(classNameForStructure(structureID, generationID));
}
catch (ClassNotFoundException ignored)
{
}
if (!failed.contains(structureID))
{
Class<? extends GenericVillagePiece> created = createClass(structureID, generationID);
if (created == null)
{
failed.add(structureID);
RecurrentComplex.logger.error("Could not create vanilla generation type class for '" + structureID + "'");
}
return created;
}
return null;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException
{
if (loaded.containsKey(name))
return loaded.get(name);
return super.findClass(name);
}
protected Class<?> define(String name, byte[] data)
{
Class<?> aClass = defineClass(name, data, 0, data.length);
loaded.put(name, aClass);
return aClass;
}
protected Class<? extends GenericVillagePiece> createClass(String structureID, String generationID)
{
try
{
String className = classNameForStructure(structureID, generationID);
return (Class<? extends GenericVillagePiece>) define(className, createClassBinary(className.replaceAll("\\.", "/")));
}
catch (Throwable t)
{
RecurrentComplex.logger.error("Can't load dynamic piece class", t);
return null;
}
}
protected String classNameForStructure(String structureID, String generationID)
{
return "ivorius.reccomplex.dynamic.vanillagen." + structureID + "_" + generationID;
}
protected byte[] createClassBinary(String className)
{
ClassWriter cw = new ClassWriter(0);
cw.visit(V1_5, ACC_PUBLIC, className, null, Type.getInternalName(GenericVillagePiece.class), null);
{
// empty constructor
String descriptor = Type.getMethodDescriptor(Type.VOID_TYPE);
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", descriptor, null, null);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", descriptor, false);
mv.visitInsn(RETURN);
mv.visitMaxs(2, 1);
mv.visitEnd();
}
{
// initial constructor
String descriptor = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(StructureVillagePieces.Start.class), Type.INT_TYPE);
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", descriptor, null, null);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ILOAD, 2);
mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", descriptor, false);
mv.visitInsn(RETURN);
mv.visitMaxs(4, 3);
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment