PluginManager class

Пакет: com.hypixel.hytale.server.core.plugin

Файл: com/hypixel/hytale/server/core/plugin/PluginManager.java

Поля (202)

МодификаторыТипИмя
break
break
break
break
break
continue
instance
private final PluginManager pluginManager
return
return
return
return
HashMap var1
boolean var1
var1
List var1
List var1
URLClassLoader var1
PluginBase var10
char[] var10
PluginManifest[] var10
var10
RawJsonReader var10
PluginBase var11
RawJsonReader var11
URL var11
ExtraInfo var11
int var12
SemverRange var12
ExtraInfo var12
Path var12
PluginManifest var12
String var13
PluginManifest var13
var13
PluginClassLoader var13
PluginClassLoader var13
PendingLoadJavaPlugin var14
var14
var14
PendingLoadJavaPlugin var14
Message var15
Message var16
URL var16
PluginClassLoader var16
PluginBase var16
PluginBase var16
PluginBase var16
Path var17
PendingLoadJavaPlugin var17
PluginBase var17
URL var17
URL var17
PluginClassLoader var18
PendingLoadJavaPlugin var18
Class var18
PluginClassLoader var19
Class var19
PluginIdentifier var2
PlayerRef var2
AssetPack var2
boolean var2
var2
int var2
PluginManifest var2
AssetModule var2
boolean var2
Path var2
PluginBase var2
InputStream var2
PluginBase var2
PluginState var2
URL var22
PluginClassLoader var23
URI var26
Path var27
URL var28
URI var28
Boolean var29
var29
PluginManifest var3
PendingLoadPlugin var3
StringBuilder var3
PluginBase var3
String var3
Path var3
URI var3
var3
PluginBase var3
Path var3
String var3
PluginBase var3
PluginClassLoader var3
InputStreamReader var3
CompletableFuture var3
boolean var3
PluginClassLoader var3
ObjectArrayList var3
Iterator var30
List var31
ClassLoader var31
PendingLoadPlugin var33
URL var34
ObjectArrayList var35
InputStream var35
ObjectArrayList var36
InputStreamReader var36
boolean var37
char[] var37
RawJsonReader var38
StringBuilder var39
ExtraInfo var39
ModConfig var4
SemverRange var4
PluginManifest var4
var4
ClassLoader var4
var4
HashSet var4
AssetModule var4
AssetPack var4
ArrayList var4
HashSet var4
char[] var4
boolean var4
AssetModule var4
String var4
Class var4
ObjectArrayList var4
PluginClassLoader var4
boolean var40
var40
PluginManifest[] var40
ObjectListIterator var42
Message var43
boolean var44
var44
PluginIdentifier var45
StringBuilder var47
int var49
boolean var5
var5
var5
PluginBase var5
Throwable var5
PluginManifest.ServerVersionCheck var5
InputStream var5
ArrayList var5
InputStream var5
String var5
RawJsonReader var5
IEventDispatcher var5
Message var5
PluginBase var5
URL var5
Message var50
HytaleServerConfig var6
PluginClassLoader var6
PluginIdentifier var6
String var6
PluginIdentifier var6
InputStreamReader var6
URL var6
InputStreamReader var6
PluginManifest var6
ExtraInfo var6
Class var6
PluginBase var6
URL var6
URL var6
PluginClassLoader var7
ModConfig var7
PluginManifest var7
var7
var7
char[] var7
URLConnection var7
char[] var7
boolean var7
InputStream var7
PendingLoadJavaPlugin var7
PluginManifest var7
PluginBase var7
Class var7
URL var7
URL var7
PluginBase var8
SemverRange var8
PendingLoadPlugin var8
PendingLoadJavaPlugin var8
RawJsonReader var8
InputStream var8
RawJsonReader var8
InputStreamReader var8
URL var8
CompletableFuture var9
StringBuilder var9
var9
ExtraInfo var9
InputStreamReader var9
ExtraInfo var9
char[] var9

Методы (119)

МодификаторыВозвратСигнатура
abstract throw new ClassNotFoundExceptionthrow new ClassNotFoundException()
public record ClasspathAssetPackrecord ClasspathAssetPack(@Nonnull Path path, @Nonnull PluginManifest manifest)
abstract throw new IllegalStateExceptionthrow new IllegalStateException("Expected PluginState.NONE but found " + this.state)
abstract throw new IllegalStateExceptionthrow new IllegalStateException("Expected PluginState.SETUP but found " + this.state)
abstract throw new IllegalStateExceptionthrow new IllegalStateException("unreachable")
abstract return new PendingLoadJavaPluginreturn new PendingLoadJavaPlugin(var1, var4, var23)
public PluginBridgeClassLoaderpublic PluginBridgeClassLoader(PluginManager var1, ClassLoader var2)
private boolean canLoadOnBootboolean canLoadOnBoot(@Nonnull PendingLoadPlugin var1)
private int collectFailedPluginsint collectFailedPlugins(StringBuilder var1)
private boolean dependenciesMatchStateboolean dependenciesMatchState(PluginBase var1, PluginState var2, PluginState var3)
private boolean failedToLoadboolean failedToLoad(@Nonnull PendingLoadPlugin var1, @Nonnull List<PluginIdentifier> var2)
private boolean findAndLoadPluginboolean findAndLoadPlugin(PluginIdentifier var1)
for for(PluginIdentifier var5 : this.outdatedPlugins)
for for(PendingLoadPlugin var4 : this.loadOrder)
for for(PendingLoadPlugin var41 : this.loadOrder)
for for(PendingLoadPlugin var48 : this.loadOrder)
for for(PendingLoadPlugin var4 : this.loadOrder)
for for(Path var7 : var5)
for for(URL var6 : var3)
for for(PluginManifest var17 : var10)
for for(PendingLoadPlugin var3 : this.corePlugins)
for for(PluginManifest var44 : var40)
for for(Path var5 : var3)
abstract for for(int var2 = 0; var2 < this.corePlugins.size()
static PluginManager getPluginManager get()
public URL getResource0public URL getResource0(@Nonnull String var1, @Nullable PluginClassLoader var2)
public URL getResource0public URL getResource0(@Nonnull String var1, @Nullable PluginClassLoader var2, @Nonnull PluginManifest var3)
public Enumeration<URL> getResources0public Enumeration<URL> getResources0(@Nonnull String var1, @Nullable PluginClassLoader var2)
public Enumeration<URL> getResources0public Enumeration<URL> getResources0(@Nonnull String var1, @Nullable PluginClassLoader var2, @Nonnull PluginManifest var3)
public ComponentType<EntityStore, PluginListPageManager.SessionSettings> getSessionSettingsComponentTypeComponentType<EntityStore, PluginListPageManager.SessionSettings> getSessionSettingsComponentType()
public boolean hasPluginboolean hasPlugin(PluginIdentifier var1, @Nonnull SemverRange var2)
if if(var5)
if if(this.state != PluginState.NONE)
if if(var2 != null)
if if(var9 != null)
if if(this.state != PluginState.SETUP)
if if(this.loading == null)
if if(var5 != PluginManifest.ServerVersionCheck.COMPATIBLE)
if if(var2 != null)
if if(var8 != null)
if if(var7 == null)
if if(var11 != null)
if if(var7 == null)
if if(var3)
if if(var8 != null)
if if(var4 == null)
if if(var6 == null)
if if(var13 == null)
if if(var7 instanceof JarURLConnection var15)
if if(var3 == null)
if if(var4 == null)
if if(var2 != null)
if if(var4 != null)
if if(var3 instanceof JavaPlugin var10)
if if(var2 == null)
if if(var3 != null)
if if(var2 != null)
if if(var34 != null)
if if(var29 != null)
if if(var29 != null)
if if(var7 == null)
if if(var1 == null)
if if(var3 == null)
if if(var4 != null)
if if(var6 != null)
if if(var7 != null)
if if(var16 != null)
if if(var18 != null)
if if(var19 != null)
if if(var3 != var1)
if if(var4 != null)
if if(var5 != null)
if if(var6 != null)
if if(var16 != null)
if if(var7 != null)
if if(var17 != null)
if if(var6 != null)
if if(var7 != null)
if if(var16 != null)
if if(var8 != null)
if if(var17 != null)
if if(var2 instanceof JavaPlugin var3)
static boolean isCorePluginboolean isCorePlugin(@Nonnull PendingLoadPlugin var0)
abstract return isCorePluginreturn isCorePlugin(var1)
public boolean loadboolean load(@Nonnull PluginIdentifier var1)
private boolean loadboolean load(@Nullable PendingLoadPlugin var1)
private void loadClasspathPluginsFromBundlevoid loadClasspathPluginsFromBundle(@Nonnull Map<PluginIdentifier, PendingLoadPlugin> var1, @Nonnull Map<PluginIdentifier, PluginManifest> var2, @Nonnull URL var3, @Nonnull URI var4)
private boolean loadClasspathPluginsFromManifestsboolean loadClasspathPluginsFromManifests(@Nonnull Map<PluginIdentifier, PendingLoadPlugin> var1, @Nonnull Map<PluginIdentifier, PluginManifest> var2, @Nonnull List<URL> var3)
static void loadPendingPluginvoid loadPendingPlugin(@Nonnull Map<PluginIdentifier, PendingLoadPlugin> var0, @Nonnull PendingLoadPlugin var1)
abstract loadPendingPlugin loadPendingPlugin(var1, var3)
abstract loadPendingPlugin loadPendingPlugin(var1, var8)
abstract loadPendingPlugin loadPendingPlugin(var1, var14)
abstract loadPendingPlugin loadPendingPlugin(var1, var18)
abstract loadPendingPlugin loadPendingPlugin(var0, var3)
private void loadPluginsFromDirectoryvoid loadPluginsFromDirectory(@Nonnull Map<PluginIdentifier, PendingLoadPlugin> var1, @Nonnull Path var2, boolean var3, @Nonnull Map<PluginIdentifier, PluginManifest> var4)
private void loadPluginsInClasspathvoid loadPluginsInClasspath(@Nonnull Map<PluginIdentifier, PendingLoadPlugin> var1, @Nonnull Map<PluginIdentifier, PluginManifest> var2)
abstract registerAsParallelCapable registerAsParallelCapable()
private boolean registerAssetPackIfNeededboolean registerAssetPackIfNeeded(@Nonnull PendingLoadPlugin var1)
public void registerCorePluginvoid registerCorePlugin(@Nonnull PluginManifest var1)
protected void releasePluginClassLoadervoid releasePluginClassLoader(JavaPlugin var1)
public boolean reloadboolean reload(@Nonnull PluginIdentifier var1)
public void setupvoid setup()
private boolean setupboolean setup(@Nonnull PluginBase var1)
public void shutdownvoid shutdown()
public void startvoid start()
private boolean startboolean start(@Nonnull PluginBase var1)
abstract super super(var2)
switch switch(var5)
abstract try try(InputStream var5 = Files.newInputStream(var3)
abstract try try(InputStream var8 = var7.getInputStream()
abstract try try(InputStream var5 = var3.openStream()
abstract try try(InputStream var7 = var6.openStream()
abstract try try(InputStream var35 = var34.openStream()
private static URL tryGetResourceprivate static URL tryGetResource(@Nonnull String var0, @Nullable PluginClassLoader var1, @Nullable PluginBase var2)
public boolean unloadboolean unload(@Nonnull PluginIdentifier var1)
private boolean unloadboolean unload(@Nonnull PluginIdentifier var1, @Nonnull Set<PluginIdentifier> var2)
private void unregisterAssetPackIfNeededvoid unregisterAssetPackIfNeeded(@Nonnull JavaPlugin var1)
private void validatePluginDepsvoid validatePluginDeps(@Nonnull PendingLoadPlugin var1, @Nullable Map<PluginIdentifier, PendingLoadPlugin> var2)
static Throwable wrapIfThirdPartyThrowable wrapIfThirdParty(@Nonnull PendingLoadPlugin var0, @Nonnull Throwable var1)

Исходный код

Показать/скрыть
class="kw">package com.hypixel.hytale.server.core.plugin;

class="kw">import com.hypixel.hytale.assetstore.AssetPack;
class="kw">import com.hypixel.hytale.assetstore.AssetRegistry;
class="kw">import com.hypixel.hytale.assetstore.AssetStore;
class="kw">import com.hypixel.hytale.codec.ExtraInfo;
class="kw">import com.hypixel.hytale.codec.codecs.array.ArrayCodec;
class="kw">import com.hypixel.hytale.codec.exception.CodecException;
class="kw">import com.hypixel.hytale.codec.util.RawJsonReader;
class="kw">import com.hypixel.hytale.common.plugin.Mod;
class="kw">import com.hypixel.hytale.common.plugin.ModLoadOrderException;
class="kw">import com.hypixel.hytale.common.plugin.PluginIdentifier;
class="kw">import com.hypixel.hytale.common.plugin.PluginManifest;
class="kw">import com.hypixel.hytale.common.semver.SemverRange;
class="kw">import com.hypixel.hytale.common.util.java.ManifestUtil;
class="kw">import com.hypixel.hytale.component.ComponentType;
class="kw">import com.hypixel.hytale.event.IEventDispatcher;
class="kw">import com.hypixel.hytale.logger.HytaleLogger;
class="kw">import com.hypixel.hytale.logger.sentry.SkipSentryException;
class="kw">import com.hypixel.hytale.metrics.MetricsRegistry;
class="kw">import com.hypixel.hytale.server.core.HytaleServer;
class="kw">import com.hypixel.hytale.server.core.HytaleServerConfig;
class="kw">import com.hypixel.hytale.server.core.Message;
class="kw">import com.hypixel.hytale.server.core.Options;
class="kw">import com.hypixel.hytale.server.core.ShutdownReason;
class="kw">import com.hypixel.hytale.server.core.asset.AssetModule;
class="kw">import com.hypixel.hytale.server.core.command.system.CommandManager;
class="kw">import com.hypixel.hytale.server.core.config.ModConfig;
class="kw">import com.hypixel.hytale.server.core.event.events.player.AddPlayerToWorldEvent;
class="kw">import com.hypixel.hytale.server.core.permissions.HytalePermissions;
class="kw">import com.hypixel.hytale.server.core.plugin.commands.PluginCommand;
class="kw">import com.hypixel.hytale.server.core.plugin.event.PluginSetupEvent;
class="kw">import com.hypixel.hytale.server.core.plugin.pending.PendingLoadJavaPlugin;
class="kw">import com.hypixel.hytale.server.core.plugin.pending.PendingLoadPlugin;
class="kw">import com.hypixel.hytale.server.core.universe.PlayerRef;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
class="kw">import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
class="kw">import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
class="kw">import it.unimi.dsi.fastutil.objects.ObjectArrayList;
class="kw">import it.unimi.dsi.fastutil.objects.ObjectListIterator;
class="kw">import java.awt.Color;
class="kw">import java.io.IOException;
class="kw">import java.io.InputStream;
class="kw">import java.io.InputStreamReader;
class="kw">import java.net.JarURLConnection;
class="kw">import java.net.MalformedURLException;
class="kw">import java.net.URI;
class="kw">import java.net.URISyntaxException;
class="kw">import java.net.URL;
class="kw">import java.net.URLClassLoader;
class="kw">import java.net.URLConnection;
class="kw">import java.nio.charset.StandardCharsets;
class="kw">import java.nio.file.DirectoryStream;
class="kw">import java.nio.file.FileSystem;
class="kw">import java.nio.file.FileSystems;
class="kw">import java.nio.file.Files;
class="kw">import java.nio.file.Path;
class="kw">import java.nio.file.Paths;
class="kw">import java.util.ArrayList;
class="kw">import java.util.Collections;
class="kw">import java.util.Enumeration;
class="kw">import java.util.HashMap;
class="kw">import java.util.HashSet;
class="kw">import java.util.Iterator;
class="kw">import java.util.List;
class="kw">import java.util.Locale;
class="kw">import java.util.Map;
class="kw">import java.util.Set;
class="kw">import java.util.Map.Entry;
class="kw">import java.util.concurrent.CompletableFuture;
class="kw">import java.util.concurrent.ConcurrentHashMap;
class="kw">import java.util.concurrent.CopyOnWriteArrayList;
class="kw">import java.util.concurrent.locks.ReentrantReadWriteLock;
class="kw">import java.util.logging.Level;
class="kw">import javax.annotation.Nonnull;
class="kw">import javax.annotation.Nullable;

class="kw">public class PluginManager {
   @Nonnull
   class="kw">private class="kw">static class="kw">final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
   @Nonnull
   class="kw">public class="kw">static class="kw">final Path MODS_PATH = Path.of("mods");
   @Nonnull
   class="kw">public class="kw">static class="kw">final MetricsRegistry<PluginManager> METRICS_REGISTRY = new MetricsRegistry<PluginManager>()
      .register("Plugins", var0 -> var0.getPlugins().toArray(PluginBase[]::new), new ArrayCodec<>(PluginBase.METRICS_REGISTRY, PluginBase[]::new));
   class="kw">private class="kw">static PluginManager instance;
   @Nonnull
   class="kw">private class="kw">final PluginClassLoader corePluginClassLoader = new PluginClassLoader(this, null, true);
   @Nonnull
   class="kw">private class="kw">final List<PendingLoadPlugin> corePlugins = new ObjectArrayList();
   class="kw">private class="kw">final PluginManager.PluginBridgeClassLoader bridgeClassLoader = new PluginManager.PluginBridgeClassLoader(this, PluginManager.class.getClassLoader());
   class="kw">private class="kw">final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
   class="kw">private class="kw">final Map<PluginIdentifier, PluginBase> plugins = new Object2ObjectLinkedOpenHashMap();
   class="kw">private class="kw">final Map<Path, PluginClassLoader> classLoaders = new ConcurrentHashMap<>();
   class="kw">private class="kw">final List<PluginIdentifier> outdatedPlugins = new ArrayList<>();
   class="kw">private class="kw">final List<PluginManager.ClasspathAssetPack> classpathAssetPacks = new CopyOnWriteArrayList<>();
   class="kw">private class="kw">final boolean loadExternalPlugins = true;
   @Nonnull
   class="kw">private PluginState state = PluginState.NONE;
   @Nullable
   class="kw">private List<PendingLoadPlugin> loadOrder;
   @Nullable
   class="kw">private Map<PluginIdentifier, PluginBase> loading;
   @Nonnull
   class="kw">private class="kw">final Map<PluginIdentifier, PluginManifest> availablePlugins = new Object2ObjectLinkedOpenHashMap();
   class="kw">public PluginListPageManager pluginListPageManager;
   class="kw">private ComponentType<EntityStore, PluginListPageManager.SessionSettings> sessionSettingsComponentType;

   class="kw">public class="kw">static PluginManager get() {
      class="kw">return instance;
   }

   class="kw">public PluginManager() {
      instance = this;
      this.pluginListPageManager = new PluginListPageManager();
   }

   class="kw">public void registerCorePlugin(@Nonnull PluginManifest var1) {
      this.corePlugins.add(new PendingLoadJavaPlugin(null, var1, this.corePluginClassLoader));
   }

   class="kw">private boolean canLoadOnBoot(@Nonnull PendingLoadPlugin var1) {
      PluginIdentifier var2 = var1.getIdentifier();
      PluginManifest var3 = var1.getManifest();
      ModConfig var4 = HytaleServer.get().getConfig().getModConfig().get(var2);
      boolean var5;
      if (var4 != null && var4.getEnabled() != null) {
         var5 = var4.getEnabled();
      } else {
         HytaleServerConfig var6 = HytaleServer.get().getConfig();
         var5 = !var3.isDisabledByDefault() && (var1.isCoreMod() || var6.getDefaultModsEnabled());
      }

      if (var5) {
         class="kw">return true;
      }

      LOGGER.at(Level.WARNING).log("Skipping mod %s (Disabled by server config)", var2);
      class="kw">return false;
   }

   class="kw">public void setup() class="kw">throws ModLoadOrderException {
      if (this.state != PluginState.NONE) {
         throw new IllegalStateException("Expected PluginState.NONE but found " + this.state);
      }

      this.state = PluginState.SETUP;
      CommandManager.get().registerSystemCommand(new PluginCommand());
      this.sessionSettingsComponentType = EntityStore.REGISTRY
         .registerComponent(PluginListPageManager.SessionSettings.class, PluginListPageManager.SessionSettings::new);
      HashMap var1 = new HashMap<>();
      this.availablePlugins.clear();
      LOGGER.at(Level.INFO).log("Loading pending core plugins!");

      for (int var2 = 0; var2 < this.corePlugins.size(); var2++) {
         PendingLoadPlugin var3 = this.corePlugins.get(var2);
         LOGGER.at(Level.INFO).log("- %s", var3.getIdentifier());
         if (this.canLoadOnBoot(var3)) {
            loadPendingPlugin(var1, var3);
         } else {
            this.availablePlugins.put(var3.getIdentifier(), var3.getManifest());
         }
      }

      if (!Options.getOptionSet().has(Options.BOOTSTRAP)) {
         this.loadPluginsInClasspath(var1, this.availablePlugins);
         this.loadPluginsFromDirectory(var1, MODS_PATH, !Options.isBare(), this.availablePlugins);

         for (Path var32 : Options.getOptionSet().valuesOf(Options.MODS_DIRECTORIES)) {
            this.loadPluginsFromDirectory(var1, var32, false, this.availablePlugins);
         }
      }

      this.lock.readLock().lock();

      try {
         this.plugins.keySet().forEach(var1x -> {
            var1.remove(var1x);
            LOGGER.at(Level.WARNING).log("Skipping loading of %s because it is already loaded!", var1x);
         });
         Iterator var30 = var1.values().iterator();

         while (var30.hasNext()) {
            PendingLoadPlugin var33 = var30.next();

            try {
               this.validatePluginDeps(var33, var1);
            } catch (MissingPluginDependencyException var26) {
               LOGGER.at(Level.SEVERE).log("%s", var26.getMessage());
               var30.remove();
            }
         }
      } class="kw">finally {
         this.lock.readLock().unlock();
      }

      if (!this.outdatedPlugins.isEmpty() && System.getProperty("hytale.allow_outdated_mods") == null) {
         LOGGER.at(Level.SEVERE)
            .log("One or more plugins are targeting a different server version. It is recommended to update these plugins to ensure compatibility.");
         HytaleServer.get()
            .getEventBus()
            .registerGlobal(
               AddPlayerToWorldEvent.class,
               var1x -> {
                  PlayerRef var2 = var1x.getHolder().getComponent(PlayerRef.getComponentType());
                  if (var2 != null) {
                     if (var2.hasPermission(HytalePermissions.MODS_OUTDATED_NOTIFY)) {
                        StringBuilder var3 = new StringBuilder();

                        for (PluginIdentifier var5 : this.outdatedPlugins) {
                           var3.append("\n - ").append(var5);
                        }

                        var2.sendMessage(
                           Message.translation("server.pluginManager.outOfDatePlugins")
                              .param("count", this.outdatedPlugins.size())
                              .param("mods", var3.toString())
                              .color(Color.RED)
                        );
                     }
                  }
               }
            );
      }

      List var31 = List.of(HytaleServer.get().getConfig().getModLoadOrder());
      this.loadOrder = Mod.calculateLoadOrder(var1, (var0, var1x) -> {
         AssetPack var2 = AssetModule.get().getAssetPack(var0.toString());
         class="kw">return var2 != null && var2.getManifest().getVersion().satisfies(var1x);
      }, var31);

      for (PendingLoadPlugin var4 : this.loadOrder) {
         if (var4 class="kw">instanceof PendingLoadJavaPlugin var5 && var5.isCoreMod() && !isCorePlugin(var5)) {
            PluginClassLoader var6 = var5.getClassLoader();
            PluginClassLoader var7 = new PluginClassLoader(this, var5.getIdentifier(), true, true, var6.getURLs());
            var5.setClassLoader(var7);
            LOGGER.at(Level.FINE).log("Using child-first classloader for classpath plugin %s", var5.getIdentifier());
         }
      }

      this.loading = new Object2ObjectOpenHashMap();
      var1.forEach((var1x, var2x) -> this.availablePlugins.put(var1x, var2x.getManifest()));
      ObjectArrayList var35 = new ObjectArrayList();
      ObjectArrayList var36 = new ObjectArrayList();
      boolean var37 = false;
      this.lock.writeLock().lock();

      try {
         LOGGER.at(Level.FINE).log("Loading plugins!");

         for (PendingLoadPlugin var41 : this.loadOrder) {
            LOGGER.at(Level.FINE).log("- %s", var41.getIdentifier());

            try {
               PluginBase var8 = var41.load();
               this.plugins.put(var8.getIdentifier(), var8);
               this.loading.put(var8.getIdentifier(), var8);
               CompletableFuture var9 = var8.preLoad();
               if (var9 != null) {
                  var35.add(var9);
               }
            } catch (ClassNotFoundException var23) {
               ((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(wrapIfThirdParty(var41, var23)))
                  .log("Failed to load plugin %s. Failed to find main class!", var41.getPath());
               var37 |= this.failedToLoad(var41, var36);
            } catch (NoSuchMethodException var24) {
               ((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(wrapIfThirdParty(var41, var24)))
                  .log("Failed to load plugin %s. Requires class="kw">default constructor!", var41.getPath());
               var37 |= this.failedToLoad(var41, var36);
            } catch (Throwable var25) {
               ((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(wrapIfThirdParty(var41, var25))).log("Failed to load plugin %s", var41.getPath());
               var37 |= this.failedToLoad(var41, var36);
            }
         }
      } class="kw">finally {
         this.lock.writeLock().unlock();
      }

      if (var36.isEmpty() || !var37 && Options.getOptionSet().has(Options.IGNORE_BROKEN_MODS)) {
         CompletableFuture.allOf((CompletableFuture<?>[])var35.toArray(CompletableFuture[]::new)).join();
         boolean var40 = false;
         boolean var44 = false;

         for (PendingLoadPlugin var48 : this.loadOrder) {
            if (HytaleServer.get().isShuttingDown()) {
               break;
            }

            PluginBase var10 = this.loading.get(var48.getIdentifier());
            if (var10 != null && !this.setup(var10)) {
               var40 = true;
               if (isCorePlugin(var48)) {
                  var44 = true;
               }
            }
         }

         if (var40 && (var44 || !Options.getOptionSet().has(Options.IGNORE_BROKEN_MODS))) {
            StringBuilder var47 = new StringBuilder();
            int var49 = this.collectFailedPlugins(var47);
            Message var50 = Message.translation("client.disconnection.shutdownReason.pluginError.detail")
               .param("count", var49)
               .param("detail", var47.toString().trim());
            HytaleServer.get().shutdownServer(ShutdownReason.MOD_ERROR.withMessage(var50));
         } else {
            this.loading.values().removeIf(var0 -> var0.getState().isInactive());
         }
      } else {
         StringBuilder var39 = new StringBuilder();
         ObjectListIterator var42 = var36.iterator();

         while (var42.hasNext()) {
            PluginIdentifier var45 = (PluginIdentifier)var42.next();
            var39.append(" - ").append(var45).append('\n');
         }

         Message var43 = Message.translation("client.disconnection.shutdownReason.pluginError.detail")
            .param("count", var36.size())
            .param("detail", var39.toString().trim());
         HytaleServer.get().shutdownServer(ShutdownReason.MOD_ERROR.withMessage(var43));
      }
   }

   class="kw">public void start() {
      if (this.state != PluginState.SETUP) {
         throw new IllegalStateException("Expected PluginState.SETUP but found " + this.state);
      }

      this.state = PluginState.START;
      boolean var1 = false;
      boolean var2 = false;

      for (PendingLoadPlugin var4 : this.loadOrder) {
         if (HytaleServer.get().isShuttingDown()) {
            break;
         }

         PluginBase var5 = this.loading.get(var4.getIdentifier());
         if (var5 != null && !this.start(var5)) {
            var1 = true;
            if (isCorePlugin(var4)) {
               var2 = true;
            }
         }
      }

      StringBuilder var9 = new StringBuilder();

      for (Entry var14 : HytaleServer.get().getConfig().getModConfig().entrySet()) {
         PluginIdentifier var6 = var14.getKey();
         ModConfig var7 = var14.getValue();
         SemverRange var8 = var7.getRequiredVersion();
         if (var8 != null && !this.hasPlugin(var6, var8)) {
            var9.append(String.format("%s, Version: %s\n", var6, var7));
         }
      }

      if (!var9.isEmpty()) {
         String var13 = "Failed to start server! Missing Mods:\n" + var9;
         LOGGER.at(Level.SEVERE).log("%s", var13);
         Message var16 = Message.translation("client.disconnection.shutdownReason.missingRequiredPlugin.detail").param("detail", var9.toString());
         HytaleServer.get().shutdownServer(ShutdownReason.MISSING_REQUIRED_PLUGIN.withMessage(var16));
      } else if (var1 && (var2 || !Options.getOptionSet().has(Options.IGNORE_BROKEN_MODS))) {
         var9 = new StringBuilder();
         int var12 = this.collectFailedPlugins(var9);
         Message var15 = Message.translation("client.disconnection.shutdownReason.pluginError.detail")
            .param("count", var12)
            .param("detail", var9.toString().trim());
         HytaleServer.get().shutdownServer(ShutdownReason.MOD_ERROR.withMessage(var15));
      } else {
         this.loadOrder = null;
         this.loading = null;
      }
   }

   class="kw">private boolean failedToLoad(@Nonnull PendingLoadPlugin var1, @Nonnull List<PluginIdentifier> var2) {
      var2.add(var1.getIdentifier());
      this.plugins.remove(var1.getIdentifier());
      this.loading.remove(var1.getIdentifier());
      class="kw">return isCorePlugin(var1);
   }

   class="kw">private class="kw">static boolean isCorePlugin(@Nonnull PendingLoadPlugin var0) {
      class="kw">return var0.isCoreMod() && "Hytale".equals(var0.getIdentifier().getGroup());
   }

   class="kw">private int collectFailedPlugins(StringBuilder var1) {
      int var2 = 0;
      if (this.loading == null) {
         class="kw">return var2;
      }

      for (Entry var4 : this.loading.entrySet()) {
         if (var4.getValue().getState() == PluginState.FAILED) {
            Throwable var5 = var4.getValue().getFailureCause();
            String var6 = var5 != null ? var5.toString() : "Unknown";
            var1.append(" - ").append(var4.getKey()).append(": ").append(var6).append('\n');
            var2++;
         }
      }

      class="kw">return var2;
   }

   class="kw">public void shutdown() {
      this.state = PluginState.SHUTDOWN;
      LOGGER.at(Level.INFO).log("Saving plugins config...");
      this.lock.writeLock().lock();

      try {
         List var1 = new ObjectArrayList(this.plugins.values());

         for (int var2 = var1.size() - 1; var2 >= 0; var2--) {
            PluginBase var3 = var1.get(var2);
            if (var3.getState() == PluginState.ENABLED) {
               LOGGER.at(Level.FINE).log("Shutting down %s %s", var3.getType().getDisplayName(), var3.getIdentifier());
               var3.shutdown0(true);
               HytaleServer.get().doneStop(var3);
               LOGGER.at(Level.INFO).log("Shut down plugin %s", var3.getIdentifier());
            }
         }

         this.plugins.clear();
      } class="kw">finally {
         this.lock.writeLock().unlock();
      }
   }

   @Nonnull
   class="kw">public PluginState getState() {
      class="kw">return this.state;
   }

   @Nonnull
   class="kw">public PluginManager.PluginBridgeClassLoader getBridgeClassLoader() {
      class="kw">return this.bridgeClassLoader;
   }

   class="kw">private void validatePluginDeps(@Nonnull PendingLoadPlugin var1, @Nullable Map<PluginIdentifier, PendingLoadPlugin> var2) {
      String var3 = ManifestUtil.getVersion();
      if (!var1.getManifest().getGroup().equals("Hytale")) {
         SemverRange var4 = var1.getManifest().getServerVersion();
         PluginManifest.ServerVersionCheck var5 = PluginManifest.checkServerVersionCompatibility(var4, var3);
         if (var5 != PluginManifest.ServerVersionCheck.COMPATIBLE) {
            class="kw">switch (var5) {
               case MISSING:
                  LOGGER.at(Level.WARNING)
                     .log(
                        "Plugin '%s' does not specify a target server version. You may encounter issues, please check for plugin updates. This will be a hard error in the future",
                        var1.getIdentifier()
                     );
                  break;
               case PARSE_FAILED:
                  LOGGER.at(Level.WARNING)
                     .log(
                        "Plugin '%s' targets server version range '%s' but the running server version '%s' could not be parsed.",
                        var1.getIdentifier(),
                        var4,
                        var3
                     );
                  break;
               case INCOMPATIBLE:
                  LOGGER.at(Level.WARNING)
                     .log(
                        "Plugin '%s' targets server version range '%s' which does not match the running server version '%s'. You may encounter issues, please check for plugin updates.",
                        var1.getIdentifier(),
                        var4,
                        var3
                     );
                  break;
               case COMPATIBLE:
                  throw new IllegalStateException("unreachable");
            }

            this.outdatedPlugins.add(var1.getIdentifier());
         }
      }

      for (Entry var10 : var1.getManifest().getDependencies().entrySet()) {
         PluginIdentifier var6 = var10.getKey();
         PluginManifest var7 = null;
         if (var2 != null) {
            PendingLoadPlugin var8 = var2.get(var6);
            if (var8 != null) {
               var7 = var8.getManifest();
            }
         }

         if (var7 == null) {
            PluginBase var11 = this.plugins.get(var6);
            if (var11 != null) {
               var7 = var11.getManifest();
            }
         }

         if (var7 == null) {
            throw new MissingPluginDependencyException(
               String.format("Failed to load '%s' because the dependency '%s' could not be found!", var1.getIdentifier(), var6)
            );
         }

         SemverRange var12 = var10.getValue();
         if (!var7.getVersion().satisfies(var12)) {
            throw new MissingPluginDependencyException(
               String.format(
                  "Failed to load '%s' because version of dependency '%s'(%s) does not satisfy '%s'!", var1.getIdentifier(), var6, var7.getVersion(), var12
               )
            );
         }
      }
   }

   class="kw">private void loadPluginsFromDirectory(
      @Nonnull Map<PluginIdentifier, PendingLoadPlugin> var1, @Nonnull Path var2, boolean var3, @Nonnull Map<PluginIdentifier, PluginManifest> var4
   ) {
      if (!Files.isDirectory(var2)) {
         if (var3) {
            try {
               Files.createDirectories(var2);
            } catch (IOException var9) {
               ((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(var9)).log("Failed to create directory: %s", var2);
            }
         }
      } else {
         LOGGER.at(Level.INFO).log("Loading pending plugins from directory: %s", var2);

         try (DirectoryStream var5 = Files.newDirectoryStream(var2)) {
            for (Path var7 : var5) {
               if (Files.isRegularFile(var7) && var7.getFileName().toString().toLowerCase(Locale.ROOT).endsWith(".jar")) {
                  PendingLoadJavaPlugin var8 = this.loadPendingJavaPlugin(var7);
                  if (var8 != null) {
                     assert var8.getPath() != null;
                     LOGGER.at(Level.INFO).log("- %s from path %s", var8.getIdentifier(), var2.relativize(var8.getPath()));
                     if (this.canLoadOnBoot(var8)) {
                        loadPendingPlugin(var1, var8);
                     } else {
                        var4.put(var8.getIdentifier(), var8.getManifest());
                     }
                  }
               }
            }
         } catch (IOException var12) {
            ((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(var12)).log("Failed to find pending plugins from: %s", var2);
         }
      }
   }

   @Nullable
   class="kw">private PendingLoadJavaPlugin loadPendingJavaPlugin(@Nonnull Path var1) {
      try (FileSystem var2 = FileSystems.newFileSystem(var1)) {
         Path var3 = var2.getPath("manifest.json");
         if (!Files.exists(var3)) {
            LOGGER.at(Level.SEVERE).log("Failed to load pending plugin from '%s'. Failed to load manifest file!", var1.toString());
            class="kw">return null;
         }

         PluginManifest var4;
         try (
            InputStream var5 = Files.newInputStream(var3);
            InputStreamReader var6 = new InputStreamReader(var5, StandardCharsets.UTF_8);
         ) {
            char[] var7 = RawJsonReader.READ_BUFFER.get();
            RawJsonReader var8 = new RawJsonReader(var6, var7);
            ExtraInfo var9 = ExtraInfo.THREAD_LOCAL.get();

            try {
               var4 = PluginManifest.CODEC.decodeJson(var8, var9);
            } catch (CodecException var15) {
               ((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(new SkipSentryException(var15))).log("Failed to load manifest for plugin at %s", var1);
               class="kw">return null;
            }

            if (var4 == null) {
               LOGGER.at(Level.SEVERE).log("Failed to load pending plugin from '%s'. Failed to decode manifest file!", var1.toString());
               class="kw">return null;
            }

            var9.getValidationResults().logOrThrowValidatorExceptions(LOGGER);
         }

         URL var22 = var1.toUri().toURL();
         PluginClassLoader var23 = this.classLoaders.computeIfAbsent(var1, var3x -> new PluginClassLoader(this, new PluginIdentifier(var4), false, var22));
         class="kw">return new PendingLoadJavaPlugin(var1, var4, var23);
      } catch (MalformedURLException var19) {
         ((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(var19))
            .log("Failed to load pending plugin from '%s'. Failed to create URLClassLoader!", var1.toString());
      } catch (IOException var20) {
         ((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(var20)).log("Failed to load pending plugin %s. Failed to load manifest file!", var1.toString());
      }

      class="kw">return null;
   }

   class="kw">private void loadPluginsInClasspath(@Nonnull Map<PluginIdentifier, PendingLoadPlugin> var1, @Nonnull Map<PluginIdentifier, PluginManifest> var2) {
      LOGGER.at(Level.INFO).log("Loading pending classpath plugins!");

      URI var3;
      ClassLoader var4;
      try {
         var3 = PluginManager.class.getProtectionDomain().getCodeSource().getLocation().toURI();
         var4 = PluginManager.class.getClassLoader();
      } catch (URISyntaxException var9) {
         ((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(var9)).log("Failed to get jar path!");
         class="kw">return;
      }

      try {
         ArrayList var5 = Collections.list(var4.getResources("manifest.json"));
         if (!this.loadClasspathPluginsFromManifests(var1, var2, var5)) {
            class="kw">return;
         }

         URL var6 = var4.getResource("manifests.json");
         if (var6 == null) {
            class="kw">return;
         }

         this.loadClasspathPluginsFromBundle(var1, var2, var6, var3);
      } catch (IOException var7) {
         ((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(var7))
            .log("Failed to load pending classpath plugin from '%s'. Failed to load manifest file!", var3.toString());
      } catch (URISyntaxException var8) {
         ((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(var8)).log("Failed to get jar path!");
      }
   }

   class="kw">private boolean loadClasspathPluginsFromManifests(
      @Nonnull Map<PluginIdentifier, PendingLoadPlugin> var1, @Nonnull Map<PluginIdentifier, PluginManifest> var2, @Nonnull List<URL> var3
   ) class="kw">throws IOException, URISyntaxException {
      HashSet var4 = new HashSet<>();

      for (URL var6 : var3) {
         if (var4.add(var6.toExternalForm())) {
            URLConnection var7 = var6.openConnection();

            try (
               InputStream var8 = var7.getInputStream();
               InputStreamReader var9 = new InputStreamReader(var8, StandardCharsets.UTF_8);
            ) {
               char[] var10 = RawJsonReader.READ_BUFFER.get();
               RawJsonReader var11 = new RawJsonReader(var9, var10);
               ExtraInfo var12 = ExtraInfo.THREAD_LOCAL.get();

               PluginManifest var13;
               try {
                  var13 = PluginManifest.CODEC.decodeJson(var11, var12);
               } catch (CodecException var22) {
                  ((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(new SkipSentryException(var22))).log("Failed to load manifest for plugin at %s", var6);
                  class="kw">continue;
               }

               var12.getValidationResults().logOrThrowValidatorExceptions(LOGGER);
               if (var13 == null) {
                  LOGGER.at(Level.SEVERE).log("Failed to load pending plugin from '%s'. Failed to decode manifest file!", var6);
                  class="kw">return false;
               }

               PendingLoadJavaPlugin var14;
               if (var7 class="kw">instanceof JarURLConnection var15) {
                  URL var16 = var15.getJarFileURL();
                  Path var17 = Path.of(var16.toURI());
                  PluginClassLoader var18 = this.classLoaders
                     .computeIfAbsent(var17, var3x -> new PluginClassLoader(this, new PluginIdentifier(var13), true, var16));
                  var14 = new PendingLoadJavaPlugin(var17, var13, var18);
               } else {
                  URI var26 = var6.toURI().resolve(".");
                  Path var27 = Paths.get(var26);
                  URL var28 = var26.toURL();
                  PluginClassLoader var19 = this.classLoaders
                     .computeIfAbsent(var27, var3x -> new PluginClassLoader(this, new PluginIdentifier(var13), true, var28));
                  var14 = new PendingLoadJavaPlugin(var27, var13, var19);
               }

               LOGGER.at(Level.INFO).log("- %s", var14.getIdentifier());
               if (var13.includesAssetPack() && var14.getPath() != null) {
                  this.classpathAssetPacks.add(new PluginManager.ClasspathAssetPack(var14.getPath(), var13));
               }

               if (this.canLoadOnBoot(var14)) {
                  loadPendingPlugin(var1, var14);
               } else {
                  var2.put(var14.getIdentifier(), var14.getManifest());
               }
            }
         }
      }

      class="kw">return true;
   }

   class="kw">private void loadClasspathPluginsFromBundle(
      @Nonnull Map<PluginIdentifier, PendingLoadPlugin> var1, @Nonnull Map<PluginIdentifier, PluginManifest> var2, @Nonnull URL var3, @Nonnull URI var4
   ) class="kw">throws IOException {
      try (
         InputStream var5 = var3.openStream();
         InputStreamReader var6 = new InputStreamReader(var5, StandardCharsets.UTF_8);
      ) {
         char[] var7 = RawJsonReader.READ_BUFFER.get();
         RawJsonReader var8 = new RawJsonReader(var6, var7);
         ExtraInfo var9 = ExtraInfo.THREAD_LOCAL.get();

         PluginManifest[] var10;
         try {
            var10 = PluginManifest.ARRAY_CODEC.decodeJson(var8, var9);
         } catch (CodecException var21) {
            ((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(new SkipSentryException(var21))).log("Failed to load manifests bundle at %s", var3);
            class="kw">return;
         }

         var9.getValidationResults().logOrThrowValidatorExceptions(LOGGER);
         URL var11 = var4.toURL();
         Path var12 = Paths.get(var4);
         PluginClassLoader var13 = this.classLoaders.computeIfAbsent(var12, var2x -> new PluginClassLoader(this, null, true, var11));

         for (PluginManifest var17 : var10) {
            PendingLoadJavaPlugin var18 = new PendingLoadJavaPlugin(var12, var17, var13);
            LOGGER.at(Level.INFO).log("- %s", var18.getIdentifier());
            if (var17.includesAssetPack() && var12 != null) {
               this.classpathAssetPacks.add(new PluginManager.ClasspathAssetPack(var12, var17));
            }

            if (this.canLoadOnBoot(var18)) {
               loadPendingPlugin(var1, var18);
            } else {
               var2.put(var18.getIdentifier(), var18.getManifest());
            }
         }
      }
   }

   @Nonnull
   class="kw">public List<PluginBase> getPlugins() {
      this.lock.readLock().lock();

      try {
         class="kw">return new ObjectArrayList(this.plugins.values());
      } class="kw">finally {
         this.lock.readLock().unlock();
      }
   }

   @Nullable
   class="kw">public PluginBase getPlugin(PluginIdentifier var1) {
      this.lock.readLock().lock();

      try {
         class="kw">return this.plugins.get(var1);
      } class="kw">finally {
         this.lock.readLock().unlock();
      }
   }

   @Nullable
   class="kw">public <T class="kw">extends PluginBase> T getPlugin(@Nonnull Class<T> var1) {
      this.lock.readLock().lock();

      try {
         for (PluginBase var3 : this.plugins.values()) {
            if (var1.isInstance(var3)) {
               class="kw">return var1.cast(var3);
            }
         }

         class="kw">return null;
      } class="kw">finally {
         this.lock.readLock().unlock();
      }
   }

   class="kw">public boolean hasPlugin(PluginIdentifier var1, @Nonnull SemverRange var2) {
      PluginBase var3 = this.getPlugin(var1);
      class="kw">return var3 != null && var3.getManifest().getVersion().satisfies(var2);
   }

   @Nonnull
   class="kw">public List<PluginManager.ClasspathAssetPack> consumeClasspathAssetPacks() {
      List var1 = List.copyOf(this.classpathAssetPacks);
      this.classpathAssetPacks.clear();
      class="kw">return var1;
   }

   class="kw">private boolean registerAssetPackIfNeeded(@Nonnull PendingLoadPlugin var1) {
      PluginManifest var2 = var1.getManifest();
      if (!var2.includesAssetPack()) {
         class="kw">return true;
      }

      Path var3 = var1.getPath();
      if (var3 == null) {
         class="kw">return true;
      }

      AssetModule var4 = AssetModule.get();
      if (var4 == null) {
         class="kw">return true;
      }

      String var5 = new PluginIdentifier(var2).toString();

      try {
         class="kw">return var4.registerPack(var5, var3, var2, AssetPack.PackSource.RUNTIME);
      } catch (Exception var7) {
         ((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(var7)).log("Failed to register asset pack for plugin %s", var1.getPath());
         class="kw">return false;
      }
   }

   class="kw">private void unregisterAssetPackIfNeeded(@Nonnull JavaPlugin var1) {
      if (var1.getManifest().includesAssetPack()) {
         AssetModule var2 = AssetModule.get();
         if (var2 != null) {
            String var3 = new PluginIdentifier(var1.getManifest()).toString();
            AssetPack var4 = var2.getAssetPack(var3);
            if (var4 != null) {
               if (var4.getPackLocation().equals(var1.getFile())) {
                  var2.unregisterPack(var3);
               }
            }
         }
      }
   }

   class="kw">public boolean reload(@Nonnull PluginIdentifier var1) {
      boolean var2 = this.unload(var1) && this.load(var1);
      this.pluginListPageManager.notifyPluginChange(this.plugins, var1);
      class="kw">return var2;
   }

   class="kw">public boolean unload(@Nonnull PluginIdentifier var1) {
      class="kw">return this.unload(var1, new HashSet<>());
   }

   class="kw">private boolean unload(@Nonnull PluginIdentifier var1, @Nonnull Set<PluginIdentifier> var2) {
      this.lock.writeLock().lock();
      AssetRegistry.ASSET_LOCK.writeLock().lock();

      try {
         PluginBase var3 = this.plugins.get(var1);
         if (var3 != null && var3.getState() == PluginState.ENABLED) {
            var2.add(var1);
            ArrayList var4 = new ArrayList<>();

            for (PluginBase var6 : this.plugins.values()) {
               if (var6.getManifest().getDependencies().containsKey(var1) && !var2.contains(var6.getIdentifier())) {
                  var4.add(var6.getIdentifier());
               }
            }

            var4.forEach(var2x -> this.unload(var2x, var2));
            var3.shutdown0(false);
            HytaleServer.get().doneStop(var3);
            this.plugins.remove(var1);
            if (var3 class="kw">instanceof JavaPlugin var10) {
               this.unregisterAssetPackIfNeeded(var10);
               this.releasePluginClassLoader(var10);
            }

            this.pluginListPageManager.notifyPluginChange(this.plugins, var1);
            class="kw">return true;
         } else {
            this.pluginListPageManager.notifyPluginChange(this.plugins, var1);
            class="kw">return false;
         }
      } class="kw">finally {
         AssetRegistry.ASSET_LOCK.writeLock().unlock();
         this.lock.writeLock().unlock();
      }
   }

   class="kw">protected void releasePluginClassLoader(JavaPlugin var1) {
      Path var2 = var1.getFile();
      if (var2 == null) {
         LOGGER.at(Level.FINE).log("Plugin %s has no jar path to unload; skipping classloader release", var1.getIdentifier());
      } else {
         PluginClassLoader var3 = this.classLoaders.remove(var2);
         if (var3 != null) {
            try {
               var3.close();
            } catch (IOException var5) {
               LOGGER.at(Level.SEVERE).log("Failed to close Class Loader for JavaPlugin %s", var1.getIdentifier());
            }
         }
      }
   }

   class="kw">public boolean load(@Nonnull PluginIdentifier var1) {
      this.lock.readLock().lock();

      try {
         PluginBase var2 = this.plugins.get(var1);
         if (var2 != null) {
            this.pluginListPageManager.notifyPluginChange(this.plugins, var1);
            class="kw">return false;
         }
      } class="kw">finally {
         this.lock.readLock().unlock();
      }

      boolean var7 = this.findAndLoadPlugin(var1);
      this.pluginListPageManager.notifyPluginChange(this.plugins, var1);
      class="kw">return var7;
   }

   class="kw">private boolean findAndLoadPlugin(PluginIdentifier var1) {
      for (PendingLoadPlugin var3 : this.corePlugins) {
         if (var3.getIdentifier().equals(var1)) {
            class="kw">return this.load(var3);
         }
      }

      try {
         URI var28 = PluginManager.class.getProtectionDomain().getCodeSource().getLocation().toURI();
         ClassLoader var31 = PluginManager.class.getClassLoader();
         HashSet var4 = new HashSet<>();

         for (URL var6 : Collections.list(var31.getResources("manifest.json"))) {
            if (var4.add(var6.toExternalForm())) {
               try (
                  InputStream var7 = var6.openStream();
                  InputStreamReader var8 = new InputStreamReader(var7, StandardCharsets.UTF_8);
               ) {
                  char[] var9 = RawJsonReader.READ_BUFFER.get();
                  RawJsonReader var10 = new RawJsonReader(var8, var9);
                  ExtraInfo var11 = ExtraInfo.THREAD_LOCAL.get();
                  PluginManifest var12 = PluginManifest.CODEC.decodeJson(var10, var11);
                  var11.getValidationResults().logOrThrowValidatorExceptions(LOGGER);
                  if (new PluginIdentifier(var12).equals(var1)) {
                     PluginClassLoader var13 = new PluginClassLoader(this, var1, true, var28.toURL());
                     PendingLoadJavaPlugin var14 = new PendingLoadJavaPlugin(Paths.get(var28), var12, var13);
                     class="kw">return this.load(var14);
                  }
               }
            }
         }

         URL var34 = var31.getResource("manifests.json");
         if (var34 != null) {
            try (
               InputStream var35 = var34.openStream();
               InputStreamReader var36 = new InputStreamReader(var35, StandardCharsets.UTF_8);
            ) {
               char[] var37 = RawJsonReader.READ_BUFFER.get();
               RawJsonReader var38 = new RawJsonReader(var36, var37);
               ExtraInfo var39 = ExtraInfo.THREAD_LOCAL.get();
               PluginManifest[] var40 = PluginManifest.ARRAY_CODEC.decodeJson(var38, var39);
               var39.getValidationResults().logOrThrowValidatorExceptions(LOGGER);

               for (PluginManifest var44 : var40) {
                  if (new PluginIdentifier(var44).equals(var1)) {
                     PluginClassLoader var16 = new PluginClassLoader(this, var1, true, var28.toURL());
                     PendingLoadJavaPlugin var17 = new PendingLoadJavaPlugin(Paths.get(var28), var44, var16);
                     class="kw">return this.load(var17);
                  }
               }
            }
         }
      } catch (IOException | URISyntaxException var27) {
         ((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(var27)).log("Failed to load pending classpath plugin. Failed to load manifest file!");
      }

      Boolean var29 = this.findPluginInDirectory(var1, MODS_PATH);
      if (var29 != null) {
         class="kw">return var29;
      }

      for (Path var33 : Options.getOptionSet().valuesOf(Options.MODS_DIRECTORIES)) {
         var29 = this.findPluginInDirectory(var1, var33);
         if (var29 != null) {
            class="kw">return var29;
         }
      }

      class="kw">return false;
   }

   @Nullable
   class="kw">private Boolean findPluginInDirectory(@Nonnull PluginIdentifier var1, @Nonnull Path var2) {
      if (!Files.isDirectory(var2)) {
         class="kw">return null;
      }

      try (DirectoryStream var3 = Files.newDirectoryStream(var2)) {
         for (Path var5 : var3) {
            if (Files.isRegularFile(var5) && var5.getFileName().toString().toLowerCase(Locale.ROOT).endsWith(".jar")) {
               PluginManifest var6 = loadManifest(var5);
               if (var6 != null && new PluginIdentifier(var6).equals(var1)) {
                  PendingLoadJavaPlugin var7 = this.loadPendingJavaPlugin(var5);
                  if (var7 == null) {
                     class="kw">return false;
                  }

                  class="kw">return this.load(var7);
               }
            }
         }
      } catch (IOException var11) {
         ((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(var11)).log("Failed to find plugins in %s!", var2);
      }

      class="kw">return null;
   }

   @Nullable
   class="kw">private class="kw">static PluginManifest loadManifest(@Nonnull Path var0) {
      try (
         URLClassLoader var1 = new URLClassLoader(new URL[]{var0.toUri().toURL()}, PluginManager.class.getClassLoader());
         InputStream var2 = var1.findResource("manifest.json").openStream();
         InputStreamReader var3 = new InputStreamReader(var2, StandardCharsets.UTF_8);
      ) {
         char[] var4 = RawJsonReader.READ_BUFFER.get();
         RawJsonReader var5 = new RawJsonReader(var3, var4);
         ExtraInfo var6 = ExtraInfo.THREAD_LOCAL.get();
         PluginManifest var7 = PluginManifest.CODEC.decodeJson(var5, var6);
         var6.getValidationResults().logOrThrowValidatorExceptions(LOGGER);
         class="kw">return var7;
      } catch (IOException var15) {
         ((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(var15)).log("Failed to load manifest %s.", var0);
         class="kw">return null;
      }
   }

   class="kw">private boolean load(@Nullable PendingLoadPlugin var1) {
      if (var1 == null) {
         class="kw">return false;
      }

      try {
         this.validatePluginDeps(var1, null);
         PluginBase var2 = var1.load();
         this.lock.writeLock().lock();

         try {
            this.plugins.put(var2.getIdentifier(), var2);
         } class="kw">finally {
            this.lock.writeLock().unlock();
         }

         CompletableFuture var3 = var2.preLoad();
         if (var3 == null) {
            if (!this.setup(var2)) {
               this.pluginListPageManager.notifyPluginChange(this.plugins, var2.getIdentifier());
               class="kw">return false;
            }

            if (!this.registerAssetPackIfNeeded(var1)) {
               var2.shutdown0(false);
               this.plugins.remove(var2.getIdentifier());
               this.pluginListPageManager.notifyPluginChange(this.plugins, var2.getIdentifier());
               class="kw">return false;
            }

            boolean var4 = this.start(var2);
            this.pluginListPageManager.notifyPluginChange(this.plugins, var2.getIdentifier());
            class="kw">return var4;
         }

         var3.thenAccept(var3x -> {
            if (!this.setup(var2)) {
               this.pluginListPageManager.notifyPluginChange(this.plugins, var2.getIdentifier());
            } else if (!this.registerAssetPackIfNeeded(var1)) {
               var2.shutdown0(false);
               this.plugins.remove(var2.getIdentifier());
               this.pluginListPageManager.notifyPluginChange(this.plugins, var2.getIdentifier());
            } else if (!this.start(var2)) {
               this.pluginListPageManager.notifyPluginChange(this.plugins, var2.getIdentifier());
            } else {
               this.pluginListPageManager.notifyPluginChange(this.plugins, var2.getIdentifier());
            }
         });
         this.pluginListPageManager.notifyPluginChange(this.plugins, var1.getIdentifier());
      } catch (ClassNotFoundException var10) {
         ((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(wrapIfThirdParty(var1, var10)))
            .log("Failed to load plugin %s. Failed to find main class!", var1.getPath());
      } catch (NoSuchMethodException var11) {
         ((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(wrapIfThirdParty(var1, var11)))
            .log("Failed to load plugin %s. Requires class="kw">default constructor!", var1.getPath());
      } catch (Throwable var12) {
         ((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(wrapIfThirdParty(var1, var12))).log("Failed to load plugin %s", var1.getPath());
      }

      class="kw">return false;
   }

   class="kw">private class="kw">static Throwable wrapIfThirdParty(@Nonnull PendingLoadPlugin var0, @Nonnull Throwable var1) {
      class="kw">return var0.isCoreMod() ? var1 : new SkipSentryException(var1);
   }

   class="kw">private boolean setup(@Nonnull PluginBase var1) {
      PluginState var2 = this.state == PluginState.SETUP ? PluginState.SETUP : PluginState.ENABLED;
      if (var1.getState() == PluginState.NONE && this.dependenciesMatchState(var1, var2, PluginState.SETUP)) {
         LOGGER.at(Level.FINE).log("Setting up plugin %s", var1.getIdentifier());
         boolean var3 = AssetStore.DISABLE_DYNAMIC_DEPENDENCIES;
         AssetStore.DISABLE_DYNAMIC_DEPENDENCIES = false;

         try {
            var1.setup0();
         } class="kw">finally {
            AssetStore.DISABLE_DYNAMIC_DEPENDENCIES = var3;
         }

         AssetModule var4 = AssetModule.get();
         if (var4 != null) {
            var4.initPendingStores();
         }

         HytaleServer.get().doneSetup(var1);
         if (!var1.getState().isInactive()) {
            IEventDispatcher var5 = HytaleServer.get().getEventBus().dispatchFor(PluginSetupEvent.class, (Class<? class="kw">extends PluginBase>)var1.getClass());
            if (var5.hasListener()) {
               var5.dispatch(new PluginSetupEvent(var1));
            }

            class="kw">return true;
         }

         var1.shutdown0(false);
         this.plugins.remove(var1.getIdentifier());
      } else {
         var1.shutdown0(false);
         this.plugins.remove(var1.getIdentifier());
      }

      class="kw">return false;
   }

   class="kw">private boolean start(@Nonnull PluginBase var1) {
      if (var1.getState() == PluginState.SETUP && this.dependenciesMatchState(var1, PluginState.ENABLED, PluginState.START)) {
         LOGGER.at(Level.FINE).log("Starting plugin %s", var1.getIdentifier());
         var1.start0();
         HytaleServer.get().doneStart(var1);
         if (!var1.getState().isInactive()) {
            LOGGER.at(Level.INFO).log("Enabled plugin %s", var1.getIdentifier());
            class="kw">return true;
         }

         var1.shutdown0(false);
         this.plugins.remove(var1.getIdentifier());
      } else {
         var1.shutdown0(false);
         this.plugins.remove(var1.getIdentifier());
      }

      class="kw">return false;
   }

   class="kw">private boolean dependenciesMatchState(PluginBase var1, PluginState var2, PluginState var3) {
      for (PluginIdentifier var6 : var1.getManifest().getDependencies().keySet()) {
         PluginBase var7 = this.plugins.get(var6);
         if (var7 == null || var7.getState() != var2) {
            LOGGER.at(Level.SEVERE).log("%s is lacking dependency %s at stage %s", var1.getName(), var6.getName(), var3);
            LOGGER.at(Level.SEVERE).log("%s DISABLED!", var1.getName());
            var1.setFailureCause(new Exception("Missing dependency " + var6.getName()));
            class="kw">return false;
         }
      }

      class="kw">return true;
   }

   class="kw">private class="kw">static void loadPendingPlugin(@Nonnull Map<PluginIdentifier, PendingLoadPlugin> var0, @Nonnull PendingLoadPlugin var1) {
      if (var0.putIfAbsent(var1.getIdentifier(), var1) != null) {
         String var4 = "Tried to load duplicate plugin: " + var1.getIdentifier();
         LOGGER.at(Level.SEVERE).log("%s", var4);
         Message var5 = Message.translation("client.disconnection.shutdownReason.pluginDuplicate").param("plugin", var1.getIdentifier().toString());
         HytaleServer.get().shutdownServer(ShutdownReason.MOD_ERROR.withMessage(var5));
      } else {
         for (PendingLoadPlugin var3 : var1.createSubPendingLoadPlugins()) {
            loadPendingPlugin(var0, var3);
         }
      }
   }

   @Nonnull
   class="kw">public Map<PluginIdentifier, PluginManifest> getAvailablePlugins() {
      class="kw">return this.availablePlugins;
   }

   class="kw">public ComponentType<EntityStore, PluginListPageManager.SessionSettings> getSessionSettingsComponentType() {
      class="kw">return this.sessionSettingsComponentType;
   }

   class="kw">public record ClasspathAssetPack(@Nonnull Path path, @Nonnull PluginManifest manifest) {
      class="kw">public ClasspathAssetPack {
      }
   }

   class="kw">public class="kw">static class PluginBridgeClassLoader class="kw">extends ClassLoader {
      class="kw">private class="kw">final PluginManager pluginManager;

      class="kw">public PluginBridgeClassLoader(PluginManager var1, ClassLoader var2) {
         super(var2);
         this.pluginManager = var1;
      }

      @Nonnull
      @Override
      class="kw">protected Class<?> loadClass(@Nonnull String var1, boolean var2) class="kw">throws ClassNotFoundException {
         class="kw">return this.loadClass0(var1, null);
      }

      @Nonnull
      class="kw">public Class<?> loadClass0(@Nonnull String var1, PluginClassLoader var2) class="kw">throws ClassNotFoundException {
         this.pluginManager.lock.readLock().lock();

         try {
            for (Entry var4 : this.pluginManager.plugins.entrySet()) {
               PluginBase var5 = var4.getValue();
               Class var6 = tryGetClass(var1, var2, var5);
               if (var6 != null) {
                  class="kw">return var6;
               }
            }
         } class="kw">finally {
            this.pluginManager.lock.readLock().unlock();
         }

         throw new ClassNotFoundException();
      }

      @Nonnull
      class="kw">public Class<?> loadClass0(@Nonnull String var1, PluginClassLoader var2, @Nonnull PluginManifest var3) class="kw">throws ClassNotFoundException {
         this.pluginManager.lock.readLock().lock();

         try {
            for (PluginIdentifier var5 : var3.getDependencies().keySet()) {
               PluginBase var6 = this.pluginManager.plugins.get(var5);
               Class var7 = tryGetClass(var1, var2, var6);
               if (var7 != null) {
                  class="kw">return var7;
               }
            }

            for (PluginIdentifier var14 : var3.getOptionalDependencies().keySet()) {
               if (!var3.getDependencies().containsKey(var14)) {
                  PluginBase var16 = this.pluginManager.plugins.get(var14);
                  if (var16 != null) {
                     Class var18 = tryGetClass(var1, var2, var16);
                     if (var18 != null) {
                        class="kw">return var18;
                     }
                  }
               }
            }

            for (Entry var15 : this.pluginManager.plugins.entrySet()) {
               if (!var3.getDependencies().containsKey(var15.getKey()) && !var3.getOptionalDependencies().containsKey(var15.getKey())) {
                  PluginBase var17 = var15.getValue();
                  Class var19 = tryGetClass(var1, var2, var17);
                  if (var19 != null) {
                     class="kw">return var19;
                  }
               }
            }
         } class="kw">finally {
            this.pluginManager.lock.readLock().unlock();
         }

         throw new ClassNotFoundException();
      }

      class="kw">public class="kw">static Class<?> tryGetClass(@Nonnull String var0, PluginClassLoader var1, PluginBase var2) {
         if (!(var2 class="kw">instanceof JavaPlugin)) {
            class="kw">return null;
         }

         try {
            PluginClassLoader var3 = ((JavaPlugin)var2).getClassLoader();
            if (var3 != var1) {
               Class var4 = var3.loadLocalClass(var0);
               if (var4 != null) {
                  class="kw">return var4;
               }
            }
         } catch (ClassNotFoundException var5) {
         }

         class="kw">return null;
      }

      @Nullable
      class="kw">public URL getResource0(@Nonnull String var1, @Nullable PluginClassLoader var2) {
         this.pluginManager.lock.readLock().lock();

         try {
            for (Entry var4 : this.pluginManager.plugins.entrySet()) {
               URL var5 = tryGetResource(var1, var2, var4.getValue());
               if (var5 != null) {
                  class="kw">return var5;
               }
            }
         } class="kw">finally {
            this.pluginManager.lock.readLock().unlock();
         }

         class="kw">return null;
      }

      @Nullable
      class="kw">public URL getResource0(@Nonnull String var1, @Nullable PluginClassLoader var2, @Nonnull PluginManifest var3) {
         this.pluginManager.lock.readLock().lock();

         try {
            for (PluginIdentifier var5 : var3.getDependencies().keySet()) {
               URL var6 = tryGetResource(var1, var2, this.pluginManager.plugins.get(var5));
               if (var6 != null) {
                  class="kw">return var6;
               }
            }

            for (PluginIdentifier var14 : var3.getOptionalDependencies().keySet()) {
               if (!var3.getDependencies().containsKey(var14)) {
                  PluginBase var16 = this.pluginManager.plugins.get(var14);
                  if (var16 != null) {
                     URL var7 = tryGetResource(var1, var2, var16);
                     if (var7 != null) {
                        class="kw">return var7;
                     }
                  }
               }
            }

            for (Entry var15 : this.pluginManager.plugins.entrySet()) {
               if (!var3.getDependencies().containsKey(var15.getKey()) && !var3.getOptionalDependencies().containsKey(var15.getKey())) {
                  URL var17 = tryGetResource(var1, var2, var15.getValue());
                  if (var17 != null) {
                     class="kw">return var17;
                  }
               }
            }
         } class="kw">finally {
            this.pluginManager.lock.readLock().unlock();
         }

         class="kw">return null;
      }

      @Nonnull
      class="kw">public Enumeration<URL> getResources0(@Nonnull String var1, @Nullable PluginClassLoader var2) {
         ObjectArrayList var3 = new ObjectArrayList();
         this.pluginManager.lock.readLock().lock();

         try {
            for (Entry var5 : this.pluginManager.plugins.entrySet()) {
               URL var6 = tryGetResource(var1, var2, var5.getValue());
               if (var6 != null) {
                  var3.add(var6);
               }
            }
         } class="kw">finally {
            this.pluginManager.lock.readLock().unlock();
         }

         class="kw">return Collections.enumeration(var3);
      }

      @Nonnull
      class="kw">public Enumeration<URL> getResources0(@Nonnull String var1, @Nullable PluginClassLoader var2, @Nonnull PluginManifest var3) {
         ObjectArrayList var4 = new ObjectArrayList();
         this.pluginManager.lock.readLock().lock();

         try {
            for (PluginIdentifier var6 : var3.getDependencies().keySet()) {
               URL var7 = tryGetResource(var1, var2, this.pluginManager.plugins.get(var6));
               if (var7 != null) {
                  var4.add(var7);
               }
            }

            for (PluginIdentifier var14 : var3.getOptionalDependencies().keySet()) {
               if (!var3.getDependencies().containsKey(var14)) {
                  PluginBase var16 = this.pluginManager.plugins.get(var14);
                  if (var16 != null) {
                     URL var8 = tryGetResource(var1, var2, var16);
                     if (var8 != null) {
                        var4.add(var8);
                     }
                  }
               }
            }

            for (Entry var15 : this.pluginManager.plugins.entrySet()) {
               if (!var3.getDependencies().containsKey(var15.getKey()) && !var3.getOptionalDependencies().containsKey(var15.getKey())) {
                  URL var17 = tryGetResource(var1, var2, var15.getValue());
                  if (var17 != null) {
                     var4.add(var17);
                  }
               }
            }
         } class="kw">finally {
            this.pluginManager.lock.readLock().unlock();
         }

         class="kw">return Collections.enumeration(var4);
      }

      @Nullable
      class="kw">private class="kw">static URL tryGetResource(@Nonnull String var0, @Nullable PluginClassLoader var1, @Nullable PluginBase var2) {
         if (var2 class="kw">instanceof JavaPlugin var3) {
            PluginClassLoader var4 = var3.getClassLoader();
            class="kw">return var4 != var1 ? var4.findResource(var0) : null;
         } else {
            class="kw">return null;
         }
      }

      class="kw">static {
         registerAsParallelCapable();
      }
   }
}