hytale-server/com/hypixel/hytale/server/spawning/util/RandomChunkColumnIterator.java

147 lines
4.1 KiB
Java

package com.hypixel.hytale.server.spawning.util;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk;
import java.util.Random;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class RandomChunkColumnIterator {
@Nonnull
private final ChunkColumnMask availablePositions = new ChunkColumnMask();
@Nullable
private final ChunkColumnMask initialPositions;
@Nonnull
private final Random random = new Random();
private final long seed;
private int currentIndex;
private int lastSavedIteratorPosition;
public RandomChunkColumnIterator() {
this.initialPositions = null;
this.seed = this.random.nextLong();
}
public RandomChunkColumnIterator(@Nonnull ChunkColumnMask initialPositions) {
this.initialPositions = initialPositions;
if (initialPositions.isEmpty()) {
throw new IllegalArgumentException();
} else {
this.seed = this.random.nextLong();
}
}
public RandomChunkColumnIterator(ChunkColumnMask initialPositions, @Nonnull WorldChunk chunk) {
this.initialPositions = initialPositions;
this.seed = (chunk.getX() * 151L + chunk.getZ()) * 131L;
}
public int getCurrentIndex() {
return this.currentIndex;
}
public int getCurrentX() {
return ChunkUtil.xFromColumn(this.currentIndex);
}
public int getCurrentZ() {
return ChunkUtil.zFromColumn(this.currentIndex);
}
@Nullable
public ChunkColumnMask getInitialPositions() {
return this.initialPositions;
}
public int nextPosition() {
if (this.availablePositions.isEmpty()) {
this.reset();
}
int start = this.random.nextInt(1024);
int index = this.availablePositions.nextSetBit(start);
if (index == -1) {
index = this.availablePositions.previousSetBit(start);
}
return this.nextPosition(index);
}
public int nextPositionAvoidBorders() {
if (this.availablePositions.isEmpty()) {
this.reset();
}
int index = this.random.nextInt(1024);
int start;
int end;
if (this.availablePositions.get(index)) {
start = this.availablePositions.previousClearBit(index) + 1;
end = this.availablePositions.nextClearBit(index) - 1;
} else {
end = this.availablePositions.previousSetBit(index);
start = this.availablePositions.nextSetBit(index);
if (end != -1 && (start == -1 || index - end <= start - index)) {
start = this.availablePositions.previousClearBit(end) + 1;
} else {
end = this.availablePositions.nextClearBit(start) - 1;
}
}
int range = end - start + 1;
if (range > 3) {
start += 1 + this.random.nextInt(range - 2);
} else if (range > 1) {
start += this.random.nextInt(range);
}
if (!this.availablePositions.get(start)) {
throw new IllegalArgumentException();
} else {
return this.nextPosition(start);
}
}
public void saveIteratorPosition() {
this.lastSavedIteratorPosition = this.positionsLeft();
}
public boolean isAtSavedIteratorPosition() {
return this.positionsLeft() == this.lastSavedIteratorPosition;
}
public int positionsLeft() {
return this.availablePositions.cardinality();
}
public void markPositionVisited(int index) {
this.availablePositions.clear(index);
}
public void markPositionVisited() {
this.markPositionVisited(this.currentIndex);
}
private void reset() {
this.random.setSeed(this.seed);
if (this.initialPositions == null) {
this.availablePositions.set();
} else {
if (this.initialPositions.isEmpty()) {
throw new IllegalArgumentException();
}
this.availablePositions.copyFrom(this.initialPositions);
}
}
private int nextPosition(int index) {
if (index == -1) {
throw new IllegalArgumentException();
} else {
this.markPositionVisited(index);
return this.currentIndex = index;
}
}
}