Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>io.github.thatsmusic99</groupId>
<artifactId>ATHENA</artifactId>
<version>1.0.0</version>
<version>1.1.0-BETA-1</version>
<build>
<plugins>
<plugin>
Expand All @@ -21,7 +21,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.0-SNAPSHOT</version>
<version>3.3.0</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
Expand Down Expand Up @@ -56,13 +56,6 @@
</repository>
</repositories>

<pluginRepositories>
<pluginRepository>
<id>shade-plugin</id>
<url>https://repository.apache.org/content/repositories/snapshots/</url>
</pluginRepository>
</pluginRepositories>

<dependencies>
<dependency>
<groupId>io.papermc.paper</groupId>
Expand All @@ -74,14 +67,14 @@
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>21.0.1</version>
<version>23.0.0</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>2.2.1</version>
<version>3.0.0</version>
</dependency>
</dependencies>

Expand Down
27 changes: 25 additions & 2 deletions src/main/java/io/github/thatsmusic99/athena/AthenaCore.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ public class AthenaCore extends JavaPlugin {
public void onEnable() {
instance = this;
getCommand("athena").setExecutor(new AthenaCommand());
new Metrics(this, 12408);
try {
new Metrics(this, 12408);
} catch (NoClassDefFoundError ignored) {}

new RemappingUtil();
Bukkit.getScheduler().runTaskAsynchronously(this, EventCache::new);
}
Expand All @@ -45,11 +48,31 @@ public static TextColor getFailColour() {
return TextColor.color(0xFCC0B3);
}

public static TextColor getNoticeColour() {
return TextColor.color(0xC2FFBB);
}

public static TextColor getNoticeColourDark() {
return TextColor.color(0x7AF47A);
}

public static void sendSuccessMessage(CommandSender sender, String message) {
sender.sendMessage(AthenaCore.getPrefix().append(Component.text(message, AthenaCore.getSuccessColour())));
sendSuccessMessage(sender, Component.text(message, AthenaCore.getSuccessColour()));
}

public static void sendSuccessMessage(CommandSender sender, Component component) {
sender.sendMessage(AthenaCore.getPrefix().append(component));
}

public static void sendFailMessage(CommandSender sender, String message) {
sender.sendMessage(AthenaCore.getPrefix().append(Component.text(message, AthenaCore.getFailColour())));
}

public static void sendNoticeMessage(CommandSender sender, String message) {
sendNoticeMessage(sender, Component.text(message, AthenaCore.getNoticeColour()));
}

public static void sendNoticeMessage(CommandSender sender, Component component) {
sender.sendMessage(AthenaCore.getPrefix().append(component));
}
}
178 changes: 178 additions & 0 deletions src/main/java/io/github/thatsmusic99/athena/util/AthenaExecutor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package io.github.thatsmusic99.athena.util;

import io.github.thatsmusic99.athena.AthenaCore;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;
import org.bukkit.command.CommandSender;
import org.bukkit.event.Event;
import org.bukkit.event.Listener;
import org.bukkit.plugin.EventExecutor;
import org.bukkit.plugin.RegisteredListener;
import org.jetbrains.annotations.NotNull;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

public class AthenaExecutor implements EventExecutor {

private final List<CommandSender> senders;
private final RegisteredListener listener;
private final EventExecutor executor;
private final Field executorField;
private final String name;

public AthenaExecutor(CommandSender sender, RegisteredListener listener, String name) throws NoSuchFieldException, IllegalAccessException {
senders = new ArrayList<>();
senders.add(sender);
this.listener = listener;
this.name = name;
executorField = listener.getClass().getDeclaredField("executor");
executorField.setAccessible(true);
executor = (EventExecutor) executorField.get(listener);
}

@Override
public void execute(@NotNull Listener listener, @NotNull Event event) {
if (!event.getClass().getSimpleName().equals(name)) return;
boolean executed = false;
try {
HashMap<String, Object> details = getEventDetails(event);
long currentMillis = System.nanoTime();
try {
executor.execute(listener, event);
} catch (Throwable ex) {
senders.forEach(sender -> AthenaCore.sendFailMessage(sender,
"An error occurred internally within " + this.listener.getPlugin().getName() + ", " +
"please report it to the developer."));
ex.printStackTrace();
return;
}
executed = true;
long finish = System.nanoTime();
HashMap<String, Object> newDetails = getEventDetails(event);
HashMap<String, RemappingUtil.Change> differences = new HashMap<>();
for (String key : details.keySet()) {

RemappingUtil.Change change = new RemappingUtil.Change(details.get(key), newDetails.get(key));
if (details.get(key) == null ^ newDetails.get(key) == null) {
differences.put(key, change);
continue;
}

if (change.getOldObject().equals(change.getNewObject())) continue;
differences.put(key, new RemappingUtil.Change(details.get(key), newDetails.get(key)));
}
dumpData(finish - currentMillis, differences);
} catch (Throwable ex) {
senders.forEach(sender -> AthenaCore.sendFailMessage(sender,
"An error occurred internally within ATHENA, please report it to the developer."));
ex.printStackTrace();
if (!executed) {
try {
AthenaCore.get().getLogger().info("Executing listener since ATHENA failed before it could.");
executor.execute(listener, event);
} catch (Throwable ex2) {
senders.forEach(sender -> AthenaCore.sendFailMessage(sender,
"An error occurred internally within " + this.listener.getPlugin().getName() + ", " +
"please report it to the developer."));
ex2.printStackTrace();
}
}
}
}

public String getName() {
return name;
}

void remapExecutor() throws IllegalAccessException {
executorField.set(listener, this);
}

private void unmapExecutor() throws IllegalAccessException {
executorField.set(listener, executor);
HashSet<AthenaExecutor> executors = RemappingUtil.get().getRegisteredEvents().get(name);
executors.remove(this);
RemappingUtil.get().getRegisteredEvents().put(name, executors);
}

private HashMap<String, Object> getEventDetails(Event event) throws IllegalAccessException {
// Create the map
HashMap<String, Object> map = new HashMap<>();
// Get all the fields
Class<?> checkedClass = event.getClass();
while (checkedClass != null) {
for (Field field : checkedClass.getDeclaredFields()) {
// Don't bother if it's static
if (Modifier.isStatic(field.getModifiers())) continue;
// Make it accessible
field.setAccessible(true);
// Get the field
map.put(field.getName(), field.get(event));
}
checkedClass = checkedClass.getSuperclass();
}

return map;
}

private void dumpData(long completionTime, HashMap<String, RemappingUtil.Change> differences) {
TextComponent infoDump;
TextComponent hoverText = Component.text().build();
if (!differences.isEmpty()) {
infoDump = Component.text(listener.getPlugin().getName(), AthenaCore.getInfoColour())
.append(Component.text(" made some changes to the event!", AthenaCore.getSuccessColour()));

for (String key : differences.keySet()) {
hoverText = hoverText.append(Component.text(key, AthenaCore.getInfoColour()))
.append(Component.text(" » ", NamedTextColor.DARK_GRAY))
.append(Component.text(differences.get(key).getOldObject(), AthenaCore.getSuccessColour()))
.append(Component.text(" to ", NamedTextColor.GRAY))
.append(Component.text(differences.get(key).getNewObject(), AthenaCore.getSuccessColour()))
.append(Component.text("\n"));
}
} else {
infoDump = Component.text(listener.getPlugin().getName() + " didn't make any changes.",
TextColor.color(0xA0B1B8), TextDecoration.ITALIC);

}
Class<?> listenerClass = listener.getListener().getClass();
hoverText = hoverText.append(Component.text("Completion time ", AthenaCore.getInfoColour()))
.append(Component.text("» ", NamedTextColor.DARK_GRAY))
.append(Component.text((completionTime / 100000) + "ms", AthenaCore.getSuccessColour()))
.append(Component.text("\n"))
.append(Component.text("Listener Class ", AthenaCore.getInfoColour()))
.append(Component.text("» ", NamedTextColor.DARK_GRAY))
.append(Component.text(listenerClass.getSimpleName() + " (" + listenerClass.getName() + ")",
AthenaCore.getSuccessColour()))
.append(Component.text("\n"))
.append(Component.text("Event Priority", AthenaCore.getInfoColour()))
.append(Component.text("» ", NamedTextColor.DARK_GRAY))
.append(Component.text(listener.getPriority().name(), AthenaCore.getSuccessColour()));
infoDump = infoDump.hoverEvent(hoverText);

Component result = AthenaCore.getPrefix().append(infoDump);

senders.forEach(sender -> sender.sendMessage(result));
}

protected void addSender(CommandSender sender) {
senders.add(sender);
}

protected void removeSender(CommandSender sender) throws IllegalAccessException {
senders.remove(sender);
if (senders.size() == 0) unmapExecutor();
}

protected boolean hasSender(CommandSender sender) {
return senders.contains(sender);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package io.github.thatsmusic99.athena.util;

import io.github.thatsmusic99.athena.AthenaCore;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import org.bukkit.command.CommandSender;
import org.bukkit.event.*;

import java.util.*;

public class AthenaListener implements Listener {

private final Set<CommandSender> senders;

public AthenaListener() {
this.senders = Collections.newSetFromMap(new WeakHashMap<>());
}

@EventHandler(priority = EventPriority.LOWEST)
public void onEvent(Event event) {
// Gather the execution source
List<String> classLoaders = new ArrayList<>();
TextComponent hoverText = Component.text().build();
Exception ex = new Exception("Boo");
try {
// >:)
throw ex;
} catch (Exception e) {
for (StackTraceElement element : e.getStackTrace()) {
hoverText = hoverText.append(Component.text(element.toString()).color(AthenaCore.getSuccessColour())).append(Component.text("\n"));
if (element.getClassLoaderName() == null) continue;
if (element.getClassLoaderName().contains("ATHENA")) continue;
if (classLoaders.contains(element.getClassLoaderName())) continue;
classLoaders.add(element.getClassLoaderName());
}
}
// Send the notice to each sender
for (CommandSender sender : senders) {
if (sender == null) return;

// "Event has been executed"
AthenaCore.sendNoticeMessage(sender, Component.text(event.getClass().getSimpleName(), AthenaCore.getNoticeColourDark())
.append(Component.text(" has been executed!", AthenaCore.getNoticeColour())));
// List classloaders found
if (!classLoaders.isEmpty()) {
AthenaCore.sendNoticeMessage(sender, Component.text("Classloaders: ", AthenaCore.getNoticeColour())
.append(Component.text(String.join(", ", classLoaders), AthenaCore.getNoticeColourDark()).hoverEvent(hoverText)));
}
}
}

public void addSender(CommandSender sender) {
senders.add(sender);
}

public void removeSender(CommandSender sender) {
if (!senders.contains(sender)) return;
senders.remove(sender);
if (senders.isEmpty()) HandlerList.unregisterAll(this);
}
}
15 changes: 14 additions & 1 deletion src/main/java/io/github/thatsmusic99/athena/util/EventCache.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package io.github.thatsmusic99.athena.util;

import io.github.thatsmusic99.athena.AthenaCore;
import org.bukkit.event.Event;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
Expand All @@ -11,20 +10,34 @@
import java.util.HashMap;
import java.util.Set;

/**
* Used to store events that are actively being listened to by the server.
*/
public class EventCache {

private final HashMap<String, Class<? extends Event>> registeredEvents;
private static EventCache instance;

/**
* Initiates the event cache.
*/
public EventCache() {
// Add the instance.
instance = this;
// Create the hashmap tracking events being listened to.
registeredEvents = new HashMap<>();
// Get the handler lists for listener classes.
for (HandlerList list : HandlerList.getHandlerLists()) {
// Get all registered listeners in a given class.
for (RegisteredListener listener : list.getRegisteredListeners()) {
Listener actualListener = listener.getListener();
// Get all the methods in the listener.
for (Method method : actualListener.getClass().getDeclaredMethods()) {
// If they aren't annotated with @EventHandler, ignore them
if (!method.isAnnotationPresent(EventHandler.class)) continue;
// Get the class of each parameter specified.
for (Class<?> clazz : method.getParameterTypes()) {
// If it's not an event, ignore it.
if (!Event.class.isAssignableFrom(clazz)) continue;
registeredEvents.put(clazz.getSimpleName(), (Class<? extends Event>) clazz);
}
Expand Down
Loading