package com.austinv11.peripheralsplusplus.utils;
import com.austinv11.peripheralsplusplus.reference.Config;
import com.gtranslate.Language;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ILuaObject;
import dan200.computercraft.api.turtle.ITurtleAccess;
import net.minecraft.tileentity.TileEntity;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.HashMap;
public class ReflectionHelper {
private static ArrayList<Integer> usedIds = new ArrayList<Integer>();
public static ITurtleAccess getTurtle(TileEntity te) throws Exception {
if (te instanceof ITurtleAccess)
return (ITurtleAccess) te;
Class teClass = te.getClass();
if (teClass.getName().equals("dan200.computercraft.shared.turtle.blocks.TileTurtleExpanded") || teClass.getName().equals("dan200.computercraft.shared.turtle.blocks.TileTurtleAdvanced") || teClass.getName().equals("dan200.computercraft.shared.turtle.blocks.TileTurtle")) {
Method getAccess = teClass.getMethod("getAccess", new Class[0]);
ITurtleAccess turtle = (ITurtleAccess)getAccess.invoke(te, new Object[0]);
if (turtle != null)
return turtle;
}
return null;
}
public static String getLangFromWord(String lang) throws NoSuchFieldException, IllegalAccessException {
Field field = Language.class.getDeclaredField("hashLanguage");
field.setAccessible(true);
HashMap<String, String> hashLanguage = (HashMap<String, String>) field.get(Language.getInstance());
for (String k : hashLanguage.keySet())
if (hashLanguage.get(k).equalsIgnoreCase(lang))
return k;
return null;
}
public static Object getICompFromId(int id) throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException, IllegalAccessException, InvocationTargetException {
Class computerRegistry = Class.forName("dan200.computercraft.shared.computer.core.ComputerRegistry");
Method getCompFromId = computerRegistry.getMethod("lookup", int.class);
Object registry = Class.forName("dan200.computercraft.ComputerCraft").getField("serverComputerRegistry").get(null);
return getCompFromId.invoke(registry, id);
}
public static Object objectToLuaValue(Object o) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class luaMachine = Class.forName("dan200.computercraft.core.lua.LuaJLuaMachine");
Object machine = luaMachine.newInstance();
Method toVal = luaMachine.getDeclaredMethod("toValue", Object.class);
toVal.setAccessible(true);
return toVal.invoke(machine, o);
}
public static Object getLuaMachineFromId(int id) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
Object iComp = getICompFromId(id);
Class iCompClass = iComp.getClass().asSubclass(Class.forName("dan200.computercraft.shared.computer.core.ServerComputer"));
Field compField = iCompClass.getDeclaredField("m_computer");
compField.setAccessible(true);
Object comp = compField.get(iComp);
Class compClass = comp.getClass();
Field machine = compClass.getDeclaredField("m_machine");
machine.setAccessible(true);
return machine.get(comp);
}
public static void runProgram(String path, int id) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, NoSuchFieldException, InstantiationException {
Object machineObject = getLuaMachineFromId(id);
Class machineClass = machineObject.getClass();
Field globals = machineClass.getDeclaredField("m_globals");
globals.setAccessible(true);
Object globalsObj = globals.get(machineObject);
Method load = globalsObj.getClass().getDeclaredMethod("get", Class.forName("org.luaj.vm2.LuaValue"));
load.setAccessible(true);
Object chunk = load.invoke(globalsObj, objectToLuaValue("os"));
Method get_ = chunk.getClass().getDeclaredMethod("get", Class.forName("org.luaj.vm2.LuaValue"));
get_.setAccessible(true);
Object run = get_.invoke(chunk, objectToLuaValue("run"));
Method call = run.getClass().getDeclaredMethod("call", Class.forName("org.luaj.vm2.LuaValue"), Class.forName("org.luaj.vm2.LuaValue"));
call.invoke(run, Class.forName("org.luaj.vm2.LuaTable").newInstance(), objectToLuaValue(path));
}
public static void registerAPI(final int id, final ILuaAPIProxy api) throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException, IllegalAccessException, InvocationTargetException {
if (!Config.enableAPIs)
return;
if (usedIds.contains(id)) {
// usedIds.remove(usedIds.indexOf(id));
return;
}
Object o;
if ((o = getLuaMachineFromId(id)) == null) {
new Thread() {
private boolean work = true;
@Override
public void run() {
if (work) {
Object serverComputerObject = null;
try {
synchronized (this) {
this.wait(20);
}
serverComputerObject = getICompFromId(id);
Class serverCompClass = serverComputerObject.getClass().asSubclass(Class.forName("dan200.computercraft.shared.computer.core.ServerComputer"));
Field comp = serverCompClass.getDeclaredField("m_computer");
comp.setAccessible(true);
Object o = comp.get(serverComputerObject);
Method addAPI = o.getClass().getDeclaredMethod("addAPI", Class.forName("dan200.computercraft.core.apis.ILuaAPI"));
addAPI.invoke(o, Proxy.newProxyInstance(Class.forName("dan200.computercraft.core.apis.ILuaAPI").getClassLoader(), new Class[]{Class.forName("dan200.computercraft.core.apis.ILuaAPI")}, api));
Method reboot = o.getClass().getDeclaredMethod("reboot");
reboot.invoke(o);
work = false;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}.start();
usedIds.add(id);
return;
}
Method addAPI = o.getClass().getDeclaredMethod("addAPI", Class.forName("dan200.computercraft.core.apis.ILuaAPI"));
addAPI.invoke(o, Proxy.newProxyInstance(Class.forName("dan200.computercraft.core.apis.ILuaAPI").getClassLoader(), new Class[]{Class.forName("dan200.computercraft.core.apis.ILuaAPI")}, api));
}
public static abstract class ILuaAPIProxy implements InvocationHandler, ILuaObject {
/**
* Gets the names that the api can be called by in lua
* @return The names
*/
public abstract String[] getNames();
/**
* Called on computer startup
*/
public abstract void startup();
/**
* Called to tick the API
* @param dt (Probably) the computer date/time
*/
public abstract void advance(double dt);
/**
* Called on computer shutdown
*/
public abstract void shutdown();
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("getNames")) {
return getNames();
}else if (method.getName().equals("startup")) {
startup();
}else if (method.getName().equals("advance")) {
advance((Double)args[0]);
}else if (method.getName().equals("shutdown")) {
shutdown();
}else if (method.getName().equals("getMethodNames")) {
return getMethodNames();
}else if (method.getName().equals("callMethod")) {
return callMethod((ILuaContext)args[0], (Integer)args[1], (Object[])args[2]);
}
return null;
}
}
}