diff --git a/pom.xml b/pom.xml
index 93d7a6c..9cfd47d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
io.github.diona-testserver
PluginHooker
- 0.6.0
+ 1.0.0
jar
PluginHooker
diff --git a/src/main/java/io/github/dionatestserver/pluginhooker/events/DionaBukkitListenerEvent.java b/src/main/java/io/github/dionatestserver/pluginhooker/events/BukkitListenerEvent.java
similarity index 81%
rename from src/main/java/io/github/dionatestserver/pluginhooker/events/DionaBukkitListenerEvent.java
rename to src/main/java/io/github/dionatestserver/pluginhooker/events/BukkitListenerEvent.java
index c8024be..2f07408 100644
--- a/src/main/java/io/github/dionatestserver/pluginhooker/events/DionaBukkitListenerEvent.java
+++ b/src/main/java/io/github/dionatestserver/pluginhooker/events/BukkitListenerEvent.java
@@ -7,7 +7,7 @@
import org.bukkit.event.HandlerList;
import org.bukkit.plugin.Plugin;
-public class DionaBukkitListenerEvent extends Event implements Cancellable {
+public class BukkitListenerEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
@@ -20,11 +20,11 @@ public class DionaBukkitListenerEvent extends Event implements Cancellable {
@Getter
private final DionaPlayer dionaPlayer;
- public DionaBukkitListenerEvent(Plugin plugin, Event event) {
+ public BukkitListenerEvent(Plugin plugin, Event event) {
this(plugin, event, null);
}
- public DionaBukkitListenerEvent(Plugin plugin, Event event, DionaPlayer dionaPlayer) {
+ public BukkitListenerEvent(Plugin plugin, Event event, DionaPlayer dionaPlayer) {
super(event.isAsynchronous());
this.plugin = plugin;
this.event = event;
diff --git a/src/main/java/io/github/dionatestserver/pluginhooker/events/DionaProtocolLibPacketEvent.java b/src/main/java/io/github/dionatestserver/pluginhooker/events/ProtocolLibPacketEvent.java
similarity index 84%
rename from src/main/java/io/github/dionatestserver/pluginhooker/events/DionaProtocolLibPacketEvent.java
rename to src/main/java/io/github/dionatestserver/pluginhooker/events/ProtocolLibPacketEvent.java
index c37b928..394a17e 100644
--- a/src/main/java/io/github/dionatestserver/pluginhooker/events/DionaProtocolLibPacketEvent.java
+++ b/src/main/java/io/github/dionatestserver/pluginhooker/events/ProtocolLibPacketEvent.java
@@ -7,7 +7,7 @@
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
-public class DionaProtocolLibPacketEvent extends Event implements Cancellable {
+public class ProtocolLibPacketEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
@@ -20,7 +20,7 @@ public class DionaProtocolLibPacketEvent extends Event implements Cancellable {
@Getter
private final boolean outbound;
- public DionaProtocolLibPacketEvent(PacketListener packetListener, PacketEvent packetEvent, boolean outbound) {
+ public ProtocolLibPacketEvent(PacketListener packetListener, PacketEvent packetEvent, boolean outbound) {
super(packetEvent.isAsynchronous());
this.packetListener = packetListener;
this.packetEvent = packetEvent;
diff --git a/src/main/java/io/github/dionatestserver/pluginhooker/hook/HookerManager.java b/src/main/java/io/github/dionatestserver/pluginhooker/hook/HookerManager.java
index b6e7615..b7a1735 100644
--- a/src/main/java/io/github/dionatestserver/pluginhooker/hook/HookerManager.java
+++ b/src/main/java/io/github/dionatestserver/pluginhooker/hook/HookerManager.java
@@ -1,27 +1,18 @@
package io.github.dionatestserver.pluginhooker.hook;
-import com.sun.tools.attach.VirtualMachine;
import io.github.dionatestserver.pluginhooker.DionaPluginHooker;
-import javassist.ClassPool;
+import io.github.dionatestserver.pluginhooker.utils.AgentUtils;
import org.reflections.Reflections;
import java.io.File;
-import java.io.OutputStream;
-import java.lang.management.ManagementFactory;
-import java.lang.management.RuntimeMXBean;
-import java.nio.file.Files;
import java.util.List;
-import java.util.jar.Attributes;
-import java.util.jar.JarEntry;
-import java.util.jar.JarOutputStream;
-import java.util.jar.Manifest;
+import java.util.Objects;
import java.util.logging.Logger;
import java.util.stream.Collectors;
public class HookerManager {
private final Logger logger = DionaPluginHooker.getInstance().getLogger();
- private static final String AGENT_CLASS = "io.github.dionatestserver.pluginhooker.hook.PluginHookerAgent";
public HookerManager() {
List injectors = this.getInjectorList();
@@ -36,26 +27,32 @@ public HookerManager() {
try {
injector.predefineClass();
logger.info( injector.getClassNameWithoutPackage() + " is now predefined!");
+ return false;
} catch (Exception e) {
logger.severe("Error while predefining " + injector.getClassNameWithoutPackage());
e.printStackTrace();
return true;
}
- return false;
})
.collect(Collectors.toList());
if (definedClasses.size() == 0) return;
- //init instrumentation field
- File agentFile = this.generateAgentFile();
- this.attachAgent(agentFile);
+ //init instrumentation field
+ try {
+ String agentClass = "io.github.dionatestserver.pluginhooker.hook.PluginHookerAgent";
+ File agentFile = AgentUtils.generateAgentFile(agentClass);
+ AgentUtils.attachSelf(Objects.requireNonNull(agentFile));
+ } catch (Exception e) {
+ logger.severe("Error while attaching agent");
+ e.printStackTrace();
+ }
definedClasses.forEach(injector -> {
try {
injector.redefineClass(PluginHookerAgent.instrumentation);
- logger.info( injector.getClassNameWithoutPackage() + " is now redefined!");
+ logger.info(injector.getClassNameWithoutPackage() + " is now redefined!");
} catch (Exception e) {
logger.severe("Error while redefining " + injector.getClassNameWithoutPackage());
e.printStackTrace();
@@ -73,53 +70,4 @@ private List getInjectorList() {
}
}).collect(Collectors.toList());
}
-
- private File generateAgentFile() {
- Manifest manifest = new Manifest();
- manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
- manifest.getMainAttributes().put(new Attributes.Name("Agent-Class"), AGENT_CLASS);
- manifest.getMainAttributes().put(new Attributes.Name("Can-Redefine-Classes"), "true");
-
- try {
- File agentFile = new File(DionaPluginHooker.getInstance().getDataFolder(), "agent.jar");
- if (!agentFile.exists()) {
- agentFile.createNewFile();
- }
-
- OutputStream outputStream = Files.newOutputStream(agentFile.toPath());
- JarOutputStream jarOutputStream = new JarOutputStream(outputStream, manifest);
- jarOutputStream.putNextEntry(new JarEntry(AGENT_CLASS.replace(".", "/") + ".class"));
-
-
- ClassPool pool = ClassPool.getDefault();
- jarOutputStream.write(pool.get(AGENT_CLASS).toBytecode());
-
- jarOutputStream.finish();
- return agentFile;
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
-
- private String getPid() {
- RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean();
- String pid = bean.getName();
- if (pid.contains("@")) {
- pid = pid.substring(0, pid.indexOf("@"));
- }
- return pid;
- }
-
- private void attachAgent(File agentFile) {
- try {
- System.loadLibrary("attach");
- VirtualMachine vm = VirtualMachine.attach(this.getPid());
- vm.loadAgent(agentFile.getAbsolutePath());
- vm.detach();
- } catch (Exception e) {
- logger.severe("Error while attaching agent");
- e.printStackTrace();
- }
- }
}
diff --git a/src/main/java/io/github/dionatestserver/pluginhooker/hook/Injector.java b/src/main/java/io/github/dionatestserver/pluginhooker/hook/Injector.java
index bf1e3f2..1e14dfc 100644
--- a/src/main/java/io/github/dionatestserver/pluginhooker/hook/Injector.java
+++ b/src/main/java/io/github/dionatestserver/pluginhooker/hook/Injector.java
@@ -1,14 +1,12 @@
package io.github.dionatestserver.pluginhooker.hook;
import io.github.dionatestserver.pluginhooker.DionaPluginHooker;
-import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.LoaderClassPath;
import javassist.util.proxy.DefineClassHelper;
import lombok.Getter;
-import java.io.IOException;
import java.lang.instrument.ClassDefinition;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Field;
@@ -18,24 +16,37 @@ public abstract class Injector {
protected static final ClassPool classPool = ClassPool.getDefault();
+ static {
+ classPool.appendClassPath(new LoaderClassPath(DionaPluginHooker.class.getClassLoader()));
+ }
+
+ protected final Class> neighbor;
+
+ protected final CtClass targetClass;
+
@Getter
- protected final String targetClass;
+ protected final String targetClassName;
@Getter
protected final String classNameWithoutPackage;
- protected final Class> neighbor;
-
- public Injector(String targetClass, Class> neighbor) {
- this.targetClass = targetClass;
+ public Injector(String targetClassName, Class> neighbor) {
+ this.targetClassName = targetClassName;
// split the class name
- String[] className = this.getTargetClass().split("\\.");
+ String[] className = this.getTargetClassName().split("\\.");
// get the class name without the package
classNameWithoutPackage = className[className.length - 1];
this.neighbor = neighbor;
- classPool.appendClassPath(new LoaderClassPath(DionaPluginHooker.class.getClassLoader()));
+
+ try {
+ this.initClassPath();
+ this.targetClass = classPool.get(targetClassName);
+ this.hookClass();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
}
public boolean isTargetClassDefined() {
@@ -43,25 +54,32 @@ public boolean isTargetClassDefined() {
Field classesField = ClassLoader.class.getDeclaredField("classes");
classesField.setAccessible(true);
AbstractList> classes = (AbstractList) classesField.get(neighbor.getClassLoader());
- return classes.stream().anyMatch(clazz -> clazz.getName().equals(targetClass));
+ return classes.stream().anyMatch(clazz -> clazz.getName().equals(targetClassName));
} catch (Exception e) {
return false;
}
}
public void predefineClass() throws Exception {
- CtClass hookedClass = this.generateHookedClass();
-
- DefineClassHelper.toClass(targetClass, neighbor, neighbor.getClassLoader(), null, hookedClass.toBytecode());
+ DefineClassHelper.toClass(
+ targetClassName,
+ neighbor,
+ neighbor.getClassLoader(),
+ null,
+ targetClass.toBytecode()
+ );
}
public void redefineClass(Instrumentation instrumentation) throws Exception {
- CtClass hookedClass = this.generateHookedClass();
-
- instrumentation.redefineClasses(new ClassDefinition(Class.forName(targetClass), hookedClass.toBytecode()));
+ instrumentation.redefineClasses(
+ new ClassDefinition(Class.forName(targetClassName), targetClass.toBytecode())
+ );
}
- public abstract CtClass generateHookedClass();
+ public abstract void hookClass() throws Exception;
public abstract boolean canHook();
+
+ protected abstract void initClassPath();
+
}
diff --git a/src/main/java/io/github/dionatestserver/pluginhooker/hook/impl/bukkit/BukkitCallbackHandler.java b/src/main/java/io/github/dionatestserver/pluginhooker/hook/impl/bukkit/BukkitCallbackHandler.java
index 1c0b33c..b98a5bf 100644
--- a/src/main/java/io/github/dionatestserver/pluginhooker/hook/impl/bukkit/BukkitCallbackHandler.java
+++ b/src/main/java/io/github/dionatestserver/pluginhooker/hook/impl/bukkit/BukkitCallbackHandler.java
@@ -2,12 +2,13 @@
import io.github.dionatestserver.pluginhooker.DionaPluginHooker;
import io.github.dionatestserver.pluginhooker.config.DionaConfig;
-import io.github.dionatestserver.pluginhooker.events.DionaBukkitListenerEvent;
+import io.github.dionatestserver.pluginhooker.events.BukkitListenerEvent;
import io.github.dionatestserver.pluginhooker.player.DionaPlayer;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
+import org.bukkit.entity.Projectile;
import org.bukkit.event.Event;
import org.bukkit.event.block.*;
import org.bukkit.event.enchantment.EnchantItemEvent;
@@ -22,13 +23,19 @@
import org.bukkit.projectiles.ProjectileSource;
import java.lang.reflect.Field;
+import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.Set;
import java.util.function.Function;
public class BukkitCallbackHandler {
private final Map, Function> eventMap = new LinkedHashMap<>();
+ private final Map, Field> eventFieldCache = new LinkedHashMap<>();
+
+ private final Set> failedFieldCache = new HashSet<>();
+
public BukkitCallbackHandler() {
this.initEventMap();
}
@@ -50,13 +57,13 @@ public boolean handleBukkitEvent(Plugin plugin, Event event) {
DionaPlayer dionaPlayer = DionaPluginHooker.getPlayerManager().getDionaPlayer(this.getPlayerByEvent(event));
if (dionaPlayer == null) {
- DionaBukkitListenerEvent bukkitListenerEvent = new DionaBukkitListenerEvent(plugin, event);
+ BukkitListenerEvent bukkitListenerEvent = new BukkitListenerEvent(plugin, event);
Bukkit.getPluginManager().callEvent(bukkitListenerEvent);
return bukkitListenerEvent.isCancelled();
} else {
if (dionaPlayer.getEnabledPlugins().contains(plugin)) {
- DionaBukkitListenerEvent bukkitListenerEvent = new DionaBukkitListenerEvent(plugin, event, dionaPlayer);
+ BukkitListenerEvent bukkitListenerEvent = new BukkitListenerEvent(plugin, event, dionaPlayer);
Bukkit.getPluginManager().callEvent(bukkitListenerEvent);
return bukkitListenerEvent.isCancelled();
} else {
@@ -75,6 +82,12 @@ private Player getPlayerByEvent(Event event) {
Entity damager = ((EntityDamageByEntityEvent) event).getDamager();
if (damager instanceof Player)
return (Player) damager;
+ if (damager instanceof Projectile) {
+ Projectile projectile = (Projectile) damager;
+ ProjectileSource projectileSource = projectile.getShooter();
+ if (projectileSource instanceof Player)
+ return (Player) projectileSource;
+ }
}
Entity entity = ((EntityEvent) event).getEntity();
if (entity instanceof Player)
@@ -91,15 +104,29 @@ else if (event instanceof ProjectileLaunchEvent) {
// Try to get the player field from the event
if (DionaConfig.useReflectionToGetEventPlayer) {
- try {
- Field playerField = event.getClass().getDeclaredField("player");
- if (!playerField.isAccessible()) playerField.setAccessible(true);
- Object player = playerField.get(event);
- if (player instanceof Player) {
- return (Player) player;
+ if (this.failedFieldCache.contains(event.getClass())) {
+ return null;
+ }
+ Field playerField = this.eventFieldCache.getOrDefault(event.getClass(), null);
+ if (playerField == null) {
+ try {
+ playerField = event.getClass().getDeclaredField("player");
+ playerField.setAccessible(true);
+ Player player = (Player) playerField.get(event);
+ this.eventFieldCache.put(event.getClass(), playerField);
+ return player;
+ } catch (Exception e) {
+ this.failedFieldCache.add(event.getClass());
+ return null;
}
- } catch (Exception ignored) {
}
+
+ try {
+ return (Player) playerField.get(event);
+ } catch (Exception e) {
+ return null;
+ }
+
}
return null;
diff --git a/src/main/java/io/github/dionatestserver/pluginhooker/hook/impl/bukkit/BukkitEventInjector.java b/src/main/java/io/github/dionatestserver/pluginhooker/hook/impl/bukkit/BukkitEventInjector.java
index 45bdd4f..557f9f5 100644
--- a/src/main/java/io/github/dionatestserver/pluginhooker/hook/impl/bukkit/BukkitEventInjector.java
+++ b/src/main/java/io/github/dionatestserver/pluginhooker/hook/impl/bukkit/BukkitEventInjector.java
@@ -4,7 +4,7 @@
import io.github.dionatestserver.pluginhooker.hook.HookerManager;
import io.github.dionatestserver.pluginhooker.hook.Injector;
import io.github.dionatestserver.pluginhooker.utils.ClassUtils;
-import javassist.CtClass;
+import javassist.CannotCompileException;
import javassist.CtMethod;
import javassist.util.proxy.DefineClassHelper;
import lombok.Getter;
@@ -17,7 +17,7 @@
public class BukkitEventInjector extends Injector {
@Getter
- private BukkitCallbackHandler callbackHandler = new BukkitCallbackHandler();
+ private final BukkitCallbackHandler callbackHandler = new BukkitCallbackHandler();
public BukkitEventInjector() {
super("org.bukkit.plugin.RegisteredListener", Plugin.class);
@@ -40,18 +40,11 @@ public BukkitEventInjector() {
}
@Override
- public CtClass generateHookedClass() {
- try {
- CtClass registeredListener = classPool.get(targetClass);
- CtMethod callEvent = ClassUtils.getMethodByName(registeredListener.getMethods(), "callEvent");
- callEvent.insertBefore(
- "if(" + BukkitEventHooker.class.getName() + ".getInstance().onCallEvent(this.plugin,$1))return;"
- );
- return registeredListener;
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
+ public void hookClass() throws CannotCompileException {
+ CtMethod callEvent = ClassUtils.getMethodByName(targetClass.getMethods(), "callEvent");
+ callEvent.insertBefore(
+ "if(" + BukkitEventHooker.class.getName() + ".getInstance().onCallEvent(this.plugin,$1))return;"
+ );
}
@Override
@@ -59,6 +52,11 @@ public boolean canHook() {
return DionaConfig.hookBukkitEvent;
}
+ @Override
+ protected void initClassPath() {
+ // empty
+ }
+
public static class BukkitEventHooker {
@Getter
diff --git a/src/main/java/io/github/dionatestserver/pluginhooker/hook/impl/protocollib/ListenerMultimapInjector.java b/src/main/java/io/github/dionatestserver/pluginhooker/hook/impl/protocollib/ListenerMultimapInjector.java
index 68ec8a9..671646c 100644
--- a/src/main/java/io/github/dionatestserver/pluginhooker/hook/impl/protocollib/ListenerMultimapInjector.java
+++ b/src/main/java/io/github/dionatestserver/pluginhooker/hook/impl/protocollib/ListenerMultimapInjector.java
@@ -16,26 +16,23 @@ public ListenerMultimapInjector() {
}
@Override
- public CtClass generateHookedClass() {
- classPool.appendClassPath(new LoaderClassPath(PacketTypeSet.class.getClassLoader()));
-
- try {
- CtClass targetClass = classPool.get(this.targetClass);
- CtMethod addListener = ClassUtils.getMethodByName(targetClass.getMethods(), "addListener");
- CtMethod removeListener = ClassUtils.getMethodByName(targetClass.getMethods(), "removeListener");
-
- String src = DionaPluginHooker.class.getName() + ".getPlayerManager().removeAllPlayerCachedListener();";
- addListener.insertBefore(src);
- removeListener.insertBefore(src);
-
- return targetClass;
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ public void hookClass() throws Exception {
+ CtClass targetClass = classPool.get(this.targetClassName);
+ CtMethod addListener = ClassUtils.getMethodByName(targetClass.getMethods(), "addListener");
+ CtMethod removeListener = ClassUtils.getMethodByName(targetClass.getMethods(), "removeListener");
+
+ String src = DionaPluginHooker.class.getName() + ".getPlayerManager().removeAllPlayerCachedListener();";
+ addListener.insertBefore(src);
+ removeListener.insertBefore(src);
}
@Override
public boolean canHook() {
return DionaConfig.hookProtocolLibPacket;
}
+
+ @Override
+ protected void initClassPath() {
+ classPool.appendClassPath(new LoaderClassPath(PacketTypeSet.class.getClassLoader()));
+ }
}
diff --git a/src/main/java/io/github/dionatestserver/pluginhooker/hook/impl/protocollib/ProtocolLibCallbackHandler.java b/src/main/java/io/github/dionatestserver/pluginhooker/hook/impl/protocollib/ProtocolLibCallbackHandler.java
index 02bd1bc..25109be 100644
--- a/src/main/java/io/github/dionatestserver/pluginhooker/hook/impl/protocollib/ProtocolLibCallbackHandler.java
+++ b/src/main/java/io/github/dionatestserver/pluginhooker/hook/impl/protocollib/ProtocolLibCallbackHandler.java
@@ -6,7 +6,7 @@
import com.comphenix.protocol.injector.PrioritizedListener;
import com.comphenix.protocol.injector.SortedPacketListenerList;
import io.github.dionatestserver.pluginhooker.DionaPluginHooker;
-import io.github.dionatestserver.pluginhooker.events.DionaProtocolLibPacketEvent;
+import io.github.dionatestserver.pluginhooker.events.ProtocolLibPacketEvent;
import io.github.dionatestserver.pluginhooker.player.DionaPlayer;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
@@ -38,7 +38,7 @@ public SortedPacketListenerList handleProtocolLibPacket(SortedPacketListenerList
if (dionaPlayer.getEnabledPlugins().contains(plugin)) {
- DionaProtocolLibPacketEvent packetEvent = new DionaProtocolLibPacketEvent(listener, event, outbound);
+ ProtocolLibPacketEvent packetEvent = new ProtocolLibPacketEvent(listener, event, outbound);
Bukkit.getPluginManager().callEvent(packetEvent);
if (packetEvent.isCancelled()) {
diff --git a/src/main/java/io/github/dionatestserver/pluginhooker/hook/impl/protocollib/ProtocolLibInjector.java b/src/main/java/io/github/dionatestserver/pluginhooker/hook/impl/protocollib/ProtocolLibInjector.java
index 54a8bc2..00e8846 100644
--- a/src/main/java/io/github/dionatestserver/pluginhooker/hook/impl/protocollib/ProtocolLibInjector.java
+++ b/src/main/java/io/github/dionatestserver/pluginhooker/hook/impl/protocollib/ProtocolLibInjector.java
@@ -12,28 +12,20 @@
public class ProtocolLibInjector extends Injector {
@Getter
- private static ProtocolLibCallbackHandler callbackHandler = new ProtocolLibCallbackHandler();
+ private static final ProtocolLibCallbackHandler callbackHandler = new ProtocolLibCallbackHandler();
public ProtocolLibInjector() {
super("com.comphenix.protocol.injector.PacketFilterManager", PacketFilterBuilder.class);
}
@Override
- public CtClass generateHookedClass() {
- classPool.appendClassPath(new LoaderClassPath(PacketFilterBuilder.class.getClassLoader()));
+ public void hookClass() throws Exception {
+ CtClass packetFilterManager = classPool.get(targetClassName);
- try {
- CtClass packetFilterManager = classPool.get(targetClass);
-
- CtMethod postPacketToListeners = ClassUtils.getMethodBySignature(packetFilterManager.getDeclaredMethods(), "(Lcom/comphenix/protocol/injector/SortedPacketListenerList;Lcom/comphenix/protocol/events/PacketEvent;Z)V");
- postPacketToListeners.insertBefore(
- "$1=" + ProtocolLibInjector.class.getName() + ".getCallbackHandler().handleProtocolLibPacket($1,$2,$3);"
- );
- return packetFilterManager;
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
+ CtMethod postPacketToListeners = ClassUtils.getMethodBySignature(packetFilterManager.getDeclaredMethods(), "(Lcom/comphenix/protocol/injector/SortedPacketListenerList;Lcom/comphenix/protocol/events/PacketEvent;Z)V");
+ postPacketToListeners.insertBefore(
+ "$1=" + ProtocolLibInjector.class.getName() + ".getCallbackHandler().handleProtocolLibPacket($1,$2,$3);"
+ );
}
@Override
@@ -41,4 +33,9 @@ public boolean canHook() {
return DionaConfig.hookProtocolLibPacket;
}
+ @Override
+ protected void initClassPath() {
+ classPool.appendClassPath(new LoaderClassPath(PacketFilterBuilder.class.getClassLoader()));
+ }
+
}
diff --git a/src/main/java/io/github/dionatestserver/pluginhooker/player/DionaPlayer.java b/src/main/java/io/github/dionatestserver/pluginhooker/player/DionaPlayer.java
index f8cedc9..b959128 100644
--- a/src/main/java/io/github/dionatestserver/pluginhooker/player/DionaPlayer.java
+++ b/src/main/java/io/github/dionatestserver/pluginhooker/player/DionaPlayer.java
@@ -9,6 +9,7 @@
import org.bukkit.plugin.Plugin;
import java.util.HashSet;
+import java.util.Objects;
import java.util.Set;
@Getter
@@ -16,7 +17,7 @@ public class DionaPlayer {
private final Player player;
- private final Set enabledPlugins;
+ private final Set enabledPlugins = new HashSet<>();
// cached Protocollib listener list
@Setter
@@ -24,7 +25,6 @@ public class DionaPlayer {
public DionaPlayer(Player player) {
this.player = player;
- this.enabledPlugins = new HashSet<>();
}
public void enablePlugin(Plugin plugin) {
@@ -45,5 +45,16 @@ public void removeCachedListener() {
cachedListeners = null;
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ DionaPlayer that = (DionaPlayer) o;
+ return player.equals(that.player);
+ }
+ @Override
+ public int hashCode() {
+ return Objects.hash(player);
+ }
}
diff --git a/src/main/java/io/github/dionatestserver/pluginhooker/player/PlayerManager.java b/src/main/java/io/github/dionatestserver/pluginhooker/player/PlayerManager.java
index c35a2f9..4f116de 100644
--- a/src/main/java/io/github/dionatestserver/pluginhooker/player/PlayerManager.java
+++ b/src/main/java/io/github/dionatestserver/pluginhooker/player/PlayerManager.java
@@ -3,14 +3,15 @@
import lombok.Getter;
import org.bukkit.entity.Player;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Set;
@Getter
public class PlayerManager {
@Getter
- private final List players = new ArrayList<>();
+ private final Set players = new HashSet<>();
public void addPlayer(Player player) {
players.add(new DionaPlayer(player));
@@ -22,7 +23,12 @@ public void removePlayer(Player player) {
public DionaPlayer getDionaPlayer(Player player) {
if (player == null) return null;
- return players.stream().filter(dionaPlayer -> dionaPlayer.getPlayer() == player).findFirst().orElse(null);
+ for (DionaPlayer dionaPlayer : players) {
+ if (dionaPlayer.getPlayer().equals(player)) {
+ return dionaPlayer;
+ }
+ }
+ return null;
}
public void removeAllPlayerCachedListener() {
diff --git a/src/main/java/io/github/dionatestserver/pluginhooker/utils/AgentUtils.java b/src/main/java/io/github/dionatestserver/pluginhooker/utils/AgentUtils.java
new file mode 100644
index 0000000..bc3b86c
--- /dev/null
+++ b/src/main/java/io/github/dionatestserver/pluginhooker/utils/AgentUtils.java
@@ -0,0 +1,61 @@
+package io.github.dionatestserver.pluginhooker.utils;
+
+import com.sun.tools.attach.VirtualMachine;
+import io.github.dionatestserver.pluginhooker.DionaPluginHooker;
+import javassist.ClassPool;
+
+import java.io.File;
+import java.io.OutputStream;
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.nio.file.Files;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+public class AgentUtils {
+ public static File generateAgentFile(String agentClass) {
+ Manifest manifest = new Manifest();
+ manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
+ manifest.getMainAttributes().put(new Attributes.Name("Agent-Class"), agentClass);
+ manifest.getMainAttributes().put(new Attributes.Name("Can-Redefine-Classes"), "true");
+
+ try {
+ File agentFile = new File(DionaPluginHooker.getInstance().getDataFolder(), "agent.jar");
+ if (!agentFile.exists()) {
+ agentFile.createNewFile();
+ }
+
+ OutputStream outputStream = Files.newOutputStream(agentFile.toPath());
+ JarOutputStream jarOutputStream = new JarOutputStream(outputStream, manifest);
+ jarOutputStream.putNextEntry(new JarEntry(agentClass.replace(".", "/") + ".class"));
+
+
+ ClassPool pool = ClassPool.getDefault();
+ jarOutputStream.write(pool.get(agentClass).toBytecode());
+
+ jarOutputStream.finish();
+ return agentFile;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ private static String getPid() {
+ RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean();
+ String pid = bean.getName();
+ if (pid.contains("@")) {
+ pid = pid.substring(0, pid.indexOf("@"));
+ }
+ return pid;
+ }
+
+ public static void attachSelf(File agentFile) throws Exception {
+ System.loadLibrary("attach");
+ VirtualMachine vm = VirtualMachine.attach(getPid());
+ vm.loadAgent(agentFile.getAbsolutePath());
+ vm.detach();
+ }
+}
\ No newline at end of file