ChainCancelledException class

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

Файл: com/hypixel/hytale/server/core/entity/InteractionManager.java

extends: RuntimeException

Поля (1)

МодификаторыТипИмя
private final InteractionState state

Исходный код

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

class="kw">import com.hypixel.hytale.common.util.FormatUtil;
class="kw">import com.hypixel.hytale.common.util.ListUtil;
class="kw">import com.hypixel.hytale.component.CommandBuffer;
class="kw">import com.hypixel.hytale.component.Component;
class="kw">import com.hypixel.hytale.component.ComponentAccessor;
class="kw">import com.hypixel.hytale.component.Ref;
class="kw">import com.hypixel.hytale.function.function.TriFunction;
class="kw">import com.hypixel.hytale.logger.HytaleLogger;
class="kw">import com.hypixel.hytale.math.util.ChunkUtil;
class="kw">import com.hypixel.hytale.protocol.BlockPosition;
class="kw">import com.hypixel.hytale.protocol.ForkedChainId;
class="kw">import com.hypixel.hytale.protocol.GameMode;
class="kw">import com.hypixel.hytale.protocol.InteractionChainData;
class="kw">import com.hypixel.hytale.protocol.InteractionCooldown;
class="kw">import com.hypixel.hytale.protocol.InteractionState;
class="kw">import com.hypixel.hytale.protocol.InteractionSyncData;
class="kw">import com.hypixel.hytale.protocol.InteractionType;
class="kw">import com.hypixel.hytale.protocol.RootInteractionSettings;
class="kw">import com.hypixel.hytale.protocol.WaitForDataFrom;
class="kw">import com.hypixel.hytale.protocol.packets.interaction.CancelInteractionChain;
class="kw">import com.hypixel.hytale.protocol.packets.interaction.SyncInteractionChain;
class="kw">import com.hypixel.hytale.protocol.packets.inventory.SetActiveSlot;
class="kw">import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
class="kw">import com.hypixel.hytale.server.core.entity.entities.Player;
class="kw">import com.hypixel.hytale.server.core.inventory.InventoryComponent;
class="kw">import com.hypixel.hytale.server.core.inventory.ItemStack;
class="kw">import com.hypixel.hytale.server.core.io.handlers.game.GamePacketHandler;
class="kw">import com.hypixel.hytale.server.core.modules.interaction.IInteractionSimulationHandler;
class="kw">import com.hypixel.hytale.server.core.modules.interaction.interaction.CooldownHandler;
class="kw">import com.hypixel.hytale.server.core.modules.interaction.interaction.config.Interaction;
class="kw">import com.hypixel.hytale.server.core.modules.interaction.interaction.config.InteractionTypeUtils;
class="kw">import com.hypixel.hytale.server.core.modules.interaction.interaction.config.RootInteraction;
class="kw">import com.hypixel.hytale.server.core.modules.interaction.interaction.config.data.Collector;
class="kw">import com.hypixel.hytale.server.core.modules.interaction.interaction.config.data.CollectorTag;
class="kw">import com.hypixel.hytale.server.core.modules.interaction.interaction.operation.Operation;
class="kw">import com.hypixel.hytale.server.core.modules.interaction.interaction.util.InteractionValidation;
class="kw">import com.hypixel.hytale.server.core.modules.time.TimeResource;
class="kw">import com.hypixel.hytale.server.core.universe.PlayerRef;
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.storage.ChunkStore;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
class="kw">import com.hypixel.hytale.server.core.util.FillerBlockUtil;
class="kw">import com.hypixel.hytale.server.core.util.UUIDUtil;
class="kw">import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
class="kw">import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
class="kw">import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
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.ObjectList;
class="kw">import it.unimi.dsi.fastutil.objects.ObjectListIterator;
class="kw">import java.util.Arrays;
class="kw">import java.util.Deque;
class="kw">import java.util.Iterator;
class="kw">import java.util.List;
class="kw">import java.util.Map;
class="kw">import java.util.Objects;
class="kw">import java.util.UUID;
class="kw">import java.util.concurrent.TimeUnit;
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">import org.joml.Vector3fc;
class="kw">import org.joml.Vector4d;

class="kw">public class InteractionManager class="kw">implements Component<EntityStore> {
   class="kw">public class="kw">static class="kw">final double MAX_REACH_DISTANCE = 8.0;
   class="kw">public class="kw">static class="kw">final float[] DEFAULT_CHARGE_TIMES = new float[]{0.0F};
   class="kw">private class="kw">static class="kw">final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
   @Nonnull
   class="kw">private class="kw">final Int2ObjectMap<InteractionChain> chains = new Int2ObjectOpenHashMap();
   @Nonnull
   class="kw">private class="kw">final Int2ObjectMap<InteractionChain> unmodifiableChains = Int2ObjectMaps.unmodifiable(this.chains);
   @Nonnull
   class="kw">private class="kw">final CooldownHandler cooldownHandler = new CooldownHandler();
   @Nullable
   class="kw">private Ref<EntityStore> ref;
   @Nullable
   class="kw">private class="kw">final PlayerRef playerRef;
   class="kw">private boolean hasRemoteClient;
   @Nonnull
   class="kw">private class="kw">final IInteractionSimulationHandler interactionSimulationHandler;
   @Nonnull
   class="kw">private class="kw">final ObjectList<InteractionSyncData> tempSyncDataList = new ObjectArrayList();
   class="kw">private int lastServerChainId;
   class="kw">private int lastClientChainId;
   class="kw">private long packetQueueTime;
   class="kw">private class="kw">final float[] globalTimeShift = new float[InteractionType.VALUES.length];
   class="kw">private class="kw">final boolean[] globalTimeShiftDirty = new boolean[InteractionType.VALUES.length];
   class="kw">private boolean timeShiftsDirty;
   class="kw">private class="kw">final ObjectList<SyncInteractionChain> syncPackets = new ObjectArrayList();
   class="kw">private long currentTime = 1L;
   @Nonnull
   class="kw">private class="kw">final ObjectList<InteractionChain> chainStartQueue = new ObjectArrayList();
   @Nonnull
   class="kw">private class="kw">final Predicate<InteractionChain> cachedTickChain = this::tickChain;
   @Nullable
   class="kw">protected CommandBuffer<EntityStore> commandBuffer;

   class="kw">public InteractionManager(@Nullable PlayerRef var1, @Nonnull IInteractionSimulationHandler var2) {
      this.playerRef = var1;
      this.hasRemoteClient = var1 != null;
      this.interactionSimulationHandler = var2;
   }

   @Nonnull
   class="kw">public Int2ObjectMap<InteractionChain> getChains() {
      class="kw">return this.unmodifiableChains;
   }

   @Nonnull
   class="kw">public IInteractionSimulationHandler getInteractionSimulationHandler() {
      class="kw">return this.interactionSimulationHandler;
   }

   class="kw">private long getOperationTimeoutThreshold() {
      if (this.playerRef != null) {
         class="kw">return this.playerRef.getPacketHandler().getOperationTimeoutThreshold();
      }

      assert this.commandBuffer != null;
      World var1 = this.commandBuffer.getExternalData().getWorld();
      class="kw">return var1.getTickStepNanos() / 1000000L * 10L;
   }

   class="kw">private boolean waitingForClient(@Nonnull Ref<EntityStore> var1) {
      assert this.commandBuffer != null;
      Player var2 = this.commandBuffer.getComponent(var1, Player.getComponentType());
      class="kw">return var2 != null ? var2.isWaitingForClientReady() : false;
   }

   @Deprecated(forRemoval = true)
   class="kw">public void setHasRemoteClient(boolean var1) {
      this.hasRemoteClient = var1;
   }

   @Deprecated
   class="kw">public void copyFrom(@Nonnull InteractionManager var1) {
      this.chains.putAll(var1.chains);
   }

   class="kw">public void tick(@Nonnull Ref<EntityStore> var1, @Nonnull CommandBuffer<EntityStore> var2, float var3) {
      if (!var1.isValid()) {
         throw new IllegalStateException("Attempted to tick Interaction Manager for an invalid entity reference!");
      }

      this.currentTime = this.currentTime + var2.getExternalData().getWorld().getTickStepNanos();
      this.ref = var1;
      this.commandBuffer = var2;
      this.clearAllGlobalTimeShift(var3);
      this.cooldownHandler.tick(var3);
      ObjectListIterator var4 = this.chainStartQueue.iterator();

      while (var4.hasNext()) {
         InteractionChain var5 = (InteractionChain)var4.next();
         this.executeChain0(var1, var5);
      }

      this.chainStartQueue.clear();
      Deque var11 = null;
      if (this.playerRef != null) {
         var11 = ((GamePacketHandler)this.playerRef.getPacketHandler()).getInteractionPacketQueue();
      }

      if (var11 != null && !var11.isEmpty()) {
         for (boolean var12 = true; this.tryConsumePacketQueue(var1, var11) || var12; var12 = false) {
            if (!this.chains.isEmpty()) {
               this.chains.values().removeIf(this.cachedTickChain);
            }

            float var6 = 0.0F;

            for (float var10 : this.globalTimeShift) {
               var6 = Math.max(var6, var10);
            }

            if (var6 > 0.0F) {
               this.cooldownHandler.tick(var6);
            }
         }

         this.commandBuffer = null;
      } else {
         if (!this.chains.isEmpty()) {
            this.chains.values().removeIf(this.cachedTickChain);
         }

         this.ref = null;
         this.commandBuffer = null;
      }
   }

   class="kw">private boolean tryConsumePacketQueue(@Nonnull Ref<EntityStore> var1, @Nonnull Deque<SyncInteractionChain> var2) {
      Iterator var3 = var2.iterator();
      boolean var4 = false;
      boolean var5 = false;
      int var6 = -1;
      boolean var7 = false;

      label116:
      while (var3.hasNext()) {
         SyncInteractionChain var8 = var3.next();
         if (var8.desync) {
            HytaleLogger.Api var9 = LOGGER.at(Level.FINE);
            if (var9.isEnabled()) {
               var9.log("Client packet flagged as desync");
            }

            var5 = true;
         }

         InteractionChain var16 = (InteractionChain)this.chains.get(var8.chainId);
         if (var16 != null && var8.forkedId != null) {
            for (ForkedChainId var10 = var8.forkedId; var10 != null; var10 = var10.forkedId) {
               InteractionChain var11 = var16.getForkedChain(var10);
               if (var11 == null) {
                  InteractionChain.TempChain var12 = var16.getTempForkedChain(var10);
                  if (var12 != null) {
                     var12.setBaseForkedChainId(var10);
                     ForkedChainId var13 = var10;

                     for (ForkedChainId var17 = var10.forkedId; var17 != null; var17 = var17.forkedId) {
                        var12 = var12.getOrCreateTempForkedChain(var17);
                        var12.setBaseForkedChainId(var17);
                        var13 = var17;
                     }

                     var12.setForkedChainId(var8.forkedId);
                     var12.setBaseForkedChainId(var13);
                     var12.setChainData(var8.data);
                     this.sync(var1, var12, var8);
                     var7 = true;
                     var3.remove();
                     this.packetQueueTime = 0L;
                  }
                  class="kw">continue label116;
               }

               var16 = var11;
            }
         }

         var6 = Math.max(var6, var8.chainId);
         boolean var18 = var8.data != null && !UUIDUtil.isEmptyOrNull(var8.data.proxyId);
         if (var16 == null && (!var4 || var18)) {
            if (this.syncStart(var1, var8)) {
               var7 = true;
               var3.remove();
               this.packetQueueTime = 0L;
            } else {
               if (!this.waitingForClient(var1)) {
                  long var20;
                  if (this.packetQueueTime == 0L) {
                     this.packetQueueTime = this.currentTime;
                     var20 = 0L;
                  } else {
                     var20 = this.currentTime - this.packetQueueTime;
                  }

                  HytaleLogger.Api var21 = LOGGER.at(Level.FINE);
                  if (var21.isEnabled()) {
                     var21.log("Queued chain %d for %s", var8.chainId, FormatUtil.nanosToString(var20));
                  }

                  if (var20 > TimeUnit.MILLISECONDS.toNanos(this.getOperationTimeoutThreshold())) {
                     this.sendCancelPacket(var8.chainId, var8.forkedId);
                     var3.remove();
                     var21 = LOGGER.at(Level.FINE);
                     if (var21.isEnabled()) {
                        var21.log("Discarding packet due to queuing for too long: %s", var8);
                     }
                  }
               }

               if (!var5 && !var18) {
                  var4 = true;
               }
            }
         } else if (var16 != null) {
            this.sync(var1, var16, var8);
            var7 = true;
            var3.remove();
            this.packetQueueTime = 0L;
         } else if (var5) {
            this.sendCancelPacket(var8.chainId, var8.forkedId);
            var3.remove();
            HytaleLogger.Api var19 = LOGGER.at(Level.FINE);
            var19.log("Discarding packet due to desync: %s", var8);
         }
      }

      if (var5 && !var2.isEmpty()) {
         HytaleLogger.Api var14 = LOGGER.at(Level.FINE);
         if (var14.isEnabled()) {
            var14.log("Discarding previous packets in queue: (before) %d", var2.size());
         }

         var2.removeIf(var1x -> {
            boolean var2 = this.getChain(var1x.chainId, var1x.forkedId) == null && UUIDUtil.isEmptyOrNull(var1x.data.proxyId) && var1x.initial;
            if (var2) {
               HytaleLogger.Api var3 = LOGGER.at(Level.FINE);
               if (var3.isEnabled()) {
                  var3.log("Discarding: %s", var1x);
               }

               this.sendCancelPacket(var1x.chainId, var1x.forkedId);
            }

            class="kw">return var2;
         });
         var14 = LOGGER.at(Level.FINE);
         if (var14.isEnabled()) {
            var14.log("Discarded previous packets in queue: (after) %d", var2.size());
         }
      }

      class="kw">return var7;
   }

   @Nullable
   class="kw">private InteractionChain getChain(int var1, @Nullable ForkedChainId var2) {
      InteractionChain var3 = (InteractionChain)this.chains.get(var1);
      if (var3 != null && var2 != null) {
         for (ForkedChainId var4 = var2; var4 != null; var4 = var4.forkedId) {
            InteractionChain var5 = var3.getForkedChain(var4);
            if (var5 == null) {
               class="kw">return null;
            }

            var3 = var5;
         }
      }

      class="kw">return var3;
   }

   class="kw">private boolean tickChain(@Nonnull InteractionChain var1) {
      if (var1.wasPreTicked()) {
         var1.setPreTicked(false);
         class="kw">return false;
      }

      if (this.ref != null && this.ref.isValid()) {
         if (!this.hasRemoteClient) {
            var1.updateSimulatedState();
         }

         var1.getForkedChains().values().removeIf(this.cachedTickChain);
         if (var1.getServerState() != InteractionState.NotFinished) {
            if (var1.requiresClient() && var1.getClientState() == InteractionState.NotFinished) {
               if (!this.waitingForClient(this.ref)) {
                  if (var1.getWaitingForClientFinished() == 0L) {
                     var1.setWaitingForClientFinished(this.currentTime);
                  }

                  long var9 = TimeUnit.NANOSECONDS.toMillis(this.currentTime - var1.getWaitingForClientFinished());
                  HytaleLogger.Api var4 = LOGGER.at(Level.FINE);
                  if (var4.isEnabled()) {
                     var4.log("Server finished chain but client hasn't! %d, %s, %s", var1.getChainId(), var1, var9);
                  }

                  long var12 = this.getOperationTimeoutThreshold();
                  TimeResource var7 = this.commandBuffer.getResource(TimeResource.getResourceType());
                  if (var7.getTimeDilationModifier() == 1.0F && var9 > var12) {
                     this.cancelChains(var1);
                     class="kw">return var1.getForkedChains().isEmpty();
                  }
               }

               class="kw">return false;
            } else {
               LOGGER.at(Level.FINE).log("Remove Chain: %d, %s", var1.getChainId(), var1);
               this.handleCancelledChain(this.ref, var1);
               var1.onCompletion(this.cooldownHandler, this.hasRemoteClient);
               class="kw">return var1.getForkedChains().isEmpty();
            }
         } else {
            int var2 = var1.getOperationIndex();

            try {
               this.doTickChain(this.ref, var1);
            } catch (InteractionManager.ChainCancelledException var8) {
               var1.setServerState(var8.state);
               var1.setClientState(var8.state);
               var1.updateServerState();
               if (!this.hasRemoteClient) {
                  var1.updateSimulatedState();
               }

               if (var1.requiresClient()) {
                  this.sendSyncPacket(var1, var2, this.tempSyncDataList);
                  this.sendCancelPacket(var1);
               }
            }

            if (var1.getServerState() != InteractionState.NotFinished) {
               HytaleLogger.Api var10 = LOGGER.at(Level.FINE);
               if (var10.isEnabled()) {
                  var10.log("Server finished chain: %d-%s, %s in %fs", var1.getChainId(), var1.getForkedChainId(), var1, var1.getTimeInSeconds());
               }

               if (!var1.requiresClient() || var1.getClientState() != InteractionState.NotFinished) {
                  var10 = LOGGER.at(Level.FINE);
                  if (var10.isEnabled()) {
                     var10.log("Remove Chain: %d-%s, %s", var1.getChainId(), var1.getForkedChainId(), var1);
                  }

                  this.handleCancelledChain(this.ref, var1);
                  var1.onCompletion(this.cooldownHandler, this.hasRemoteClient);
                  class="kw">return var1.getForkedChains().isEmpty();
               }
            } else if (var1.getClientState() != InteractionState.NotFinished && !this.waitingForClient(this.ref)) {
               if (var1.getWaitingForServerFinished() == 0L) {
                  var1.setWaitingForServerFinished(this.currentTime);
               }

               long var3 = TimeUnit.NANOSECONDS.toMillis(this.currentTime - var1.getWaitingForServerFinished());
               HytaleLogger.Api var5 = LOGGER.at(Level.FINE);
               if (var5.isEnabled()) {
                  var5.log("Client finished chain but server hasn't! %d, %s, %s", var1.getChainId(), var1, var3);
               }

               long var6 = this.getOperationTimeoutThreshold();
               if (var3 > var6) {
                  LOGGER.at(Level.FINE).log("Client finished chain earlier than server! %d, %s", var1.getChainId(), var1);
                  this.cancelChains(var1);
               }
            }

            class="kw">return false;
         }
      } else {
         throw new IllegalStateException("Entity ref was null or invalid during chain tick!");
      }
   }

   class="kw">private void handleCancelledChain(@Nonnull Ref<EntityStore> var1, @Nonnull InteractionChain var2) {
      assert this.commandBuffer != null;
      RootInteraction var3 = var2.getRootInteraction();
      int var4 = var3.getOperationMax();
      if (var2.getOperationCounter() < var4) {
         InteractionEntry var5 = var2.getInteraction(var2.getOperationIndex());
         if (var5 != null) {
            Operation var6 = var3.getOperation(var2.getOperationCounter());
            if (var6 == null) {
               throw new IllegalStateException("Failed to find operation during simulation tick of chain '" + var3.getId() + "'");
            }

            InteractionContext var7 = var2.getContext();
            var5.getServerState().state = InteractionState.Failed;
            if (var5.getClientState() != null) {
               var5.getClientState().state = InteractionState.Failed;
            }

            try {
               var7.initEntry(var2, var5, var1);
               TimeResource var8 = this.commandBuffer.getResource(TimeResource.getResourceType());
               var6.handle(var1, false, var5.getTimeInSeconds(this.currentTime) * var8.getTimeDilationModifier(), var2.getType(), var7);
            } class="kw">finally {
               var7.deinitEntry(var2, var5, var1);
            }

            var2.setOperationCounter(var4);
         }
      }
   }

   class="kw">private void doTickChain(@Nonnull Ref<EntityStore> var1, @Nonnull InteractionChain var2) {
      ObjectList var3 = this.tempSyncDataList;
      var3.clear();
      RootInteraction var4 = var2.getRootInteraction();
      int var5 = var4.getOperationMax();
      int var6 = var2.getOperationCounter();
      int var7 = var2.getOperationIndex();
      int var8 = var2.getCallDepth();
      if (var2.consumeFirstRun()) {
         if (var2.getForkedChainId() == null) {
            var2.setTimeShift(this.getGlobalTimeShift(var2.getType()));
         } else {
            InteractionChain var9 = (InteractionChain)this.chains.get(var2.getChainId());
            var2.setFirstRun(var9 != null && var9.isFirstRun());
         }
      } else {
         var2.setTimeShift(0.0F);
      }

      if (!var2.getContext().getEntity().isValid()) {
         throw new InteractionManager.ChainCancelledException(var2.getServerState());
      }

      while (true) {
         if (var6 >= var5) {
            while (var8 > 0 && var6 >= var5) {
               var2.popRoot();
               var8 = var2.getCallDepth();
               var6 = var2.getOperationCounter();
               var4 = var2.getRootInteraction();
               var5 = var4.getOperationMax();
            }

            if (var8 == 0 && var6 >= var5) {
               break;
            }
         }

         Operation var13 = !this.hasRemoteClient ? var4.getOperation(var2.getSimulatedOperationCounter()) : null;
         WaitForDataFrom var10 = var13 != null ? var13.getWaitForDataFrom() : null;
         long var11 = this.currentTime;
         if (!this.hasRemoteClient && var10 != WaitForDataFrom.Server) {
            this.simulationTick(var1, var2, var11);
         }

         var3.add(this.serverTick(var1, var2, var11));
         if (!var2.getContext().getEntity().isValid() && var2.getServerState() != InteractionState.Finished && var2.getServerState() != InteractionState.Failed
            )
          {
            throw new InteractionManager.ChainCancelledException(var2.getServerState());
         }

         if (!this.hasRemoteClient && var10 == WaitForDataFrom.Server) {
            this.simulationTick(var1, var2, var11);
         }

         if (!this.hasRemoteClient) {
            if (var2.getRootInteraction() != var2.getSimulatedRootInteraction()) {
               throw new IllegalStateException(
                  "Simulation and server tick are not in sync (root interaction).\n"
                     + var2.getRootInteraction().getId()
                     + " vs "
                     + var2.getSimulatedRootInteraction()
               );
            }

            if (var2.getOperationCounter() != var2.getSimulatedOperationCounter()) {
               throw new IllegalStateException(
                  "Simulation and server tick are not in sync (operation position).\nRoot: "
                     + var2.getRootInteraction().getId()
                     + "\nCounter: "
                     + var2.getOperationCounter()
                     + " vs "
                     + var2.getSimulatedOperationCounter()
                     + "\nIndex: "
                     + var2.getOperationIndex()
               );
            }
         }

         if (var8 != var2.getCallDepth()) {
            var8 = var2.getCallDepth();
            var4 = var2.getRootInteraction();
            var5 = var4.getOperationMax();
         } else if (var6 == var2.getOperationCounter()) {
            break;
         }

         var2.nextOperationIndex();
         var6 = var2.getOperationCounter();
         if (var6 >= var5) {
            while (var8 > 0) {
               var2.popRoot();
               var8 = var2.getCallDepth();
               var6 = var2.getOperationCounter();
               var4 = var2.getRootInteraction();
               var5 = var4.getOperationMax();
               if (var6 < var5 || var8 == 0) {
                  break;
               }
            }

            if (var8 == 0 && var6 >= var5) {
               break;
            }
         }
      }

      var2.updateServerState();
      if (!this.hasRemoteClient) {
         var2.updateSimulatedState();
      }

      if (var2.requiresClient()) {
         this.sendSyncPacket(var2, var7, var3);
      }
   }

   @Nullable
   class="kw">private InteractionSyncData serverTick(@Nonnull Ref<EntityStore> var1, @Nonnull InteractionChain var2, long var3) {
      assert this.commandBuffer != null;
      RootInteraction var5 = var2.getRootInteraction();
      Operation var6 = var5.getOperation(var2.getOperationCounter());
      assert var6 != null;
      InteractionEntry var7 = var2.getOrCreateInteractionEntry(var2.getOperationIndex());
      InteractionSyncData var8 = null;
      boolean var9 = var7.consumeDesyncFlag();
      if (var7.getClientState() == null) {
         var9 |= !var7.setClientState(var2.removeInteractionSyncData(var2.getOperationIndex()));
      }

      if (var9) {
         var8 = var7.getServerState();
         var2.flagDesync();
         var2.clearInteractionSyncData(var2.getOperationIndex());
      }

      TimeResource var10 = this.commandBuffer.getResource(TimeResource.getResourceType());
      float var11 = var10.getTimeDilationModifier();
      if (var6.getWaitForDataFrom() != WaitForDataFrom.Client || var7.getClientState() != null) {
         int var25 = var7.getServerDataHashCode();
         InteractionContext var13 = var2.getContext();
         float var26 = var7.getTimeInSeconds(var3);
         boolean var28 = false;
         if (var7.getTimestamp() == 0L) {
            var26 = var2.getTimeShift();
            var7.setTimestamp(var3, var26);
            var28 = true;
         }

         var26 *= var11;

         try {
            var13.initEntry(var2, var7, var1);
            var6.tick(var1, var28, var26, var2.getType(), var13, this.cooldownHandler);
         } class="kw">finally {
            var13.deinitEntry(var2, var7, var1);
         }

         InteractionSyncData var16 = var7.getServerState();
         if (var28 || var25 != var7.getServerDataHashCode()) {
            var8 = var16;
         }

         try {
            var13.initEntry(var2, var7, var1);
            var6.handle(var1, var28, var26, var2.getType(), var13);
         } class="kw">finally {
            var13.deinitEntry(var2, var7, var1);
         }

         this.removeInteractionIfFinished(var1, var2, var7);
         class="kw">return var8;
      } else {
         if (this.waitingForClient(var1)) {
            class="kw">return null;
         }

         if (var7.getWaitingForSyncData() == 0L) {
            var7.setWaitingForSyncData(this.currentTime);
         }

         long var12 = TimeUnit.NANOSECONDS.toMillis(this.currentTime - var7.getWaitingForSyncData());
         HytaleLogger.Api var14 = LOGGER.at(Level.FINE);
         if (var14.isEnabled()) {
            var14.log("Wait for interaction clientData: %d, %s, %s", var2.getOperationIndex(), var7, var12);
         }

         long var15 = this.getOperationTimeoutThreshold();
         if (var11 == 1.0F && var12 > var15) {
            ((HytaleLogger.Api)LOGGER.atWarning()).log("Client failed to send client data, ending early to prevent desync.");
            var2.setServerState(InteractionState.Failed);
            var2.setClientState(InteractionState.Failed);
            this.cancelChains(var2);
            class="kw">return null;
         }

         if (var7.consumeSendInitial() || var9) {
            var8 = var7.getServerState();
         }

         class="kw">return var8;
      }
   }

   class="kw">private void removeInteractionIfFinished(@Nonnull Ref<EntityStore> var1, @Nonnull InteractionChain var2, @Nonnull InteractionEntry var3) {
      if (var2.getOperationIndex() == var3.getIndex() && var3.getServerState().state != InteractionState.NotFinished) {
         var2.setFinalState(var3.getServerState().state);
      }

      if (var3.getServerState().state != InteractionState.NotFinished) {
         LOGGER.at(Level.FINE).log("Server finished interaction: %d, %s", var3.getIndex(), var3);
         if (!var2.requiresClient() || var3.getClientState() != null && var3.getClientState().state != InteractionState.NotFinished) {
            LOGGER.at(Level.FINER).log("Remove Interaction: %d, %s", var3.getIndex(), var3);
            var2.removeInteractionEntry(this, var3.getIndex());
         }
      } else if (var3.getClientState() != null && var3.getClientState().state != InteractionState.NotFinished && !this.waitingForClient(var1)) {
         if (var3.getWaitingForServerFinished() == 0L) {
            var3.setWaitingForServerFinished(this.currentTime);
         }

         long var4 = TimeUnit.NANOSECONDS.toMillis(this.currentTime - var3.getWaitingForServerFinished());
         HytaleLogger.Api var6 = LOGGER.at(Level.FINE);
         if (var6.isEnabled()) {
            var6.log("Client finished interaction but server hasn't! %s, %d, %s, %s", var3.getClientState().state, var3.getIndex(), var3, var4);
         }

         long var7 = this.getOperationTimeoutThreshold();
         if (var4 > var7) {
            HytaleLogger.Api var9 = LOGGER.at(Level.FINE);
            if (var9.isEnabled()) {
               var9.log("Client finished interaction earlier than server! %d, %s", var3.getIndex(), var3);
            }

            this.cancelChains(var2);
         }
      }
   }

   class="kw">private void simulationTick(@Nonnull Ref<EntityStore> var1, @Nonnull InteractionChain var2, long var3) {
      assert this.commandBuffer != null;
      RootInteraction var5 = var2.getRootInteraction();
      Operation var6 = var5.getOperation(var2.getSimulatedOperationCounter());
      if (var6 == null) {
         throw new IllegalStateException("Failed to find operation during simulation tick of chain '" + var5.getId() + "'");
      }

      InteractionEntry var7 = var2.getOrCreateInteractionEntry(var2.getClientOperationIndex());
      InteractionContext var8 = var2.getContext();
      var7.setUseSimulationState(true);

      try {
         var8.initEntry(var2, var7, var1);
         float var9 = var7.getTimeInSeconds(var3);
         boolean var10 = false;
         if (var7.getTimestamp() == 0L) {
            var9 = var2.getTimeShift();
            var7.setTimestamp(var3, var9);
            var10 = true;
         }

         TimeResource var11 = this.commandBuffer.getResource(TimeResource.getResourceType());
         float var12 = var11.getTimeDilationModifier();
         var9 *= var12;
         var6.simulateTick(var1, var10, var9, var2.getType(), var8, this.cooldownHandler);
      } class="kw">finally {
         var8.deinitEntry(var2, var7, var1);
         var7.setUseSimulationState(false);
      }

      if (!var7.setClientState(var7.getSimulationState())) {
         throw new RuntimeException("Simulation failed");
      }

      this.removeInteractionIfFinished(var1, var2, var7);
   }

   class="kw">private boolean syncStart(@Nonnull Ref<EntityStore> var1, @Nonnull SyncInteractionChain var2) {
      assert this.commandBuffer != null;
      int var3 = var2.chainId;
      if (!var2.initial) {
         if (var2.forkedId == null) {
            HytaleLogger.Api var29 = LOGGER.at(Level.FINE);
            if (var29.isEnabled()) {
               var29.log("Got syncStart for %d-%s but packet wasn't the first.", var3, var2.forkedId);
            }

            this.sendCancelPacket(var3, var2.forkedId);
         }

         class="kw">return true;
      } else if (var2.forkedId != null) {
         HytaleLogger.Api var28 = LOGGER.at(Level.FINE);
         if (var28.isEnabled()) {
            var28.log("Can't start a forked chain from the client: %d %s", var3, var2.forkedId);
         }

         this.sendCancelPacket(var3, var2.forkedId);
         class="kw">return true;
      } else {
         InteractionType var4 = var2.interactionType;
         if (var3 <= 0) {
            HytaleLogger.Api var31 = LOGGER.at(Level.FINE);
            if (var31.isEnabled()) {
               var31.log("Invalid client chainId! Got %d but client id's should be > 0", var3);
            }

            this.sendCancelPacket(var3, var2.forkedId);
            class="kw">return true;
         } else if (var3 <= this.lastClientChainId) {
            HytaleLogger.Api var30 = LOGGER.at(Level.FINE);
            if (var30.isEnabled()) {
               var30.log("Invalid client chainId! The last clientChainId was %d but just got %d", this.lastClientChainId, var3);
            }

            this.sendCancelPacket(var3, var2.forkedId);
            class="kw">return true;
         } else {
            InteractionContext var5;
            if (var2.data != null && !UUIDUtil.isEmptyOrNull(var2.data.proxyId)) {
               UUID var6 = var2.data.proxyId;
               World var7 = this.commandBuffer.getExternalData().getWorld();
               Ref var8 = var7.getEntityStore().getRefFromUUID(var6);
               if (var8 == null) {
                  if (this.packetQueueTime != 0L
                     && this.currentTime - this.packetQueueTime > TimeUnit.MILLISECONDS.toNanos(this.getOperationTimeoutThreshold()) / 2L) {
                     HytaleLogger.Api var36 = LOGGER.at(Level.FINE);
                     if (var36.isEnabled()) {
                        var36.log("Proxy entity never spawned");
                     }

                     this.sendCancelPacket(var3, var2.forkedId);
                     class="kw">return true;
                  }

                  class="kw">return false;
               }

               if (!InteractionValidation.isAccessibleProxyTarget(var1, var8, var4)) {
                  LOGGER.at(Level.WARNING).log("%s cannot access entity %s as interaction proxy", EntityUtils.getEntityName(var1, this.commandBuffer), var6);
                  this.sendCancelPacket(var3, var2.forkedId);
                  class="kw">return true;
               }

               var5 = InteractionContext.forProxyEntity(this, var1, var8, this.commandBuffer);
            } else {
               var5 = InteractionContext.forInteraction(this, var1, var4, var2.equipSlot, this.commandBuffer);
            }

            String var32 = var5.getRootInteractionId(var4);
            if (var32 == null) {
               HytaleLogger.Api var34 = LOGGER.at(Level.FINE);
               if (var34.isEnabled()) {
                  var34.log("Missing root interaction: %d, %s, %s", var3, InventoryComponent.getItemInHand(this.commandBuffer, var1), var4);
               }

               this.sendCancelPacket(var3, var2.forkedId);
               class="kw">return true;
            } else {
               RootInteraction var33 = RootInteraction.getRootInteractionOrUnknown(var32);
               if (var33 == null) {
                  class="kw">return false;
               }

               if (var33.getOperationMax() == 0) {
                  ((HytaleLogger.Api)LOGGER.atWarning()).log("Root interaction '%s' has no operations, cancelling chain %d (%s)", var32, var3, var4);
                  this.sendCancelPacket(var3, var2.forkedId);
                  class="kw">return true;
               }

               if (!this.applyRules(var5, var2.data, var4, var33)) {
                  class="kw">return false;
               }

               InventoryComponent.Hotbar var35 = this.commandBuffer.getComponent(var1, InventoryComponent.Hotbar.getComponentType());
               if (var35 == null) {
                  class="kw">return false;
               }

               InventoryComponent.Utility var9 = this.commandBuffer.getComponent(var1, InventoryComponent.Utility.getComponentType());
               if (var9 == null) {
                  class="kw">return false;
               }

               ItemStack var10 = var35.getActiveItem();
               ItemStack var11 = var9.getActiveItem();
               String var12 = var10 != null ? var10.getItemId() : null;
               String var13 = var11 != null ? var11.getItemId() : null;
               byte var14 = var35.getActiveSlot();
               byte var15 = var9.getActiveSlot();
               if (var2.activeHotbarSlot != var14) {
                  HytaleLogger.Api var40 = LOGGER.at(Level.FINE);
                  if (var40.isEnabled()) {
                     var40.log("Active slot miss match: %d, %d != %d, %s, %s, %s", var3, var14, var2.activeHotbarSlot, var12, var2.itemInHandId, var4);
                  }

                  this.sendCancelPacket(var3, var2.forkedId);
                  if (this.playerRef != null) {
                     this.playerRef.getPacketHandler().writeNoCache(new SetActiveSlot(-1, var14));
                  }

                  class="kw">return true;
               } else if (var2.activeUtilitySlot != var15) {
                  HytaleLogger.Api var39 = LOGGER.at(Level.FINE);
                  if (var39.isEnabled()) {
                     var39.log("Active slot miss match: %d, %d != %d, %s, %s, %s", var3, var15, var2.activeUtilitySlot, var12, var2.itemInHandId, var4);
                  }

                  this.sendCancelPacket(var3, var2.forkedId);
                  if (this.playerRef != null) {
                     this.playerRef.getPacketHandler().writeNoCache(new SetActiveSlot(-5, var15));
                  }

                  class="kw">return true;
               } else if (!Objects.equals(var12, var2.itemInHandId)) {
                  HytaleLogger.Api var38 = LOGGER.at(Level.FINE);
                  if (var38.isEnabled()) {
                     var38.log("ItemInHand miss match: %d, %s, %s, %s", var3, var12, var2.itemInHandId, var4);
                  }

                  this.sendCancelPacket(var3, var2.forkedId);
                  class="kw">return true;
               } else if (!Objects.equals(var13, var2.utilityItemId)) {
                  HytaleLogger.Api var37 = LOGGER.at(Level.FINE);
                  if (var37.isEnabled()) {
                     var37.log("UtilityItem miss match: %d, %s, %s, %s", var3, var13, var2.utilityItemId, var4);
                  }

                  this.sendCancelPacket(var3, var2.forkedId);
                  class="kw">return true;
               } else {
                  if (this.isOnCooldown(var1, var4, var33, true)) {
                     class="kw">return false;
                  }

                  InteractionChain var16 = this.initChain(var2.data, var4, var5, var33, null, true);
                  var16.setChainId(var3);
                  this.sync(var1, var16, var2);
                  World var17 = this.commandBuffer.getExternalData().getWorld();
                  if (var2.data.blockPosition != null) {
                     ChunkStore var18 = var17.getChunkStore();
                     BlockPosition var19 = var2.data.blockPosition;
                     Ref var20 = var18.getChunkSectionReferenceAtBlock(var19.x, var19.y, var19.z);
                     if (var20 == null || !var20.isValid()) {
                        HytaleLogger.Api var44 = LOGGER.at(Level.FINE);
                        if (var44.isEnabled()) {
                           var44.log("Unloaded section interacted with: %d, %s", var3, var4);
                        }

                        this.sendCancelPacket(var3, var2.forkedId);
                        class="kw">return true;
                     }

                     BlockSection var21 = var18.getStore().getComponent(var20, BlockSection.getComponentType());
                     if (var21 == null) {
                        HytaleLogger.Api var45 = LOGGER.at(Level.FINE);
                        if (var45.isEnabled()) {
                           var45.log("Unloaded section interacted with: %d, %s", var3, var4);
                        }

                        this.sendCancelPacket(var3, var2.forkedId);
                        class="kw">return true;
                     }

                     int var22 = var21.getFiller(var19.x, var19.y, var19.z);
                     if (var22 != 0) {
                        var19 = new BlockPosition(
                           var19.x - FillerBlockUtil.unpackX(var22), var19.y - FillerBlockUtil.unpackY(var22), var19.z - FillerBlockUtil.unpackZ(var22)
                        );
                     }

                     var5.getMetaStore().putMetaObject(Interaction.TARGET_BLOCK, var19);
                     var5.getMetaStore().putMetaObject(Interaction.TARGET_BLOCK_RAW, var2.data.blockPosition);
                     if (!var2.data.blockPosition.equals(var19)) {
                        BlockSection var24 = var21;
                        if (!ChunkUtil.isSameChunkSection(
                           var19.x, var19.y, var19.z, var2.data.blockPosition.x, var2.data.blockPosition.y, var2.data.blockPosition.z
                        )) {
                           Ref var23 = var18.getChunkSectionReferenceAtBlock(var19.x, var19.y, var19.z);
                           if (var23 == null || !var23.isValid()) {
                              HytaleLogger.Api var47 = LOGGER.at(Level.FINE);
                              if (var47.isEnabled()) {
                                 var47.log("Unloaded section interacted with: %d, %s", var3, var4);
                              }

                              this.sendCancelPacket(var3, var2.forkedId);
                              class="kw">return true;
                           }

                           var24 = var18.getStore().getComponent(var23, BlockSection.getComponentType());
                           if (var24 == null) {
                              HytaleLogger.Api var46 = LOGGER.at(Level.FINE);
                              if (var46.isEnabled()) {
                                 var46.log("Unloaded section interacted with: %d, %s", var3, var4);
                              }

                              this.sendCancelPacket(var3, var2.forkedId);
                              class="kw">return true;
                           }
                        }

                        int var25 = var24.get(var19.x, var19.y, var19.z);
                        int var26 = var21.get(var2.data.blockPosition.x, var2.data.blockPosition.y, var2.data.blockPosition.z);
                        if (var25 != var26) {
                           int var27 = 1036;
                           if (var25 != 0) {
                              var27 |= 16;
                           }

                           BlockOperations.setBlock(
                              var18, var20, var2.data.blockPosition.x, var2.data.blockPosition.y, var2.data.blockPosition.z, 0, BlockType.EMPTY, 0, 0, var27
                           );
                        }
                     }
                  }

                  if (var2.data.entityId >= 0) {
                     EntityStore var41 = var17.getEntityStore();
                     Ref var43 = var41.getRefFromNetworkId(var2.data.entityId);
                     if (var43 != null) {
                        var5.getMetaStore().putMetaObject(Interaction.TARGET_ENTITY, var43);
                     }
                  }

                  if (var2.data.targetSlot != Integer.MIN_VALUE) {
                     var5.getMetaStore().putMetaObject(Interaction.TARGET_SLOT, var2.data.targetSlot);
                  }

                  if (var2.data.hitLocation != null) {
                     Vector3fc var42 = var2.data.hitLocation;
                     var5.getMetaStore().putMetaObject(Interaction.HIT_LOCATION, new Vector4d(var42.x(), var42.y(), var42.z(), 1.0));
                  }

                  if (var2.data.hitDetail != null) {
                     var5.getMetaStore().putMetaObject(Interaction.HIT_DETAIL, var2.data.hitDetail);
                  }

                  this.lastClientChainId = var3;
                  if (!this.tickChain(var16)) {
                     var16.setPreTicked(true);
                     this.chains.put(var3, var16);
                  }

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

   class="kw">public void sync(@Nonnull Ref<EntityStore> var1, @Nonnull ChainSyncStorage var2, @Nonnull SyncInteractionChain var3) {
      assert this.commandBuffer != null;
      if (var3.newForks != null) {
         for (SyncInteractionChain var7 : var3.newForks) {
            var2.syncFork(var1, this, var7);
         }
      }

      if (var3.interactionData == null) {
         var2.setClientState(var3.state);
      } else {
         for (int var12 = 0; var12 < var3.interactionData.length; var12++) {
            InteractionSyncData var14 = var3.interactionData[var12];
            if (var14 != null) {
               int var15 = var3.operationBaseIndex + var12;
               if (!var2.isSyncDataOutOfOrder(var15)) {
                  InteractionEntry var16 = var2.getInteraction(var15);
                  if (var16 != null && var2 class="kw">instanceof InteractionChain var8) {
                     if (var16.getClientState() != null
                           && var16.getClientState().state != InteractionState.NotFinished
                           && var14.state == InteractionState.NotFinished
                        || !var16.setClientState(var14)) {
                        var2.clearInteractionSyncData(var15);
                        var16.flagDesync();
                        var8.flagDesync();
                        class="kw">return;
                     }

                     var2.updateSyncPosition(var15);
                     HytaleLogger.Api var9 = LOGGER.at(Level.FINEST);
                     if (var9.isEnabled()) {
                        TimeResource var10 = this.commandBuffer.getResource(TimeResource.getResourceType());
                        float var11 = var10.getTimeDilationModifier();
                        var9.log(
                           "%d, %d: Time (Sync) - Server: %s vs Client: %s",
                           var3.chainId,
                           var15,
                           var16.getTimeInSeconds(this.currentTime) * var11,
                           var16.getClientState().progress
                        );
                     }

                     this.removeInteractionIfFinished(var1, var8, var16);
                  } else {
                     var2.putInteractionSyncData(var15, var14);
                  }
               }
            }
         }

         int var13 = var3.operationBaseIndex + var3.interactionData.length;
         var2.clearInteractionSyncData(var13);
         var2.setClientState(var3.state);
      }
   }

   class="kw">public boolean canRun(@Nonnull InteractionType var1, @Nonnull RootInteraction var2) {
      class="kw">return this.canRun(var1, (short)-1, var2);
   }

   class="kw">public boolean canRun(@Nonnull InteractionType var1, short var2, @Nonnull RootInteraction var3) {
      class="kw">return applyRules(null, var1, var2, var3, this.chains, null);
   }

   class="kw">public boolean applyRules(@Nonnull InteractionContext var1, @Nonnull InteractionChainData var2, @Nonnull InteractionType var3, @Nonnull RootInteraction var4) {
      List var5 = new ObjectArrayList();
      if (!applyRules(var2, var3, var1.getHeldItemSlot(), var4, this.chains, var5)) {
         class="kw">return false;
      }

      for (InteractionChain var7 : var5) {
         this.cancelChains(var7);
      }

      class="kw">return true;
   }

   class="kw">public void cancelChains(@Nonnull InteractionChain var1) {
      var1.setServerState(InteractionState.Failed);
      var1.setClientState(InteractionState.Failed);
      this.sendCancelPacket(var1);
      ObjectIterator var2 = var1.getForkedChains().values().iterator();

      while (var2.hasNext()) {
         InteractionChain var3 = (InteractionChain)var2.next();
         this.cancelChains(var3);
      }
   }

   class="kw">private class="kw">static boolean applyRules(
      @Nullable InteractionChainData var0,
      @Nonnull InteractionType var1,
      int var2,
      @Nullable RootInteraction var3,
      @Nonnull Map<?, InteractionChain> var4,
      @Nullable List<InteractionChain> var5
   ) {
      if (!var4.isEmpty() && var3 != null) {
         for (InteractionChain var7 : var4.values()) {
            if ((var7.getForkedChainId() == null || var7.isPredicted())
               && (var0 == null || Objects.equals(var7.getChainData().proxyId, var0.proxyId))
               && (var1 != InteractionType.Equipped || var7.getType() != InteractionType.Equipped || var7.getContext().getHeldItemSlot() == var2)) {
               if (var7.getServerState() == InteractionState.NotFinished) {
                  RootInteraction var8 = var7.getRootInteraction();
                  Operation var9 = var8.getOperation(var7.getOperationCounter());
                  if (var3.getRules().validateInterrupts(var1, var3.getData().getTags(), var7.getType(), var8.getData().getTags(), var8.getRules())) {
                     if (var5 != null) {
                        var5.add(var7);
                     }
                  } else if (var9 != null
                     && var9.getRules() != null
                     && var3.getRules().validateInterrupts(var1, var3.getData().getTags(), var7.getType(), var9.getTags(), var9.getRules())) {
                     if (var5 != null) {
                        var5.add(var7);
                     }
                  } else {
                     if (var3.getRules().validateBlocked(var1, var3.getData().getTags(), var7.getType(), var8.getData().getTags(), var8.getRules())) {
                        class="kw">return false;
                     }

                     if (var9 != null
                        && var9.getRules() != null
                        && var3.getRules().validateBlocked(var1, var3.getData().getTags(), var7.getType(), var9.getTags(), var9.getRules())) {
                        class="kw">return false;
                     }
                  }
               }

               if ((var5 == null || var5.isEmpty()) && !applyRules(var0, var1, var2, var3, var7.getForkedChains(), var5)) {
                  class="kw">return false;
               }
            }
         }

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

   class="kw">public boolean tryStartChain(
      @Nonnull Ref<EntityStore> var1,
      @Nonnull CommandBuffer<EntityStore> var2,
      @Nonnull InteractionType var3,
      @Nonnull InteractionContext var4,
      @Nonnull RootInteraction var5
   ) {
      InteractionChain var6 = this.initChain(var3, var4, var5, false);
      if (!this.applyRules(var4, var6.getChainData(), var3, var5)) {
         class="kw">return false;
      }

      this.executeChain(var1, var2, var6);
      class="kw">return true;
   }

   class="kw">public void startChain(
      @Nonnull Ref<EntityStore> var1,
      @Nonnull CommandBuffer<EntityStore> var2,
      @Nonnull InteractionType var3,
      @Nonnull InteractionContext var4,
      @Nonnull RootInteraction var5
   ) {
      InteractionChain var6 = this.initChain(var3, var4, var5, false);
      this.executeChain(var1, var2, var6);
   }

   @Nonnull
   class="kw">public InteractionChain initChain(@Nonnull InteractionType var1, @Nonnull InteractionContext var2, @Nonnull RootInteraction var3, boolean var4) {
      class="kw">return this.initChain(var1, var2, var3, -1, null, var4);
   }

   @Nonnull
   class="kw">public InteractionChain initChain(
      @Nonnull InteractionType var1, @Nonnull InteractionContext var2, @Nonnull RootInteraction var3, int var4, @Nullable BlockPosition var5, boolean var6
   ) {
      InteractionChainData var7 = new InteractionChainData(var4, UUIDUtil.EMPTY_UUID, null, null, var5, Integer.MIN_VALUE, null);
      class="kw">return this.initChain(var7, var1, var2, var3, null, var6);
   }

   @Nonnull
   class="kw">public InteractionChain initChain(
      @Nonnull InteractionChainData var1,
      @Nonnull InteractionType var2,
      @Nonnull InteractionContext var3,
      @Nonnull RootInteraction var4,
      @Nullable Runnable var5,
      boolean var6
   ) {
      class="kw">return new InteractionChain(var2, var3, var1, var4, var5, var6 || !this.hasRemoteClient);
   }

   class="kw">public void queueExecuteChain(@Nonnull InteractionChain var1) {
      this.chainStartQueue.add(var1);
   }

   class="kw">public void executeChain(@Nonnull Ref<EntityStore> var1, @Nonnull CommandBuffer<EntityStore> var2, @Nonnull InteractionChain var3) {
      this.commandBuffer = var2;
      this.ref = var1;
      this.executeChain0(var1, var3);
      this.ref = null;
      this.commandBuffer = null;
   }

   class="kw">private void executeChain0(@Nonnull Ref<EntityStore> var1, @Nonnull InteractionChain var2) {
      if (this.isOnCooldown(var1, var2.getType(), var2.getInitialRootInteraction(), false)) {
         var2.setServerState(InteractionState.Failed);
         var2.setClientState(InteractionState.Failed);
      } else {
         int var3 = --this.lastServerChainId;
         if (var3 >= 0) {
            var3 = this.lastServerChainId = -1;
         }

         var2.setChainId(var3);
         if (!this.tickChain(var2)) {
            LOGGER.at(Level.FINE).log("Add Chain: %d, %s", var3, var2);
            var2.setPreTicked(true);
            this.chains.put(var3, var2);
         }
      }
   }

   class="kw">private boolean isOnCooldown(@Nonnull Ref<EntityStore> var1, @Nonnull InteractionType var2, @Nonnull RootInteraction var3, boolean var4) {
      assert this.commandBuffer != null;
      InteractionCooldown var5 = var3.getCooldown();
      String var6 = var3.getId();
      float var7 = InteractionTypeUtils.getDefaultCooldown(var2);
      float[] var8 = DEFAULT_CHARGE_TIMES;
      boolean var9 = false;
      if (var5 != null) {
         var7 = var5.cooldown;
         if (var5.chargeTimes != null && var5.chargeTimes.length > 0) {
            var8 = var5.chargeTimes;
         }

         if (var5.cooldownId != null) {
            var6 = var5.cooldownId;
         }

         if (var5.interruptRecharge) {
            var9 = true;
         }

         if (var5.clickBypass && var4) {
            this.cooldownHandler.resetCooldown(var6, var7, var8, var9);
            class="kw">return false;
         }
      }

      Player var10 = this.commandBuffer.getComponent(var1, Player.getComponentType());
      GameMode var11 = var10 != null ? var10.getGameMode() : GameMode.Adventure;
      RootInteractionSettings var12 = var3.getSettings().get(var11);
      if (var12 != null) {
         var5 = var12.cooldown;
         if (var5 != null) {
            var7 = var5.cooldown;
            if (var5.chargeTimes != null && var5.chargeTimes.length > 0) {
               var8 = var5.chargeTimes;
            }

            if (var5.cooldownId != null) {
               var6 = var5.cooldownId;
            }

            if (var5.interruptRecharge) {
               var9 = true;
            }

            if (var5.clickBypass && var4) {
               this.cooldownHandler.resetCooldown(var6, var7, var8, var9);
               class="kw">return false;
            }
         }

         if (var12.allowSkipChainOnClick && var4) {
            this.cooldownHandler.resetCooldown(var6, var7, var8, var9);
            class="kw">return false;
         }
      }

      class="kw">return this.cooldownHandler.isOnCooldown(var3, var6, var7, var8, var9);
   }

   class="kw">public void tryRunHeldInteraction(@Nonnull Ref<EntityStore> var1, @Nonnull CommandBuffer<EntityStore> var2, @Nonnull InteractionType var3) {
      this.tryRunHeldInteraction(var1, var2, var3, (short)-1);
   }

   class="kw">public void tryRunHeldInteraction(@Nonnull Ref<EntityStore> var1, @Nonnull CommandBuffer<EntityStore> var2, @Nonnull InteractionType var3, short var4) {
      ItemStack var5 = null;

      var5 = class="kw">switch (var3) {
         case Held -> InventoryComponent.getItemInHand(var2, var1);
         case HeldOffhand -> {
            InventoryComponent.Utility var9 = var2.getComponent(var1, InventoryComponent.Utility.getComponentType());
            if (var9 != null) {
               yield var9.getActiveItem();
            }
         }
         case Equipped -> {
            if (var4 == -1) {
               throw new IllegalArgumentException();
            }

            InventoryComponent.Armor var6 = var2.getComponent(var1, InventoryComponent.Armor.getComponentType());
            if (var6 != null) {
               yield var6.getInventory().getItemStack(var4);
            }
         }
         class="kw">default -> throw new IllegalArgumentException();
      };
      if (var5 != null && !var5.isEmpty()) {
         String var10 = var5.getItem().getInteractions().get(var3);
         if (var10 != null) {
            RootInteraction var7 = RootInteraction.getAssetMap().getAsset(var10);
            if (var7 != null && this.canRun(var3, var4, var7)) {
               InteractionContext var8 = InteractionContext.forInteraction(this, var1, var3, var4, var2);
               this.startChain(var1, var2, var3, var8, var7);
            }
         }
      }
   }

   class="kw">public void sendSyncPacket(@Nonnull InteractionChain var1, int var2, @Nullable List<InteractionSyncData> var3) {
      if (!var1.hasSentInitial() || var3 != null && !ListUtil.emptyOrAllNull(var3) || !var1.getNewForks().isEmpty()) {
         if (this.playerRef != null) {
            SyncInteractionChain var4 = makeSyncPacket(var1, var2, var3);
            this.syncPackets.add(var4);
         }
      }
   }

   @Nonnull
   class="kw">private class="kw">static SyncInteractionChain makeSyncPacket(@Nonnull InteractionChain var0, int var1, @Nullable List<InteractionSyncData> var2) {
      SyncInteractionChain[] var3 = null;
      List var4 = var0.getNewForks();
      if (!var4.isEmpty()) {
         var3 = new SyncInteractionChain[var4.size()];

         for (int var5 = 0; var5 < var4.size(); var5++) {
            InteractionChain var6 = var4.get(var5);
            var3[var5] = makeSyncPacket(var6, 0, null);
         }

         var4.clear();
      }

      SyncInteractionChain var7 = new SyncInteractionChain(
         0,
         0,
         0,
         null,
         null,
         null,
         !var0.hasSentInitial(),
         false,
         var0.hasSentInitial() ? Integer.MIN_VALUE : RootInteraction.getRootInteractionIdOrUnknown(var0.getInitialRootInteraction().getId()),
         var0.getType(),
         var0.getContext().getHeldItemSlot(),
         var0.getChainId(),
         var0.getForkedChainId(),
         var0.getChainData(),
         var0.getServerState(),
         var3,
         var1,
         var2 == null ? null : var2.toArray(InteractionSyncData[]::new)
      );
      var0.setSentInitial(true);
      class="kw">return var7;
   }

   class="kw">private void sendCancelPacket(@Nonnull InteractionChain var1) {
      this.sendCancelPacket(var1.getChainId(), var1.getForkedChainId());
   }

   class="kw">public void sendCancelPacket(int var1, ForkedChainId var2) {
      if (this.playerRef != null) {
         this.playerRef.getPacketHandler().writeNoCache(new CancelInteractionChain(var1, var2));
      }
   }

   class="kw">public void clear() {
      this.forEachInteraction((var1, var2, var3) -> {
         var1.setServerState(InteractionState.Failed);
         var1.setClientState(InteractionState.Failed);
         this.sendCancelPacket(var1);
         class="kw">return null;
      }, null);
      this.chainStartQueue.clear();
   }

   class="kw">public void clearAllGlobalTimeShift(float var1) {
      if (this.timeShiftsDirty) {
         boolean var2 = true;

         for (int var3 = 0; var3 < this.globalTimeShift.length; var3++) {
            if (!this.globalTimeShiftDirty[var3]) {
               this.globalTimeShift[var3] = 0.0F;
            } else {
               var2 = false;
               this.globalTimeShift[var3] = this.globalTimeShift[var3] + var1;
            }
         }

         Arrays.fill(this.globalTimeShiftDirty, false);
         if (var2) {
            this.timeShiftsDirty = false;
         }
      }
   }

   class="kw">public void setGlobalTimeShift(@Nonnull InteractionType var1, float var2) {
      if (var2 < 0.0F) {
         throw new IllegalArgumentException("Can't shift backwards");
      }

      this.globalTimeShift[var1.ordinal()] = var2;
      this.globalTimeShiftDirty[var1.ordinal()] = true;
      this.timeShiftsDirty = true;
   }

   class="kw">public float getGlobalTimeShift(@Nonnull InteractionType var1) {
      class="kw">return this.globalTimeShift[var1.ordinal()];
   }

   class="kw">public <T> T forEachInteraction(@Nonnull TriFunction<InteractionChain, Interaction, T, T> var1, T var2) {
      class="kw">return forEachInteraction(this.chains, var1, var2);
   }

   class="kw">private class="kw">static <T> T forEachInteraction(@Nonnull Map<?, InteractionChain> var0, @Nonnull TriFunction<InteractionChain, Interaction, T, T> var1, T var2) {
      if (var0.isEmpty()) {
         class="kw">return var2;
      }

      for (InteractionChain var4 : var0.values()) {
         Operation var5 = var4.getRootInteraction().getOperation(var4.getOperationCounter());
         if (var5 != null && var5.getInnerOperation() class="kw">instanceof Interaction var6) {
            var2 = var1.apply(var4, var6, var2);
         }

         var2 = forEachInteraction(var4.getForkedChains(), var1, var2);
      }

      class="kw">return var2;
   }

   class="kw">public void walkChain(@Nonnull Ref<EntityStore> var1, @Nonnull Collector var2, @Nonnull InteractionType var3, @Nonnull ComponentAccessor<EntityStore> var4) {
      this.walkChain(var1, var2, var3, null, var4);
   }

   class="kw">public void walkChain(
      @Nonnull Ref<EntityStore> var1,
      @Nonnull Collector var2,
      @Nonnull InteractionType var3,
      @Nullable RootInteraction var4,
      @Nonnull ComponentAccessor<EntityStore> var5
   ) {
      walkChain(var2, var3, InteractionContext.forInteraction(this, var1, var3, var5), var4);
   }

   class="kw">public class="kw">static void walkChain(@Nonnull Collector var0, @Nonnull InteractionType var1, @Nonnull InteractionContext var2, @Nullable RootInteraction var3) {
      if (var3 == null) {
         String var4 = var2.getRootInteractionId(var1);
         if (var4 == null) {
            throw new IllegalArgumentException("No interaction ID found for " + var1 + ", " + var2);
         }

         var3 = RootInteraction.getAssetMap().getAsset(var4);
      }

      if (var3 == null) {
         throw new IllegalArgumentException("No interactions are defined for " + var1 + ", " + var2);
      }

      var0.start();
      var0.into(var2, null);
      walkInteractions(var0, var2, CollectorTag.ROOT, var3.getInteractionIds());
      var0.outof();
      var0.finished();
   }

   class="kw">public class="kw">static boolean walkInteractions(@Nonnull Collector var0, @Nonnull InteractionContext var1, @Nonnull CollectorTag var2, @Nonnull String[] var3) {
      for (String var7 : var3) {
         if (walkInteraction(var0, var1, var2, var7)) {
            class="kw">return true;
         }
      }

      class="kw">return false;
   }

   class="kw">public class="kw">static boolean walkInteraction(@Nonnull Collector var0, @Nonnull InteractionContext var1, @Nonnull CollectorTag var2, @Nullable String var3) {
      if (var3 == null) {
         class="kw">return false;
      }

      Interaction var4 = Interaction.getAssetMap().getAsset(var3);
      if (var4 == null) {
         throw new IllegalArgumentException("Failed to find interaction: " + var3);
      }

      if (var0.collect(var2, var1, var4)) {
         class="kw">return true;
      }

      var0.into(var1, var4);
      var4.walk(var0, var1);
      var0.outof();
      class="kw">return false;
   }

   class="kw">public ObjectList<SyncInteractionChain> getSyncPackets() {
      class="kw">return this.syncPackets;
   }

   @Nonnull
   @Override
   class="kw">public Component<EntityStore> clone() {
      InteractionManager var1 = new InteractionManager(this.playerRef, this.interactionSimulationHandler);
      var1.copyFrom(this);
      class="kw">return var1;
   }

   class="kw">public class="kw">static class ChainCancelledException class="kw">extends RuntimeException {
      @Nonnull
      class="kw">private class="kw">final InteractionState state;

      class="kw">public ChainCancelledException(@Nonnull InteractionState var1) {
         this.state = var1;
      }
   }
}