SpawningContext class

Пакет: com.hypixel.hytale.server.spawning

Файл: com/hypixel/hytale/server/spawning/SpawningContext.java

Поля (99)

МодификаторыТипИмя
return this.spawnSpansUsed > 0
return this.spawnSpansUsed > 0
int bottom
break
break
break
int groundLevel
return
int top
ModelAsset var1
EnumSet var1
SpawningContext.SpawnSpan var1
int var1
int var10
int var10
SpawningContext.SpawnSpan[] var10
int var11
BlockChunk var11
SpawningContext.SpawnSpan var11
EnvironmentColumn var12
int var13
int var14
int var15
var15
int var16
var16
var16
int var18
var18
var18
SpawningContext.SpawnSpan var19
BlockChunk var2
SpawningContext.SpawnSpan var2
int var2
BlockChunk var2
String var3
var3
String var3
Ref var3
BlockChunk var3
BlockChunk var3
var3
long var3
SpawnTestResult var3
var3
var3
ChunkColumn var3
int var3
ChunkColumn var3
Box var3
CollisionFilter var3
float var3
ModelAsset var4
BlockChunk var4
ChunkColumn var4
ChunkColumn var4
Ref var4
int var4
double var4
BlockType var4
double var4
double[] var4
Model var5
var5
int var5
EnvironmentColumn var5
int var5
int var5
Ref var5
int var5
int var6
int var6
var6
var6
int var6
int var6
var6
int var6
WorldChunk var6
int var6
double var6
int var7
int var7
int var7
var7
var7
int var8
int var8
ChunkStore var8
ChunkStore var8
int var8
var8
var8
double var8
int var9
int var9
Ref var9
Ref var9
int waterLevel

Методы (116)

МодификаторыВозвратСигнатура
abstract throw new IllegalStateExceptionthrow new IllegalStateException("SpawningContext not initialised")
abstract throw new IllegalStateExceptionthrow new IllegalStateException("SpawningContext not bound to a chunk")
abstract throw new IllegalStateExceptionthrow new IllegalStateException("minSpawnSpanHeight not set - forgot to set model or role?")
abstract throw new IllegalStateExceptionthrow new IllegalStateException("spawnModel not set - forgot to set model or role?")
abstract throw new IllegalStateExceptionthrow new IllegalStateException("SpawningContext not bound to a world")
abstract return new Rotation3freturn new Rotation3f(this.rotation)
private SpawnSpanprivate SpawnSpan()
abstract return new Vector3dreturn new Vector3d(this.xSpawn, this.ySpawn, this.zSpawn)
private void addSpawnSpanvoid addSpawnSpan(int var1, int var2, int var3, int var4, @Nonnull ComponentAccessor<ChunkStore> var5, @Nonnull BlockChunk var6, @Nonnull ChunkColumn var7)
public boolean canBreatheboolean canBreathe(boolean var1, boolean var2)
public boolean canSpawnOnBlockboolean canSpawnOnBlock(@Nullable IntSet var1, int var2)
private void clearModelvoid clearModel()
private void commonInitvoid commonInit()
public void deleteCurrentSpawnSpanvoid deleteCurrentSpawnSpan()
static boolean fillMovementModeWeightsboolean fillMovementModeWeights(@Nonnull double[] var0, @Nullable Map<MovementMode, Double> var1, @Nonnull Set<MovementMode> var2, @Nonnull Set<MovementMode> var3, @Nullable Set<MovementMode> var4)
for for(int var1 = 0; var1 < this.spawnSpans.length; var1++)
for for(int var17 = 0; var17 < this.spawnSpansUsed; var17++)
for for(int var9 = this.spawnSpansUsed; var9 < var10.length; var9++)
for for(MovementMode var6 : var3)
for for(double var21 : var0)
abstract for for(int var6 = var5.indexOf(0)
abstract for for(int var8 = isSpawnSpanBlock(this.xBlock, var3, this.zBlock, var5, var6, var7)
public int getAirHeightint getAirHeight()
public int getWaterLevelint getWaterLevel()
if if(var1 == this.spawnable)
if if(var1 == null)
if if(var4 != null)
if if(this.spawnModel != null)
if if(var1 != null)
if if(this.spawnMovementModes != null)
if if(this.spawnable == null)
if if(this.spawnable == null)
if if(!var2)
if if(this.chunkRef != null && this.chunkStore != null)
if if(this.chunkRef != null && this.chunkStore != null)
if if(var8 >= var7)
if if(this.chunkRef != null && this.chunkStore != null)
if if(var4 != null)
if if(var7 == this.environmentIndex)
if if(var8 > 320)
if if(var9 > var10)
if if(this.world != null && this.chunkRef != null && this.chunkStore != null)
if if(var2 == null)
if if(this.minSpawnSpanHeight == Integer.MAX_VALUE)
if if(var11 == null)
if if(this.spawnSpansUsed == 0)
if if(var19.top < var10)
if if(var19.bottom <= var10)
if if(var18 < var15)
if if(this.spawnModel == null)
if if(--this.spawnSpansUsed > this.currentSpawnSpanIndex)
if if(this.chunkRef == null || this.chunkStore == null)
if if(var1 >= 0 && var1 < this.spawnSpansUsed)
if if(var3 != null && var4 != null)
if if(this.waterLevel != -1)
if if(this.waterLevel < 319)
if if(this.chunkRef != null && this.chunkStore != null)
if if(var3 != null && var4 != null)
if if(var5 != -1)
if if(var5 == 1)
if if(var6 > this.minSpawnSpanHeight)
if if(var6 > this.minSpawnSpanHeight)
if if(var3 == -1)
if if(var4 == -1 && var8 == 1)
if if(var3 <= 0)
if if(var4 == var1 - 1)
if if(this.spawnSpans.length <= this.spawnSpansUsed)
if if(var1)
if if(var3 != SpawnTestResult.TEST_OK)
if if(var2)
if if(this.chunkRef == null || this.chunkStore == null)
if if(this.waterLevel != -1 && var2 != Integer.MIN_VALUE)
if if(var3 == null)
if if(this.spawnModel != null && this.spawnable != null)
if if(this.spawnModel != null && this.waterLevel >= 0)
if if(var2 < var3)
if if(this.chunkRef == null || this.chunkStore == null)
if if(var1 != this.yBlock)
if if(var2 != null && var3 != null)
if if(this.spawnModel != null && this.airHeight >= 0)
if if(var6 < var4)
if if(this.world == null)
if if(this.spawnModel == null)
if if(this.spawnModel == null)
if if(var1 && var2)
if if(!var1 && !var2)
if if(var4 != null)
if if(var21 != 0.0)
public boolean isInAirboolean isInAir(double var1)
public boolean isInWaterboolean isInWater(float var1)
public boolean isInsideSpanboolean isInsideSpan(double var1)
public boolean isOnSolidGroundboolean isOnSolidGround()
static int isSpawnSpanBlockint isSpawnSpanBlock(int var0, int var1, int var2, @Nonnull ComponentAccessor<ChunkStore> var3, @Nonnull BlockChunk var4, @Nonnull ChunkColumn var5)
static boolean isTickingSectionboolean isTickingSection(@Nonnull ChunkStore var0, int var1, int var2, int var3)
static boolean isWaterBlockboolean isWaterBlock(int var0)
public void newModelvoid newModel()
public void releasevoid release()
public void releaseFullvoid releaseFull()
public boolean selectRandomSpawnSpanboolean selectRandomSpawnSpan()
private boolean selectSpawnSpanboolean selectSpawnSpan(int var1)
public boolean setboolean set(@Nonnull World var1, double var2, double var4, double var6)
public void setChunkvoid setChunk(@Nonnull World var1, @Nonnull Ref<ChunkStore> var2, int var3)
public boolean setColumnboolean setColumn(int var1, int var2, int var3, @Nonnull int[] var4)
public boolean setColumnboolean setColumn(int var1, int var2, int var3, @Nonnull int[] var4, @Nonnull SuppressionSpanHelper var5)
public void setColumnvoid setColumn(int var1, int var2, @Nonnull SuppressionSpanHelper var3)
public boolean setExactboolean setExact(@Nonnull World var1, double var2, double var4, double var6)
private boolean setModelboolean setModel(@Nullable String var1, boolean var2)
public boolean setMovementModeboolean setMovementMode(MovementMode var1, boolean var2)
public boolean setSpawnableboolean setSpawnable(@Nonnull ISpawnableWithModel var1)
public boolean setSpawnableboolean setSpawnable(@Nonnull ISpawnableWithModel var1, boolean var2)
private void splitRangeToSpawnSpansvoid splitRangeToSpawnSpans(int var1, int var2)
return switchreturn switch(var1)
public boolean validatePositionboolean validatePosition(int var1)
public boolean validatePositionboolean validatePosition(int var1, boolean var2)
while while(var6 <= var7)
while while(var1 <= var2)

Исходный код

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

class="kw">import com.hypixel.hytale.assetstore.map.BlockTypeAssetMap;
class="kw">import com.hypixel.hytale.component.ComponentAccessor;
class="kw">import com.hypixel.hytale.component.Ref;
class="kw">import com.hypixel.hytale.logger.HytaleLogger;
class="kw">import com.hypixel.hytale.math.random.RandomExtra;
class="kw">import com.hypixel.hytale.math.shape.Box;
class="kw">import com.hypixel.hytale.math.util.ChunkUtil;
class="kw">import com.hypixel.hytale.math.util.MathUtil;
class="kw">import com.hypixel.hytale.math.vector.Rotation3f;
class="kw">import com.hypixel.hytale.protocol.BlockMaterial;
class="kw">import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
class="kw">import com.hypixel.hytale.server.core.asset.type.fluid.Fluid;
class="kw">import com.hypixel.hytale.server.core.asset.type.model.config.Model;
class="kw">import com.hypixel.hytale.server.core.asset.type.model.config.ModelAsset;
class="kw">import com.hypixel.hytale.server.core.modules.collision.BoxBlockIntersectionEvaluator;
class="kw">import com.hypixel.hytale.server.core.modules.collision.CollisionFilter;
class="kw">import com.hypixel.hytale.server.core.modules.collision.CollisionModule;
class="kw">import com.hypixel.hytale.server.core.modules.collision.CollisionResult;
class="kw">import com.hypixel.hytale.server.core.modules.collision.WorldUtil;
class="kw">import com.hypixel.hytale.server.core.universe.world.World;
class="kw">import com.hypixel.hytale.server.core.universe.world.chunk.BlockChunk;
class="kw">import com.hypixel.hytale.server.core.universe.world.chunk.ChunkColumn;
class="kw">import com.hypixel.hytale.server.core.universe.world.chunk.ChunkFlag;
class="kw">import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk;
class="kw">import com.hypixel.hytale.server.core.universe.world.chunk.environment.EnvironmentColumn;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
class="kw">import com.hypixel.hytale.server.npc.movement.MovementMode;
class="kw">import com.hypixel.hytale.server.npc.util.NPCPhysicsMath;
class="kw">import com.hypixel.hytale.server.npc.util.expression.ExecutionContext;
class="kw">import com.hypixel.hytale.server.npc.util.expression.Scope;
class="kw">import com.hypixel.hytale.server.spawning.suppression.SuppressionSpanHelper;
class="kw">import it.unimi.dsi.fastutil.ints.IntSet;
class="kw">import java.util.Arrays;
class="kw">import java.util.EnumSet;
class="kw">import java.util.Map;
class="kw">import java.util.Set;
class="kw">import java.util.Map.Entry;
class="kw">import java.util.concurrent.ThreadLocalRandom;
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">public class SpawningContext {
   @Nonnull
   class="kw">private class="kw">static class="kw">final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
   @Nonnull
   class="kw">private class="kw">static class="kw">final BlockTypeAssetMap<String, BlockType> BLOCK_ASSET_MAP = BlockType.getAssetMap();
   @Nullable
   class="kw">private World world;
   @Nullable
   class="kw">private Ref<ChunkStore> chunkRef;
   @Nullable
   class="kw">private ComponentAccessor<ChunkStore> chunkStore;
   class="kw">public int xBlock;
   class="kw">public int zBlock;
   class="kw">public double ySpawnHint;
   class="kw">public int groundLevel;
   class="kw">public int groundBlockId;
   class="kw">public int groundRotation;
   @Nullable
   class="kw">public BlockType groundBlockType;
   class="kw">public int groundFluidId;
   @Nullable
   class="kw">public Fluid groundFluid;
   @Nullable
   class="kw">public MovementMode movementMode;
   class="kw">public boolean enableSafeSpawning = true;
   @Nullable
   class="kw">public String activeMotionControllerType;
   class="kw">public int ySpanMin;
   class="kw">public int ySpanMax;
   class="kw">public int yBlock;
   class="kw">public int waterLevel;
   class="kw">public int airHeight;
   class="kw">public double ySpawnMin;
   class="kw">public double xSpawn;
   class="kw">public double zSpawn;
   class="kw">public double ySpawn;
   class="kw">private int environmentIndex = Integer.MIN_VALUE;
   class="kw">private int minSpawnSpanHeight = Integer.MAX_VALUE;
   @Nonnull
   class="kw">public class="kw">final Rotation3f rotation = new Rotation3f();
   class="kw">public boolean breathesInAir = true;
   class="kw">public boolean breathesInWater;
   class="kw">public int invalidMaterials = -1;
   class="kw">public double swimDepth = Double.NaN;
   @Nullable
   class="kw">private ISpawnableWithModel spawnable;
   @Nullable
   class="kw">private Model spawnModel;
   @Nullable
   class="kw">private Scope modifierScope;
   @Nullable
   class="kw">private EnumSet<MovementMode> spawnMovementModes;
   @Nonnull
   class="kw">private class="kw">final EnumSet<MovementMode> supportedMovementModes = EnumSet.noneOf(MovementMode.class);
   @Nonnull
   class="kw">private class="kw">final EnumSet<MovementMode> safeMovementModes = EnumSet.noneOf(MovementMode.class);
   @Nonnull
   class="kw">private class="kw">final CollisionResult collisionResult = new CollisionResult();
   @Nonnull
   class="kw">private class="kw">final Vector3d position = new Vector3d();
   @Nonnull
   class="kw">private class="kw">final ExecutionContext executionContext = new ExecutionContext();
   class="kw">private SpawningContext.SpawnSpan[] spawnSpans = new SpawningContext.SpawnSpan[4];
   class="kw">private int spawnSpansUsed;
   class="kw">private int currentSpawnSpanIndex;
   class="kw">private class="kw">static class="kw">final int SOLID_BLOCK = -1;
   class="kw">private class="kw">static class="kw">final int EMPTY_BLOCK = 0;
   class="kw">private class="kw">static class="kw">final int FLUID_BLOCK = 1;

   class="kw">public SpawningContext() {
      for (int var1 = 0; var1 < this.spawnSpans.length; var1++) {
         this.spawnSpans[var1] = new SpawningContext.SpawnSpan();
      }

      this.spawnSpansUsed = 0;
   }

   class="kw">public boolean setSpawnable(@Nonnull ISpawnableWithModel var1) {
      class="kw">return this.setSpawnable(var1, false);
   }

   class="kw">public boolean setSpawnable(@Nonnull ISpawnableWithModel var1, boolean var2) {
      if (var1 == this.spawnable) {
         class="kw">return true;
      }

      this.spawnable = var1;

      String var3;
      try {
         this.executionContext.setScope(var1.createExecutionScope());
         this.modifierScope = this.spawnable.createModifierScope(this.executionContext);
         this.breathesInAir = var1.breathesInAir(this.executionContext, this.modifierScope);
         this.breathesInWater = var1.breathesInWater(this.executionContext, this.modifierScope);
         this.movementMode = null;
         this.invalidMaterials = -1;
         this.swimDepth = Double.NaN;
         this.spawnMovementModes = null;
         var3 = var1.getSpawnModelName(this.executionContext, this.modifierScope);
      } catch (Throwable var5) {
         LOGGER.at(Level.WARNING).log("Can't set role in spawning context %s: %s", var1.getIdentifier(), var5.getMessage());
         var1.markNeedsReload();
         this.spawnable = null;
         class="kw">return false;
      }

      if (!this.setModel(var3, var2)) {
         LOGGER.at(Level.WARNING).log("Can't set model in spawning context %s: %s", var1.getIdentifier(), var3);
         var1.markNeedsReload();
         this.spawnable = null;
         class="kw">return false;
      } else {
         class="kw">return true;
      }
   }

   class="kw">private boolean setModel(@Nullable String var1, boolean var2) {
      if (var1 == null) {
         this.clearModel();
         class="kw">return false;
      }

      String var3 = this.spawnModel != null ? this.spawnModel.getModelAssetId() : null;
      if (var1.equals(var3)) {
         class="kw">return true;
      }

      ModelAsset var4 = ModelAsset.getAssetMap().getAsset(var1);
      Model var5 = null;
      if (var4 != null) {
         var5 = var2 ? Model.createScaledModel(var4, var4.getMaxScale()) : Model.createRandomScaleModel(var4);
      }

      if (var5 != null && var5.getBoundingBox() != null) {
         this.spawnModel = var5;
         this.minSpawnSpanHeight = MathUtil.ceil(var5.getBoundingBox().height() + 0.2F);
         class="kw">return true;
      } else {
         this.clearModel();
         class="kw">return false;
      }
   }

   class="kw">private void clearModel() {
      this.spawnModel = null;
      this.minSpawnSpanHeight = Integer.MAX_VALUE;
   }

   class="kw">public void newModel() {
      if (this.spawnModel != null) {
         ModelAsset var1 = ModelAsset.getAssetMap().getAsset(this.spawnModel.getModelAssetId());
         if (var1 != null) {
            this.spawnModel = Model.createRandomScaleModel(var1);
         }
      }
   }

   @Nullable
   class="kw">public Model getModel() {
      class="kw">return this.spawnModel;
   }

   @Nonnull
   class="kw">public Set<MovementMode> getSpawnMovementModes() {
      if (this.spawnMovementModes != null) {
         class="kw">return this.spawnMovementModes;
      }

      if (this.spawnable == null) {
         throw new IllegalStateException("SpawningContext not initialised");
      }

      this.supportedMovementModes.clear();
      this.safeMovementModes.clear();
      EnumSet var1 = EnumSet.noneOf(MovementMode.class);
      this.spawnable.getMovementModes(this, this.supportedMovementModes, var1, this.safeMovementModes);
      var1.retainAll(this.safeMovementModes);
      if (!var1.isEmpty()) {
         this.spawnMovementModes = var1;
      }

      class="kw">return var1;
   }

   class="kw">public boolean setMovementMode(MovementMode var1, boolean var2) {
      if (this.spawnable == null) {
         class="kw">return false;
      }

      this.movementMode = var1;
      this.enableSafeSpawning = var2;
      if (!var2) {
         class="kw">return true;
      }

      class="kw">return class="kw">switch (var1) {
         case WALK, WADE, FLY -> this.breathesInAir;
         case UNDERWATER_WALK, DIVE -> this.breathesInWater;
      };
   }

   class="kw">public void setChunk(@Nonnull World var1, @Nonnull Ref<ChunkStore> var2, int var3) {
      this.world = var1;
      this.chunkRef = var2;
      this.chunkStore = var1.getChunkStore().getStore();
      this.environmentIndex = var3;
      this.commonInit();
   }

   class="kw">public boolean setColumn(int var1, int var2, int var3, @Nonnull int[] var4) {
      if (this.chunkRef != null && this.chunkStore != null) {
         this.xBlock = var1;
         this.zBlock = var2;
         this.ySpawnHint = -1.0;
         this.spawnSpansUsed = 0;
         int var5 = Math.max(0, var3 + var4[0]);
         int var6 = Math.min(319, var3 + var4[1]);
         this.splitRangeToSpawnSpans(var5, var6);
         class="kw">return this.spawnSpansUsed > 0;
      } else {
         throw new IllegalStateException("SpawningContext not bound to a chunk");
      }
   }

   class="kw">public boolean setColumn(int var1, int var2, int var3, @Nonnull int[] var4, @Nonnull SuppressionSpanHelper var5) {
      if (this.chunkRef != null && this.chunkStore != null) {
         this.xBlock = var1;
         this.zBlock = var2;
         this.ySpawnHint = -1.0;
         this.spawnSpansUsed = 0;
         int var6 = Math.max(0, var3 + var4[0]);
         int var7 = Math.min(319, var3 + var4[1]);

         while (var6 <= var7) {
            int var8 = var5.adjustSpawnRangeMin(var6);
            if (var8 >= var7) {
               break;
            }

            int var9 = Math.min(var5.adjustSpawnRangeMax(var8, var7), var7);
            var6 = var9 + 1;
            this.splitRangeToSpawnSpans(var8, var9);
         }

         class="kw">return this.spawnSpansUsed > 0;
      } else {
         throw new IllegalStateException("SpawningContext not bound to a chunk");
      }
   }

   class="kw">public void setColumn(int var1, int var2, @Nonnull SuppressionSpanHelper var3) {
      if (this.chunkRef != null && this.chunkStore != null) {
         this.xBlock = var1;
         this.zBlock = var2;
         this.ySpawnHint = -1.0;
         this.spawnSpansUsed = 0;
         BlockChunk var4 = this.chunkStore.getComponent(this.chunkRef, BlockChunk.getComponentType());
         if (var4 != null) {
            EnvironmentColumn var5 = var4.getEnvironmentColumn(this.xBlock, this.zBlock);

            for (int var6 = var5.indexOf(0); var6 < var5.size(); var6++) {
               int var7 = var5.getValue(var6);
               if (var7 == this.environmentIndex) {
                  int var8 = Math.max(0, var5.getValueMin(var6));
                  if (var8 > 320) {
                     break;
                  }

                  int var9 = var3.adjustSpawnRangeMin(var8);
                  int var10 = var5.getValueMax(var6);
                  if (var9 > var10) {
                     var6 = var5.indexOf(var9) - 1;
                  } else {
                     int var11 = var3.adjustSpawnRangeMax(var9, var10);
                     this.splitRangeToSpawnSpans(var9, Math.min(var11, 319));
                  }
               }
            }
         }
      } else {
         throw new IllegalStateException("SpawningContext not bound to a chunk");
      }
   }

   @Nullable
   class="kw">public Scope getModifierScope() {
      class="kw">return this.modifierScope;
   }

   @Nullable
   class="kw">public World getWorld() {
      class="kw">return this.world;
   }

   @Nullable
   class="kw">public Ref<ChunkStore> getChunkRef() {
      class="kw">return this.chunkRef;
   }

   @Nullable
   class="kw">public Ref<ChunkStore> getSectionRefAtBlockY(int var1) {
      if (this.world != null && this.chunkRef != null && this.chunkStore != null) {
         BlockChunk var2 = this.chunkStore.getComponent(this.chunkRef, BlockChunk.getComponentType());
         if (var2 == null) {
            class="kw">return null;
         }

         Ref var3 = this.world.getChunkStore().getChunkSectionReference(var2.getX(), ChunkUtil.chunkCoordinate(var1), var2.getZ());
         class="kw">return var3 != null && var3.isValid() ? var3 : null;
      } else {
         class="kw">return null;
      }
   }

   @Nullable
   class="kw">public ComponentAccessor<ChunkStore> getChunkStore() {
      class="kw">return this.chunkStore;
   }

   class="kw">public boolean set(@Nonnull World var1, double var2, double var4, double var6) {
      if (this.minSpawnSpanHeight == Integer.MAX_VALUE) {
         throw new IllegalStateException("minSpawnSpanHeight not set - forgot to set model or role?");
      }

      this.xBlock = MathUtil.floor(var2);
      this.zBlock = MathUtil.floor(var6);
      this.ySpawnHint = var4;
      ChunkStore var8 = var1.getChunkStore();
      Ref var9 = resolveTickingChunk(var8, this.xBlock, this.zBlock);
      if (var9 != null && isTickingSection(var8, this.xBlock, MathUtil.floor(var4), this.zBlock)) {
         this.xBlock = ChunkUtil.localCoordinate(this.xBlock);
         this.zBlock = ChunkUtil.localCoordinate(this.zBlock);
         this.world = var1;
         this.chunkRef = var9;
         this.chunkStore = var8.getStore();
         this.environmentIndex = Integer.MIN_VALUE;
         this.commonInit();
         int var10 = MathUtil.floor(var4);
         this.spawnSpansUsed = 0;
         BlockChunk var11 = this.chunkStore.getComponent(var9, BlockChunk.getComponentType());
         if (var11 == null) {
            class="kw">return false;
         }

         EnvironmentColumn var12 = var11.getEnvironmentColumn(this.xBlock, this.zBlock);
         int var13 = Math.max(0, var12.getMin(var10));
         int var14 = Math.min(var12.getMax(var10), 319);
         this.splitRangeToSpawnSpans(var13, var14);
         if (this.spawnSpansUsed == 0) {
            class="kw">return false;
         }

         int var15 = Integer.MAX_VALUE;
         int var16 = -1;

         for (int var17 = 0; var17 < this.spawnSpansUsed; var17++) {
            SpawningContext.SpawnSpan var19 = this.spawnSpans[var17];
            int var18;
            if (var19.top < var10) {
               var18 = var10 - var19.top;
            } else {
               if (var19.bottom <= var10) {
                  var16 = var17;
                  break;
               }

               var18 = var19.bottom - var10;
            }

            if (var18 < var15) {
               var16 = var17;
               var15 = var18;
            }
         }

         class="kw">return this.selectSpawnSpan(var16);
      } else {
         class="kw">return false;
      }
   }

   class="kw">public boolean setExact(@Nonnull World var1, double var2, double var4, double var6) {
      if (this.spawnModel == null) {
         throw new IllegalStateException("spawnModel not set - forgot to set model or role?");
      } else {
         this.xBlock = MathUtil.floor(var2);
         this.zBlock = MathUtil.floor(var6);
         this.ySpawnHint = var4;
         ChunkStore var8 = var1.getChunkStore();
         Ref var9 = resolveTickingChunk(var8, this.xBlock, this.zBlock);
         if (var9 != null && isTickingSection(var8, this.xBlock, MathUtil.floor(var4), this.zBlock)) {
            this.xBlock = ChunkUtil.localCoordinate(this.xBlock);
            this.zBlock = ChunkUtil.localCoordinate(this.zBlock);
            this.world = var1;
            this.chunkRef = var9;
            this.chunkStore = var8.getStore();
            this.environmentIndex = Integer.MIN_VALUE;
            this.commonInit();
            this.xSpawn = var2;
            this.ySpawn = var4;
            this.zSpawn = var6;
            class="kw">return true;
         } else {
            class="kw">return false;
         }
      }
   }

   class="kw">public void deleteCurrentSpawnSpan() {
      if (--this.spawnSpansUsed > this.currentSpawnSpanIndex) {
         SpawningContext.SpawnSpan var1 = this.spawnSpans[this.currentSpawnSpanIndex];
         System.arraycopy(
            this.spawnSpans, this.currentSpawnSpanIndex + 1, this.spawnSpans, this.currentSpawnSpanIndex, this.spawnSpansUsed - this.currentSpawnSpanIndex
         );
         this.spawnSpans[this.spawnSpansUsed] = var1;
      }
   }

   class="kw">public boolean selectRandomSpawnSpan() {
      class="kw">return this.spawnSpansUsed > 0 && this.selectSpawnSpan(ThreadLocalRandom.current().nextInt(0, this.spawnSpansUsed));
   }

   class="kw">private boolean selectSpawnSpan(int var1) {
      if (this.chunkRef == null || this.chunkStore == null) {
         throw new IllegalStateException("SpawningContext not bound to a chunk");
      }

      if (var1 >= 0 && var1 < this.spawnSpansUsed) {
         this.currentSpawnSpanIndex = var1;
         SpawningContext.SpawnSpan var2 = this.spawnSpans[this.currentSpawnSpanIndex];
         this.ySpanMin = var2.bottom;
         this.ySpanMax = var2.top;
         this.waterLevel = var2.waterLevel;
         this.groundLevel = var2.groundLevel;
         BlockChunk var3 = this.chunkStore.getComponent(this.chunkRef, BlockChunk.getComponentType());
         ChunkColumn var4 = this.chunkStore.getComponent(this.chunkRef, ChunkColumn.getComponentType());
         if (var3 != null && var4 != null) {
            if (this.waterLevel != -1) {
               this.airHeight = -1;
               if (this.waterLevel < 319) {
                  int var5 = var3.getBlock(this.xBlock, this.waterLevel + 1, this.zBlock);
                  int var6 = WorldUtil.getFluidIdAtPosition(this.chunkStore, var4, this.xBlock, this.waterLevel + 1, this.zBlock);
                  if (var5 == 0 && var6 == 0 || BLOCK_ASSET_MAP.getAsset(var5).getMaterial() == BlockMaterial.Empty && var6 == 0) {
                     this.airHeight = this.waterLevel + 1;
                  }
               }
            } else {
               this.airHeight = this.groundLevel + 1;
            }

            this.yBlock = this.groundLevel;
            this.groundBlockId = var3.getBlock(this.xBlock, this.groundLevel, this.zBlock);
            this.groundRotation = var3.getSectionAtBlockY(this.groundLevel).getRotationIndex(this.xBlock, this.groundLevel, this.zBlock);
            this.groundBlockType = BLOCK_ASSET_MAP.getAsset(this.groundBlockId);
            this.groundFluidId = WorldUtil.getFluidIdAtPosition(this.chunkStore, var4, this.xBlock, this.groundLevel, this.zBlock);
            this.groundFluid = Fluid.getAssetMap().getAsset(this.groundFluidId);
            this.ySpawnMin = this.yBlock + NPCPhysicsMath.blockHeight(this.groundBlockType, this.groundRotation);
            this.xSpawn = ChunkUtil.minBlock(var3.getX()) + this.xBlock + 0.5;
            this.zSpawn = ChunkUtil.minBlock(var3.getZ()) + this.zBlock + 0.5;
            this.ySpawn = this.ySpawnMin - this.spawnModel.getBoundingBox().min.y;
            class="kw">return true;
         } else {
            class="kw">return false;
         }
      } else {
         class="kw">return false;
      }
   }

   class="kw">private void splitRangeToSpawnSpans(int var1, int var2) {
      if (this.chunkRef != null && this.chunkStore != null) {
         BlockChunk var3 = this.chunkStore.getComponent(this.chunkRef, BlockChunk.getComponentType());
         ChunkColumn var4 = this.chunkStore.getComponent(this.chunkRef, ChunkColumn.getComponentType());
         if (var3 != null && var4 != null) {
            int var6 = 0;
            int var7 = -1;
            int var8 = -1;

            while (var1 <= var2) {
               int var5 = isSpawnSpanBlock(this.xBlock, var1, this.zBlock, this.chunkStore, var3, var4);
               if (var5 != -1) {
                  if (var5 == 1) {
                     var7 = var1;
                  }

                  var6++;
               } else {
                  if (var6 > this.minSpawnSpanHeight) {
                     this.addSpawnSpan(var1, var6, var8, var7, this.chunkStore, var3, var4);
                  }

                  var6 = 0;
                  var7 = -1;
                  var8 = var1;
               }

               var1++;
            }

            if (var6 > this.minSpawnSpanHeight) {
               this.addSpawnSpan(var1, var6, var8, var7, this.chunkStore, var3, var4);
            }
         }
      } else {
         throw new IllegalStateException("SpawningContext not bound to a chunk");
      }
   }

   class="kw">private void addSpawnSpan(
      int var1, int var2, int var3, int var4, @Nonnull ComponentAccessor<ChunkStore> var5, @Nonnull BlockChunk var6, @Nonnull ChunkColumn var7
   ) {
      if (var3 == -1) {
         var3 = var1 - var2;

         for (int var8 = isSpawnSpanBlock(this.xBlock, var3, this.zBlock, var5, var6, var7);
            var8 != -1;
            var8 = isSpawnSpanBlock(this.xBlock, --var3, this.zBlock, var5, var6, var7)
         ) {
            if (var4 == -1 && var8 == 1) {
               var4 = var3;
            }

            if (var3 <= 0) {
               class="kw">return;
            }
         }
      }

      if (var4 == var1 - 1) {
         while (var4 < 319 && isSpawnSpanBlock(this.xBlock, var4 + 1, this.zBlock, var5, var6, var7) == 1) {
            var4++;
         }
      }

      if (this.spawnSpans.length <= this.spawnSpansUsed) {
         SpawningContext.SpawnSpan[] var10 = new SpawningContext.SpawnSpan[this.spawnSpansUsed + 4];
         System.arraycopy(this.spawnSpans, 0, var10, 0, this.spawnSpansUsed);

         for (int var9 = this.spawnSpansUsed; var9 < var10.length; var9++) {
            var10[var9] = new SpawningContext.SpawnSpan();
         }

         this.spawnSpans = var10;
      }

      SpawningContext.SpawnSpan var11 = this.spawnSpans[this.spawnSpansUsed++];
      var11.bottom = var1 - var2;
      var11.top = var1 - 1;
      var11.waterLevel = var4;
      var11.groundLevel = var3;
   }

   class="kw">private class="kw">static int isSpawnSpanBlock(
      int var0, int var1, int var2, @Nonnull ComponentAccessor<ChunkStore> var3, @Nonnull BlockChunk var4, @Nonnull ChunkColumn var5
   ) {
      int var6 = var4.getBlock(var0, var1, var2);
      if (var6 != 0 && BLOCK_ASSET_MAP.getAsset(var6).getMaterial() != BlockMaterial.Empty) {
         class="kw">return -1;
      } else {
         class="kw">return WorldUtil.getFluidIdAtPosition(var3, var5, var0, var1, var2) == 0 ? 0 : 1;
      }
   }

   class="kw">private void commonInit() {
      this.rotation.set(0.0F, RandomExtra.randomRange(0.0F, (float) (Math.PI * 2)), 0.0F);
   }

   @Nullable
   class="kw">private class="kw">static Ref<ChunkStore> resolveTickingChunk(@Nonnull ChunkStore var0, int var1, int var2) {
      long var3 = ChunkUtil.indexChunkFromBlock(var1, var2);
      Ref var5 = var0.getChunkReference(var3);
      if (var5 != null && var5.isValid()) {
         WorldChunk var6 = var0.getStore().getComponent(var5, WorldChunk.getComponentType());
         class="kw">return var6 != null && var6.is(ChunkFlag.TICKING) ? var5 : null;
      } else {
         class="kw">return null;
      }
   }

   class="kw">private class="kw">static boolean isTickingSection(@Nonnull ChunkStore var0, int var1, int var2, int var3) {
      Ref var4 = var0.getChunkSectionReferenceAtBlock(var1, var2, var3);
      class="kw">return var4 != null && var4.isValid() ? !var0.getStore().getArchetype(var4).contains(ChunkStore.REGISTRY.getNonTickingComponentType()) : false;
   }

   @Nonnull
   class="kw">public SpawnTestResult canSpawn(boolean var1, boolean var2) {
      SpawnTestResult var3 = SpawnTestResult.TEST_OK;
      if (var1) {
         var3 = this.intersectsBlock();
         if (var3 != SpawnTestResult.TEST_OK) {
            class="kw">return var3;
         }
      }

      if (var2) {
         var3 = intersectsEntity();
      }

      class="kw">return var3;
   }

   @Nonnull
   class="kw">public SpawnTestResult canSpawn() {
      class="kw">return this.canSpawn(true, true);
   }

   class="kw">public boolean canSpawnOnBlock(@Nullable IntSet var1, int var2) {
      if (this.chunkRef == null || this.chunkStore == null) {
         throw new IllegalStateException("SpawningContext not bound to a chunk");
      }

      if (var1 != null && !var1.contains(this.groundBlockId)) {
         class="kw">return false;
      }

      if (this.waterLevel != -1 && var2 != Integer.MIN_VALUE) {
         ChunkColumn var3 = this.chunkStore.getComponent(this.chunkRef, ChunkColumn.getComponentType());
         if (var3 == null) {
            class="kw">return false;
         }

         int var4 = WorldUtil.getFluidIdAtPosition(this.chunkStore, var3, this.xBlock, this.waterLevel, this.zBlock);
         class="kw">return Fluid.getAssetMap().getIndexesForTag(var2).contains(var4);
      } else {
         class="kw">return true;
      }
   }

   @Nonnull
   class="kw">private class="kw">static SpawnTestResult intersectsEntity() {
      class="kw">return SpawnTestResult.TEST_OK;
   }

   @Nonnull
   class="kw">private SpawnTestResult intersectsBlock() {
      if (this.spawnModel != null && this.spawnable != null) {
         class="kw">return this.spawnable.canSpawn(this);
      } else {
         throw new IllegalStateException("SpawningContext not initialised");
      }
   }

   class="kw">public class="kw">static boolean isWaterBlock(int var0) {
      class="kw">return var0 != 0;
   }

   class="kw">public int getWaterLevel() {
      class="kw">return this.waterLevel;
   }

   class="kw">public int getAirHeight() {
      class="kw">return this.airHeight;
   }

   class="kw">public boolean isInsideSpan(double var1) {
      class="kw">return var1 >= this.ySpanMin && var1 < this.ySpanMax + 1;
   }

   class="kw">public boolean isInWater(float var1) {
      if (this.spawnModel != null && this.waterLevel >= 0) {
         int var2 = this.waterLevel - this.groundLevel - 1;
         int var3 = Math.max(0, MathUtil.fastCeil(var1));
         if (var2 < var3) {
            class="kw">return false;
         }

         double var4 = this.waterLevel - var3;
         if (!this.isInsideSpan(var4)) {
            class="kw">return false;
         }

         this.ySpawn = var4 - this.spawnModel.getBoundingBox().min.y;
         class="kw">return true;
      } else {
         class="kw">return false;
      }
   }

   class="kw">public boolean isOnSolidGround() {
      if (this.chunkRef == null || this.chunkStore == null) {
         throw new IllegalStateException("SpawningContext not bound to a chunk");
      }

      if (this.waterLevel == -1 && isWaterBlock(this.groundFluidId)) {
         class="kw">return false;
      }

      this.ySpawn = this.ySpawnMin - this.spawnModel.getBoundingBox().min.y;
      int var1 = MathUtil.floor(this.ySpawnMin);
      if (var1 != this.yBlock) {
         BlockChunk var2 = this.chunkStore.getComponent(this.chunkRef, BlockChunk.getComponentType());
         ChunkColumn var3 = this.chunkStore.getComponent(this.chunkRef, ChunkColumn.getComponentType());
         if (var2 != null && var3 != null) {
            BlockType var4 = BLOCK_ASSET_MAP.getAsset(var2.getBlock(this.xBlock, var1, this.zBlock));
            int var5 = WorldUtil.getFluidIdAtPosition(this.chunkStore, var3, this.xBlock, var1, this.zBlock);
            int var6 = var2.getSectionAtBlockY(var1).getRotationIndex(this.xBlock, var1, this.zBlock);
            if (WorldUtil.isEmptyOnlyBlock(var4, var5) || var5 != 0) {
               class="kw">return this.isInsideSpan(this.ySpawn);
            } else if (WorldUtil.isSolidOnlyBlock(var4, var5)) {
               this.ySpawn = var1 + NPCPhysicsMath.blockHeight(var4, var6) - this.spawnModel.getBoundingBox().min.y;
               class="kw">return this.isInsideSpan(this.ySpawn);
            } else {
               class="kw">return false;
            }
         } else {
            class="kw">return false;
         }
      } else {
         class="kw">return this.ySpawn >= this.ySpanMin - 1 && this.ySpawn < this.ySpanMax + 1;
      }
   }

   class="kw">public boolean isInAir(double var1) {
      if (this.spawnModel != null && this.airHeight >= 0) {
         Box var3 = this.spawnModel.getBoundingBox();
         double var4 = this.airHeight - var3.min.y;
         double var6 = this.ySpanMax + 1 - var3.max.y;
         if (var6 < var4) {
            class="kw">return false;
         }

         double var8 = Math.min(var4 + Math.max(0.0, var1), var6);
         if (!this.isInsideSpan(var8)) {
            class="kw">return false;
         }

         this.ySpawn = var8;
         class="kw">return true;
      } else {
         class="kw">return false;
      }
   }

   class="kw">public boolean validatePosition(int var1) {
      class="kw">return this.validatePosition(var1, false);
   }

   class="kw">public boolean validatePosition(int var1, boolean var2) {
      if (this.world == null) {
         throw new IllegalStateException("SpawningContext not bound to a world");
      }

      if (this.spawnModel == null) {
         class="kw">return false;
      }

      this.position.set(this.xSpawn, this.ySpawn, this.zSpawn);
      CollisionFilter var3 = var2
         ? (var0, var1x, var2x, var3x) -> var3x.blockId != -1 && var3x.blockType != null && var3x.blockType.getHitboxTypeIndex() == 0
         : (var0, var1x, var2x, var3x) -> var3x.blockId != -1;
      class="kw">return CollisionModule.get().validatePosition(this.world, this.spawnModel.getBoundingBox(), this.position, var1, null, var3, this.collisionResult) != -1;
   }

   class="kw">public boolean canBreathe(boolean var1, boolean var2) {
      if (this.spawnModel == null) {
         class="kw">return false;
      }

      if (var1 && var2) {
         class="kw">return true;
      }

      if (!var1 && !var2) {
         class="kw">return false;
      }

      float var3 = this.spawnModel.getEyeHeight();
      class="kw">return var1 ? this.waterLevel + 1 - this.ySpawn < var3 : this.ySpawn + var3 < this.airHeight;
   }

   class="kw">public void release() {
      this.world = null;
      this.chunkRef = null;
      this.chunkStore = null;
      this.groundBlockType = null;
   }

   class="kw">public void releaseFull() {
      this.release();
      this.spawnable = null;
      this.movementMode = null;
      this.enableSafeSpawning = true;
      this.activeMotionControllerType = null;
      this.breathesInAir = true;
      this.breathesInWater = false;
      this.invalidMaterials = -1;
      this.swimDepth = Double.NaN;
      this.modifierScope = null;
      this.spawnMovementModes = null;
      this.spawnModel = null;
      this.executionContext.setScope(null);
   }

   @Nullable
   class="kw">public class="kw">static double[] buildMovementModeWeights(
      @Nullable Map<MovementMode, Double> var0, @Nonnull Set<MovementMode> var1, @Nonnull Set<MovementMode> var2, @Nullable Set<MovementMode> var3
   ) {
      double[] var4 = new double[MovementMode.values().length];
      class="kw">return fillMovementModeWeights(var4, var0, var1, var2, var3) ? var4 : null;
   }

   class="kw">private class="kw">static boolean fillMovementModeWeights(
      @Nonnull double[] var0,
      @Nullable Map<MovementMode, Double> var1,
      @Nonnull Set<MovementMode> var2,
      @Nonnull Set<MovementMode> var3,
      @Nullable Set<MovementMode> var4
   ) {
      assert var0.length == MovementMode.values().length : "weights array length must match number of MovementMode values";
      Arrays.fill(var0, 0.0);
      if (var1 != null && !var1.isEmpty()) {
         for (Entry var14 : var1.entrySet()) {
            var0[var14.getKey().ordinal()] = var14.getValue();
         }
      } else {
         for (MovementMode var6 : var3) {
            var0[var6.ordinal()] = 1.0;
         }
      }

      for (MovementMode var8 : MovementMode.values()) {
         if (!var2.contains(var8)) {
            var0[var8.ordinal()] = 0.0;
         }
      }

      if (var4 != null) {
         for (MovementMode var20 : MovementMode.values()) {
            if (!var4.contains(var20)) {
               var0[var20.ordinal()] = 0.0;
            }
         }
      }

      for (double var21 : var0) {
         if (var21 != 0.0) {
            class="kw">return true;
         }
      }

      class="kw">return false;
   }

   @Nonnull
   class="kw">public ExecutionContext getExecutionContext() {
      class="kw">return this.executionContext;
   }

   @Nonnull
   class="kw">public Vector3d newPosition() {
      class="kw">return new Vector3d(this.xSpawn, this.ySpawn, this.zSpawn);
   }

   @Nonnull
   class="kw">public Rotation3f newRotation() {
      class="kw">return new Rotation3f(this.rotation);
   }

   @Nonnull
   @Override
   class="kw">public String toString() {
      class="kw">return "SpawningContext{xBlock="
         + this.xBlock
         + ", zBlock="
         + this.zBlock
         + ", yBlock="
         + this.yBlock
         + ", ySpawnMin="
         + this.ySpawnMin
         + ", xSpawn="
         + this.xSpawn
         + ", zSpawn="
         + this.zSpawn
         + ", ySpawn="
         + this.ySpawn
         + ", rotation="
         + this.rotation
         + ", groundBlockId="
         + this.groundBlockId
         + "}";
   }

   class="kw">private class="kw">static class SpawnSpan {
      int bottom;
      int top;
      int waterLevel;
      int groundLevel;

      class="kw">private SpawnSpan() {
      }
   }
}