Skip to content

Commit

Permalink
Added all linkstone stuff back
Browse files Browse the repository at this point in the history
  • Loading branch information
ApionXD committed Feb 13, 2023
1 parent b5b512c commit cd1c0b7
Show file tree
Hide file tree
Showing 4 changed files with 257 additions and 15 deletions.
34 changes: 19 additions & 15 deletions src/main/java/net/glowstone/GlowServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,12 @@
import net.glowstone.io.ScoreboardIoService;
import net.glowstone.io.WorldStorageProviderFactory;
import net.glowstone.io.anvil.AnvilWorldStorageProvider;
//import net.glowstone.linkstone.runtime.Boxes;
//import net.glowstone.linkstone.runtime.FieldSet;
//import net.glowstone.linkstone.runtime.LinkstoneRuntimeData;
//import net.glowstone.linkstone.runtime.inithook.ClassInitHook;
import net.glowstone.linkstone.runtime.Boxes;
import net.glowstone.linkstone.runtime.FieldSet;
import net.glowstone.linkstone.runtime.LinkstoneRuntimeData;
import net.glowstone.linkstone.runtime.inithook.ClassInitHook;
import net.glowstone.linkstone.runtime.FieldSet;
import net.glowstone.linkstone.runtime.LinkstoneRuntimeData;
import net.glowstone.map.GlowMapView;
import net.glowstone.net.GameServer;
import net.glowstone.net.GlowSession;
Expand Down Expand Up @@ -137,9 +139,11 @@
import net.glowstone.util.library.Library;
import net.glowstone.util.library.LibraryKey;
import net.glowstone.util.library.LibraryManager;
//import net.glowstone.util.linkstone.LinkstoneClassInitObserver;
//import net.glowstone.util.linkstone.LinkstonePluginLoader;
//import net.glowstone.util.linkstone.LinkstonePluginScanner;
import net.glowstone.util.linkstone.LinkstoneClassInitObserver;
import net.glowstone.util.linkstone.LinkstonePluginLoader;
import net.glowstone.util.linkstone.LinkstonePluginScanner;
import net.glowstone.util.linkstone.LinkstoneClassInitObserver;
import net.glowstone.util.linkstone.LinkstonePluginScanner;
import net.glowstone.util.loot.LootingManager;
import net.glowstone.util.mojangson.Mojangson;
import net.glowstone.util.mojangson.ex.MojangsonParseException;
Expand Down Expand Up @@ -543,7 +547,7 @@ public GlowServer(ServerConfig config) {
nameBans = new GlowBanList(this, Type.NAME);
ipBans = new GlowBanList(this, Type.IP);

//ClassInitHook.register(new LinkstoneClassInitObserver());
ClassInitHook.register(new LinkstoneClassInitObserver());

loadConfig();
bossBars = new ConcurrentHashMap<>();
Expand Down Expand Up @@ -1335,16 +1339,16 @@ private void loadPlugins() {
pluginTypeDetector.scan();

// scan plugins for @Field and @Box annotated fields
//FieldSet annotatedFields = new FieldSet();
//Boxes boxes = new Boxes();
//LinkstoneRuntimeData.setFields(annotatedFields);
//LinkstoneRuntimeData.setBoxes(boxes);
//new LinkstonePluginScanner(annotatedFields, boxes)
// .scanPlugins(pluginTypeDetector.bukkitPlugins);
FieldSet annotatedFields = new FieldSet();
Boxes boxes = new Boxes();
LinkstoneRuntimeData.setFields(annotatedFields);
LinkstoneRuntimeData.setBoxes(boxes);
new LinkstonePluginScanner(annotatedFields, boxes)
.scanPlugins(pluginTypeDetector.bukkitPlugins);

// clear plugins and prepare to load (Bukkit)
pluginManager.clearPlugins();
//pluginManager.registerInterface(LinkstonePluginLoader.class);
pluginManager.registerInterface(LinkstonePluginLoader.class);
Plugin[] plugins = pluginManager
.loadPlugins(folder, pluginTypeDetector.bukkitPlugins);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package net.glowstone.util.linkstone;

import net.glowstone.linkstone.annotations.LBox;
import net.glowstone.linkstone.annotations.LField;
import net.glowstone.linkstone.runtime.inithook.ClassInitHook;
import net.glowstone.linkstone.runtime.reflectionredirect.DynamicClassLoader;
import net.glowstone.linkstone.runtime.reflectionredirect.ReflectionUtil;
import net.glowstone.linkstone.runtime.reflectionredirect.field.BoxingFieldAccessor;
import net.glowstone.linkstone.runtime.reflectionredirect.field.FieldAccessorUtility;
import net.glowstone.linkstone.runtime.reflectionredirect.field.LFieldAccessor;
import net.glowstone.linkstone.runtime.reflectionredirect.field.RedirectFieldAccessorGenerator;
import net.glowstone.linkstone.runtime.reflectionredirect.method.BoxingMethodAccessor;
import net.glowstone.linkstone.runtime.reflectionredirect.method.LMethodAccessor;
import net.glowstone.linkstone.runtime.reflectionredirect.method.MethodAccessorUtility;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.WeakHashMap;

/**
* Utility that redirects reflective uses of annotated fields to their getters and setters.
*/
public class LinkstoneClassInitObserver implements ClassInitHook.Observer {
private final FieldAccessorUtility fieldAccessorUtil;
private final MethodAccessorUtility methodAccessorUtil;

private final Map<ClassLoader, DynamicClassLoader> classLoaders = new WeakHashMap<>();

/**
* Create a new observer instance.
*/
public LinkstoneClassInitObserver() {
try {
fieldAccessorUtil = FieldAccessorUtility.isSupported()
? new FieldAccessorUtility() : null;
} catch (Exception t) {
throw new IllegalStateException("Could not initialize FieldAccessorUtility");
}

try {
methodAccessorUtil = MethodAccessorUtility.isSupported()
? new MethodAccessorUtility() : null;
} catch (Exception e) {
throw new IllegalStateException("Could not initialize MethodAccessorUtility");
}
}

@Override
public void onInit(Class<?> clazz) {
try {
hijackFields(clazz);
hijackMethods(clazz);
} catch (Exception e) {
e.printStackTrace();
}
}

private void hijackFields(Class<?> clazz) throws ReflectiveOperationException {
if (fieldAccessorUtil == null) {
return;
}

boolean isBox = clazz.getAnnotation(LBox.class) != null;

for (Field field : ReflectionUtil.getInternalFields(clazz)) {
LField[] fieldAnnotations = field.getAnnotationsByType(LField.class);
if (fieldAnnotations.length > 0) {
LFieldAccessor accessor = newRedirectFieldAccessor(field);
fieldAccessorUtil.setAccessor(field, accessor);
fieldAccessorUtil.setOverrideAccessor(field, accessor);
}

if (isBox) {
LFieldAccessor accessor = fieldAccessorUtil.getAccessor(field);
accessor = new BoxingFieldAccessor(accessor, field);
fieldAccessorUtil.setAccessor(field, accessor);

LFieldAccessor overrideAccessor = fieldAccessorUtil.getOverrideAccessor(field);
overrideAccessor = new BoxingFieldAccessor(overrideAccessor, field);
fieldAccessorUtil.setOverrideAccessor(field, overrideAccessor);
}
}
}

private LFieldAccessor newRedirectFieldAccessor(Field field)
throws ReflectiveOperationException {
DynamicClassLoader classloader = classLoaders.computeIfAbsent(
field.getDeclaringClass().getClassLoader(), DynamicClassLoader::new);

RedirectFieldAccessorGenerator generator = new RedirectFieldAccessorGenerator(field);
String className = generator.getClassName().replace('/', '.');

Class<?> accessorClass;
try {
accessorClass = Class.forName(className, false, classloader);
} catch (ClassNotFoundException e) {
byte[] bytecode = generator.generateAccessor();
accessorClass = classloader.loadBytecode(className, bytecode);
}

return (LFieldAccessor) accessorClass.getDeclaredConstructor().newInstance();
}

private void hijackMethods(Class<?> clazz) throws ReflectiveOperationException {
if (methodAccessorUtil == null || clazz.getAnnotation(LBox.class) == null) {
return;
}

for (Method method : ReflectionUtil.getInternalMethods(clazz)) {
LMethodAccessor accessor = methodAccessorUtil.getAccessor(method);
accessor = new BoxingMethodAccessor(method, accessor);
methodAccessorUtil.setAccessor(method, accessor);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package net.glowstone.util.linkstone;

import net.glowstone.linkstone.runtime.LinkstoneRuntimeData;
import net.glowstone.linkstone.runtime.boxing.BoxPatchVisitor;
import net.glowstone.linkstone.runtime.direct.DirectFieldAccessReplaceVisitor;
import net.glowstone.linkstone.runtime.inithook.ClassInitInvokeVisitor;
import net.glowstone.linkstone.runtime.reflectionredirect.field.FieldAccessorUtility;
import net.glowstone.linkstone.runtime.reflectionredirect.method.MethodAccessorUtility;
import net.glowstone.linkstone.runtime.reflectionreplace.ReflectionReplaceVisitor;
import org.bukkit.Server;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPluginLoader;
import org.bukkit.plugin.java.PluginClassLoader;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;

import java.io.File;

public class LinkstonePluginLoader extends JavaPluginLoader {
/**
* Bukkit will invoke this constructor via reflection.
* Its signature should therefore not be changed!
*
* @param instance the server instance
*/
public LinkstonePluginLoader(Server instance) {
super(instance);
LinkstoneRuntimeData.setPluginClassLoader(new ClassLoader() {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
return loadClass(name);
}
});
}

@Override
protected PluginClassLoader newPluginLoader(JavaPluginLoader loader, ClassLoader parent, PluginDescriptionFile description, File dataFolder, File file, ClassLoader libraryLoader) throws Exception {
return new PluginClassLoader(loader, parent, description, dataFolder, file, libraryLoader) {
@Override
protected byte[] transformBytecode(byte[] bytecode) {
if (LinkstoneRuntimeData.getFields().isEmpty()
&& LinkstoneRuntimeData.getBoxes().isEmpty()) {
// There are no plugins installed that use a @LField or @LBox annotation
// so there's no need for runtime support
return bytecode;
}
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);

ClassVisitor cv = cw;
cv = new DirectFieldAccessReplaceVisitor(LinkstoneRuntimeData.getFields(), cv);
if (!FieldAccessorUtility.isSupported() || !MethodAccessorUtility.isSupported()) {
cv = new ReflectionReplaceVisitor(cv);
}
cv = new ClassInitInvokeVisitor(cv);
cv = new BoxPatchVisitor(LinkstoneRuntimeData.getBoxes(), cv);

new ClassReader(bytecode).accept(cv, 0);
return cw.toByteArray();
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package net.glowstone.util.linkstone;

import net.glowstone.linkstone.annotations.LField;
import net.glowstone.linkstone.runtime.Boxes;
import net.glowstone.linkstone.runtime.FieldSet;
import net.glowstone.linkstone.runtime.collect.AnnotatedFieldCollectVisitor;
import net.glowstone.linkstone.runtime.collect.BoxCollectVisitor;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class LinkstonePluginScanner {
private final FieldSet fields;
private final Boxes boxes;

public LinkstonePluginScanner(final FieldSet fields, final Boxes boxes) {
this.fields = fields;
this.boxes = boxes;
}

/**
* Look through a list of plugins jar files and store all
* fields annotated with a {@link LField} annotation.
*
* @param pluginJars list of plugins jars to be scanned
*/
public void scanPlugins(List<File> pluginJars) {
for (File pluginJar : pluginJars) {
try {
scanPlugin(pluginJar);
} catch (Throwable t) {
t.printStackTrace();
}
}
}

private void scanPlugin(File pluginJar) throws IOException {
ZipInputStream zin = new ZipInputStream(new FileInputStream(pluginJar));
ZipEntry entry;
while ((entry = zin.getNextEntry()) != null) {
if (entry.isDirectory() || !entry.getName().endsWith(".class")) {
continue;
}

ClassVisitor cv = new AnnotatedFieldCollectVisitor(this.fields);
cv = new BoxCollectVisitor(this.boxes, cv);

new ClassReader(zin).accept(cv, ClassReader.SKIP_CODE);
zin.closeEntry();
}
zin.close();
}
}

0 comments on commit cd1c0b7

Please sign in to comment.