SpawnSpan class
Пакет: com.hypixel.hytale.server.spawning
Файл: com/hypixel/hytale/server/spawning/SpawningContext.java
Поля (4)
| Модификаторы | Тип | Имя |
|---|---|---|
|
int |
bottom |
|
int |
groundLevel |
|
int |
top |
|
int |
waterLevel |
Исходный код
Показать/скрыть
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() {
}
}
}