diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index 5dab60f..cea2a0f 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -32,8 +32,8 @@ tasks.shadowJar { relocate("eu.okaeri.configs", "dev.xhyrom.lighteco.libraries.okaeri.configs") relocate("eu.okaeri.validator", "dev.xhyrom.lighteco.libraries.okaeri.validator") - relocate("net.kyori.adventure", "dev.xhyrom.lighteco.libraries.net.kyori.adventure") - relocate("net.kyori.examination", "dev.xhyrom.lighteco.libraries.net.kyori.examination") + //relocate("net.kyori.adventure", "dev.xhyrom.lighteco.libraries.net.kyori.adventure") + //relocate("net.kyori.examination", "dev.xhyrom.lighteco.libraries.net.kyori.examination") relocate("org.yaml.snakeyaml", "dev.xhyrom.lighteco.libraries.org.yaml.snakeyaml") diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoPlugin.java b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoPlugin.java index ec04dc1..22475ee 100644 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoPlugin.java +++ b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoPlugin.java @@ -12,6 +12,7 @@ import dev.xhyrom.lighteco.common.manager.user.StandardUserManager; import lombok.Getter; import org.bukkit.entity.Player; import org.bukkit.plugin.ServicePriority; +import org.bukkit.plugin.java.PluginClassLoader; import org.checkerframework.checker.nullness.qual.NonNull; @Getter diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/dependencies/DependencyManagerImpl.java b/common/src/main/java/dev/xhyrom/lighteco/common/dependencies/DependencyManagerImpl.java index 27ccb5c..016bce9 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/dependencies/DependencyManagerImpl.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/dependencies/DependencyManagerImpl.java @@ -3,10 +3,12 @@ package dev.xhyrom.lighteco.common.dependencies; import com.google.common.collect.ImmutableSet; import com.google.common.io.MoreFiles; import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin; +import dev.xhyrom.lighteco.common.plugin.classpath.URLClassLoaderAccess; import dev.xhyrom.lighteco.common.storage.StorageType; import java.io.IOException; import java.net.URL; +import java.net.URLClassLoader; import java.nio.file.Files; import java.nio.file.Path; import java.util.EnumMap; @@ -22,10 +24,13 @@ public class DependencyManagerImpl implements DependencyManager { private final DependencyRegistry registry; private final Path cacheDirectory; + private final URLClassLoaderAccess classLoader; public DependencyManagerImpl(LightEcoPlugin plugin) { this.registry = new DependencyRegistry(); this.cacheDirectory = setupCacheDirectory(plugin); + this.classLoader = URLClassLoaderAccess.create((URLClassLoader) plugin.getBootstrap().getClass().getClassLoader()); + System.out.println(this.classLoader); } @Override @@ -56,17 +61,24 @@ public class DependencyManagerImpl implements DependencyManager { } } - private void loadDependency(Dependency dependency) { + private void loadDependency(Dependency dependency) throws Exception { if (this.loaded.containsKey(dependency)) { return; } - try { - Path file = downloadDependency(dependency); + Path file = downloadDependency(dependency); - this.loaded.put(dependency, file); - } catch (Exception e) { - throw new RuntimeException(e); + this.loaded.put(dependency, file); + + System.out.println("HHHH"); + if (this.registry.shouldAutoLoad(dependency)) { + System.out.println("Loaded dependency " + dependency + " from " + file); + + try { + this.classLoader.addURL(file.toUri().toURL()); + } catch (Exception e) { + e.printStackTrace(); + } } } diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/dependencies/DependencyRegistry.java b/common/src/main/java/dev/xhyrom/lighteco/common/dependencies/DependencyRegistry.java index 08d2d27..0b27e34 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/dependencies/DependencyRegistry.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/dependencies/DependencyRegistry.java @@ -24,4 +24,11 @@ public class DependencyRegistry { return dependencies; } + + public boolean shouldAutoLoad(Dependency dependency) { + return switch (dependency) { + case H2_DRIVER, SQLITE_DRIVER -> false; + default -> true; + }; + } } diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/plugin/classpath/URLClassLoaderAccess.java b/common/src/main/java/dev/xhyrom/lighteco/common/plugin/classpath/URLClassLoaderAccess.java new file mode 100644 index 0000000..66361d2 --- /dev/null +++ b/common/src/main/java/dev/xhyrom/lighteco/common/plugin/classpath/URLClassLoaderAccess.java @@ -0,0 +1,134 @@ +package dev.xhyrom.lighteco.common.plugin.classpath; + +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Collection; + +public abstract class URLClassLoaderAccess { + public static URLClassLoaderAccess create(URLClassLoader classLoader) { + if (Reflection.isSupported()) { + return new Reflection(classLoader); + } else if (Unsafe.isSupported()) { + return new Unsafe(classLoader); + } else { + return Noop.INSTANCE; + } + } + + private final URLClassLoader classLoader; + + protected URLClassLoaderAccess(URLClassLoader classLoader) { + this.classLoader = classLoader; + } + + public abstract void addURL(@NonNull URL url); + + private static class Reflection extends URLClassLoaderAccess { + private static final Method ADD_URL_METHOD; + + static { + Method addUrlMethod; + try { + addUrlMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); + addUrlMethod.setAccessible(true); + } catch (Exception e) { + addUrlMethod = null; + } + ADD_URL_METHOD = addUrlMethod; + } + + private static boolean isSupported() { + return ADD_URL_METHOD != null; + } + + Reflection(URLClassLoader classLoader) { + super(classLoader); + } + + @Override + public void addURL(@NonNull URL url) { + try { + ADD_URL_METHOD.invoke(super.classLoader, url); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + } + + private static class Unsafe extends URLClassLoaderAccess { + private static final sun.misc.Unsafe UNSAFE; + + static { + sun.misc.Unsafe unsafe; + try { + Field unsafeField = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + unsafeField.setAccessible(true); + unsafe = (sun.misc.Unsafe) unsafeField.get(null); + } catch (Throwable t) { + unsafe = null; + } + UNSAFE = unsafe; + } + + private static boolean isSupported() { + return UNSAFE != null; + } + + private final Collection unopenedURLs; + private final Collection pathURLs; + + @SuppressWarnings("unchecked") + Unsafe(URLClassLoader classLoader) { + super(classLoader); + + Collection unopenedURLs; + Collection pathURLs; + try { + Object ucp = fetchField(URLClassLoader.class, classLoader, "ucp"); + unopenedURLs = (Collection) fetchField(ucp.getClass(), ucp, "unopenedUrls"); + pathURLs = (Collection) fetchField(ucp.getClass(), ucp, "path"); + } catch (Throwable e) { + unopenedURLs = null; + pathURLs = null; + } + + this.unopenedURLs = unopenedURLs; + this.pathURLs = pathURLs; + } + + private static Object fetchField(final Class clazz, final Object object, final String name) throws NoSuchFieldException { + Field field = clazz.getDeclaredField(name); + long offset = UNSAFE.objectFieldOffset(field); + return UNSAFE.getObject(object, offset); + } + + @Override + public void addURL(@NonNull URL url) { + if (this.unopenedURLs == null || this.pathURLs == null) { + throw new NullPointerException("unopenedURLs or pathURLs"); + } + + synchronized (this.unopenedURLs) { + this.unopenedURLs.add(url); + this.pathURLs.add(url); + } + } + } + + private static class Noop extends URLClassLoaderAccess { + private static final Noop INSTANCE = new Noop(); + + private Noop() { + super(null); + } + + @Override + public void addURL(@NonNull URL url) { + throw new UnsupportedOperationException("Noop"); + } + } +} diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/storage/provider/sql/SqlStorageProvider.java b/common/src/main/java/dev/xhyrom/lighteco/common/storage/provider/sql/SqlStorageProvider.java index fe34690..4519400 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/storage/provider/sql/SqlStorageProvider.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/storage/provider/sql/SqlStorageProvider.java @@ -21,17 +21,17 @@ public class SqlStorageProvider implements StorageProvider { private final String SAVE_USER_LOCAL_CURRENCY; private final String SAVE_USER_GLOBAL_CURRENCY; private static final String LOAD_WHOLE_USER = """ - SELECT currency_identifier, balance - FROM - ( - SELECT currency_identifier, balance - FROM {prefix}_users - WHERE uuid=?1 - UNION ALL - SELECT currency_identifier, balance - FROM {prefix}_{context}_users - WHERE uuid=?1 - ); +SELECT currency_identifier, balance +FROM + ( + SELECT currency_identifier, balance + FROM '{prefix}_users' + WHERE uuid=?1 + UNION ALL + SELECT currency_identifier, balance + FROM '{prefix}_{context}_users' + WHERE uuid=?1 + ) AS combined_currencies; """; private final LightEcoPlugin plugin; @@ -86,6 +86,7 @@ public class SqlStorageProvider implements StorageProvider { try (Connection c = this.connectionFactory.getConnection()) { try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(LOAD_WHOLE_USER))) { ps.setString(1, uniqueIdString); + ps.setString(2, uniqueIdString); ResultSet rs = ps.executeQuery();