BenchUpgradingJob class

Пакет: com.hypixel.hytale.builtin.crafting.component

Файл: com/hypixel/hytale/builtin/crafting/component/CraftingManager.java

Поля (4)

МодификаторыТипИмя
private float lastSentPercent
private final float timeSeconds
private float timeSecondsCompleted
private final BenchWindow window

Методы (2)

МодификаторыВозвратСигнатура
public float computeLoadingPercentpublic float computeLoadingPercent()
public String toStringpublic String toString()

Исходный код

Показать/скрыть
class="kw">package com.hypixel.hytale.builtin.crafting.component;

class="kw">import com.google.gson.JsonArray;
class="kw">import com.hypixel.hytale.builtin.adventure.memories.MemoriesPlugin;
class="kw">import com.hypixel.hytale.builtin.crafting.CraftingPlugin;
class="kw">import com.hypixel.hytale.builtin.crafting.window.BenchWindow;
class="kw">import com.hypixel.hytale.builtin.crafting.window.CraftingWindow;
class="kw">import com.hypixel.hytale.component.Component;
class="kw">import com.hypixel.hytale.component.ComponentAccessor;
class="kw">import com.hypixel.hytale.component.ComponentType;
class="kw">import com.hypixel.hytale.component.Ref;
class="kw">import com.hypixel.hytale.component.Store;
class="kw">import com.hypixel.hytale.component.spatial.SpatialResource;
class="kw">import com.hypixel.hytale.event.IEventDispatcher;
class="kw">import com.hypixel.hytale.logger.HytaleLogger;
class="kw">import com.hypixel.hytale.math.shape.Box;
class="kw">import com.hypixel.hytale.math.util.ChunkUtil;
class="kw">import com.hypixel.hytale.protocol.BenchRequirement;
class="kw">import com.hypixel.hytale.protocol.BenchType;
class="kw">import com.hypixel.hytale.protocol.GameMode;
class="kw">import com.hypixel.hytale.protocol.ItemQuantity;
class="kw">import com.hypixel.hytale.protocol.ItemResourceType;
class="kw">import com.hypixel.hytale.protocol.SoundCategory;
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.type.blockhitbox.BlockBoundingBoxes;
class="kw">import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
class="kw">import com.hypixel.hytale.server.core.asset.type.blocktype.config.bench.Bench;
class="kw">import com.hypixel.hytale.server.core.asset.type.blocktype.config.bench.BenchTierLevel;
class="kw">import com.hypixel.hytale.server.core.asset.type.blocktype.config.bench.BenchUpgradeRequirement;
class="kw">import com.hypixel.hytale.server.core.asset.type.item.config.CraftingRecipe;
class="kw">import com.hypixel.hytale.server.core.asset.type.item.config.Item;
class="kw">import com.hypixel.hytale.server.core.entity.EntityUtils;
class="kw">import com.hypixel.hytale.server.core.entity.entities.Player;
class="kw">import com.hypixel.hytale.server.core.entity.entities.player.data.PlayerConfigData;
class="kw">import com.hypixel.hytale.server.core.entity.entities.player.windows.MaterialExtraResourcesSection;
class="kw">import com.hypixel.hytale.server.core.event.events.ecs.CraftRecipeEvent;
class="kw">import com.hypixel.hytale.server.core.event.events.player.PlayerCraftEvent;
class="kw">import com.hypixel.hytale.server.core.inventory.InventoryComponent;
class="kw">import com.hypixel.hytale.server.core.inventory.InventoryUtils;
class="kw">import com.hypixel.hytale.server.core.inventory.ItemStack;
class="kw">import com.hypixel.hytale.server.core.inventory.MaterialQuantity;
class="kw">import com.hypixel.hytale.server.core.inventory.container.CombinedItemContainer;
class="kw">import com.hypixel.hytale.server.core.inventory.container.DelegateItemContainer;
class="kw">import com.hypixel.hytale.server.core.inventory.container.EmptyItemContainer;
class="kw">import com.hypixel.hytale.server.core.inventory.container.ItemContainer;
class="kw">import com.hypixel.hytale.server.core.inventory.container.SimpleItemContainer;
class="kw">import com.hypixel.hytale.server.core.inventory.container.filter.FilterType;
class="kw">import com.hypixel.hytale.server.core.inventory.transaction.ListTransaction;
class="kw">import com.hypixel.hytale.server.core.inventory.transaction.MaterialSlotTransaction;
class="kw">import com.hypixel.hytale.server.core.inventory.transaction.MaterialTransaction;
class="kw">import com.hypixel.hytale.server.core.modules.block.BlockModule;
class="kw">import com.hypixel.hytale.server.core.modules.block.components.ItemContainerBlock;
class="kw">import com.hypixel.hytale.server.core.modules.entity.player.PlayerSettings;
class="kw">import com.hypixel.hytale.server.core.universe.PlayerRef;
class="kw">import com.hypixel.hytale.server.core.universe.world.SoundUtil;
class="kw">import com.hypixel.hytale.server.core.universe.world.World;
class="kw">import com.hypixel.hytale.server.core.universe.world.chunk.BlockOperations;
class="kw">import com.hypixel.hytale.server.core.universe.world.chunk.section.BlockSection;
class="kw">import com.hypixel.hytale.server.core.universe.world.chunk.section.ChunkSection;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
class="kw">import com.hypixel.hytale.server.core.util.NotificationUtil;
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.objects.Object2ObjectOpenHashMap;
class="kw">import it.unimi.dsi.fastutil.objects.ObjectArrayList;
class="kw">import it.unimi.dsi.fastutil.objects.ObjectList;
class="kw">import java.util.Collections;
class="kw">import java.util.List;
class="kw">import java.util.Map;
class="kw">import java.util.Objects;
class="kw">import java.util.Set;
class="kw">import java.util.concurrent.BlockingQueue;
class="kw">import java.util.concurrent.LinkedBlockingQueue;
class="kw">import java.util.logging.Level;
class="kw">import javax.annotation.Nonnull;
class="kw">import javax.annotation.Nullable;
class="kw">import org.joml.Vector3d;
class="kw">import org.joml.Vector3i;

class="kw">public class CraftingManager class="kw">implements Component<EntityStore> {
   @Nonnull
   class="kw">private class="kw">static class="kw">final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
   class="kw">private class="kw">static class="kw">final int QUEUED_CRAFTING_JOBS_MAX_CAPACITY = 32;
   @Nonnull
   class="kw">private class="kw">final BlockingQueue<CraftingManager.CraftingJob> queuedCraftingJobs = new LinkedBlockingQueue<>(32);
   @Nullable
   class="kw">private CraftingManager.BenchUpgradingJob upgradingJob;
   class="kw">private int x;
   class="kw">private int y;
   class="kw">private int z;
   @Nullable
   class="kw">private BlockType blockType;

   @Nonnull
   class="kw">public class="kw">static ComponentType<EntityStore, CraftingManager> getComponentType() {
      class="kw">return CraftingPlugin.get().getCraftingManagerComponentType();
   }

   class="kw">public CraftingManager() {
   }

   class="kw">private CraftingManager(@Nonnull CraftingManager var1) {
      this.x = var1.x;
      this.y = var1.y;
      this.z = var1.z;
      this.blockType = var1.blockType;
      this.queuedCraftingJobs.addAll(var1.queuedCraftingJobs);
      this.upgradingJob = var1.upgradingJob;
   }

   class="kw">public boolean hasBenchSet() {
      class="kw">return this.blockType != null;
   }

   class="kw">public void setBench(int var1, int var2, int var3, @Nonnull BlockType var4) {
      Bench var5 = var4.getBench();
      Objects.requireNonNull(var5, "blockType isn't a bench!");
      if (var5.getType() != BenchType.Crafting
         && var5.getType() != BenchType.DiagramCrafting
         && var5.getType() != BenchType.StructuralCrafting
         && var5.getType() != BenchType.Processing) {
         throw new IllegalArgumentException("blockType isn't a crafting bench!");
      }

      if (this.blockType != null) {
         throw new IllegalArgumentException("Bench blockType is already set! Must be cleared (close UI).");
      }

      if (!this.queuedCraftingJobs.isEmpty()) {
         throw new IllegalArgumentException("Queue already has jobs!");
      }

      if (this.upgradingJob != null) {
         throw new IllegalArgumentException("Upgrading job is already set!");
      }

      this.x = var1;
      this.y = var2;
      this.z = var3;
      this.blockType = var4;
   }

   class="kw">public boolean clearBench(@Nonnull Ref<EntityStore> var1, @Nonnull ComponentAccessor<EntityStore> var2) {
      boolean var3 = this.cancelAllCrafting(var1, var2);
      this.x = 0;
      this.y = 0;
      this.z = 0;
      this.blockType = null;
      this.upgradingJob = null;
      class="kw">return var3;
   }

   class="kw">public boolean craftItem(
      @Nonnull Ref<EntityStore> var1, @Nonnull ComponentAccessor<EntityStore> var2, @Nonnull CraftingRecipe var3, int var4, @Nonnull ItemContainer var5
   ) {
      if (this.upgradingJob != null) {
         class="kw">return false;
      }

      Objects.requireNonNull(var3, "Recipe can't be null");
      int var6 = this.resolveCraftQuantity(var1, var2, var3, var5, var4);
      if (var6 < 1) {
         class="kw">return false;
      }

      CraftRecipeEvent.Pre var7 = new CraftRecipeEvent.Pre(var3, var6);
      var2.invoke(var1, var7);
      if (var7.isCancelled()) {
         class="kw">return false;
      }

      if (!this.isValidBenchForRecipe(var1, var2, var3)) {
         class="kw">return false;
      }

      World var8 = var2.getExternalData().getWorld();
      Player var9 = var2.getComponent(var1, Player.getComponentType());
      assert var9 != null;
      if (var9.getGameMode() != GameMode.Creative && !removeInputFromInventory(var5, var3, var6)) {
         PlayerRef var12 = var2.getComponent(var1, PlayerRef.getComponentType());
         assert var12 != null;
         String var13 = getRecipeOutputTranslationKey(var3);
         if (var13 != null) {
            NotificationUtil.sendNotification(
               var12.getPacketHandler(),
               Message.translation("server.general.crafting.missingIngredient").param("item", Message.translation(var13)),
               NotificationStyle.Danger
            );
         }

         LOGGER.at(Level.FINE).log("Missing items required to craft the item: %s", var3);
         class="kw">return false;
      } else {
         CraftRecipeEvent.Post var10 = new CraftRecipeEvent.Post(var3, var6);
         var2.invoke(var1, var10);
         if (var10.isCancelled()) {
            class="kw">return true;
         }

         giveOutput(var1, var2, var3, var6);
         IEventDispatcher var11 = HytaleServer.get().getEventBus().dispatchFor(PlayerCraftEvent.class, var8.getName());
         if (var11.hasListener()) {
            var11.dispatch(new PlayerCraftEvent(var1, var9, var3, var6));
         }

         class="kw">return true;
      }
   }

   @Nullable
   class="kw">private class="kw">static String getRecipeOutputTranslationKey(@Nonnull CraftingRecipe var0) {
      MaterialQuantity var1 = var0.getPrimaryOutput();
      if (var1 == null) {
         class="kw">return null;
      }

      String var2 = var1.getItemId();
      if (var2 == null) {
         class="kw">return null;
      }

      Item var3 = Item.getAssetMap().getAsset(var2);
      class="kw">return var3 != null ? var3.getTranslationKey() : null;
   }

   class="kw">public boolean queueCraft(
      @Nonnull Ref<EntityStore> var1,
      @Nonnull ComponentAccessor<EntityStore> var2,
      @Nonnull CraftingWindow var3,
      int var4,
      @Nonnull CraftingRecipe var5,
      int var6,
      @Nonnull ItemContainer var7,
      @Nonnull CraftingManager.InputRemovalType var8
   ) {
      if (this.upgradingJob != null) {
         class="kw">return false;
      }

      Objects.requireNonNull(var5, "Recipe can't be null");
      if (!this.isValidBenchForRecipe(var1, var2, var5)) {
         class="kw">return false;
      }

      int var9 = this.resolveCraftQuantity(var1, var2, var5, var7, var6);
      if (var9 < 1) {
         class="kw">return false;
      }

      CraftRecipeEvent.Pre var10 = new CraftRecipeEvent.Pre(var5, var9);
      var2.invoke(var1, var10);
      if (var10.isCancelled()) {
         class="kw">return false;
      }

      float var11 = var5.getTimeSeconds();
      if (var11 > 0.0F) {
         int var12 = this.getBenchTierLevel(var2);
         if (var12 > 1) {
            BenchTierLevel var13 = this.getBenchTierLevelData(var12 - 1);
            if (var13 != null) {
               var11 -= var11 * var13.getCraftingTimeReductionModifier();
            }
         }
      }

      boolean var14 = this.queuedCraftingJobs.offer(new CraftingManager.CraftingJob(var3, var4, var5, var9, var11, var7, var8));
      if (!var14) {
         LOGGER.at(Level.WARNING)
            .log(
               "Rejecting crafting job for %s (%s) due to lack of queue capacity (%d, %d, %d) (%d entries)",
               EntityUtils.getEntityName(var1, var2),
               var5.getId(),
               this.x,
               this.y,
               this.z,
               this.queuedCraftingJobs.size()
            );
         class="kw">return false;
      } else {
         class="kw">return true;
      }
   }

   class="kw">private int resolveCraftQuantity(
      @Nonnull Ref<EntityStore> var1, @Nonnull ComponentAccessor<EntityStore> var2, @Nonnull CraftingRecipe var3, @Nonnull ItemContainer var4, int var5
   ) {
      Player var6 = var2.getComponent(var1, Player.getComponentType());
      boolean var7 = var6 != null && var6.getGameMode() == GameMode.Creative;
      if (!var7) {
         int var8 = getMaterialCraftLimit(var3, var4);
         if (var5 > var8) {
            LOGGER.at(Level.WARNING)
               .log(
                  "Crafting quantity mismatch for %s: asked for %d of %s but %d are craftable", EntityUtils.getEntityName(var1, var2), var5, var3.getId(), var8
               );
         }
      }

      class="kw">return Math.min(var5, getOutputCraftCeiling(var1, var2, var3));
   }

   class="kw">public int getRemainingQueueSize() {
      int var1 = 0;

      for (CraftingManager.CraftingJob var3 : this.queuedCraftingJobs) {
         var1 += var3.quantity - var3.quantityCompleted;
      }

      class="kw">return var1;
   }

   class="kw">public void tick(@Nonnull Ref<EntityStore> var1, @Nonnull ComponentAccessor<EntityStore> var2, float var3) {
      if (this.upgradingJob != null) {
         if (var3 > 0.0F) {
            this.upgradingJob.timeSecondsCompleted += var3;
         }

         this.upgradingJob.window.updateBenchUpgradeJob(this.upgradingJob.computeLoadingPercent());
         if (this.upgradingJob.timeSecondsCompleted >= this.upgradingJob.timeSeconds) {
            this.upgradingJob.window.updateBenchTierLevel(this.finishTierUpgrade(var1, var2));
            this.upgradingJob = null;
         }
      } else {
         Player var4 = var2.getComponent(var1, Player.getComponentType());
         assert var4 != null;
         PlayerRef var5 = var2.getComponent(var1, PlayerRef.getComponentType());
         assert var5 != null;

         while (var3 > 0.0F && !this.queuedCraftingJobs.isEmpty()) {
            CraftingManager.CraftingJob var6 = this.queuedCraftingJobs.peek();
            boolean var7 = var4.getGameMode() == GameMode.Creative;
            if (var6 != null && var6.quantityStarted < var6.quantity && var6.quantityStarted <= var6.quantityCompleted) {
               LOGGER.at(Level.FINE).log("Removing Items for next quantity: %s", var6);
               int var8 = var6.quantityStarted++;
               if (!var7 && !removeInputFromInventory(var6, var8)) {
                  String var9 = getRecipeOutputTranslationKey(var6.recipe);
                  if (var9 != null) {
                     NotificationUtil.sendNotification(
                        var5.getPacketHandler(),
                        Message.translation("server.general.crafting.missingIngredient").param("item", Message.translation(var9)),
                        NotificationStyle.Danger
                     );
                  }

                  LOGGER.at(Level.FINE).log("Missing items required to craft the item: %s", var6);
                  this.queuedCraftingJobs.poll();
                  var6.window.updateQueueSize(this.getRemainingQueueSize());
                  if (this.queuedCraftingJobs.isEmpty()) {
                     var6.window.setBlockInteractionState("class="kw">default", var2.getExternalData().getWorld());
                  }

                  var6 = null;
               }

               if (!var7 && var6 != null && var6.quantityStarted < var6.quantity && var6.quantityStarted <= var6.quantityCompleted) {
                  NotificationUtil.sendNotification(
                     var5.getPacketHandler(), Message.translation("server.general.crafting.failedTakingCorrectQuantity"), NotificationStyle.Danger
                  );
                  LOGGER.at(Level.SEVERE).log("Failed to remove the correct quantity of input, removing crafting job %s", var6);
                  this.queuedCraftingJobs.poll();
                  var6.window.updateQueueSize(this.getRemainingQueueSize());
                  if (this.queuedCraftingJobs.isEmpty()) {
                     var6.window.setBlockInteractionState("class="kw">default", var2.getExternalData().getWorld());
                  }

                  var6 = null;
               }
            }

            if (var6 != null) {
               var6.timeSecondsCompleted += var3;
               float var11 = var6.timeSeconds <= 0.0F ? 1.0F : var6.timeSecondsCompleted / var6.timeSeconds;
               if (var11 > 1.0F) {
                  var11 = 1.0F;
               }

               var6.window.updateCraftingJob(var11);
               LOGGER.at(Level.FINEST).log("Update time: %s", var6);
               var3 = 0.0F;
               if (var6.timeSecondsCompleted >= var6.timeSeconds) {
                  var3 = var6.timeSecondsCompleted - var6.timeSeconds;
                  int var12 = var6.quantityCompleted++;
                  var6.timeSecondsCompleted = 0.0F;
                  LOGGER.at(Level.FINE).log("Crafted 1 Quantity: %s", var6);
                  CraftRecipeEvent.Post var10 = new CraftRecipeEvent.Post(var6.recipe, var6.quantity);
                  var2.invoke(var1, var10);
                  if (var6.quantityCompleted == var6.quantity) {
                     if (!var10.isCancelled()) {
                        giveOutput(var1, var2, var6, var12);
                     }

                     LOGGER.at(Level.FINE).log("Crafting Finished: %s", var6);
                     this.queuedCraftingJobs.poll();
                  } else {
                     if (var6.quantityCompleted > var6.quantity) {
                        this.queuedCraftingJobs.poll();
                        throw new RuntimeException("QuantityCompleted is greater than the Quality! " + var6);
                     }

                     if (!var10.isCancelled()) {
                        giveOutput(var1, var2, var6, var12);
                     }
                  }

                  var6.window.updateQueueSize(this.getRemainingQueueSize());
                  if (this.queuedCraftingJobs.isEmpty()) {
                     var6.window.setBlockInteractionState("class="kw">default", var2.getExternalData().getWorld());
                  }
               }
            }
         }
      }
   }

   class="kw">public boolean cancelAllCrafting(@Nonnull Ref<EntityStore> var1, @Nonnull ComponentAccessor<EntityStore> var2) {
      LOGGER.at(Level.FINE).log("Cancel Crafting!");
      ObjectList var3 = new ObjectArrayList(this.queuedCraftingJobs.size());
      this.queuedCraftingJobs.drainTo(var3);
      if (!var3.isEmpty()) {
         CraftingManager.CraftingJob var4 = (CraftingManager.CraftingJob)var3.getFirst();
         LOGGER.at(Level.FINE).log("Refunding Items for: %s", var4);
         refundInputToInventory(var1, var2, var4, var4.quantityStarted - 1);
         class="kw">return true;
      } else {
         class="kw">return false;
      }
   }

   class="kw">private boolean isValidBenchForRecipe(@Nonnull Ref<EntityStore> var1, @Nonnull ComponentAccessor<EntityStore> var2, @Nonnull CraftingRecipe var3) {
      Player var4 = var2.getComponent(var1, Player.getComponentType());
      assert var4 != null;
      PlayerConfigData var5 = var4.getPlayerConfigData();
      MaterialQuantity var6 = var3.getPrimaryOutput();
      String var7 = var6 != null ? var6.getItemId() : null;
      if (!var3.isKnowledgeRequired() || var7 != null && var5.getKnownRecipes().contains(var7)) {
         World var8 = var2.getExternalData().getWorld();
         if (var3.getRequiredMemoriesLevel() > 1 && MemoriesPlugin.get().getMemoriesLevel(var8.getGameplayConfig()) < var3.getRequiredMemoriesLevel()) {
            LOGGER.at(Level.WARNING).log("Attempted to craft %s but doesn't have the required world memories level!", var3.getId());
            class="kw">return false;
         }

         BenchType var9 = this.blockType != null ? this.blockType.getBench().getType() : BenchType.Crafting;
         String var10 = this.blockType != null ? this.blockType.getBench().getId() : "Fieldcraft";
         boolean var11 = false;
         int var12 = this.getBenchTierLevel(var2);
         BenchRequirement[] var13 = var3.getBenchRequirement();
         if (var13 != null) {
            for (BenchRequirement var17 : var13) {
               if (var17.type == var9 && var10.equals(var17.id) && var17.requiredTierLevel <= var12 && this.benchHasRequiredAugmentTags(var2, var17)) {
                  var11 = true;
                  break;
               }
            }
         }

         if (!var11) {
            LOGGER.at(Level.WARNING).log("Attempted to craft %s using %s, %s but requires bench %s but a bench is NOT set!", var3.getId(), var9, var10, var13);
            class="kw">return false;
         } else if (var9 == BenchType.Crafting && !"Fieldcraft".equals(var10)) {
            CraftingManager.CraftingJob var18 = this.queuedCraftingJobs.peek();
            class="kw">return var18 == null || var18.recipe.getId().equals(var3.getId());
         } else {
            class="kw">return true;
         }
      } else {
         LOGGER.at(Level.WARNING).log("Attempted to craft %s but doesn't know the recipe!", var3.getId());
         class="kw">return false;
      }
   }

   class="kw">private class="kw">static void giveOutput(
      @Nonnull Ref<EntityStore> var0, @Nonnull ComponentAccessor<EntityStore> var1, @Nonnull CraftingManager.CraftingJob var2, int var3
   ) {
      var2.removedItems.remove(var3);
      String var4 = var2.recipe.getId();
      CraftingRecipe var5 = CraftingRecipe.getAssetMap().getAsset(var4);
      if (var5 == null) {
         throw new RuntimeException("A non-existent item ID was provided! " + var4);
      }

      giveOutput(var0, var1, var5, 1);
   }

   class="kw">private class="kw">static void giveOutput(@Nonnull Ref<EntityStore> var0, @Nonnull ComponentAccessor<EntityStore> var1, @Nonnull CraftingRecipe var2, int var3) {
      Player var4 = var1.getComponent(var0, Player.getComponentType());
      if (var4 == null) {
         LOGGER.at(Level.WARNING).log("Attempted to give output to a non-player entity: %s", var0);
      } else {
         List var5 = getOutputItemStacks(var2, var3);
         PlayerSettings var6 = var1.getComponent(var0, PlayerSettings.getComponentType());
         if (var6 == null) {
            var6 = PlayerSettings.defaults();
         }

         for (ItemStack var8 : var5) {
            if (!ItemStack.isEmpty(var8)) {
               ItemContainer var9 = InventoryUtils.getContainerForItemPickup(var0, var8.getItem(), var6, var1);
               SimpleItemContainer.addOrDropItemStack(var1, var0, var9, var8);
            }
         }
      }
   }

   class="kw">private class="kw">static boolean removeInputFromInventory(@Nonnull CraftingManager.CraftingJob var0, int var1) {
      Objects.requireNonNull(var0, "Job can't be null!");
      CraftingRecipe var2 = var0.recipe;
      Objects.requireNonNull(var2, "CraftingRecipe can't be null!");
      List var3 = getInputMaterials(var2);
      if (var3.isEmpty()) {
         class="kw">return true;
      }

      LOGGER.at(Level.FINEST).log("Removing Materials: %s - %s", var0, var3);
      ObjectList var4 = new ObjectArrayList();

      boolean var5 = class="kw">switch (var0.inputRemovalType) {
         case NORMAL -> {
            ListTransaction var11 = var0.inputItemContainer.removeMaterials(var3, true, true, true);

            for (MaterialTransaction var13 : var11.getList()) {
               for (MaterialSlotTransaction var10 : var13.getList()) {
                  if (!ItemStack.isEmpty(var10.getOutput())) {
                     var4.add(var10.getOutput());
                  }
               }
            }

            yield var11.succeeded();
         }
         case ORDERED -> {
            ListTransaction var6 = var0.inputItemContainer.removeMaterialsOrdered(var3, true, true, true);

            for (MaterialSlotTransaction var8 : var6.getList()) {
               if (!ItemStack.isEmpty(var8.getOutput())) {
                  var4.add(var8.getOutput());
               }
            }

            yield var6.succeeded();
         }
         class="kw">default -> throw new IllegalArgumentException("Unknown enum: " + var0.inputRemovalType);
      };
      var0.removedItems.put(var1, var4);
      var0.window.invalidateExtraResources();
      class="kw">return var5;
   }

   class="kw">private class="kw">static boolean removeInputFromInventory(@Nonnull ItemContainer var0, @Nonnull CraftingRecipe var1, int var2) {
      List var3 = getInputMaterials(var1, var2);
      if (var3.isEmpty()) {
         class="kw">return true;
      }

      LOGGER.at(Level.FINEST).log("Removing Materials: %s - %s", var1, var3);
      ListTransaction var4 = var0.removeMaterials(var3, true, true, true);
      class="kw">return var4.succeeded();
   }

   class="kw">private class="kw">static void refundInputToInventory(
      @Nonnull Ref<EntityStore> var0, @Nonnull ComponentAccessor<EntityStore> var1, @Nonnull CraftingManager.CraftingJob var2, int var3
   ) {
      Objects.requireNonNull(var2, "Job can't be null!");
      List var4 = (List<ItemStack>)var2.removedItems.get(var3);
      if (var4 != null) {
         CombinedItemContainer var5 = InventoryComponent.getCombined(var1, var0, InventoryComponent.HOTBAR_FIRST);
         SimpleItemContainer.addOrDropItemStacks(var1, var0, var5, var4);
      }
   }

   @Nonnull
   class="kw">public class="kw">static List<ItemStack> getOutputItemStacks(@Nonnull CraftingRecipe var0) {
      class="kw">return getOutputItemStacks(var0, 1);
   }

   @Nonnull
   class="kw">public class="kw">static List<ItemStack> getOutputItemStacks(@Nonnull CraftingRecipe var0, int var1) {
      Objects.requireNonNull(var0);
      MaterialQuantity[] var2 = var0.getOutputs();
      if (var2 == null) {
         class="kw">return List.of();
      }

      ObjectList var3 = new ObjectArrayList();

      for (MaterialQuantity var7 : var2) {
         ItemStack var8 = getOutputItemStack(var7, var1);
         if (var8 != null) {
            var3.add(var8);
         }
      }

      class="kw">return var3;
   }

   @Nullable
   class="kw">public class="kw">static ItemStack getOutputItemStack(@Nonnull MaterialQuantity var0, @Nonnull String var1) {
      class="kw">return getOutputItemStack(var0, 1);
   }

   @Nullable
   class="kw">public class="kw">static ItemStack getOutputItemStack(@Nonnull MaterialQuantity var0, int var1) {
      String var2 = var0.getItemId();
      if (var2 == null) {
         class="kw">return null;
      }

      int var3 = var0.getQuantity() <= 0 ? 1 : var0.getQuantity();
      class="kw">return new ItemStack(var2, var3 * var1, var0.getMetadata());
   }

   @Nonnull
   class="kw">public class="kw">static List<MaterialQuantity> getInputMaterials(@Nonnull CraftingRecipe var0) {
      class="kw">return getInputMaterials(var0, 1);
   }

   @Nonnull
   class="kw">private class="kw">static List<MaterialQuantity> getInputMaterials(@Nonnull MaterialQuantity[] var0) {
      class="kw">return getInputMaterials(var0, 1);
   }

   @Nonnull
   class="kw">public class="kw">static List<MaterialQuantity> getInputMaterials(@Nonnull CraftingRecipe var0, int var1) {
      Objects.requireNonNull(var0);
      class="kw">return var0.getInput() == null ? Collections.emptyList() : getInputMaterials(var0.getInput(), var1);
   }

   @Nonnull
   class="kw">private class="kw">static List<MaterialQuantity> getInputMaterials(@Nonnull MaterialQuantity[] var0, int var1) {
      ObjectList var2 = new ObjectArrayList();

      for (MaterialQuantity var6 : var0) {
         var2.add(var6.clone(var6.getQuantity() * var1));
      }

      class="kw">return var2;
   }

   class="kw">public class="kw">static boolean matches(@Nonnull MaterialQuantity var0, @Nonnull ItemStack var1) {
      String var2 = var0.getItemId();
      if (var2 != null) {
         class="kw">return var2.equals(var1.getItemId());
      }

      if (var0.isItemExcluded(var1.getItemId())) {
         class="kw">return false;
      }

      String var3 = var0.getResourceTypeId();
      if (var3 != null && var1.getItem().getResourceTypes() != null) {
         for (ItemResourceType var7 : var1.getItem().getResourceTypes()) {
            if (var3.equals(var7.id)) {
               class="kw">return true;
            }
         }
      }

      class="kw">return false;
   }

   @Nonnull
   class="kw">public class="kw">static JsonArray generateInventoryHints(@Nonnull List<CraftingRecipe> var0, int var1, @Nonnull ItemContainer var2) {
      JsonArray var3 = new JsonArray();
      short var4 = 0;

      for (short var5 = var2.getCapacity(); var4 < var5; var4++) {
         ItemStack var6 = var2.getItemStack(var4);
         if (var6 != null && !var6.isEmpty() && matchesAnyRecipe(var0, var1, var6)) {
            var3.add(var4);
         }
      }

      class="kw">return var3;
   }

   class="kw">public class="kw">static boolean matchesAnyRecipe(@Nonnull List<CraftingRecipe> var0, int var1, @Nonnull ItemStack var2) {
      for (CraftingRecipe var4 : var0) {
         MaterialQuantity[] var5 = var4.getInput();
         if (var1 < var5.length && matches(var5[var1], var2)) {
            class="kw">return true;
         }
      }

      class="kw">return false;
   }

   class="kw">private class="kw">static int getMaterialCraftLimit(@Nonnull CraftingRecipe var0, @Nonnull ItemContainer var1) {
      MaterialQuantity[] var2 = var0.getInput();
      if (var2 != null && var2.length != 0) {
         int var3 = Integer.MAX_VALUE;
         boolean var4 = false;

         for (MaterialQuantity var8 : var2) {
            int var9 = var8.getQuantity();
            if (var9 > 0) {
               var4 = true;
               var3 = Math.min(var3, var1.countRemovableMaterial(var8) / var9);
               if (var3 == 0) {
                  break;
               }
            }
         }

         class="kw">return var4 ? var3 : 1;
      } else {
         class="kw">return 1;
      }
   }

   class="kw">private class="kw">static int getOutputCraftCeiling(@Nonnull Ref<EntityStore> var0, @Nonnull ComponentAccessor<EntityStore> var1, @Nonnull CraftingRecipe var2) {
      MaterialQuantity var3 = var2.getPrimaryOutput();
      String var4 = var3 != null ? var3.getItemId() : null;
      if (var4 == null) {
         class="kw">return 1;
      }

      int var5 = Math.max(1, var3.getQuantity());
      Item var6 = Item.getAssetMap().getAsset(var4);
      int var7 = var6 != null ? Math.max(1, var6.getMaxStack()) : 1;
      CombinedItemContainer var8 = InventoryComponent.getCombined(var1, var0, InventoryComponent.BACKPACK_STORAGE_HOTBAR);
      long var9 = (long)var8.getCapacity() * var7;
      class="kw">return (int)Math.max(1L, Math.min(var9 / var5, 2147483647L));
   }

   class="kw">public boolean startTierUpgrade(@Nonnull Ref<EntityStore> var1, @Nonnull ComponentAccessor<EntityStore> var2, @Nonnull BenchWindow var3) {
      if (this.upgradingJob != null) {
         class="kw">return false;
      }

      BenchUpgradeRequirement var4 = this.getBenchUpgradeRequirement(this.getBenchTierLevel(var2));
      if (var4 == null) {
         class="kw">return false;
      }

      List var5 = getInputMaterials(var4.getInput());
      if (var5.isEmpty()) {
         class="kw">return false;
      }

      Player var6 = var2.getComponent(var1, Player.getComponentType());
      assert var6 != null;
      if (var6.getGameMode() != GameMode.Creative) {
         CombinedItemContainer var7 = InventoryComponent.getCombined(var2, var1, InventoryComponent.BACKPACK_STORAGE_HOTBAR);
         CombinedItemContainer var8 = new CombinedItemContainer(var7, var3.getExtraResourcesSection().getItemContainer());
         if (!var8.canRemoveMaterials(var5)) {
            class="kw">return false;
         }
      }

      this.upgradingJob = new CraftingManager.BenchUpgradingJob(var3, var4.getTimeSeconds());
      this.cancelAllCrafting(var1, var2);
      class="kw">return true;
   }

   class="kw">private int finishTierUpgrade(@Nonnull Ref<EntityStore> var1, @Nonnull ComponentAccessor<EntityStore> var2) {
      if (this.upgradingJob == null) {
         class="kw">return 0;
      }

      World var3 = var2.getExternalData().getWorld();
      ChunkStore var4 = var3.getChunkStore();
      Ref var5 = var4.getChunkSectionReferenceAtBlock(this.x, this.y, this.z);
      if (var5 != null && var5.isValid()) {
         Ref var6 = BlockModule.getBlockEntity(var4.getStore(), var5, this.x, this.y, this.z);
         if (var6 == null) {
            class="kw">return 0;
         }

         BlockModule.BlockStateInfo var7 = var4.getStore().getComponent(var6, BlockModule.BlockStateInfo.getComponentType());
         if (var7 == null) {
            class="kw">return 0;
         }

         BenchBlock var8 = var4.getStore().getComponent(var6, BenchBlock.getComponentType());
         if (var8 != null && var8.getTierLevel() != 0) {
            BenchUpgradeRequirement var9 = this.getBenchUpgradeRequirement(var8.getTierLevel());
            if (var9 == null) {
               class="kw">return var8.getTierLevel();
            }

            List var10 = getInputMaterials(var9.getInput());
            if (var10.isEmpty()) {
               class="kw">return var8.getTierLevel();
            }

            Player var11 = var2.getComponent(var1, Player.getComponentType());
            assert var11 != null;
            boolean var12 = var11.getGameMode() == GameMode.Creative;
            if (!var12) {
               CombinedItemContainer var13 = InventoryComponent.getCombined(var2, var1, InventoryComponent.BACKPACK_STORAGE_HOTBAR);
               CombinedItemContainer var14 = new CombinedItemContainer(var13, this.upgradingJob.window.getExtraResourcesSection().getItemContainer());
               ListTransaction var15 = var14.removeMaterials(var10);
               if (var15.succeeded()) {
                  List var16 = new ObjectArrayList();

                  for (MaterialTransaction var18 : var15.getList()) {
                     for (MaterialSlotTransaction var20 : var18.getList()) {
                        var16.add(var20.getOutput());
                     }
                  }

                  var8.addUpgradeItems(var16);
                  var7.markNeedsSaving();
                  var12 = true;
               }
            }

            if (var12) {
               var8.setTierLevel(var8.getTierLevel() + 1);
               var7.markNeedsSaving();
               BlockSection var21 = var4.getStore().getComponent(var5, BlockSection.getComponentType());
               assert var21 != null;
               BlockType var22 = BenchBlock.getBaseBlockType(this.blockType);
               BlockOperations.setBlockInteractionState(var4, var5, this.x, this.y, this.z, var22, var8.getTierStateName(), true);
               ProcessingBenchBlock var23 = var4.getStore().getComponent(var6, ProcessingBenchBlock.getComponentType());
               if (var23 != null) {
                  int var24 = var21.getRotationIndex(this.x, this.y, this.z);
                  var23.setupSlots(var3, var8, var7, this.x, this.y, this.z, this.blockType, var24);
               }

               int var25 = var21.get(this.x, this.y, this.z);
               BlockType var26 = BlockType.getAssetMap().getAsset(var25);
               if (var26 != null && var26.getBench().getBenchUpgradeCompletedSoundEventIndex() != 0) {
                  SoundUtil.playSoundEvent3d(
                     var26.getBench().getBenchUpgradeCompletedSoundEventIndex(), SoundCategory.SFX, this.x + 0.5, this.y + 0.5, this.z + 0.5, var2
                  );
               }
            }

            class="kw">return var8.getTierLevel();
         } else {
            class="kw">return 0;
         }
      } else {
         class="kw">return 0;
      }
   }

   @Nullable
   class="kw">private BenchTierLevel getBenchTierLevelData(int var1) {
      if (this.blockType == null) {
         class="kw">return null;
      }

      Bench var2 = this.blockType.getBench();
      class="kw">return var2 == null ? null : var2.getTierLevel(var1);
   }

   @Nullable
   class="kw">private BenchUpgradeRequirement getBenchUpgradeRequirement(int var1) {
      BenchTierLevel var2 = this.getBenchTierLevelData(var1);
      class="kw">return var2 == null ? null : var2.getUpgradeRequirement();
   }

   class="kw">private int getBenchTierLevel(@Nonnull ComponentAccessor<EntityStore> var1) {
      World var2 = var1.getExternalData().getWorld();
      ChunkStore var3 = var2.getChunkStore();
      Ref var4 = BlockModule.getBlockEntity(var2, this.x, this.y, this.z);
      if (var4 == null) {
         class="kw">return 0;
      }

      BenchBlock var5 = var3.getStore().getComponent(var4, BenchBlock.getComponentType());
      class="kw">return var5 != null && var5.getTierLevel() != 0 ? var5.getTierLevel() : 0;
   }

   class="kw">private boolean benchHasRequiredAugmentTags(@Nonnull ComponentAccessor<EntityStore> var1, @Nonnull BenchRequirement var2) {
      String[] var3 = var2.requiredAugmentTags;
      if (var3 != null && var3.length != 0) {
         Set var4 = this.getBenchGrantedAugmentTags(var1);

         for (String var8 : var3) {
            if (!var4.contains(var8)) {
               class="kw">return false;
            }
         }

         class="kw">return true;
      } else {
         class="kw">return true;
      }
   }

   @Nonnull
   class="kw">private Set<String> getBenchGrantedAugmentTags(@Nonnull ComponentAccessor<EntityStore> var1) {
      World var2 = var1.getExternalData().getWorld();
      ChunkStore var3 = var2.getChunkStore();
      Ref var4 = BlockModule.getBlockEntity(var2, this.x, this.y, this.z);
      if (var4 == null) {
         class="kw">return Set.of();
      }

      BenchBlock var5 = var3.getStore().getComponent(var4, BenchBlock.getComponentType());
      if (var5 == null) {
         class="kw">return Set.of();
      }

      BenchBlock.refreshGrantedAugmentTags(var3.getStore(), var4, new Vector3i(this.x, this.y, this.z));
      class="kw">return var5.getGrantedAugmentTags();
   }

   class="kw">public class="kw">static int feedExtraResourcesSection(
      @Nonnull World var0,
      int var1,
      int var2,
      int var3,
      @Nonnull BlockType var4,
      int var5,
      @Nonnull Bench var6,
      int var7,
      @Nonnull MaterialExtraResourcesSection var8
   ) {
      CraftingManager.ChestLookupResult var9 = getContainersAroundBench(var0, var1, var2, var3, var4, var5);
      List var10 = var9.containers;
      List var11 = var9.states;
      ItemContainer var12 = EmptyItemContainer.INSTANCE;
      if (!var10.isEmpty()) {
         var12 = new CombinedItemContainer(var10.stream().map(var0x -> {
            DelegateItemContainer var1 = new DelegateItemContainer<>(var0x);
            var1.setGlobalFilter(FilterType.ALLOW_OUTPUT_ONLY);
            class="kw">return var1;
         }).toArray(ItemContainer[]::new));
      }

      Map var13 = new Object2ObjectOpenHashMap();

      for (ItemContainer var15 : var10) {
         var15.forEach((var3x, var4x) -> {
            if (CraftingPlugin.isValidUpgradeMaterialForBench(var6, var7, var4x) || CraftingPlugin.isValidCraftingMaterialForBench(var6, var4x)) {
               ItemQuantity var10000 = var13.computeIfAbsent(var4x.getItemId(), var1x -> new ItemQuantity(var4x.getItemId(), 0));
               var10000.quantity = var10000.quantity + var4x.getQuantity();
            }
         });
      }

      var8.setItemContainer(var12);
      var8.setExtraMaterials(var13.values().toArray(new ItemQuantity[0]));
      var8.setValid(true);
      class="kw">return var11.size();
   }

   @Nonnull
   class="kw">protected class="kw">static CraftingManager.ChestLookupResult getContainersAroundBench(
      @Nonnull World var0, int var1, int var2, int var3, @Nonnull BlockType var4, int var5
   ) {
      List var6 = new ObjectArrayList();
      List var7 = new ObjectArrayList();
      List var8 = new ObjectArrayList();
      Store var9 = var0.getChunkStore().getStore();
      int var10 = var0.getGameplayConfig().getCraftingConfig().getBenchMaterialChestLimit();
      double var11 = var0.getGameplayConfig().getCraftingConfig().getBenchMaterialHorizontalChestSearchRadius();
      double var13 = var0.getGameplayConfig().getCraftingConfig().getBenchMaterialVerticalChestSearchRadius();
      Vector3d var15 = new Vector3d(var1, var2, var3);
      BlockBoundingBoxes var16 = BlockBoundingBoxes.getAssetMap().getAsset(var4.getHitboxTypeIndex());
      BlockBoundingBoxes.RotatedVariantBoxes var17 = var16.get(var5);
      Box var18 = var17.getBoundingBox();
      double var19 = var18.width();
      double var21 = var18.height();
      double var23 = var18.depth();
      double var25 = Math.max(var19, Math.max(var23, var21)) - 1.0;
      SpatialResource var27 = var9.getResource(BlockModule.get().getItemContainerSpatialResourceType());
      List var28 = SpatialResource.getThreadLocalReferenceList();
      var27.getSpatialStructure().ordered3DAxis(var15, var11 + var25, var13 + var25, var11 + var25, var28);
      if (!var28.isEmpty()) {
         int var29 = (int)Math.floor(var18.min.x);
         int var30 = (int)Math.floor(var18.min.y);
         int var31 = (int)Math.floor(var18.min.z);
         int var32 = (int)Math.ceil(var18.max.x) - 1;
         int var33 = (int)Math.ceil(var18.max.y) - 1;
         int var34 = (int)Math.ceil(var18.max.z) - 1;
         double var35 = var15.x + var29 - var11;
         double var37 = var15.y + var30 - var13;
         double var39 = var15.z + var31 - var11;
         double var41 = var15.x + var32 + var11;
         double var43 = var15.y + var33 + var13;
         double var45 = var15.z + var34 + var11;

         for (Ref var48 : var28) {
            if (var48.isValid()) {
               ItemContainerBlock var49 = var9.getComponent(var48, ItemContainerBlock.getComponentType());
               if (var49 != null) {
                  BlockModule.BlockStateInfo var50 = var9.getComponent(var48, BlockModule.BlockStateInfo.getComponentType());
                  if (var50 != null) {
                     ChunkSection var51 = var9.getComponent(var50.getSectionRef(), ChunkSection.getComponentType());
                     if (var51 != null) {
                        int var52 = ChunkUtil.worldCoordFromLocalCoord(var51.getX(), ChunkUtil.xFromIndex(var50.getIndex()));
                        int var53 = ChunkUtil.worldCoordFromLocalCoord(var51.getY(), ChunkUtil.yFromIndex(var50.getIndex()));
                        int var54 = ChunkUtil.worldCoordFromLocalCoord(var51.getZ(), ChunkUtil.zFromIndex(var50.getIndex()));
                        if (var52 >= var35 && var52 <= var41 && var53 >= var37 && var53 <= var43 && var54 >= var39 && var54 <= var45) {
                           var6.add(var49.getItemContainer());
                           var7.add(var49);
                           if (var6.size() >= var10) {
                              break;
                           }
                        } else {
                           var8.add(var49);
                        }
                     }
                  }
               }
            }
         }
      }

      class="kw">return new CraftingManager.ChestLookupResult(var6, var7, var8, var15);
   }

   @Nonnull
   @Override
   class="kw">public String toString() {
      class="kw">return "CraftingManager{queuedCraftingJobs="
         + this.queuedCraftingJobs
         + ", x="
         + this.x
         + ", y="
         + this.y
         + ", z="
         + this.z
         + ", blockType="
         + this.blockType
         + "}";
   }

   @Nonnull
   @Override
   class="kw">public Component<EntityStore> clone() {
      class="kw">return new CraftingManager(this);
   }

   class="kw">private class="kw">static class BenchUpgradingJob {
      @Nonnull
      class="kw">private class="kw">final BenchWindow window;
      class="kw">private class="kw">final float timeSeconds;
      class="kw">private float timeSecondsCompleted;
      class="kw">private float lastSentPercent;

      class="kw">private BenchUpgradingJob(@Nonnull BenchWindow var1, float var2) {
         this.window = var1;
         this.timeSeconds = var2;
      }

      @Nonnull
      @Override
      class="kw">public String toString() {
         class="kw">return "BenchUpgradingJob{window=" + this.window + ", timeSeconds=" + this.timeSeconds + "}";
      }

      class="kw">public float computeLoadingPercent() {
         class="kw">return this.timeSeconds <= 0.0F ? 1.0F : Math.min(this.timeSecondsCompleted / this.timeSeconds, 1.0F);
      }
   }

   class="kw">protected record ChestLookupResult(
      List<ItemContainer> containers, List<ItemContainerBlock> states, List<ItemContainerBlock> filteredOut, Vector3d benchCenteredPos
   ) {
      class="kw">protected ChestLookupResult {
      }
   }

   class="kw">private class="kw">static class CraftingJob {
      @Nonnull
      class="kw">private class="kw">final CraftingWindow window;
      class="kw">private class="kw">final int transactionId;
      @Nonnull
      class="kw">private class="kw">final CraftingRecipe recipe;
      class="kw">private class="kw">final int quantity;
      class="kw">private class="kw">final float timeSeconds;
      @Nonnull
      class="kw">private class="kw">final ItemContainer inputItemContainer;
      @Nonnull
      class="kw">private class="kw">final CraftingManager.InputRemovalType inputRemovalType;
      @Nonnull
      class="kw">private class="kw">final Int2ObjectMap<List<ItemStack>> removedItems = new Int2ObjectOpenHashMap();
      class="kw">private int quantityStarted;
      class="kw">private int quantityCompleted;
      class="kw">private float timeSecondsCompleted;

      class="kw">public CraftingJob(
         @Nonnull CraftingWindow var1,
         int var2,
         @Nonnull CraftingRecipe var3,
         int var4,
         float var5,
         @Nonnull ItemContainer var6,
         @Nonnull CraftingManager.InputRemovalType var7
      ) {
         this.window = var1;
         this.transactionId = var2;
         this.recipe = var3;
         this.quantity = var4;
         this.timeSeconds = var5;
         this.inputItemContainer = var6;
         this.inputRemovalType = var7;
      }

      @Nonnull
      @Override
      class="kw">public String toString() {
         class="kw">return "CraftingJob{window="
            + this.window
            + ", transactionId="
            + this.transactionId
            + ", recipe="
            + this.recipe
            + ", quantity="
            + this.quantity
            + ", timeSeconds="
            + this.timeSeconds
            + ", inputItemContainer="
            + this.inputItemContainer
            + ", inputRemovalType="
            + this.inputRemovalType
            + ", removedItems="
            + this.removedItems
            + ", quantityStarted="
            + this.quantityStarted
            + ", quantityCompleted="
            + this.quantityCompleted
            + ", timeSecondsCompleted="
            + this.timeSecondsCompleted
            + "}";
      }
   }

   class="kw">public enum InputRemovalType {
      NORMAL,
      ORDERED;

      InputRemovalType() {
      }
   }
}