131 lines
4.2 KiB
Java
131 lines
4.2 KiB
Java
package net.minecraft.server.level;
|
|
|
|
import com.google.common.annotations.VisibleForTesting;
|
|
import java.util.function.Consumer;
|
|
import net.minecraft.world.level.ChunkPos;
|
|
|
|
public interface ChunkTrackingView {
|
|
ChunkTrackingView EMPTY = new ChunkTrackingView() {
|
|
@Override
|
|
public boolean contains(int x, int z, boolean includeOuterChunksAdjacentToViewBorder) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void forEach(Consumer<ChunkPos> action) {
|
|
}
|
|
};
|
|
|
|
static ChunkTrackingView of(ChunkPos center, int viewDistance) {
|
|
return new ChunkTrackingView.Positioned(center, viewDistance);
|
|
}
|
|
|
|
/**
|
|
* Calculates the chunks that the player needs to drop in the {@code oldChunkTrackingView} and the chunks that need to be sent for the {@code newChunkTrackingView}. The chunks that overlap in both views can be kept.
|
|
*/
|
|
static void difference(
|
|
ChunkTrackingView oldChunkTrackingView, ChunkTrackingView newChunkTrackingView, Consumer<ChunkPos> chunkMarker, Consumer<ChunkPos> chunkDropper
|
|
) {
|
|
if (!oldChunkTrackingView.equals(newChunkTrackingView)) {
|
|
if (oldChunkTrackingView instanceof ChunkTrackingView.Positioned positioned
|
|
&& newChunkTrackingView instanceof ChunkTrackingView.Positioned positioned2
|
|
&& positioned.squareIntersects(positioned2)) {
|
|
int i = Math.min(positioned.minX(), positioned2.minX());
|
|
int j = Math.min(positioned.minZ(), positioned2.minZ());
|
|
int k = Math.max(positioned.maxX(), positioned2.maxX());
|
|
int l = Math.max(positioned.maxZ(), positioned2.maxZ());
|
|
|
|
for (int m = i; m <= k; m++) {
|
|
for (int n = j; n <= l; n++) {
|
|
boolean bl = positioned.contains(m, n);
|
|
boolean bl2 = positioned2.contains(m, n);
|
|
if (bl != bl2) {
|
|
if (bl2) {
|
|
chunkMarker.accept(new ChunkPos(m, n));
|
|
} else {
|
|
chunkDropper.accept(new ChunkPos(m, n));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
oldChunkTrackingView.forEach(chunkDropper);
|
|
newChunkTrackingView.forEach(chunkMarker);
|
|
}
|
|
}
|
|
}
|
|
|
|
default boolean contains(ChunkPos chunkPos) {
|
|
return this.contains(chunkPos.x, chunkPos.z);
|
|
}
|
|
|
|
default boolean contains(int x, int z) {
|
|
return this.contains(x, z, true);
|
|
}
|
|
|
|
boolean contains(int x, int z, boolean includeOuterChunksAdjacentToViewBorder);
|
|
|
|
void forEach(Consumer<ChunkPos> action);
|
|
|
|
default boolean isInViewDistance(int x, int z) {
|
|
return this.contains(x, z, false);
|
|
}
|
|
|
|
static boolean isInViewDistance(int centerX, int centerZ, int viewDistance, int x, int z) {
|
|
return isWithinDistance(centerX, centerZ, viewDistance, x, z, false);
|
|
}
|
|
|
|
/**
|
|
* Check if a chunk {@code (x,z)} is within a {@code viewDistance} which is centered on {@code (centerX, centerZ)}
|
|
*/
|
|
static boolean isWithinDistance(int centerX, int centerZ, int viewDistance, int x, int z, boolean includeOuterChunksAdjacentToViewBorder) {
|
|
int i = includeOuterChunksAdjacentToViewBorder ? 2 : 1;
|
|
long l = Math.max(0, Math.abs(x - centerX) - i);
|
|
long m = Math.max(0, Math.abs(z - centerZ) - i);
|
|
long n = l * l + m * m;
|
|
int j = viewDistance * viewDistance;
|
|
return n < j;
|
|
}
|
|
|
|
public record Positioned(ChunkPos center, int viewDistance) implements ChunkTrackingView {
|
|
int minX() {
|
|
return this.center.x - this.viewDistance - 1;
|
|
}
|
|
|
|
int minZ() {
|
|
return this.center.z - this.viewDistance - 1;
|
|
}
|
|
|
|
int maxX() {
|
|
return this.center.x + this.viewDistance + 1;
|
|
}
|
|
|
|
int maxZ() {
|
|
return this.center.z + this.viewDistance + 1;
|
|
}
|
|
|
|
/**
|
|
* Determines if another {@link ChunkTrackingView}'s bounds intersects with its own
|
|
*/
|
|
@VisibleForTesting
|
|
protected boolean squareIntersects(ChunkTrackingView.Positioned other) {
|
|
return this.minX() <= other.maxX() && this.maxX() >= other.minX() && this.minZ() <= other.maxZ() && this.maxZ() >= other.minZ();
|
|
}
|
|
|
|
@Override
|
|
public boolean contains(int x, int z, boolean includeOuterChunksAdjacentToViewBorder) {
|
|
return ChunkTrackingView.isWithinDistance(this.center.x, this.center.z, this.viewDistance, x, z, includeOuterChunksAdjacentToViewBorder);
|
|
}
|
|
|
|
@Override
|
|
public void forEach(Consumer<ChunkPos> action) {
|
|
for (int i = this.minX(); i <= this.maxX(); i++) {
|
|
for (int j = this.minZ(); j <= this.maxZ(); j++) {
|
|
if (this.contains(i, j)) {
|
|
action.accept(new ChunkPos(i, j));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|