TestType enum

Пакет: com.hypixel.hytale.server.npc.asset.builder

Файл: com/hypixel/hytale/server/npc/asset/builder/BuilderManager.java

Поля (1)

МодификаторыТипИмя
NORMAL, FAILING

Исходный код

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

class="kw">import com.google.gson.FieldNamingPolicy;
class="kw">import com.google.gson.Gson;
class="kw">import com.google.gson.GsonBuilder;
class="kw">import com.google.gson.JsonElement;
class="kw">import com.google.gson.JsonObject;
class="kw">import com.google.gson.JsonParser;
class="kw">import com.google.gson.JsonPrimitive;
class="kw">import com.google.gson.JsonSerializer;
class="kw">import com.google.gson.stream.JsonReader;
class="kw">import com.hypixel.fastutil.ints.Int2ObjectConcurrentHashMap;
class="kw">import com.hypixel.hytale.assetstore.AssetExtraInfo;
class="kw">import com.hypixel.hytale.assetstore.AssetPack;
class="kw">import com.hypixel.hytale.assetstore.map.CaseInsensitiveHashStrategy;
class="kw">import com.hypixel.hytale.codec.schema.SchemaContext;
class="kw">import com.hypixel.hytale.codec.schema.config.ObjectSchema;
class="kw">import com.hypixel.hytale.codec.schema.config.Schema;
class="kw">import com.hypixel.hytale.codec.schema.config.StringSchema;
class="kw">import com.hypixel.hytale.common.util.ArrayUtil;
class="kw">import com.hypixel.hytale.event.IEventDispatcher;
class="kw">import com.hypixel.hytale.logger.sentry.SkipSentryException;
class="kw">import com.hypixel.hytale.protocol.packets.interface_.NotificationStyle;
class="kw">import com.hypixel.hytale.server.core.HytaleServer;
class="kw">import com.hypixel.hytale.server.core.Message;
class="kw">import com.hypixel.hytale.server.core.asset.AssetModule;
class="kw">import com.hypixel.hytale.server.core.asset.monitor.AssetMonitor;
class="kw">import com.hypixel.hytale.server.core.asset.monitor.AssetMonitorHandler;
class="kw">import com.hypixel.hytale.server.core.asset.monitor.EventKind;
class="kw">import com.hypixel.hytale.server.core.asset.type.model.config.Model;
class="kw">import com.hypixel.hytale.server.core.asset.type.model.config.ModelAsset;
class="kw">import com.hypixel.hytale.server.core.util.NotificationUtil;
class="kw">import com.hypixel.hytale.server.core.util.io.FileUtil;
class="kw">import com.hypixel.hytale.server.npc.AllNPCsLoadedEvent;
class="kw">import com.hypixel.hytale.server.npc.NPCPlugin;
class="kw">import com.hypixel.hytale.server.npc.asset.builder.providerevaluators.ProviderEvaluatorTypeRegistry;
class="kw">import com.hypixel.hytale.server.npc.asset.builder.validators.ValidatorTypeRegistry;
class="kw">import com.hypixel.hytale.server.npc.decisionmaker.core.Evaluator;
class="kw">import com.hypixel.hytale.server.npc.role.Role;
class="kw">import com.hypixel.hytale.server.npc.util.expression.ExecutionContext;
class="kw">import com.hypixel.hytale.server.npc.util.expression.StdLib;
class="kw">import com.hypixel.hytale.server.npc.validators.NPCLoadTimeValidationHelper;
class="kw">import com.hypixel.hytale.server.spawning.ISpawnableWithModel;
class="kw">import com.hypixel.hytale.server.spawning.LoadedNPCEvent;
class="kw">import com.hypixel.hytale.sneakythrow.SneakyThrow;
class="kw">import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
class="kw">import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
class="kw">import it.unimi.dsi.fastutil.ints.IntArrayList;
class="kw">import it.unimi.dsi.fastutil.ints.IntIterator;
class="kw">import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
class="kw">import it.unimi.dsi.fastutil.ints.IntSet;
class="kw">import it.unimi.dsi.fastutil.objects.Object2IntMap;
class="kw">import it.unimi.dsi.fastutil.objects.Object2IntMaps;
class="kw">import it.unimi.dsi.fastutil.objects.Object2IntOpenCustomHashMap;
class="kw">import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
class="kw">import it.unimi.dsi.fastutil.objects.ObjectArrayList;
class="kw">import it.unimi.dsi.fastutil.objects.ObjectIterator;
class="kw">import it.unimi.dsi.fastutil.objects.ObjectListIterator;
class="kw">import java.io.BufferedReader;
class="kw">import java.io.BufferedWriter;
class="kw">import java.io.IOException;
class="kw">import java.nio.file.FileVisitResult;
class="kw">import java.nio.file.Files;
class="kw">import java.nio.file.Path;
class="kw">import java.nio.file.SimpleFileVisitor;
class="kw">import java.nio.file.attribute.BasicFileAttributes;
class="kw">import java.time.Duration;
class="kw">import java.time.Period;
class="kw">import java.util.Collection;
class="kw">import java.util.HashMap;
class="kw">import java.util.HashSet;
class="kw">import java.util.List;
class="kw">import java.util.Locale;
class="kw">import java.util.Map;
class="kw">import java.util.Objects;
class="kw">import java.util.Set;
class="kw">import java.util.Map.Entry;
class="kw">import java.util.concurrent.atomic.AtomicInteger;
class="kw">import java.util.concurrent.locks.ReentrantReadWriteLock;
class="kw">import java.util.function.BiConsumer;
class="kw">import java.util.function.BiPredicate;
class="kw">import java.util.function.Consumer;
class="kw">import java.util.function.Predicate;
class="kw">import java.util.logging.Level;
class="kw">import javax.annotation.Nonnull;
class="kw">import javax.annotation.Nullable;

class="kw">public class BuilderManager {
   class="kw">public class="kw">static class="kw">final String CONTENT_KEY = "Content";
   class="kw">private class="kw">static class="kw">final String CLASS_KEY = "Class";
   class="kw">private class="kw">static class="kw">final String TEST_TYPE_KEY = "TestType";
   class="kw">private class="kw">static class="kw">final String FAIL_REASON_KEY = "FailReason";
   class="kw">private class="kw">static class="kw">final String PLAYER_GROUP_TAG = "$player";
   class="kw">private class="kw">static class="kw">final String SELF_GROUP_TAG = "$self";
   class="kw">private class="kw">static class="kw">final int PLAYER_GROUP_ID = 0;
   class="kw">private class="kw">static class="kw">final int SELF_GROUP_ID = 1;
   class="kw">private class="kw">final Int2ObjectConcurrentHashMap<BuilderInfo> builderCache = new Int2ObjectConcurrentHashMap<>();
   class="kw">private class="kw">final String elementTypeName = "NPC";
   class="kw">private class="kw">final String defaultFileType = "Role";
   class="kw">private boolean autoReload;
   class="kw">private class="kw">final Map<Class<?>, BuilderFactory<?>> factoryMap = new HashMap<>();
   class="kw">private class="kw">final Map<String, Class<?>> categoryNames = new HashMap<>();
   @Nonnull
   class="kw">private class="kw">final Object2IntMap<String> nameToIndexMap;
   class="kw">private class="kw">final AtomicInteger nextIndex = new AtomicInteger();
   class="kw">private class="kw">final ReentrantReadWriteLock indexLock = new ReentrantReadWriteLock();
   class="kw">private boolean setup;
   class="kw">private class="kw">final List<BuilderManager.AssetPath> assetPaths = new ObjectArrayList(List.of(new BuilderManager.AssetPath("Server/NPC/Roles", "NPC")));
   class="kw">private class="kw">final List<Consumer<BuilderInfo>> builderReloadListeners = new ObjectArrayList();
   @Nullable
   class="kw">public class="kw">static BuilderManager SCHEMA_BUILDER_MANAGER;

   class="kw">public BuilderManager() {
      this.nameToIndexMap = new Object2IntOpenCustomHashMap(CaseInsensitiveHashStrategy.getInstance());
      this.nameToIndexMap.defaultReturnValue(Integer.MIN_VALUE);
      if (this.getOrCreateIndex("$player") != 0 || this.getOrCreateIndex("$self") != 1) {
         throw new IllegalStateException("Group tags must occupy the first indexes of the name-to-index map");
      }
   }

   class="kw">public <T> void registerFactory(@Nonnull BuilderFactory<T> var1) {
      Class var2 = var1.getCategory();
      if (var2 == null) {
         throw new IllegalArgumentException();
      }

      if (this.factoryMap.containsKey(var2)) {
         throw new IllegalArgumentException(var1.getClass().getSimpleName());
      }

      this.factoryMap.put(var2, var1);
   }

   class="kw">public void addCategory(String var1, Class<?> var2) {
      this.categoryNames.put(var1, var2);
   }

   class="kw">public void registerAssetPath(@Nonnull String var1, @Nonnull String var2) {
      if (this.assetPaths.stream().noneMatch(var1x -> var1x.path().equals(var1))) {
         this.assetPaths.add(new BuilderManager.AssetPath(var1, var2));
      }
   }

   class="kw">public void addBuilderReloadListener(@Nonnull Consumer<BuilderInfo> var1) {
      this.builderReloadListeners.add(var1);
   }

   class="kw">public String getCategoryName(@Nonnull Class<?> var1) {
      for (Entry var3 : this.categoryNames.entrySet()) {
         if (var3.getValue() == var1) {
            class="kw">return var3.getKey();
         }
      }

      class="kw">return var1.getSimpleName();
   }

   class="kw">public int getIndex(@Nullable String var1) {
      if (var1 != null && !var1.isEmpty()) {
         this.indexLock.readLock().lock();

         try {
            class="kw">return this.nameToIndexMap.getInt(var1);
         } class="kw">finally {
            this.indexLock.readLock().unlock();
         }
      } else {
         class="kw">return Integer.MIN_VALUE;
      }
   }

   class="kw">public void setAutoReload(boolean var1) {
      this.autoReload = var1;
   }

   @Nullable
   class="kw">public String lookupName(int var1) {
      if (var1 < 0) {
         class="kw">return null;
      }

      BuilderInfo var2 = this.builderCache.get(var1);
      if (var2 != null) {
         class="kw">return var2.getKeyName();
      }

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

      try {
         ObjectIterator var3 = Object2IntMaps.fastIterator(this.nameToIndexMap);

         while (var3.hasNext()) {
            it.unimi.dsi.fastutil.objects.Object2IntMap.Entry var4 = (it.unimi.dsi.fastutil.objects.Object2IntMap.Entry<String>)var3.next();
            if (var4.getIntValue() == var1) {
               class="kw">return (String)var4.getKey();
            }
         }
      } class="kw">finally {
         this.indexLock.readLock().unlock();
      }

      class="kw">return null;
   }

   class="kw">public int getOrCreateIndex(String var1) {
      this.indexLock.writeLock().lock();

      try {
         int var2 = this.nameToIndexMap.getInt(var1);
         if (var2 >= 0) {
            class="kw">return var2;
         }

         var2 = this.nextIndex.getAndIncrement();
         this.nameToIndexMap.put(var1, var2);
         class="kw">return var2;
      } class="kw">finally {
         this.indexLock.writeLock().unlock();
      }
   }

   @Nullable
   class="kw">public BuilderInfo tryGetBuilderInfo(int var1) {
      class="kw">return var1 < 0 ? null : this.builderCache.get(var1);
   }

   class="kw">public void unloadBuilders(AssetPack var1) {
      AssetMonitor var2 = AssetModule.get().getAssetMonitor();

      try {
         for (BuilderManager.AssetPath var4 : this.assetPaths) {
            Path var5 = var1.getRoot().resolve(var4.path());
            if (Files.isDirectory(var5)) {
               if (var2 != null) {
                  var2.removeMonitorDirectoryFiles(var5, var1);
               }

               Files.walkFileTree(var5, FileUtil.DEFAULT_WALK_TREE_OPTIONS_SET, Integer.MAX_VALUE, new SimpleFileVisitor<Path>() {
                  @Nonnull
                  class="kw">public FileVisitResult visitFile(@Nonnull Path var1, @Nonnull BasicFileAttributes var2) {
                     if (BuilderManager.isJsonFile(var1) && !BuilderManager.isIgnoredFile(var1)) {
                        String var3 = BuilderManager.builderNameFromPath(var1);
                        BuilderManager.this.removeBuilder(var3);
                        NPCPlugin.get().getLogger().at(Level.INFO).log("Deleted builder %s", var3);
                     }

                     class="kw">return FileVisitResult.CONTINUE;
                  }
               });
            }
         }
      } catch (IOException var6) {
         throw SneakyThrow.sneakyThrow(var6);
      }
   }

   class="kw">public boolean loadBuilders(@Nonnull AssetPack var1, class="kw">final boolean var2) {
      boolean var3 = true;
      NPCPlugin.get().getLogger().at(Level.INFO).log("Starting to load builders!");
      ObjectArrayList var4 = new ObjectArrayList();

      try {
         AssetMonitor var5 = AssetModule.get().getAssetMonitor();
         class="kw">final ObjectArrayList var6 = new ObjectArrayList();

         for (BuilderManager.AssetPath var8 : this.assetPaths) {
            Path var9 = var1.getRoot().resolve(var8.path());
            if (Files.isDirectory(var9)) {
               if (var5 != null && !var1.isImmutable()) {
                  var5.removeMonitorDirectoryFiles(var9, var1);
                  var5.monitorDirectoryFiles(var9, new BuilderManager.BuilderAssetMonitorHandler(var1, var2));
               }

               class="kw">final Object2IntOpenHashMap var10 = new Object2IntOpenHashMap();
               int var11 = this.builderCache.size();
               Files.walkFileTree(var9, FileUtil.DEFAULT_WALK_TREE_OPTIONS_SET, Integer.MAX_VALUE, new SimpleFileVisitor<Path>() {
                  @Nonnull
                  class="kw">public FileVisitResult visitFile(@Nonnull Path var1, @Nonnull BasicFileAttributes var2x) {
                     if (BuilderManager.isJsonFile(var1) && !BuilderManager.isIgnoredFile(var1)) {
                        BuilderManager.this.loadFile(var1, var6, var10, var2, false);
                     }

                     class="kw">return FileVisitResult.CONTINUE;
                  }
               });
               StringBuilder var12 = new StringBuilder();
               var12.append("Loaded ").append(this.builderCache.size() - var11).append(' ').append(var8.label()).append(" configurations");
               ObjectIterator var13 = var10.object2IntEntrySet().iterator();

               while (var13.hasNext()) {
                  it.unimi.dsi.fastutil.objects.Object2IntMap.Entry var14 = (it.unimi.dsi.fastutil.objects.Object2IntMap.Entry<String>)var13.next();
                  var12.append(", ").append((String)var14.getKey()).append(": ").append(var14.getIntValue());
               }

               var4.add(var12.toString());
            }
         }

         Int2ObjectOpenHashMap var19 = new Int2ObjectOpenHashMap();

         for (BuilderInfo var22 : this.builderCache.values()) {
            try {
               if (this.validateBuilder(var22)) {
                  var19.put(var22.getIndex(), var22);
               } else {
                  var3 = false;
               }
            } catch (IllegalArgumentException | IllegalStateException var15) {
               var3 = false;
               var6.add(String.format("%s: %s", var22.getKeyName(), var15.getMessage()));
            }
         }

         this.setup = true;
         this.validateAllLoadedBuilders(var19, false, var6);
         if (!var6.isEmpty()) {
            var3 = false;
            ObjectListIterator var21 = var6.iterator();

            while (var21.hasNext()) {
               String var23 = (String)var21.next();
               NPCPlugin.get().getLogger().at(Level.SEVERE).log("FAIL: %s", var23);
            }
         }

         var6.clear();
         this.onAllBuildersLoaded(var19);
      } catch (IOException var16) {
         throw new SkipSentryException(new RuntimeException(var16));
      }

      ObjectListIterator var17 = var4.iterator();

      while (var17.hasNext()) {
         String var18 = (String)var17.next();
         NPCPlugin.get().getLogger().at(Level.INFO).log("%s", var18);
      }

      class="kw">return var3;
   }

   class="kw">private void finishLoadingBuilders(@Nonnull Int2ObjectOpenHashMap<BuilderInfo> var1, @Nonnull List<String> var2) {
      this.onAllBuildersLoaded(var1);
      this.validateAllLoadedBuilders(var1, true, var2);
      if (!var2.isEmpty()) {
         for (String var4 : var2) {
            NPCPlugin.get().getLogger().at(Level.SEVERE).log("%s", var4);
         }
      }

      var2.clear();
   }

   class="kw">public void assetEditorLoadFile(@Nonnull Path var1) {
      HashSet var2 = new HashSet<>();
      ObjectArrayList var3 = new ObjectArrayList();
      Int2ObjectOpenHashMap var4 = new Int2ObjectOpenHashMap();
      HashSet var5 = new HashSet<>();

      try {
         int var6 = this.loadFile(var1, var3, null, true, true);
         if (var6 < 0) {
            class="kw">return;
         }

         String var7 = builderNameFromPath(var1);
         NPCPlugin.get().getLogger().at(Level.INFO).log("Reloaded builder %s", var7);
         var5.add(var7);

         for (BuilderInfo var9 : this.builderCache.values()) {
            if (this.isDependant(var9.getBuilder(), var9.getIndex(), var6)) {
               var9.setNeedsValidation();
            }
         }

         if (this.autoReload) {
            this.reloadDependants(var6);
         }

         BuilderInfo var11 = this.builderCache.get(var6);
         onBuilderReloaded(var11);
         var4.put(var6, var11);
      } catch (Throwable var10) {
         NPCPlugin.get().getLogger().at(Level.SEVERE).log("Failed to reload config %s: %s", var1, var10.getMessage());
         var2.add(builderNameFromPath(var1) + ": " + var10.getMessage());
      }

      sendReloadNotification(Message.translation("server.general.assetstore.reloadAssets").param("class", "builder"), var5);
      sendReloadNotification(Message.translation("server.general.assetstore.loadFailed").param("class", "builder"), var2);
      this.finishLoadingBuilders(var4, var3);
   }

   class="kw">public void assetEditorRemoveFile(@Nonnull Path var1) {
      String var2 = builderNameFromPath(var1);
      this.removeBuilder(var2);
      NPCPlugin.get().getLogger().at(Level.INFO).log("Deleted builder %s", var2);
      sendReloadNotification(Message.translation("server.general.assetstore.removedAssets").param("class", "builder"), Set.of(var2));
      ObjectArrayList var3 = new ObjectArrayList();
      this.finishLoadingBuilders(new Int2ObjectOpenHashMap(), var3);
   }

   class="kw">public int loadFile(@Nonnull Path var1, boolean var2, @Nonnull List<String> var3) {
      class="kw">return this.loadFile(var1, var3, null, false, var2);
   }

   class="kw">public int loadFile(@Nonnull Path var1, @Nonnull List<String> var2, @Nullable Object2IntMap<String> var3, boolean var4, boolean var5) {
      int var6 = var2.size();

      JsonObject var7;
      try (BufferedReader var8 = Files.newBufferedReader(var1)) {
         JsonReader var9 = new JsonReader(var8);

         try {
            var7 = JsonParser.parseReader(var9).getAsJsonObject();
         } catch (Throwable var36) {
            try {
               var9.close();
            } catch (Throwable var30) {
               var36.addSuppressed(var30);
            }

            throw var36;
         }

         var9.close();
      } catch (Exception var38) {
         var2.add(var1 + ": Failed to load builder: " + var38.getMessage());
         class="kw">return Integer.MIN_VALUE;
      }

      String var39 = "Role";
      JsonElement var40 = var7;
      BuilderManager.TestType var10 = null;
      JsonElement var11 = var7.get("TestType");
      if (var11 != null) {
         try {
            var10 = Enum.valueOf(BuilderManager.TestType.class, var11.getAsString().toUpperCase(Locale.ROOT));
         } catch (Exception var35) {
            var2.add(var1 + ": " + var35.getMessage());
         }

         if (!var4) {
            class="kw">return Integer.MIN_VALUE;
         }
      }

      String var12 = builderNameFromPath(var1);
      String var13 = null;
      StateMappingHelper var14 = new StateMappingHelper();
      JsonElement var15 = var7.get("Class");
      if (var15 != null) {
         var39 = var15.getAsString();
         var14.readComponentDefaultLocalState(var7);
         JsonElement var16 = var7.get("Interface");
         if (var16 != null) {
            var13 = var16.getAsString();
         }
      }

      Class var41 = this.categoryNames.get(var39);
      if (var41 == null) {
         var2.add(var1 + ": Failed to load builder, unknown class " + var39);
         class="kw">return Integer.MIN_VALUE;
      }

      if (var3 != null) {
         JsonElement var17 = var7.get("Type");
         String var18 = var10 == null ? (var17 != null ? var17.getAsString() : var39) : "Test";
         var3.mergeInt(var18, 1, Integer::sum);
      }

      BuilderFactory var42 = this.getFactory(var41);

      Builder var43;
      try {
         var43 = var42.createBuilder(var40);
      } catch (Exception var34) {
         var2.add(var1 + ": " + var34.getMessage());
         class="kw">return Integer.MIN_VALUE;
      }

      String var19 = var1.toString();
      this.checkIfDeprecated(var43, var42, var40, var19, var39);
      var43.setLabel(var39 + "|" + var42.getKeyName(var40));
      var43.ignoreAttribute("TestType");
      if (var10 == BuilderManager.TestType.FAILING) {
         var43.ignoreAttribute("FailReason");
      }

      var43.ignoreAttribute("Parameters");
      BuilderParameters var20 = new BuilderParameters(StdLib.getInstance(), var19, var13);

      try {
         var20.readJSON(var7, var14);
      } catch (Exception var33) {
         var2.add(var19 + ": Failed to load builder, 'Parameters' section invalid: " + var33.getMessage());
         class="kw">return Integer.MIN_VALUE;
      }

      if (var15 != null) {
         var43.ignoreAttribute("Class");
         var43.ignoreAttribute("Interface");
         var43.ignoreAttribute("DefaultState");
         var43.ignoreAttribute("ResetOnStateChange");
      }

      var20.addParametersToScope();
      InternalReferenceResolver var21 = new InternalReferenceResolver();
      AssetExtraInfo.Data var22 = new AssetExtraInfo.Data(null, var12, null);
      AssetExtraInfo var23 = new AssetExtraInfo<>(var22);
      ObjectArrayList var24 = new ObjectArrayList();
      BuilderValidationHelper var25 = new BuilderValidationHelper(
         var19,
         new FeatureEvaluatorHelper(var43.canRequireFeature()),
         var21,
         var14,
         new InstructionContextHelper(InstructionType.Component),
         var23,
         var24,
         var2
      );

      try {
         var43.readConfig(null, var40, this, var20, var25);
      } catch (Exception var32) {
         var2.add(var19 + ": Failed to load builder: " + var32.getMessage());
         class="kw">return Integer.MIN_VALUE;
      }

      var21.validateInternalReferences(var19, var2);
      var22.loadContainedAssets(var5);
      ObjectListIterator var26 = var24.iterator();

      while (var26.hasNext()) {
         Evaluator var27 = (Evaluator<?>)var26.next();
         var27.initialise();
      }

      var21.optimise();
      var20.disposeCompileContext();
      var14.validate(var19, var2);
      var14.optimise();
      BuilderInfo var44 = this.tryGetBuilderInfo(this.getIndex(var12));
      if (var44 != null && var44.getPath() != null) {
         try {
            if (!Files.isSameFile(var1, var44.getPath())) {
               NPCPlugin.get().getLogger().at(Level.WARNING).log("Replacing asset '%s' of file '%s' with other file '%s'", var12, var44.getPath(), var1);
            }
         } catch (IOException var31) {
         }
      }

      if (var10 == BuilderManager.TestType.FAILING) {
         JsonElement var45 = var7.get("FailReason");
         if (var45 == null) {
            var2.add(var1 + ": Missing fail reason!");
            class="kw">return Integer.MIN_VALUE;
         }

         if (var2.size() == var6) {
            var2.add(var1 + ": Should have failed validation: " + var45.getAsString());
            class="kw">return Integer.MIN_VALUE;
         }

         if (var2.size() - var6 > 1) {
            var2.add(var1 + ": Should have failed validation: " + var45.getAsString() + ", but additional errors were also detected.");
            class="kw">return Integer.MIN_VALUE;
         }

         String var28 = var2.removeLast();
         if (!var28.contains(var45.getAsString())) {
            var2.add(var1 + ": Should have failed validation: " + var45.getAsString() + ", but was instead: " + var28);
            class="kw">return Integer.MIN_VALUE;
         }

         if (NPCPlugin.get().isLogFailingTestErrors()) {
            NPCPlugin.get().getLogger().at(Level.WARNING).log("Expected test failure: %s", var28);
         }

         class="kw">return Integer.MIN_VALUE;
      } else {
         class="kw">return var2.size() > var6 ? Integer.MIN_VALUE : this.cacheBuilder(var12, var43, var1);
      }
   }

   class="kw">public boolean validateBuilder(@Nonnull BuilderInfo var1) {
      if (var1.isValidated()) {
         class="kw">return var1.isValid();
      }

      if (!var1.canBeValidated()) {
         class="kw">return false;
      }

      Builder var2 = var1.getBuilder();
      class="kw">return var2.getDependencies().isEmpty() && !var2.hasDynamicDependencies()
         ? var1.setValidated(true)
         : this.validateBuilder(var1, new IntOpenHashSet(), new IntArrayList());
   }

   @Nonnull
   class="kw">public <T> BuilderFactory<T> getFactory(@Nonnull Class<?> var1) {
      if (var1 == null) {
         throw new IllegalArgumentException("No factory class supplied!");
      } else {
         BuilderFactory var2 = (BuilderFactory<T>)this.factoryMap.get(var1);
         if (var2 == null) {
            throw new NullPointerException(String.format("Factory for type '%s' is not registered!", var1.getSimpleName()));
         } else if (var2.getCategory() != var1) {
            throw new IllegalArgumentException(
               String.format("Factory class mismatch! Expected %s, was %s", var1.getSimpleName(), var2.getCategory().getSimpleName())
            );
         } else {
            class="kw">return var2;
         }
      }
   }

   @Nonnull
   class="kw">public BuilderInfo getCachedBuilderInfo(int var1, @Nonnull Class<?> var2) {
      if (var1 < 0) {
         throw new SkipSentryException(new IllegalArgumentException("Builder asset can't have negative index " + var1));
      } else {
         BuilderInfo var3 = this.tryGetCachedBuilderInfo(var1, var2);
         if (var3 == null) {
            throw new SkipSentryException(new IllegalArgumentException(String.format("Asset '%s' (%s) is not available", this.lookupName(var1), var1)));
         } else {
            class="kw">return var3;
         }
      }
   }

   @Nullable
   class="kw">public <T> Builder<T> tryGetCachedValidBuilder(int var1, @Nonnull Class<?> var2) {
      BuilderInfo var3 = this.tryGetCachedBuilderInfo(var1, var2);
      class="kw">return (Builder<T>)(var3 != null && var3.isValid() ? var3.getBuilder() : null);
   }

   class="kw">public <T> Builder<T> getCachedBuilder(int var1, @Nonnull Class<?> var2) {
      BuilderInfo var3 = this.getCachedBuilderInfo(var1, var2);
      class="kw">return (Builder<T>)var3.getBuilder();
   }

   class="kw">public boolean isEmpty() {
      class="kw">return this.builderCache.isEmpty();
   }

   @Nonnull
   class="kw">public Int2ObjectMap<BuilderInfo> getAllBuilders() {
      Int2ObjectOpenHashMap var1 = new Int2ObjectOpenHashMap();

      for (BuilderInfo var3 : this.builderCache.values()) {
         var1.put(var3.getIndex(), var3);
      }

      class="kw">return var1;
   }

   class="kw">public <T class="kw">extends Collection<?>> T collectMatchingBuilders(T var1, @Nonnull Predicate<BuilderInfo> var2, @Nonnull BiConsumer<BuilderInfo, T> var3) {
      for (BuilderInfo var5 : this.builderCache.values()) {
         if (var2.test(var5)) {
            var3.accept(var5, var1);
         }
      }

      class="kw">return var1;
   }

   @Nonnull
   class="kw">public Object2IntMap<String> getNameToIndexMap() {
      Object2IntOpenHashMap var1 = new Object2IntOpenHashMap();
      if (!this.setup) {
         class="kw">return Object2IntMaps.unmodifiable(var1);
      }

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

      try {
         ObjectIterator var2 = Object2IntMaps.fastIterator(this.nameToIndexMap);

         while (var2.hasNext()) {
            it.unimi.dsi.fastutil.objects.Object2IntMap.Entry var3 = (it.unimi.dsi.fastutil.objects.Object2IntMap.Entry<String>)var2.next();
            var1.put((String)var3.getKey(), var3.getIntValue());
         }
      } class="kw">finally {
         this.indexLock.readLock().unlock();
      }

      class="kw">return Object2IntMaps.unmodifiable(var1);
   }

   @Nullable
   class="kw">public <T> BuilderInfo findMatchingBuilder(@Nonnull BiPredicate<BuilderInfo, T> var1, T var2) {
      for (BuilderInfo var4 : this.builderCache.values()) {
         if (var1.test(var4, var2)) {
            class="kw">return var4;
         }
      }

      class="kw">return null;
   }

   @Nullable
   class="kw">public BuilderInfo getBuilderInfo(Builder<?> var1) {
      class="kw">return this.findMatchingBuilder((var0, var1x) -> var0.getBuilder() == var1x, var1);
   }

   class="kw">public List<String> getTemplateNames() {
      class="kw">return this.collectMatchingBuilders(new ObjectArrayList(), var0 -> true, (var0, var1) -> var1.add(var0.getKeyName()));
   }

   class="kw">public void forceValidation(int var1) {
      BuilderInfo var2 = this.tryGetBuilderInfo(var1);
      if (var2 != null) {
         IntSet var3 = this.computeAllDependencies(var2.getBuilder(), var2.getIndex());
         var2.setForceValidation();
         IntIterator var4 = var3.iterator();

         while (var4.hasNext()) {
            var2 = this.tryGetBuilderInfo(var4.nextInt());
            if (var2 != null) {
               var2.setForceValidation();
            }
         }
      }
   }

   class="kw">public void checkIfDeprecated(@Nonnull Builder<?> var1, @Nonnull BuilderFactory<?> var2, @Nonnull JsonElement var3, String var4, String var5) {
      if (var1.isDeprecated()) {
         NPCPlugin.get()
            .getLogger()
            .at(Level.WARNING)
            .log(
               "Builder %s of type %s is deprecated and should be replaced in %s: %s",
               var2.getKeyName(var3),
               this.getCategoryName(var2.getCategory()),
               var5,
               var4
            );
      }
   }

   @Nonnull
   class="kw">public Schema generateSchema(@Nonnull SchemaContext var1) {
      class="kw">return this.generateSchema(var1, Role.class);
   }

   @Nonnull
   class="kw">public Schema generateSchema(@Nonnull SchemaContext var1, @Nonnull Class<?> var2) {
      try {
         SCHEMA_BUILDER_MANAGER = this;
         BuilderFactory var3 = this.factoryMap.get(var2);
         Schema var4 = var3.toSchema(var1, true);
         ObjectSchema var5 = new ObjectSchema();
         var5.setRequired("Class", "Type");
         StringSchema var6 = new StringSchema();
         var6.setEnum(this.categoryNames.keySet().toArray(String[]::new));
         var5.setProperties(Map.of("Class", var6));
         var5.setProperties(Map.of("Type", StringSchema.constant("Component")));
         Schema var7 = new Schema();
         var7.setIf(var5);
         Schema[] var8 = new Schema[this.categoryNames.size()];
         int var9 = 0;

         for (Entry var11 : this.categoryNames.entrySet()) {
            BuilderFactory var12 = this.getFactory(var11.getValue());
            Schema var13 = var12.toSchema(var1, true);
            Schema var14 = new Schema();
            ObjectSchema var15 = new ObjectSchema();
            var15.setProperties(Map.of("Class", StringSchema.constant(var11.getKey())));
            var14.setIf(var15);
            var14.setThen(var13);
            var14.setElse(false);
            var8[var9++] = var14;
         }

         var7.setThen(Schema.anyOf(var8));
         var7.setElse(false);
         var4.getThen().setAnyOf(ArrayUtil.append(var4.getThen().getAnyOf(), var7));
         class="kw">return var4;
      } class="kw">finally {
         SCHEMA_BUILDER_MANAGER = null;
      }
   }

   @Nonnull
   class="kw">public List<BuilderDescriptor> generateDescriptors() {
      ObjectArrayList var1 = new ObjectArrayList();

      for (BuilderFactory var3 : this.factoryMap.values()) {
         String var4 = this.getCategoryName(var3.getCategory());
         Builder var5 = var3.tryCreateDefaultBuilder();
         if (var5 != null) {
            try {
               var1.add(var5.getDescriptor(var4, var4, this));
            } catch (IllegalStateException | NullPointerException var11) {
               NPCPlugin.get().getLogger().at(Level.SEVERE).log("Failed to build descriptor for %s %s: %s", var4, var4, var11.getMessage());
            }
         }

         for (String var7 : var3.getBuilderNames()) {
            Builder var8 = var3.createBuilder(var7);
            Objects.requireNonNull(var8, "Unable to create builder for descriptor generation");
            String var9 = var7 != null && !var7.isEmpty() ? var7 : var4;
            if (!var9.equals("Component")) {
               try {
                  var1.add(var8.getDescriptor(var9, var4, this));
               } catch (IllegalStateException | NullPointerException var12) {
                  NPCPlugin.get().getLogger().at(Level.SEVERE).log("Failed to build descriptor for %s %s: %s", var4, var9, var12.getMessage());
               }
            }
         }
      }

      class="kw">return var1;
   }

   class="kw">public class="kw">static void saveDescriptors(List<BuilderDescriptor> var0, @Nonnull Path var1) {
      try (BufferedWriter var2 = Files.newBufferedWriter(var1)) {
         GsonBuilder var3 = new GsonBuilder().setPrettyPrinting().serializeNulls().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE);
         var3.registerTypeAdapter(Duration.class, (JsonSerializer)(var0x, var1x, var2x) -> new JsonPrimitive(var0x.toString()));
         var3.registerTypeAdapter(Period.class, (JsonSerializer)(var0x, var1x, var2x) -> new JsonPrimitive(var0x.toString()));
         ValidatorTypeRegistry.registerTypes(var3);
         ProviderEvaluatorTypeRegistry.registerTypes(var3);
         Gson var4 = var3.create();
         var4.toJson(var0, var2);
      } catch (IOException var7) {
         NPCPlugin.get().getLogger().at(Level.SEVERE).log("Failed to write builder descriptors to %s", var1);
      }
   }

   @Nullable
   class="kw">public Builder<Role> tryGetCachedValidRole(int var1) {
      class="kw">return this.tryGetCachedValidBuilder(var1, Role.class);
   }

   class="kw">public void validateAllLoadedBuilders(@Nonnull Int2ObjectMap<BuilderInfo> var1, boolean var2, @Nonnull List<String> var3) {
      NPCPlugin.get().getLogger().at(Level.INFO).log("Validating loaded configurations...");
      validateAllSpawnableNPCs(var1, var3);
      validateOfflineValidatableBuilders(var1, var3);
      if (var2) {
         Int2ObjectOpenHashMap var4 = new Int2ObjectOpenHashMap();
         var1.forEach(
            (var2x, var3x) -> {
               for (BuilderInfo var5 : this.builderCache.values()) {
                  int var6 = var5.getIndex();
                  Builder var7 = var5.getBuilder();

                  boolean var8;
                  try {
                     var8 = this.isDependant(var7, var6, var2x);
                  } catch (SkipSentryException | IllegalStateException | IllegalArgumentException var10) {
                     NPCPlugin.get()
                        .getLogger()
                        .at(Level.WARNING)
                        .log("Could not check if builder %s was dependent: %s", this.lookupName(var5.getIndex()), var10.getMessage());
                     class="kw">continue;
                  }

                  if ((var7.isSpawnable() || var7 class="kw">instanceof OfflineValidatable) && var8) {
                     var4.put(var6, var5);
                  }
               }
            }
         );
         validateAllSpawnableNPCs(var4, var3);
         validateOfflineValidatableBuilders(var4, var3);
      }

      NPCPlugin.get().getLogger().at(Level.INFO).log("Validation complete.");
   }

   class="kw">public void onAllBuildersLoaded(@Nonnull Int2ObjectMap<BuilderInfo> var1) {
      if (!var1.isEmpty()) {
         IEventDispatcher var2 = HytaleServer.get().getEventBus().dispatchFor(AllNPCsLoadedEvent.class);
         if (var2.hasListener()) {
            var2.dispatch(new AllNPCsLoadedEvent(this.getAllBuilders(), var1));
         }

         this.getAllBuilders().forEach((var1x, var2x) -> {
            if (var2x.needsValidation()) {
               if (var2x.getBuilder().category() == Role.class) {
                  NPCPlugin.get().testAndValidateRole(var2x);
               } else {
                  this.validateBuilder(var2x);
               }
            }
         });
      }
   }

   class="kw">public class="kw">static void onBuilderReloaded(@Nonnull BuilderInfo var0) {
      var0.getBuilder().clearDynamicDependencies();
      if (var0.getBuilder().category() == Role.class) {
         NPCPlugin.reloadNPCsWithRole(var0.getIndex());
      }

      BuilderManager var1 = NPCPlugin.get().getBuilderManager();

      for (Consumer var3 : var1.builderReloadListeners) {
         var3.accept(var0);
      }
   }

   class="kw">public class="kw">static int getPlayerGroupID() {
      class="kw">return 0;
   }

   class="kw">public class="kw">static int getSelfGroupID() {
      class="kw">return 1;
   }

   class="kw">protected class="kw">static void onBuilderAdded(@Nonnull BuilderInfo var0) {
      if (var0.getBuilder().isSpawnable()) {
         IEventDispatcher var1 = HytaleServer.get().getEventBus().dispatchFor(LoadedNPCEvent.class);
         if (var1.hasListener()) {
            var1.dispatch(new LoadedNPCEvent(var0));
         }
      }
   }

   class="kw">protected boolean isDependant(@Nonnull Builder<?> var1, int var2, int var3) {
      class="kw">return var2 == var3 ? true : this.computeAllDependencies(var1, var2).contains(var3);
   }

   class="kw">protected int cacheBuilder(String var1, Builder<?> var2, Path var3) {
      this.indexLock.writeLock().lock();

      int var4;
      try {
         var4 = this.nameToIndexMap.getInt(var1);
         if (var4 >= 0) {
            this.removeBuilder(var4);
         } else {
            var4 = this.nextIndex.getAndIncrement();
            this.nameToIndexMap.put(var1, var4);
         }
      } class="kw">finally {
         this.indexLock.writeLock().unlock();
      }

      BuilderInfo var5 = new BuilderInfo(var4, var1, var2, var3);
      this.builderCache.put(var4, var5);
      onBuilderAdded(var5);
      class="kw">return var4;
   }

   class="kw">private void removeBuilder(int var1) {
      BuilderInfo var2 = this.builderCache.remove(var1);
      if (var2 != null) {
         var2.setRemoved();
      }
   }

   class="kw">private void removeBuilder(String var1) {
      int var2 = this.getIndex(var1);
      if (var2 >= 0) {
         this.removeBuilder(var2);
      }
   }

   @Nullable
   class="kw">private Builder<?> tryGetCachedBuilder(int var1) {
      BuilderInfo var2 = this.tryGetBuilderInfo(var1);
      class="kw">return var2 == null ? null : var2.getBuilder();
   }

   @Nullable
   class="kw">private BuilderInfo tryGetCachedBuilderInfo(int var1, @Nonnull Class<?> var2) {
      BuilderInfo var3 = this.tryGetBuilderInfo(var1);
      if (var3 == null) {
         class="kw">return null;
      } else {
         Builder var4 = var3.getBuilder();
         if (var4.category() != var2) {
            throw new IllegalArgumentException(
               String.format(
                  "Asset '%s'(%s) is different type. Is '%s' but should be '%s'", this.lookupName(var1), var1, var4.category().getName(), var2.getName()
               )
            );
         } else {
            class="kw">return var3;
         }
      }
   }

   class="kw">private class="kw">static void validateAllSpawnableNPCs(@Nonnull Int2ObjectMap<BuilderInfo> var0, @Nonnull List<String> var1) {
      var0.forEach(
         (var1x, var2) -> {
            Builder var3 = var2.getBuilder();
            if (var3.isSpawnable() && var3 class="kw">instanceof ISpawnableWithModel var4) {
               ExecutionContext var5 = new ExecutionContext(var3.getBuilderParameters().createScope());
               String var6 = var2.getPath().toString();

               String var7;
               try {
                  var7 = var4.getSpawnModelName(var5, var4.createModifierScope(var5));
               } catch (SkipSentryException | IllegalStateException var12) {
                  var1.add(String.format("%s: %s", var6, var12.getMessage()));
                  var2.setValidated(false);
                  class="kw">return;
               }

               ModelAsset var8 = ModelAsset.getAssetMap().getAsset(var7);
               if (var8 == null) {
                  var1.add(String.format("%s: Model %s does not exist.", var6, var7));
                  var2.setValidated(false);
               } else {
                  Model var9 = Model.createScaledModel(var8, var8.getMaxScale());
                  Builder var10 = var2.getBuilder();
                  NPCLoadTimeValidationHelper var11 = new NPCLoadTimeValidationHelper(var6, var9, !var10.isSpawnable());
                  if (!var10.validate(var6, var11, var5, var5.getScope(), var1)
                     || !var11.validateMotionControllers(var1)
                     || !var11.getValueStoreValidator().validate(var1)) {
                     var2.setValidated(false);
                  }
               }
            }
         }
      );
   }

   class="kw">private class="kw">static void validateOfflineValidatableBuilders(@Nonnull Int2ObjectMap<BuilderInfo> var0, @Nonnull List<String> var1) {
      ObjectIterator var2 = var0.entrySet().iterator();

      while (var2.hasNext()) {
         Entry var3 = (Entry<Integer, BuilderInfo>)var2.next();
         BuilderInfo var4 = var3.getValue();
         Builder var5 = var4.getBuilder();
         if (var5 class="kw">instanceof OfflineValidatable) {
            ExecutionContext var6 = new ExecutionContext(var5.getBuilderParameters().createScope());
            String var7 = var4.getPath().toString();
            NPCLoadTimeValidationHelper var8 = new NPCLoadTimeValidationHelper(var7, null, !var5.isSpawnable());
            if (!var5.validate(var7, var8, var6, var6.getScope(), var1) || !var8.getValueStoreValidator().validate(var1)) {
               var4.setValidated(false);
            }
         }
      }
   }

   class="kw">private class="kw">static void sendReloadNotification(Message var0, @Nonnull Set<String> var1) {
      if (!var1.isEmpty()) {
         NotificationUtil.sendNotificationToUniverse(var0, Message.raw(var1.toString()), NotificationStyle.Warning);
      }
   }

   class="kw">private class="kw">static boolean isIgnoredFile(@Nonnull Path var0) {
      class="kw">return !var0.getFileName().toString().isEmpty() && var0.getFileName().toString().charAt(0) == '!';
   }

   class="kw">private class="kw">static boolean isJsonFile(@Nonnull Path var0) {
      class="kw">return Files.isRegularFile(var0) && var0.toString().endsWith(".json");
   }

   class="kw">private class="kw">static boolean isJsonFileName(@Nonnull Path var0, EventKind var1) {
      class="kw">return var0.toString().endsWith(".json");
   }

   @Nonnull
   class="kw">private class="kw">static String builderNameFromPath(@Nonnull Path var0) {
      String var1 = var0.getFileName().toString();
      if (var1.startsWith("NPCRole-")) {
         var1 = var1.split("-", 2)[1];
      }

      int var2 = var1.lastIndexOf(46);
      class="kw">return var2 >= 0 ? var1.substring(0, var2) : var1;
   }

   @Nonnull
   class="kw">private String buildPathString(@Nonnull IntArrayList var1, int var2) {
      if (var1.isEmpty()) {
         class="kw">return "";
      }

      StringBuilder var3 = new StringBuilder();
      var3.append(" (Path: ");
      IntIterator var4 = var1.iterator();

      while (var4.hasNext()) {
         var3.append(this.lookupName(var4.nextInt())).append(" -> ");
      }

      var3.append(this.lookupName(var2)).append(')');
      class="kw">return var3.toString();
   }

   class="kw">private boolean validateBuilder(@Nonnull BuilderInfo var1, @Nonnull IntSet var2, @Nonnull IntArrayList var3) {
      int var4 = var1.getIndex();
      if (var3.contains(var4)) {
         NPCPlugin.get()
            .getLogger()
            .at(Level.SEVERE)
            .log(
               "Builder '%s' validation failed: Cyclic reference detected for builder '%s'%s",
               this.lookupName(var3.getInt(0)),
               this.lookupName(var4),
               this.buildPathString(var3, var4)
            );
         class="kw">return var1.setValidated(false);
      }

      var3.add(var4);

      IntSet var5;
      try {
         var5 = this.computeAllDependencies(var1.getBuilder(), var1.getIndex());
      } catch (SkipSentryException | IllegalStateException | IllegalArgumentException var10) {
         NPCPlugin.get().getLogger().at(Level.SEVERE).log("Builder '%s' validation failed: %s", this.lookupName(var3.getInt(0)), var10.getMessage());
         class="kw">return var1.setValidated(false);
      }

      boolean var6 = true;
      IntIterator var7 = var5.iterator();

      while (var7.hasNext()) {
         int var8 = var7.nextInt();
         if (var3.contains(var8)) {
            NPCPlugin.get()
               .getLogger()
               .at(Level.SEVERE)
               .log(
                  "Builder '%s' validation failed: Cyclic reference detected for builder '%s'%s",
                  this.lookupName(var3.getInt(0)),
                  this.lookupName(var8),
                  this.buildPathString(var3, var4)
               );
            class="kw">return var1.setValidated(false);
         }

         if (var2.add(var8)) {
            BuilderInfo var9 = this.builderCache.get(var8);
            if (var9 == null) {
               NPCPlugin.get()
                  .getLogger()
                  .at(Level.SEVERE)
                  .log(
                     "Builder '%s' validation failed: Reference to unknown builder '%s'%s",
                     this.lookupName(var3.getInt(0)),
                     this.lookupName(var8),
                     this.buildPathString(var3, var8)
                  );
               var6 = false;
            } else if (!var9.isValidated()) {
               var6 = this.validateBuilder(var9, var2, var3);
            } else if (!var9.isValid()) {
               NPCPlugin.get()
                  .getLogger()
                  .at(Level.SEVERE)
                  .log(
                     "Builder '%s' validation failed: Reference to invalid builder '%s'%s",
                     this.lookupName(var3.getInt(0)),
                     var9.getKeyName(),
                     this.buildPathString(var3, var8)
                  );
               var6 = false;
            }
         }
      }

      var3.removeInt(var3.size() - 1);
      class="kw">return var1.setValidated(var6);
   }

   @Nonnull
   class="kw">private IntSet computeAllDependencies(@Nonnull Builder<?> var1, int var2) {
      class="kw">return this.computeAllDependencies(var1, var2, new IntOpenHashSet(), new IntArrayList());
   }

   @Nonnull
   class="kw">private IntSet computeAllDependencies(@Nonnull Builder<?> var1, int var2, @Nonnull IntSet var3, @Nonnull IntArrayList var4) {
      if (var4.contains(var2)) {
         throw new SkipSentryException(new IllegalArgumentException("Cyclic reference detected for builder: " + this.lookupName(var2)));
      }

      var4.add(var2);
      this.iterateDependencies(var1.getDependencies().iterator(), var3, var4);
      if (var1.hasDynamicDependencies()) {
         this.iterateDependencies(var1.getDynamicDependencies().iterator(), var3, var4);
      }

      var4.removeInt(var4.size() - 1);
      class="kw">return var3;
   }

   class="kw">private void iterateDependencies(@Nonnull IntIterator var1, @Nonnull IntSet var2, @Nonnull IntArrayList var3) {
      while (var1.hasNext()) {
         int var4 = var1.nextInt();
         if (!var2.contains(var4)) {
            var2.add(var4);
            Builder var5 = this.tryGetCachedBuilder(var4);
            if (var5 == null) {
               throw new SkipSentryException(new IllegalStateException("Reference to unknown builder: " + this.lookupName(var4)));
            }

            this.computeAllDependencies(var5, var4, var2, var3);
         }
      }
   }

   class="kw">private void reloadDependants(int var1) {
      for (BuilderInfo var3 : this.builderCache.values()) {
         int var4 = var3.getIndex();
         String var5 = var3.getKeyName();
         Builder var6 = var3.getBuilder();

         try {
            if (var6.isSpawnable() && this.isDependant(var6, var4, var1)) {
               NPCPlugin.get().getLogger().at(Level.INFO).log("Reloading entities of type '%s' because dependency '%s' changed", var5, this.lookupName(var1));
               onBuilderReloaded(var3);
            }
         } catch (Throwable var8) {
            NPCPlugin.get().getLogger().at(Level.INFO).log("Failed to reload entities of type '%s': %s", var5, var8.getMessage());
         }
      }
   }

   class="kw">private record AssetPath(String path, String label) {
      class="kw">private AssetPath {
      }
   }

   class="kw">private class BuilderAssetMonitorHandler class="kw">implements AssetMonitorHandler {
      class="kw">private class="kw">final AssetPack pack;
      class="kw">private class="kw">final boolean includeTests;

      class="kw">public BuilderAssetMonitorHandler(AssetPack nullx, boolean nullxx) {
         this.pack = nullx;
         this.includeTests = nullxx;
      }

      @Override
      class="kw">public Object getKey() {
         class="kw">return this.pack;
      }

      class="kw">public boolean test(Path var1, EventKind var2) {
         class="kw">return BuilderManager.isJsonFileName(var1, var2);
      }

      class="kw">public void accept(Map<Path, EventKind> var1) {
         Int2ObjectOpenHashMap var2 = new Int2ObjectOpenHashMap();
         HashSet var3 = new HashSet<>();
         HashSet var4 = new HashSet<>();
         HashSet var5 = new HashSet<>();
         ObjectArrayList var6 = new ObjectArrayList();

         for (Entry var8 : var1.entrySet()) {
            Path var9 = var8.getKey();
            EventKind var10 = var8.getValue();
            if (var10 != EventKind.ENTRY_CREATE && var10 != EventKind.ENTRY_MODIFY) {
               if (var10 == EventKind.ENTRY_DELETE) {
                  String var18 = BuilderManager.builderNameFromPath(var9);
                  BuilderManager.this.removeBuilder(var18);
                  NPCPlugin.get().getLogger().at(Level.INFO).log("Deleted builder %s", var18);
                  var5.add(var18);
               }
            } else if (Files.isRegularFile(var9) && !BuilderManager.isIgnoredFile(var9)) {
               try {
                  int var11 = BuilderManager.this.loadFile(var9, var6, null, this.includeTests, true);
                  if (var11 >= 0) {
                     String var12 = BuilderManager.builderNameFromPath(var9);
                     NPCPlugin.get().getLogger().at(Level.INFO).log("Reloaded builder %s", var12);
                     var3.add(var12);

                     for (BuilderInfo var14 : BuilderManager.this.builderCache.values()) {
                        try {
                           if (BuilderManager.this.isDependant(var14.getBuilder(), var14.getIndex(), var11)) {
                              var14.setNeedsValidation();
                           }
                        } catch (IllegalStateException | IllegalArgumentException var16) {
                           NPCPlugin.get()
                              .getLogger()
                              .at(Level.WARNING)
                              .log("Could not check if builder %s was dependent: %s", BuilderManager.this.lookupName(var14.getIndex()), var16.getMessage());
                        }
                     }

                     if (BuilderManager.this.autoReload) {
                        BuilderManager.this.reloadDependants(var11);
                     }

                     BuilderInfo var19 = BuilderManager.this.builderCache.get(var11);
                     BuilderManager.onBuilderReloaded(var19);
                     var2.put(var11, var19);
                  }
               } catch (Throwable var17) {
                  NPCPlugin.get().getLogger().at(Level.SEVERE).log("Failed to reload config %s: %s", var9, var17.getMessage());
                  var4.add(BuilderManager.builderNameFromPath(var9) + ": " + var17.getMessage());
               }
            }
         }

         BuilderManager.sendReloadNotification(Message.translation("server.general.assetstore.reloadAssets").param("class", "builder"), var3);
         BuilderManager.sendReloadNotification(Message.translation("server.general.assetstore.loadFailed").param("class", "builder"), var4);
         BuilderManager.sendReloadNotification(Message.translation("server.general.assetstore.removedAssets").param("class", "builder"), var5);
         BuilderManager.this.finishLoadingBuilders(var2, var6);
      }
   }

   class="kw">private enum TestType {
      NORMAL,
      FAILING;

      TestType() {
      }
   }
}