Created
December 26, 2012 21:17
-
-
Save main--/4383236 to your computer and use it in GitHub Desktop.
Hell yeah.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package me.main__.nanotech.dirty; | |
import javassist.ClassPool; | |
import javassist.CtClass; | |
import javassist.CtMethod; | |
import me.main__.nanotech.NanoTech; | |
import org.bukkit.Bukkit; | |
import java.lang.reflect.Array; | |
import java.lang.reflect.Constructor; | |
import java.lang.reflect.Field; | |
import java.lang.reflect.Modifier; | |
import java.util.logging.Level; | |
import java.util.regex.Matcher; | |
import java.util.regex.Pattern; | |
public class CraftBukkitHelper { | |
private static final class PatchInformation { | |
private final String nmsPackage; | |
private final String diodeCanStayMethod; | |
private final String diodeCanStyDesc; | |
private PatchInformation(final String nmsPackage, final String diodeCanStayMethod, final String diodeCanStyDesc) { | |
this.nmsPackage = nmsPackage; | |
this.diodeCanStayMethod = diodeCanStayMethod; | |
this.diodeCanStyDesc = diodeCanStyDesc; | |
} | |
} | |
private static final Pattern CB_VERSION = Pattern.compile("git-Bukkit-\\d\\.\\d\\.\\d-R\\d\\.\\d-[\\d]+-g[\\dabcdef]+ \\(MC: (?<major>[\\d]+)\\.(?<minor>[\\d]+)\\.(?<rev>[\\d]+)\\)"); | |
private static final PatchInformation[][][] SUPPORTED_VERSIONS = { | |
null, // 0.X | |
{ // 1.X | |
null, // 1.0 | |
null, // 1.1 | |
null, // 1.2 | |
null, // 1.3 | |
{ // 1.4 | |
null, // 1.4.0 | |
null, // 1.4.1 | |
null, // 1.4.2 | |
null, // 1.4.3 | |
null, // 1.4.4 | |
null, // 1.4.5 | |
new PatchInformation("net.minecraft.server.v1_4_6.", "d", "(Lnet/minecraft/server/v1_4_6/World;III)Z"), // 1.4.6 | |
} | |
} | |
}; | |
public static void run(final NanoTech plugin, boolean force) { | |
if (!Bukkit.getName().equals("CraftBukkit")) | |
return; // nope. | |
Matcher matcher = CB_VERSION.matcher(Bukkit.getVersion()); | |
if (!matcher.matches()) | |
return; // nope. | |
int major = Integer.parseInt(matcher.group("major")); | |
int minor = Integer.parseInt(matcher.group("minor")); | |
int rev = Integer.parseInt(matcher.group("rev")); | |
try { | |
PatchInformation[] revs = SUPPORTED_VERSIONS[major][minor]; | |
if (revs != null) { | |
PatchInformation pi = (revs.length > rev) ? revs[rev] : null; | |
if ((pi == null) && force) { | |
for (int i = Math.min(revs.length - 1, rev); i >= 0; i--) { | |
if (revs[i] != null) { | |
pi = revs[i]; | |
break; | |
} | |
} | |
} | |
if (pi != null) | |
doIt(plugin, pi.nmsPackage, pi.diodeCanStayMethod, pi.diodeCanStyDesc); | |
return; | |
} | |
} catch (NullPointerException e) { | |
e.printStackTrace(); | |
} catch (ArrayIndexOutOfBoundsException e) { | |
e.printStackTrace(); | |
} | |
// illegal major/minor. nope. | |
} | |
private static void USE_DA_FORCE(Field f, Object obj, Object val) throws Exception { | |
// Meta-Reflection. Enough said. | |
Field ff = Field.class.getDeclaredField("modifiers"); | |
ff.setAccessible(true); | |
ff.set(f, ((Integer)ff.get(f)) & ~Modifier.FINAL); | |
f.setAccessible(true); | |
f.set(obj, val); | |
} | |
private static void doIt(final NanoTech plugin, final String nmsPackage, final String diodeCanStayMethod, final String diodeCanStyDesc) { | |
try { | |
ClassPool pool = ClassPool.getDefault(); | |
CtClass diodeClass = pool.get(nmsPackage + "BlockDiode"); | |
CtClass proxyDiode = pool.makeClass("me.main__.nanotech.dirty.proxy.BlockDiode", diodeClass); | |
CtMethod realCanStay = diodeClass.getMethod(diodeCanStayMethod, diodeCanStyDesc); | |
CtMethod newCanStay = new CtMethod(realCanStay, proxyDiode, null); | |
newCanStay.setBody("return true;"); | |
proxyDiode.addMethod(newCanStay); | |
Class<?> clazz = proxyDiode.toClass(); | |
Constructor<?> ctor = clazz.getDeclaredConstructor(int.class, boolean.class); | |
ctor.setAccessible(true); | |
// we have to clear them out of the blocks list before we can instantiate them | |
Class<?> blockClass = Class.forName(nmsPackage + "Block"); | |
Field blocksListField = blockClass.getField("byId"); | |
Object blocksList = blocksListField.get(null); | |
Array.set(blocksList, 93, null); | |
Array.set(blocksList, 94, null); | |
Object repeaterOff = ctor.newInstance(93, false); | |
Object repeaterOn = ctor.newInstance(94, true); | |
USE_DA_FORCE(blockClass.getField("DIODE_OFF"), null, repeaterOff); | |
USE_DA_FORCE(blockClass.getField("DIODE_ON"), null, repeaterOn); | |
} catch (Throwable t) { | |
plugin.getLogger().log(Level.WARNING, "CraftBukkit injection failed.", t); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment