WeightedPosition class
Пакет: com.hypixel.hytale.server.spawning.util
Файл: com/hypixel/hytale/server/spawning/util/FloodFillPositionSelector.java
Поля (3)
| Модификаторы | Тип | Имя |
|---|---|---|
|
private final Vector3i |
position |
|
private final int |
validMovementModesMask |
|
private double |
weight |
Методы (1)
| Модификаторы | Возврат | Сигнатура |
|---|---|---|
|
public double |
getWeightpublic double getWeight() |
Исходный код
Показать/скрыть
class="kw">package com.hypixel.hytale.server.spawning.util;
class="kw">import com.hypixel.fastutil.longs.Long2ObjectConcurrentHashMap;
class="kw">import com.hypixel.hytale.component.Component;
class="kw">import com.hypixel.hytale.component.ComponentType;
class="kw">import com.hypixel.hytale.math.random.RandomExtra;
class="kw">import com.hypixel.hytale.math.util.ChunkUtil;
class="kw">import com.hypixel.hytale.math.util.MathUtil;
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.universe.world.World;
class="kw">import com.hypixel.hytale.server.core.universe.world.accessor.ChunkAccessor;
class="kw">import com.hypixel.hytale.server.core.universe.world.accessor.LocalCachedChunkAccessor;
class="kw">import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
class="kw">import com.hypixel.hytale.server.npc.NPCPlugin;
class="kw">import com.hypixel.hytale.server.npc.asset.builder.Builder;
class="kw">import com.hypixel.hytale.server.npc.movement.MovementMode;
class="kw">import com.hypixel.hytale.server.npc.role.Role;
class="kw">import com.hypixel.hytale.server.spawning.ISpawnable;
class="kw">import com.hypixel.hytale.server.spawning.ISpawnableWithModel;
class="kw">import com.hypixel.hytale.server.spawning.SpawnTestResult;
class="kw">import com.hypixel.hytale.server.spawning.SpawningContext;
class="kw">import com.hypixel.hytale.server.spawning.SpawningPlugin;
class="kw">import com.hypixel.hytale.server.spawning.assets.spawns.config.RoleSpawnParameters;
class="kw">import com.hypixel.hytale.server.spawning.suppression.component.ChunkSuppressionEntry;
class="kw">import com.hypixel.hytale.server.spawning.suppression.component.SpawnSuppressionController;
class="kw">import com.hypixel.hytale.server.spawning.wrappers.BeaconSpawnWrapper;
class="kw">import it.unimi.dsi.fastutil.ints.Int2IntMap;
class="kw">import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
class="kw">import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
class="kw">import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
class="kw">import it.unimi.dsi.fastutil.ints.IntArrayList;
class="kw">import it.unimi.dsi.fastutil.ints.IntLists;
class="kw">import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
class="kw">import it.unimi.dsi.fastutil.ints.IntSet;
class="kw">import it.unimi.dsi.fastutil.objects.ObjectArrayList;
class="kw">import it.unimi.dsi.fastutil.objects.ObjectArrays;
class="kw">import java.util.ArrayDeque;
class="kw">import java.util.Arrays;
class="kw">import java.util.BitSet;
class="kw">import java.util.Comparator;
class="kw">import java.util.Deque;
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">import org.joml.Vector3i;
class="kw">public class FloodFillPositionSelector class="kw">implements Component<EntityStore> {
class="kw">private class="kw">static class="kw">final int MAX_SPAWN_POSITIONS_HINT = 30;
class="kw">private class="kw">static class="kw">final double SPAWN_POSITION_DENSITY = 0.1;
class="kw">private class="kw">static class="kw">final int CONCURRENT_POSITION_OPTION_MULTIPLIER = 3;
class="kw">private class="kw">static class="kw">final double MAX_FAILED_SPAWN_POSITION_RATIO = 0.25;
class="kw">private class="kw">static class="kw">final double IRREGULAR_MIN_SPAWNS_MULTIPLIER = 0.3;
class="kw">private class="kw">static class="kw">final double IRREGULAR_MAX_SPAWNS_MULTIPLIER = 5.0;
class="kw">private class="kw">static class="kw">final int NOT_CHECKED = -1;
class="kw">private class="kw">static class="kw">final int BLOCKED = -2;
class="kw">private class="kw">static class="kw">final int TOO_HIGH = Integer.MAX_VALUE;
class="kw">private class="kw">static class="kw">final int TOO_LOW = Integer.MIN_VALUE;
class="kw">private class="kw">static class="kw">final int MAX_RESOLUTION_DIVISOR = 8;
class="kw">private class="kw">static class="kw">final ThreadLocal<FloodFillPositionSelector.SortBufferProvider> sortBufferProvider = ThreadLocal.withInitial(
FloodFillPositionSelector.SortBufferProvider::new
);
class="kw">private class="kw">static class="kw">final Comparator<Object> WEIGHTED_POSITION_COMPARATOR = (var0, var1) -> Double.compare(
((FloodFillPositionSelector.WeightedPosition)var1).getWeight(), ((FloodFillPositionSelector.WeightedPosition)var0).getWeight()
);
class="kw">private class="kw">final World world;
@Nullable
class="kw">private ChunkAccessor chunkAccessor;
class="kw">private class="kw">final int size;
class="kw">private int beaconY;
class="kw">private int minY;
class="kw">private int maxY;
@Nonnull
class="kw">private class="kw">final BeaconSpawnWrapper spawnWrapper;
@Nonnull
class="kw">private class="kw">final int[] roleIndexes;
@Nonnull
class="kw">private class="kw">final int[] heightGrid;
@Nonnull
class="kw">private class="kw">final Int2ObjectMap<BitSet> resolutionMaps;
class="kw">private class="kw">final BitSet fullResolutionMap;
class="kw">private int desiredPositionCount;
class="kw">private class="kw">final IntArrayList highResolutionOptions = new IntArrayList(4);
class="kw">private class="kw">final Deque<int[]> floodFillQueue = new ArrayDeque<>();
class="kw">private class="kw">final SpawningContext spawningContext = new SpawningContext();
@Nullable
class="kw">private WorldChunk chunk;
class="kw">private class="kw">final IntSet positionIndexes = new IntOpenHashSet();
class="kw">private class="kw">final Int2ObjectMap<ObjectArrayList<FloodFillPositionSelector.WeightedPosition>> positionsByRole = new Int2ObjectOpenHashMap();
class="kw">private class="kw">final Int2IntMap failedSpawnsByRole = new Int2IntOpenHashMap();
class="kw">private double lowestSpawnOverYRange;
@Nullable
class="kw">private MovementMode lowestSpawnOverYRangeMode;
class="kw">private boolean hasRun;
class="kw">private FloodFillPositionSelector.Debug debug;
class="kw">private boolean irregularCase;
class="kw">private IntSet failedPositionTestIndexes;
class="kw">private double calculatePositionsAfter;
class="kw">public class="kw">static ComponentType<EntityStore, FloodFillPositionSelector> getComponentType() {
class="kw">return SpawningPlugin.get().getFloodFillPositionSelectorComponentType();
}
class="kw">public FloodFillPositionSelector(World var1, @Nonnull BeaconSpawnWrapper var2) {
this.world = var1;
int var3 = MathUtil.ceil(var2.getSpawnRadius()) * 2;
this.size = (var3 + 8 - 1) / 8 * 8;
this.heightGrid = new int[this.size * this.size];
Arrays.fill(this.heightGrid, -1);
this.resolutionMaps = new Int2ObjectOpenHashMap();
for (int var4 = 1; var4 <= 8; var4 *= 2) {
this.resolutionMaps.put(var4, new BitSet(this.heightGrid.length / var4));
}
this.fullResolutionMap = (BitSet)this.resolutionMaps.get(1);
this.spawnWrapper = var2;
RoleSpawnParameters[] var7 = var2.getSpawn().getNPCs();
this.roleIndexes = new int[var7.length];
for (int var5 = 0; var5 < this.roleIndexes.length; var5++) {
int var6 = NPCPlugin.get().getIndex(var7[var5].getId());
this.roleIndexes[var5] = var6;
this.positionsByRole.put(var6, new ObjectArrayList());
}
this.debug = var2.getSpawn().getDebug();
if (this.debug != FloodFillPositionSelector.Debug.DISABLED) {
this.failedPositionTestIndexes = new IntOpenHashSet();
}
}
class="kw">public void setCalculatePositionsAfter(double var1) {
this.calculatePositionsAfter = var1;
}
class="kw">public boolean tickCalculatePositionsAfter(float var1) {
class="kw">return (this.calculatePositionsAfter -= var1) <= 0.0;
}
class="kw">public boolean hasPositionsForRole(int var1) {
class="kw">return !((ObjectArrayList)this.positionsByRole.get(var1)).isEmpty();
}
class="kw">public boolean hasValidMovementModeWeights(int var1, @Nonnull SpawningContext var2) {
ISpawnable var3 = (ISpawnable)NPCPlugin.get().tryGetCachedValidRole(var1);
class="kw">return var3 == null ? true : ((RoleSpawnParameters)this.spawnWrapper.getRoles().get(var1)).getOrComputeMovementModeWeights(var3, var2) != null;
}
class="kw">public boolean prepareSpawnContext(@Nonnull Vector3d var1, int var2, int var3, @Nonnull SpawningContext var4, @Nonnull BeaconSpawnWrapper var5) {
ObjectArrayList var6 = (ObjectArrayList<FloodFillPositionSelector.WeightedPosition>)this.positionsByRole.get(var3);
if (var6.isEmpty()) {
class="kw">return false;
}
RoleSpawnParameters var7 = (RoleSpawnParameters)var5.getRoles().get(var3);
ISpawnable var8 = (ISpawnable)NPCPlugin.get().tryGetCachedValidRole(var3);
if (var8 == null) {
class="kw">return false;
}
double[] var9 = var7.getOrComputeMovementModeWeights(var8, var4);
if (var9 == null) {
class="kw">return false;
}
int var10 = RandomExtra.pickWeightedIndex(var9);
int var11 = 1 << var10;
if (!var4.setMovementMode(MovementMode.values()[var10], var5.getEnableSafeSpawning(var3))) {
class="kw">return false;
}
double var12 = var5.getMinDistanceFromPlayerSquared();
double var14 = var5.getTargetDistanceFromPlayerSquared();
for (int var16 = 0; var16 < var6.size(); var16++) {
FloodFillPositionSelector.WeightedPosition var17 = (FloodFillPositionSelector.WeightedPosition)var6.get(var16);
if ((var17.validMovementModesMask & var11) == 0) {
var17.weight = 0.0;
} else {
double var18 = var1.distanceSquared(var17.position.x, var17.position.y, var17.position.z);
var17.weight = var18 < var12 ? 0.0 : Math.max(0.0, var14 - Math.abs(var18 - var14));
}
}
int var29 = var2 * 3;
int var30 = var6.size();
FloodFillPositionSelector.WeightedPosition[] var31 = sortBufferProvider.get().getBuffer(var30);
System.arraycopy(var6.elements(), 0, var31, 0, var30);
ObjectArrays.mergeSort(var6.elements(), 0, var30, WEIGHTED_POSITION_COMPARATOR, var31);
double var19 = 0.0;
for (int var21 = 0; var21 < var29 && var21 < var6.size(); var21++) {
FloodFillPositionSelector.WeightedPosition var22 = (FloodFillPositionSelector.WeightedPosition)var6.get(var21);
if (var22.weight == 0.0) {
break;
}
var19 += var22.weight;
}
if (var19 == 0.0) {
class="kw">return false;
}
var19 = ThreadLocalRandom.current().nextDouble(var19);
int var33 = -1;
FloodFillPositionSelector.WeightedPosition var34 = null;
for (int var23 = 0; var23 < var29 && var23 < var6.size(); var23++) {
var34 = (FloodFillPositionSelector.WeightedPosition)var6.get(var23);
var33 = var23;
var19 -= var34.weight;
if (var19 < 0.0) {
break;
}
}
if (var34 == null) {
class="kw">return false;
}
Vector3i var35 = var34.position;
SpawnSuppressionController var24 = this.world.getEntityStore().getStore().getResource(SpawnSuppressionController.getResourceType());
long var25 = ChunkUtil.indexChunk(ChunkUtil.chunkCoordinate(var35.x), ChunkUtil.chunkCoordinate(var35.z));
ChunkSuppressionEntry var27 = var24.getChunkSuppressionMap().get(var25);
if ((var27 == null || !var27.isSuppressingRoleAt(var3, var35.y))
&& var4.set(this.world, var35.x, var35.y, var35.z)
&& var4.canSpawn() == SpawnTestResult.TEST_OK) {
class="kw">return true;
}
var6.remove(var33);
int var28 = this.failedSpawnsByRole.mergeInt(var3, 1, Integer::sum);
if (var28 > var6.size() * 0.25) {
this.hasRun = false;
}
class="kw">return false;
}
class="kw">public boolean shouldRebuildCache() {
class="kw">return !this.hasRun;
}
class="kw">public void forceRebuildCache() {
this.hasRun = false;
}
class="kw">public void init() {
Arrays.fill(this.heightGrid, -1);
for (int var1 = 1; var1 <= 8; var1 *= 2) {
((BitSet)this.resolutionMaps.get(var1)).clear();
}
for (int var4 : this.roleIndexes) {
((ObjectArrayList)this.positionsByRole.get(var4)).clear();
this.failedSpawnsByRole.put(var4, 0);
}
this.irregularCase = false;
}
class="kw">public void buildPositionCache(@Nonnull Vector3d var1, @Nonnull FloodFillEntryPoolSimple var2) {
int var3 = this.size / 2;
int var4 = MathUtil.floor(var1.x());
int var5 = MathUtil.floor(var1.y());
int var6 = MathUtil.floor(var1.z());
this.chunkAccessor = LocalCachedChunkAccessor.atWorldCoords(this.world, var4, var6, var3);
this.chunk = this.chunkAccessor.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(var4, var6));
if (this.chunk != null) {
int[] var7 = this.spawnWrapper.getSpawn().getYRange();
this.beaconY = var5;
this.minY = Math.max(0, var5 + var7[0]);
this.maxY = Math.min(319, var5 + var7[1]);
this.floodFill(var4, var5, var6, var3, var3, var2);
this.desiredPositionCount = Math.min(MathUtil.ceil(this.fullResolutionMap.cardinality() * 0.1), 30);
if (this.desiredPositionCount > 0) {
this.findPositions(var4, var6);
} else {
SpawningPlugin.get().getLogger().at(Level.WARNING).log("Spawn beacon at: %s unable to find any suitable positions to check", var1);
}
if (this.debug != FloodFillPositionSelector.Debug.DISABLED && (this.irregularCase || this.debug == FloodFillPositionSelector.Debug.ALL)) {
for (int var8 = 2; var8 <= 8; var8 *= 2) {
BitSet var9 = (BitSet)this.resolutionMaps.get(var8);
if (var9.cardinality() > 0) {
SpawningPlugin.get().getLogger().at(Level.WARNING).log("%s", this.debugDumpLowResolutionMap(var9, this.size / var8));
}
}
SpawningPlugin.get().getLogger().at(Level.WARNING).log("Spawn beacon at: %s%s", var1, this.irregularCase ? " is an irregular case" : "");
}
this.chunkAccessor = null;
this.chunk = null;
this.spawningContext.releaseFull();
this.hasRun = true;
}
}
class="kw">private void floodFill(int var1, int var2, int var3, int var4, int var5, @Nonnull FloodFillEntryPoolSimple var6) {
if (this.chunk != null) {
this.floodFillQueue.clear();
int[] var7 = var6.allocate();
var7[0] = var1;
var7[1] = var2;
var7[2] = var3;
var7[3] = var4;
var7[4] = var5;
this.floodFillQueue.add(var7);
int var8 = this.chunk.getX();
int var9 = this.chunk.getZ();
label66:
while (!this.floodFillQueue.isEmpty()) {
int[] var10 = this.floodFillQueue.poll();
var1 = var10[0];
var2 = var10[1];
var3 = var10[2];
var4 = var10[3];
var5 = var10[4];
if (var4 >= 0 && var4 < this.size && var5 >= 0 && var5 < this.size) {
int var11 = getPositionIndex(var4, var5, this.size);
if (this.heightGrid[var11] != -1) {
var6.deallocate(var10);
} else {
if (!ChunkUtil.isInsideChunk(var8, var9, var1, var3)) {
WorldChunk var12 = this.chunkAccessor.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(var1, var3));
if (var12 == null) {
this.heightGrid[var11] = -2;
var6.deallocate(var10);
class="kw">continue;
}
this.chunk = var12;
var8 = this.chunk.getX();
var9 = this.chunk.getZ();
}
int var21 = this.chunk.getBlock(var1, var2, var3);
if (var21 != 0 && BlockType.getAssetMap().getAsset(var21).getMaterial() == BlockMaterial.Solid) {
while (var21 != 0) {
var21 = this.chunk.getBlock(var1, ++var2, var3);
if (var2 > this.maxY) {
this.heightGrid[var11] = Integer.MAX_VALUE;
var6.deallocate(var10);
class="kw">continue label66;
}
}
} else {
while (var21 == 0) {
var21 = this.chunk.getBlock(var1, --var2, var3);
if (var2 < this.minY) {
this.heightGrid[var11] = Integer.MIN_VALUE;
var6.deallocate(var10);
class="kw">continue label66;
}
}
var2++;
}
this.heightGrid[var11] = var2;
this.fullResolutionMap.set(var11);
var10[0] = var1 + 1;
var10[1] = var2;
var10[2] = var3;
var10[3] = var4 + 1;
var10[4] = var5;
this.floodFillQueue.add(var10);
int[] var13 = var6.allocate();
var13[0] = var1 - 1;
var13[1] = var2;
var13[2] = var3;
var13[3] = var4 - 1;
var13[4] = var5;
this.floodFillQueue.add(var13);
int[] var14 = var6.allocate();
var14[0] = var1;
var14[1] = var2;
var14[2] = var3 + 1;
var14[3] = var4;
var14[4] = var5 + 1;
this.floodFillQueue.add(var14);
int[] var15 = var6.allocate();
var15[0] = var1;
var15[1] = var2;
var15[2] = var3 - 1;
var15[3] = var4;
var15[4] = var5 - 1;
this.floodFillQueue.add(var15);
}
} else {
var6.deallocate(var10);
}
}
}
}
class="kw">private void findPositions(int var1, int var2) {
int var3 = 1;
int var4;
do {
var3 *= 2;
var4 = this.buildLowerResolutionMap(
(BitSet)this.resolutionMaps.get(var3), this.size / var3, (BitSet)this.resolutionMaps.get(var3 / 2), this.size / (var3 / 2)
);
} while (var3 < 8 && var4 / this.desiredPositionCount > 1);
BitSet var5 = (BitSet)this.resolutionMaps.get(var3);
int var6 = var5.cardinality();
if (var6 < this.desiredPositionCount) {
var3 /= 2;
var5 = (BitSet)this.resolutionMaps.get(var3);
}
int var7 = this.size / 2;
int var8 = var1 - var7;
int var9 = var2 - var7;
SpawnSuppressionController var10 = this.world.getEntityStore().getStore().getResource(SpawnSuppressionController.getResourceType());
long var11 = ChunkUtil.NOT_FOUND;
ChunkSuppressionEntry var13 = null;
Long2ObjectConcurrentHashMap var14 = var10.getChunkSuppressionMap();
for (int var18 : this.roleIndexes) {
Builder var19 = NPCPlugin.get().tryGetCachedValidRole(var18);
if (var19 != null
&& var19.isSpawnable()
&& var19 class="kw">instanceof ISpawnableWithModel
&& this.spawningContext.setSpawnable((ISpawnableWithModel)var19, true)) {
RoleSpawnParameters var20 = (RoleSpawnParameters)this.spawnWrapper.getRoles().get(var18);
double[] var21 = var20.getOrComputeMovementModeWeights((ISpawnable)var19, this.spawningContext);
if (var21 != null) {
boolean var22 = this.spawnWrapper.getEnableSafeSpawning(var18);
ObjectArrayList var23 = (ObjectArrayList<FloodFillPositionSelector.WeightedPosition>)this.positionsByRole.get(var18);
this.lowestSpawnOverYRange = Double.MAX_VALUE;
this.lowestSpawnOverYRangeMode = null;
for (int var24 = var5.nextSetBit(0); var24 >= 0; var24 = var5.nextSetBit(var24 + 1)) {
int var25 = var24;
for (int var26 = var3; var26 > 1; var26 /= 2) {
int var27 = var26 / 2;
var25 = this.pickOpenSegment(var25, this.size / var26, (BitSet)this.resolutionMaps.get(var27), this.size / var27);
}
int var34 = var8 + xFromIndex(var25, this.size);
int var35 = this.heightGrid[var25];
int var28 = var9 + zFromIndex(var25, this.size);
long var29 = ChunkUtil.indexChunk(ChunkUtil.chunkCoordinate(var34), ChunkUtil.chunkCoordinate(var28));
if (var11 != var29) {
var13 = var14.get(var29);
var11 = var29;
}
int var31 = this.getValidMovementModesMask(var34, var35, var28, var18, var13, var21, var22);
if (var31 == 0) {
if (this.debug != FloodFillPositionSelector.Debug.DISABLED) {
this.failedPositionTestIndexes.add(var25);
}
int var32 = var25;
var25 = this.shiftIndexAwayFromWall(var25);
if (var25 == var32) {
class="kw">continue;
}
var34 = var8 + xFromIndex(var25, this.size);
var35 = this.heightGrid[var25];
var28 = var9 + zFromIndex(var25, this.size);
var29 = ChunkUtil.indexChunk(ChunkUtil.chunkCoordinate(var34), ChunkUtil.chunkCoordinate(var28));
if (var11 != var29) {
var13 = var14.get(var29);
var11 = var29;
}
var31 = this.getValidMovementModesMask(var34, var35, var28, var18, var13, var21, var22);
if (var31 == 0) {
if (this.debug != FloodFillPositionSelector.Debug.DISABLED) {
this.failedPositionTestIndexes.add(var25);
}
class="kw">continue;
}
}
if (this.positionIndexes.add(var25)) {
var23.add(new FloodFillPositionSelector.WeightedPosition(var34, var35, var28, var31));
}
if (var24 == Integer.MAX_VALUE) {
break;
}
}
if (var23.isEmpty() && this.lowestSpawnOverYRangeMode != null && var20.claimSpawnOverYRangeReport()) {
SpawningPlugin.get()
.getLogger()
.at(Level.WARNING)
.log(
"Spawn beacon %s found no position for role '%s'. Movement mode %s needs a YRange maximum of %d over the beacon. The asset allows %d. Raise YRange in the beacon asset.",
this.spawnWrapper.getSpawn().getId(),
NPCPlugin.get().getName(var18),
this.lowestSpawnOverYRangeMode,
MathUtil.ceil(this.lowestSpawnOverYRange) - this.beaconY,
this.maxY - this.beaconY
);
}
int var33 = this.positionIndexes.size();
if (this.debug != FloodFillPositionSelector.Debug.DISABLED
&& (var33 < this.desiredPositionCount * 0.3 || var33 > this.desiredPositionCount * 5.0)) {
this.irregularCase = true;
}
if (this.irregularCase || this.debug == FloodFillPositionSelector.Debug.ALL) {
SpawningPlugin.get().getLogger().at(Level.WARNING).log("Role: %s", NPCPlugin.get().getName(var18));
SpawningPlugin.get().getLogger().at(Level.WARNING).log("%s", this.debugDumpBaseFloodFill());
this.failedPositionTestIndexes.clear();
}
this.positionIndexes.clear();
}
}
}
}
class="kw">private int buildLowerResolutionMap(@Nonnull BitSet var1, int var2, @Nonnull BitSet var3, int var4) {
for (int var5 = 0; var5 < var2; var5++) {
for (int var6 = 0; var6 < var2; var6++) {
int var7 = var5 * 2;
int var8 = var6 * 2;
int var9 = getPositionIndex(var7, var8, var4);
if (var3.get(var9) || var3.get(var9 + 1) || var3.get(var9 + var4) || var3.get(var9 + var4 + 1)) {
var1.set(getPositionIndex(var5, var6, var2));
}
}
}
class="kw">return var1.cardinality();
}
class="kw">private int pickOpenSegment(int var1, int var2, @Nonnull BitSet var3, int var4) {
int var5 = xFromIndex(var1, var2);
int var6 = zFromIndex(var1, var2);
int var7 = var5 * 2;
int var8 = var6 * 2;
int var9 = getPositionIndex(var7, var8, var4);
if (var3.get(var9)) {
this.highResolutionOptions.add(var9);
}
int var10 = var9 + 1;
if (var3.get(var10)) {
this.highResolutionOptions.add(var10);
}
var10 = var9 + var4;
if (var3.get(var10)) {
this.highResolutionOptions.add(var10);
}
var10 = var9 + var4 + 1;
if (var3.get(var10)) {
this.highResolutionOptions.add(var10);
}
if (this.highResolutionOptions.size() > 1) {
IntLists.shuffle(this.highResolutionOptions, ThreadLocalRandom.current());
}
var10 = this.highResolutionOptions.getInt(0);
this.highResolutionOptions.clear();
class="kw">return var10;
}
class="kw">private int shiftIndexAwayFromWall(int var1) {
int var2 = var1;
int var3 = var1 - 1;
if (var3 < 0 || !this.fullResolutionMap.get(var3)) {
var2++;
}
var3 = var1 + 1;
if (var3 >= this.heightGrid.length || !this.fullResolutionMap.get(var3)) {
var2--;
}
var3 = var1 - this.size;
if (var3 < 0 || !this.fullResolutionMap.get(var3)) {
var2 += this.size;
}
var3 = var1 + this.size;
if (var3 >= this.heightGrid.length || !this.fullResolutionMap.get(var3)) {
var2 -= this.size;
}
class="kw">return var2 >= 0 && var2 < this.heightGrid.length && this.fullResolutionMap.get(var2) ? var2 : var1;
}
class="kw">private int getValidMovementModesMask(int var1, int var2, int var3, int var4, @Nullable ChunkSuppressionEntry var5, double[] var6, boolean var7) {
if (!this.spawnWrapper.getSpawn().isOverrideSpawnSuppressors() && var5 != null && var5.isSuppressingRoleAt(var4, var2)) {
class="kw">return 0;
}
if (!this.spawningContext.set(this.world, var1, var2, var3)) {
class="kw">return 0;
}
if (!this.spawnWrapper.withinLightRange(this.spawningContext)) {
class="kw">return 0;
}
IntSet var8 = this.spawnWrapper.getSpawnBlockSet(var4);
int var9 = this.spawnWrapper.getSpawnFluidTag(var4);
if (!this.spawningContext.canSpawnOnBlock(var8, var9)) {
class="kw">return 0;
}
int var10 = 0;
MovementMode[] var11 = MovementMode.values();
for (int var12 = 0; var12 < var6.length; var12++) {
if (var6[var12] != 0.0) {
this.spawningContext.invalidMaterials = -1;
if (this.spawningContext.setMovementMode(var11[var12], var7)) {
SpawnTestResult var13 = this.spawningContext.canSpawn();
if (var13 == SpawnTestResult.TEST_OK) {
if (this.spawningContext.ySpawn > this.maxY) {
if (this.spawningContext.ySpawn < this.lowestSpawnOverYRange) {
this.lowestSpawnOverYRange = this.spawningContext.ySpawn;
this.lowestSpawnOverYRangeMode = var11[var12];
}
} else {
var10 |= 1 << var12;
}
}
}
}
}
class="kw">return var10;
}
@Nonnull
class="kw">private String debugDumpBaseFloodFill() {
StringBuilder var1 = new StringBuilder();
int var2 = this.size / 2;
int var3 = getPositionIndex(var2, var2, this.size);
for (int var4 = 0; var4 < this.size; var4++) {
for (int var5 = 0; var5 < this.size; var5++) {
int var6 = getPositionIndex(var5, var4, this.size);
if (var6 == var3) {
var1.append('B');
} else if (this.positionIndexes.contains(var6)) {
var1.append('S');
} else if (this.failedPositionTestIndexes.contains(var6)) {
var1.append('F');
} else {
class="kw">switch (this.heightGrid[var6]) {
case Integer.MIN_VALUE:
var1.append('v');
break;
case -2:
case -1:
var1.append('X');
break;
case Integer.MAX_VALUE:
var1.append('^');
break;
class="kw">default:
var1.append('.');
}
}
var1.append(' ');
}
var1.append('\n');
}
class="kw">return var1.toString();
}
@Nonnull
class="kw">private String debugDumpLowResolutionMap(@Nonnull BitSet var1, int var2) {
StringBuilder var3 = new StringBuilder();
for (int var4 = 0; var4 < var2; var4++) {
for (int var5 = 0; var5 < var2; var5++) {
var3.append((char)(var1.get(getPositionIndex(var5, var4, var2)) ? '.' : 'X')).append(' ');
}
var3.append('\n');
}
class="kw">return var3.toString();
}
class="kw">public class="kw">static int getPositionIndex(int var0, int var1, int var2) {
class="kw">return var0 * var2 + var1;
}
class="kw">public class="kw">static int xFromIndex(int var0, int var1) {
class="kw">return var0 / var1;
}
class="kw">public class="kw">static int zFromIndex(int var0, int var1) {
class="kw">return var0 % var1;
}
@Nonnull
@Override
class="kw">public Component<EntityStore> clone() {
FloodFillPositionSelector var1 = new FloodFillPositionSelector(this.world, this.spawnWrapper);
var1.init();
class="kw">return var1;
}
class="kw">public enum Debug {
DISABLED,
IRREGULARITIES,
ALL;
Debug() {
}
}
class="kw">public class="kw">static class SortBufferProvider {
class="kw">protected FloodFillPositionSelector.WeightedPosition[] buffer = new FloodFillPositionSelector.WeightedPosition[10];
class="kw">public SortBufferProvider() {
}
class="kw">public FloodFillPositionSelector.WeightedPosition[] getBuffer(int var1) {
if (var1 <= this.buffer.length) {
class="kw">return this.buffer;
}
this.buffer = (FloodFillPositionSelector.WeightedPosition[])ObjectArrays.grow(this.buffer, var1);
class="kw">return this.buffer;
}
}
class="kw">private class="kw">static class WeightedPosition {
@Nonnull
class="kw">private class="kw">final Vector3i position;
class="kw">private double weight;
class="kw">private class="kw">final int validMovementModesMask;
class="kw">private WeightedPosition(int var1, int var2, int var3, int var4) {
this.position = new Vector3i(var1, var2, var3);
this.validMovementModesMask = var4;
}
class="kw">public double getWeight() {
class="kw">return this.weight;
}
}
}