mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-03 23:17:48 +01:00
Optimize chunk index to coordinate conversion + made the chunk map in InstanceContainer using long primitive but non-concurrent, requiring synchronization
This commit is contained in:
parent
97a1141583
commit
e5e1d1614b
@ -63,14 +63,15 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
|
|||||||
protected float cacheX, cacheY, cacheZ; // Used to synchronize with #getPosition
|
protected float cacheX, cacheY, cacheZ; // Used to synchronize with #getPosition
|
||||||
protected float lastYaw, lastPitch;
|
protected float lastYaw, lastPitch;
|
||||||
protected float cacheYaw, cachePitch;
|
protected float cacheYaw, cachePitch;
|
||||||
// Synchronization
|
|
||||||
private static final long SYNCHRONIZATION_DELAY = 1500; // In ms
|
|
||||||
|
|
||||||
private BoundingBox boundingBox;
|
private BoundingBox boundingBox;
|
||||||
|
|
||||||
protected Entity vehicle;
|
protected Entity vehicle;
|
||||||
|
|
||||||
// Velocity
|
// Velocity
|
||||||
protected Vector velocity = new Vector(); // Movement in block per second
|
protected Vector velocity = new Vector(); // Movement in block per second
|
||||||
|
protected long lastVelocityUpdateTime; // Reset velocity to 0 after countdown
|
||||||
|
|
||||||
protected float gravityDragPerTick;
|
protected float gravityDragPerTick;
|
||||||
protected float eyeHeight;
|
protected float eyeHeight;
|
||||||
|
|
||||||
@ -84,13 +85,17 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
|
|||||||
private boolean removed;
|
private boolean removed;
|
||||||
private boolean shouldRemove;
|
private boolean shouldRemove;
|
||||||
private long scheduledRemoveTime;
|
private long scheduledRemoveTime;
|
||||||
|
|
||||||
private final Set<Entity> passengers = new CopyOnWriteArraySet<>();
|
private final Set<Entity> passengers = new CopyOnWriteArraySet<>();
|
||||||
private long lastUpdate;
|
private long lastUpdate;
|
||||||
private final EntityType entityType;
|
private final EntityType entityType;
|
||||||
protected long lastVelocityUpdateTime; // Reset velocity to 0 after countdown
|
|
||||||
private final Map<Class<? extends Event>, List<EventCallback>> eventCallbacks = new ConcurrentHashMap<>();
|
// Synchronization
|
||||||
|
private static final long SYNCHRONIZATION_DELAY = 1500; // In ms
|
||||||
private long lastSynchronizationTime;
|
private long lastSynchronizationTime;
|
||||||
|
|
||||||
|
private final Map<Class<? extends Event>, List<EventCallback>> eventCallbacks = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
// Metadata
|
// Metadata
|
||||||
protected boolean onFire;
|
protected boolean onFire;
|
||||||
protected boolean crouched;
|
protected boolean crouched;
|
||||||
@ -990,8 +995,10 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
|
|||||||
|
|
||||||
final int[] oldChunksEntity = ArrayUtils.getDifferencesBetweenArray(lastVisibleChunksEntity, updatedVisibleChunksEntity);
|
final int[] oldChunksEntity = ArrayUtils.getDifferencesBetweenArray(lastVisibleChunksEntity, updatedVisibleChunksEntity);
|
||||||
for (int index : oldChunksEntity) {
|
for (int index : oldChunksEntity) {
|
||||||
final int[] chunkPos = ChunkUtils.getChunkCoord(lastVisibleChunksEntity[index]);
|
final long chunkIndex = lastVisibleChunksEntity[index];
|
||||||
final Chunk chunk = instance.getChunk(chunkPos[0], chunkPos[1]);
|
final int chunkX = ChunkUtils.getChunkCoordX(chunkIndex);
|
||||||
|
final int chunkZ = ChunkUtils.getChunkCoordZ(chunkIndex);
|
||||||
|
final Chunk chunk = instance.getChunk(chunkX, chunkZ);
|
||||||
if (chunk == null)
|
if (chunk == null)
|
||||||
continue;
|
continue;
|
||||||
instance.getChunkEntities(chunk).forEach(ent -> {
|
instance.getChunkEntities(chunk).forEach(ent -> {
|
||||||
@ -1010,8 +1017,10 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
|
|||||||
|
|
||||||
final int[] newChunksEntity = ArrayUtils.getDifferencesBetweenArray(updatedVisibleChunksEntity, lastVisibleChunksEntity);
|
final int[] newChunksEntity = ArrayUtils.getDifferencesBetweenArray(updatedVisibleChunksEntity, lastVisibleChunksEntity);
|
||||||
for (int index : newChunksEntity) {
|
for (int index : newChunksEntity) {
|
||||||
final int[] chunkPos = ChunkUtils.getChunkCoord(updatedVisibleChunksEntity[index]);
|
final long chunkIndex = updatedVisibleChunksEntity[index];
|
||||||
final Chunk chunk = instance.getChunk(chunkPos[0], chunkPos[1]);
|
final int chunkX = ChunkUtils.getChunkCoordX(chunkIndex);
|
||||||
|
final int chunkZ = ChunkUtils.getChunkCoordZ(chunkIndex);
|
||||||
|
final Chunk chunk = instance.getChunk(chunkX, chunkZ);
|
||||||
if (chunk == null)
|
if (chunk == null)
|
||||||
continue;
|
continue;
|
||||||
instance.getChunkEntities(chunk).forEach(ent -> {
|
instance.getChunkEntities(chunk).forEach(ent -> {
|
||||||
|
@ -551,9 +551,9 @@ public class Player extends LivingEntity implements CommandSender {
|
|||||||
|
|
||||||
AtomicInteger counter = new AtomicInteger(0);
|
AtomicInteger counter = new AtomicInteger(0);
|
||||||
for (long visibleChunk : visibleChunks) {
|
for (long visibleChunk : visibleChunks) {
|
||||||
final int[] chunkPos = ChunkUtils.getChunkCoord(visibleChunk);
|
final int chunkX = ChunkUtils.getChunkCoordX(visibleChunk);
|
||||||
final int chunkX = chunkPos[0];
|
final int chunkZ = ChunkUtils.getChunkCoordZ(visibleChunk);
|
||||||
final int chunkZ = chunkPos[1];
|
|
||||||
Consumer<Chunk> callback = (chunk) -> {
|
Consumer<Chunk> callback = (chunk) -> {
|
||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
chunk.addViewer(this);
|
chunk.addViewer(this);
|
||||||
@ -1200,13 +1200,16 @@ public class Player extends LivingEntity implements CommandSender {
|
|||||||
|
|
||||||
// Unload old chunks
|
// Unload old chunks
|
||||||
for (int index : oldChunks) {
|
for (int index : oldChunks) {
|
||||||
final int[] chunkPos = ChunkUtils.getChunkCoord(lastVisibleChunks[index]);
|
final long chunkIndex = lastVisibleChunks[index];
|
||||||
|
final int chunkX = ChunkUtils.getChunkCoordX(chunkIndex);
|
||||||
|
final int chunkZ = ChunkUtils.getChunkCoordZ(chunkIndex);
|
||||||
|
|
||||||
UnloadChunkPacket unloadChunkPacket = new UnloadChunkPacket();
|
UnloadChunkPacket unloadChunkPacket = new UnloadChunkPacket();
|
||||||
unloadChunkPacket.chunkX = chunkPos[0];
|
unloadChunkPacket.chunkX = chunkX;
|
||||||
unloadChunkPacket.chunkZ = chunkPos[1];
|
unloadChunkPacket.chunkZ = chunkZ;
|
||||||
playerConnection.sendPacket(unloadChunkPacket);
|
playerConnection.sendPacket(unloadChunkPacket);
|
||||||
|
|
||||||
final Chunk chunk = instance.getChunk(chunkPos[0], chunkPos[1]);
|
final Chunk chunk = instance.getChunk(chunkX, chunkZ);
|
||||||
if (chunk != null)
|
if (chunk != null)
|
||||||
chunk.removeViewer(this);
|
chunk.removeViewer(this);
|
||||||
}
|
}
|
||||||
@ -1215,8 +1218,11 @@ public class Player extends LivingEntity implements CommandSender {
|
|||||||
|
|
||||||
// Load new chunks
|
// Load new chunks
|
||||||
for (int index : newChunks) {
|
for (int index : newChunks) {
|
||||||
final int[] chunkPos = ChunkUtils.getChunkCoord(updatedVisibleChunks[index]);
|
final long chunkIndex = updatedVisibleChunks[index];
|
||||||
instance.loadOptionalChunk(chunkPos[0], chunkPos[1], chunk -> {
|
final int chunkX = ChunkUtils.getChunkCoordX(chunkIndex);
|
||||||
|
final int chunkZ = ChunkUtils.getChunkCoordZ(chunkIndex);
|
||||||
|
|
||||||
|
instance.loadOptionalChunk(chunkX, chunkZ, chunk -> {
|
||||||
if (chunk == null) {
|
if (chunk == null) {
|
||||||
// Cannot load chunk (auto load is not enabled)
|
// Cannot load chunk (auto load is not enabled)
|
||||||
return;
|
return;
|
||||||
|
@ -832,7 +832,7 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Set<Entity> getEntitiesInChunk(long index) {
|
private Set<Entity> getEntitiesInChunk(long index) {
|
||||||
final Set<Entity> entities = chunkEntities.getOrDefault(index, new CopyOnWriteArraySet<>());
|
final Set<Entity> entities = chunkEntities.computeIfAbsent(index, i -> new CopyOnWriteArraySet<>());
|
||||||
return entities;
|
return entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package net.minestom.server.instance;
|
package net.minestom.server.instance;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.MinecraftServer;
|
||||||
import net.minestom.server.data.Data;
|
import net.minestom.server.data.Data;
|
||||||
@ -30,7 +32,6 @@ import net.minestom.server.world.DimensionType;
|
|||||||
import net.minestom.server.world.biomes.Biome;
|
import net.minestom.server.world.biomes.Biome;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
@ -52,7 +53,8 @@ public class InstanceContainer extends Instance {
|
|||||||
private List<SharedInstance> sharedInstances = new CopyOnWriteArrayList<>();
|
private List<SharedInstance> sharedInstances = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
private ChunkGenerator chunkGenerator;
|
private ChunkGenerator chunkGenerator;
|
||||||
private Map<Long, Chunk> chunks = new ConcurrentHashMap<>();
|
// WARNING: need to be synchronized properly
|
||||||
|
private Long2ObjectMap<Chunk> chunks = new Long2ObjectOpenHashMap();
|
||||||
private Set<Chunk> scheduledChunksToRemove = new HashSet<>();
|
private Set<Chunk> scheduledChunksToRemove = new HashSet<>();
|
||||||
|
|
||||||
private ReadWriteLock changingBlockLock = new ReentrantReadWriteLock();
|
private ReadWriteLock changingBlockLock = new ReentrantReadWriteLock();
|
||||||
@ -333,7 +335,8 @@ public class InstanceContainer extends Instance {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Chunk getChunk(int chunkX, int chunkZ) {
|
public Chunk getChunk(int chunkX, int chunkZ) {
|
||||||
final Chunk chunk = chunks.get(ChunkUtils.getChunkIndex(chunkX, chunkZ));
|
final long index = ChunkUtils.getChunkIndex(chunkX, chunkZ);
|
||||||
|
final Chunk chunk = chunks.get(index);
|
||||||
return ChunkUtils.isLoaded(chunk) ? chunk : null;
|
return ChunkUtils.isLoaded(chunk) ? chunk : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,11 +393,13 @@ public class InstanceContainer extends Instance {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final Iterator<Chunk> chunks = getChunks().iterator();
|
synchronized (chunks) {
|
||||||
while (chunks.hasNext()) {
|
final Iterator<Chunk> chunkIterator = chunks.values().iterator();
|
||||||
final Chunk chunk = chunks.next();
|
while (chunkIterator.hasNext()) {
|
||||||
final boolean isLast = !chunks.hasNext();
|
final Chunk chunk = chunkIterator.next();
|
||||||
saveChunkToStorageFolder(chunk, isLast ? callback : null);
|
final boolean isLast = !chunkIterator.hasNext();
|
||||||
|
saveChunkToStorageFolder(chunk, isLast ? callback : null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -503,6 +508,11 @@ public class InstanceContainer extends Instance {
|
|||||||
this.chunkGenerator = chunkGenerator;
|
this.chunkGenerator = chunkGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the instance chunks
|
||||||
|
*
|
||||||
|
* @return the chunks of this instance
|
||||||
|
*/
|
||||||
public Collection<Chunk> getChunks() {
|
public Collection<Chunk> getChunks() {
|
||||||
return Collections.unmodifiableCollection(chunks.values());
|
return Collections.unmodifiableCollection(chunks.values());
|
||||||
}
|
}
|
||||||
|
@ -94,8 +94,10 @@ public abstract class ThreadProvider {
|
|||||||
* @param time the time of the update in milliseconds
|
* @param time the time of the update in milliseconds
|
||||||
*/
|
*/
|
||||||
protected void processChunkTick(Instance instance, long chunkIndex, long time) {
|
protected void processChunkTick(Instance instance, long chunkIndex, long time) {
|
||||||
final int[] chunkCoordinates = ChunkUtils.getChunkCoord(chunkIndex);
|
final int chunkX = ChunkUtils.getChunkCoordX(chunkIndex);
|
||||||
final Chunk chunk = instance.getChunk(chunkCoordinates[0], chunkCoordinates[1]);
|
final int chunkZ = ChunkUtils.getChunkCoordZ(chunkIndex);
|
||||||
|
|
||||||
|
final Chunk chunk = instance.getChunk(chunkX, chunkZ);
|
||||||
if (!ChunkUtils.isLoaded(chunk))
|
if (!ChunkUtils.isLoaded(chunk))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -10,199 +10,211 @@ import net.minestom.server.utils.Position;
|
|||||||
|
|
||||||
public final class ChunkUtils {
|
public final class ChunkUtils {
|
||||||
|
|
||||||
private ChunkUtils() {
|
private ChunkUtils() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get if a chunk is loaded
|
* Get if a chunk is loaded
|
||||||
*
|
*
|
||||||
* @param chunk the chunk to check
|
* @param chunk the chunk to check
|
||||||
* @return true if the chunk is loaded, false otherwise
|
* @return true if the chunk is loaded, false otherwise
|
||||||
*/
|
*/
|
||||||
public static boolean isLoaded(Chunk chunk) {
|
public static boolean isLoaded(Chunk chunk) {
|
||||||
return chunk != null && chunk.isLoaded();
|
return chunk != null && chunk.isLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get if a chunk is loaded
|
* Get if a chunk is loaded
|
||||||
*
|
*
|
||||||
* @param instance the instance to check
|
* @param instance the instance to check
|
||||||
* @param x instance X coordinate
|
* @param x instance X coordinate
|
||||||
* @param z instance Z coordinate
|
* @param z instance Z coordinate
|
||||||
* @return true if the chunk is loaded, false otherwise
|
* @return true if the chunk is loaded, false otherwise
|
||||||
*/
|
*/
|
||||||
public static boolean isLoaded(Instance instance, float x, float z) {
|
public static boolean isLoaded(Instance instance, float x, float z) {
|
||||||
final int chunkX = getChunkCoordinate((int) x);
|
final int chunkX = getChunkCoordinate((int) x);
|
||||||
final int chunkZ = getChunkCoordinate((int) z);
|
final int chunkZ = getChunkCoordinate((int) z);
|
||||||
|
|
||||||
final Chunk chunk = instance.getChunk(chunkX, chunkZ);
|
final Chunk chunk = instance.getChunk(chunkX, chunkZ);
|
||||||
return isLoaded(chunk);
|
return isLoaded(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param xz the instance coordinate to convert
|
* @param xz the instance coordinate to convert
|
||||||
* @return the chunk X or Z based on the argument
|
* @return the chunk X or Z based on the argument
|
||||||
*/
|
*/
|
||||||
public static int getChunkCoordinate(int xz) {
|
public static int getChunkCoordinate(int xz) {
|
||||||
// Assume Chunk.CHUNK_SIZE_X == Chunk.CHUNK_SIZE_Z
|
// Assume Chunk.CHUNK_SIZE_X == Chunk.CHUNK_SIZE_Z
|
||||||
return Math.floorDiv(xz, Chunk.CHUNK_SIZE_X);
|
return Math.floorDiv(xz, Chunk.CHUNK_SIZE_X);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the chunk index of chunk coordinates
|
* Get the chunk index of chunk coordinates
|
||||||
*
|
*
|
||||||
* @param chunkX the chunk X
|
* @param chunkX the chunk X
|
||||||
* @param chunkZ the chunk Z
|
* @param chunkZ the chunk Z
|
||||||
* @return a number storing the chunk X and Z
|
* @return a number storing the chunk X and Z
|
||||||
*/
|
*/
|
||||||
public static long getChunkIndex(int chunkX, int chunkZ) {
|
public static long getChunkIndex(int chunkX, int chunkZ) {
|
||||||
return (((long) chunkX) << 32) | (chunkZ & 0xffffffffL);
|
return (((long) chunkX) << 32) | (chunkZ & 0xffffffffL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long getChunkIndexWithSection(int chunkX, int chunkZ, int section) {
|
public static long getChunkIndexWithSection(int chunkX, int chunkZ, int section) {
|
||||||
long l = 0L;
|
long l = 0L;
|
||||||
l |= ((long) chunkX & 4194303L) << 42;
|
l |= ((long) chunkX & 4194303L) << 42;
|
||||||
l |= ((long) section & 1048575L);
|
l |= ((long) section & 1048575L);
|
||||||
l |= ((long) chunkZ & 4194303L) << 20;
|
l |= ((long) chunkZ & 4194303L) << 20;
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param index the chunk index computed by {@link #getChunkIndex(int, int)}
|
* Convert a chunk index to its chunk X position
|
||||||
* @return an array containing both the chunk X and Z (index 0 = X; index 1 = Z)
|
*
|
||||||
*/
|
* @param index the chunk index computed by {@link #getChunkIndex(int, int)}
|
||||||
public static int[] getChunkCoord(long index) {
|
* @return the chunk X based on the index
|
||||||
final int chunkX = (int) (index >> 32);
|
*/
|
||||||
final int chunkZ = (int) index;
|
public static int getChunkCoordX(long index) {
|
||||||
return new int[]{chunkX, chunkZ};
|
return (int) (index >> 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static short getLocalBlockPosAsShort(int x, int y, int z) {
|
/**
|
||||||
x = x % 16;
|
* Convert a chunk index to its chunk Z position
|
||||||
z = z % 16;
|
*
|
||||||
return (short) (x << 8 | y << 4 | z);
|
* @param index the chunk index computed by {@link #getChunkIndex(int, int)}
|
||||||
}
|
* @return the chunk Z based on the index
|
||||||
|
*/
|
||||||
|
public static int getChunkCoordZ(long index) {
|
||||||
|
final int chunkX = (int) (index >> 32);
|
||||||
|
final int chunkZ = (int) index;
|
||||||
|
return (int) index;
|
||||||
|
}
|
||||||
|
|
||||||
public static int getSectionAt(int y) {
|
public static short getLocalBlockPosAsShort(int x, int y, int z) {
|
||||||
return y / Chunk.CHUNK_SECTION_SIZE;
|
x = x % 16;
|
||||||
}
|
z = z % 16;
|
||||||
|
return (short) (x << 8 | y << 4 | z);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
public static int getSectionAt(int y) {
|
||||||
* Get the chunks in range of a position
|
return y / Chunk.CHUNK_SECTION_SIZE;
|
||||||
*
|
}
|
||||||
* @param position the initial position
|
|
||||||
* @param range how far should it retrieves chunk
|
|
||||||
* @return an array containing chunks index which can be converted using {@link #getChunkCoord(long)}
|
|
||||||
*/
|
|
||||||
public static long[] getChunksInRange(final Position position, int range) {
|
|
||||||
range = range * 2;
|
|
||||||
long[] visibleChunks = new long[MathUtils.square(range + 1)];
|
|
||||||
final int startLoop = -(range / 2);
|
|
||||||
final int endLoop = range / 2 + 1;
|
|
||||||
int counter = 0;
|
|
||||||
for (int x = startLoop; x < endLoop; x++) {
|
|
||||||
for (int z = startLoop; z < endLoop; z++) {
|
|
||||||
final int chunkX = getChunkCoordinate((int) (position.getX() + Chunk.CHUNK_SIZE_X * x));
|
|
||||||
final int chunkZ = getChunkCoordinate((int) (position.getZ() + Chunk.CHUNK_SIZE_Z * z));
|
|
||||||
visibleChunks[counter] = getChunkIndex(chunkX, chunkZ);
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return visibleChunks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all the loaded neighbours of a chunk and itself, no diagonals
|
* Get the chunks in range of a position
|
||||||
*
|
*
|
||||||
* @param instance the instance of the chunks
|
* @param position the initial position
|
||||||
* @param chunkX the chunk X
|
* @param range how far should it retrieves chunk
|
||||||
* @param chunkZ the chunk Z
|
* @return an array containing chunks index
|
||||||
* @return an array containing all the loaded neighbours
|
*/
|
||||||
* can be deserialized using {@link #indexToChunkPosition(int)}
|
public static long[] getChunksInRange(final Position position, int range) {
|
||||||
*/
|
range = range * 2;
|
||||||
public static long[] getNeighbours(Instance instance, int chunkX, int chunkZ) {
|
long[] visibleChunks = new long[MathUtils.square(range + 1)];
|
||||||
LongList chunks = new LongArrayList();
|
final int startLoop = -(range / 2);
|
||||||
// Constants used to loop through the neighbors
|
final int endLoop = range / 2 + 1;
|
||||||
final int[] posX = {1, 0, -1};
|
int counter = 0;
|
||||||
final int[] posZ = {1, 0, -1};
|
for (int x = startLoop; x < endLoop; x++) {
|
||||||
|
for (int z = startLoop; z < endLoop; z++) {
|
||||||
|
final int chunkX = getChunkCoordinate((int) (position.getX() + Chunk.CHUNK_SIZE_X * x));
|
||||||
|
final int chunkZ = getChunkCoordinate((int) (position.getZ() + Chunk.CHUNK_SIZE_Z * z));
|
||||||
|
visibleChunks[counter] = getChunkIndex(chunkX, chunkZ);
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return visibleChunks;
|
||||||
|
}
|
||||||
|
|
||||||
for (int x : posX) {
|
/**
|
||||||
for (int z : posZ) {
|
* Get all the loaded neighbours of a chunk and itself, no diagonals
|
||||||
|
*
|
||||||
|
* @param instance the instance of the chunks
|
||||||
|
* @param chunkX the chunk X
|
||||||
|
* @param chunkZ the chunk Z
|
||||||
|
* @return an array containing all the loaded neighbours
|
||||||
|
* can be deserialized using {@link #indexToChunkPosition(int)}
|
||||||
|
*/
|
||||||
|
public static long[] getNeighbours(Instance instance, int chunkX, int chunkZ) {
|
||||||
|
LongList chunks = new LongArrayList();
|
||||||
|
// Constants used to loop through the neighbors
|
||||||
|
final int[] posX = {1, 0, -1};
|
||||||
|
final int[] posZ = {1, 0, -1};
|
||||||
|
|
||||||
// No diagonal check
|
for (int x : posX) {
|
||||||
if ((Math.abs(x) + Math.abs(z)) == 2)
|
for (int z : posZ) {
|
||||||
continue;
|
|
||||||
|
|
||||||
final int targetX = chunkX + x;
|
// No diagonal check
|
||||||
final int targetZ = chunkZ + z;
|
if ((Math.abs(x) + Math.abs(z)) == 2)
|
||||||
final Chunk chunk = instance.getChunk(targetX, targetZ);
|
continue;
|
||||||
if (ChunkUtils.isLoaded(chunk)) {
|
|
||||||
// Chunk is loaded, add it
|
|
||||||
final long index = getChunkIndex(targetX, targetZ);
|
|
||||||
chunks.add(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
final int targetX = chunkX + x;
|
||||||
}
|
final int targetZ = chunkZ + z;
|
||||||
return chunks.toArray(new long[0]);
|
final Chunk chunk = instance.getChunk(targetX, targetZ);
|
||||||
}
|
if (ChunkUtils.isLoaded(chunk)) {
|
||||||
|
// Chunk is loaded, add it
|
||||||
|
final long index = getChunkIndex(targetX, targetZ);
|
||||||
|
chunks.add(index);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
}
|
||||||
* Get the block index of a position
|
}
|
||||||
*
|
return chunks.toArray(new long[0]);
|
||||||
* @param x the block X
|
}
|
||||||
* @param y the block Y
|
|
||||||
* @param z the block Z
|
|
||||||
* @return an index which can be used to store and retrieve later data linked to a block position
|
|
||||||
*/
|
|
||||||
public static int getBlockIndex(int x, int y, int z) {
|
|
||||||
x = x % Chunk.CHUNK_SIZE_X;
|
|
||||||
z = z % Chunk.CHUNK_SIZE_Z;
|
|
||||||
|
|
||||||
short index = (short) (x & 0x000F);
|
/**
|
||||||
index |= (y << 4) & 0x0FF0;
|
* Get the block index of a position
|
||||||
index |= (z << 12) & 0xF000;
|
*
|
||||||
return index & 0xffff;
|
* @param x the block X
|
||||||
}
|
* @param y the block Y
|
||||||
|
* @param z the block Z
|
||||||
|
* @return an index which can be used to store and retrieve later data linked to a block position
|
||||||
|
*/
|
||||||
|
public static int getBlockIndex(int x, int y, int z) {
|
||||||
|
x = x % Chunk.CHUNK_SIZE_X;
|
||||||
|
z = z % Chunk.CHUNK_SIZE_Z;
|
||||||
|
|
||||||
/**
|
short index = (short) (x & 0x000F);
|
||||||
* @param index an index computed from {@link #getBlockIndex(int, int, int)}
|
index |= (y << 4) & 0x0FF0;
|
||||||
* @param chunkX the chunk X
|
index |= (z << 12) & 0xF000;
|
||||||
* @param chunkZ the chunk Z
|
return index & 0xffff;
|
||||||
* @return the instance position of the block located in {@code index}
|
}
|
||||||
*/
|
|
||||||
public static BlockPosition getBlockPosition(int index, int chunkX, int chunkZ) {
|
|
||||||
final int[] pos = indexToPosition(index, chunkX, chunkZ);
|
|
||||||
return new BlockPosition(pos[0], pos[1], pos[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param index an index computed from {@link #getBlockIndex(int, int, int)}
|
* @param index an index computed from {@link #getBlockIndex(int, int, int)}
|
||||||
* @param chunkX the chunk X
|
* @param chunkX the chunk X
|
||||||
* @param chunkZ the chunk Z
|
* @param chunkZ the chunk Z
|
||||||
* @return the world position of the specified index with its chunks being {@code chunkX} and {@code chunk Z}
|
* @return the instance position of the block located in {@code index}
|
||||||
* positions in the array are in the order X/Y/Z
|
*/
|
||||||
*/
|
public static BlockPosition getBlockPosition(int index, int chunkX, int chunkZ) {
|
||||||
public static int[] indexToPosition(int index, int chunkX, int chunkZ) {
|
final int[] pos = indexToPosition(index, chunkX, chunkZ);
|
||||||
int z = (byte) (index >> 12 & 0xF);
|
return new BlockPosition(pos[0], pos[1], pos[2]);
|
||||||
final int y = (index >>> 4 & 0xFF);
|
}
|
||||||
// index >> 0 = index
|
|
||||||
int x = (byte) (index & 0xF);
|
|
||||||
|
|
||||||
x += 16 * chunkX;
|
/**
|
||||||
z += 16 * chunkZ;
|
* @param index an index computed from {@link #getBlockIndex(int, int, int)}
|
||||||
|
* @param chunkX the chunk X
|
||||||
|
* @param chunkZ the chunk Z
|
||||||
|
* @return the world position of the specified index with its chunks being {@code chunkX} and {@code chunk Z}
|
||||||
|
* positions in the array are in the order X/Y/Z
|
||||||
|
*/
|
||||||
|
public static int[] indexToPosition(int index, int chunkX, int chunkZ) {
|
||||||
|
int z = (byte) (index >> 12 & 0xF);
|
||||||
|
final int y = (index >>> 4 & 0xFF);
|
||||||
|
// index >> 0 = index
|
||||||
|
int x = (byte) (index & 0xF);
|
||||||
|
|
||||||
return new int[]{x, y, z};
|
x += 16 * chunkX;
|
||||||
}
|
z += 16 * chunkZ;
|
||||||
|
|
||||||
/**
|
return new int[]{x, y, z};
|
||||||
* @param index an index computed from {@link #getBlockIndex(int, int, int)}
|
}
|
||||||
* @return the chunk position (O-15) of the specified index,
|
|
||||||
* positions in the array are in the order X/Y/Z
|
/**
|
||||||
*/
|
* @param index an index computed from {@link #getBlockIndex(int, int, int)}
|
||||||
public static int[] indexToChunkPosition(int index) {
|
* @return the chunk position (O-15) of the specified index,
|
||||||
return indexToPosition(index, 0, 0);
|
* positions in the array are in the order X/Y/Z
|
||||||
}
|
*/
|
||||||
|
public static int[] indexToChunkPosition(int index) {
|
||||||
|
return indexToPosition(index, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,9 @@ public final class EntityUtils {
|
|||||||
|
|
||||||
long[] visibleChunksEntity = ChunkUtils.getChunksInRange(ent2.getPosition(), MinecraftServer.ENTITY_VIEW_DISTANCE);
|
long[] visibleChunksEntity = ChunkUtils.getChunksInRange(ent2.getPosition(), MinecraftServer.ENTITY_VIEW_DISTANCE);
|
||||||
for (long visibleChunk : visibleChunksEntity) {
|
for (long visibleChunk : visibleChunksEntity) {
|
||||||
final int[] chunkPos = ChunkUtils.getChunkCoord(visibleChunk);
|
final int chunkX = ChunkUtils.getChunkCoordX(visibleChunk);
|
||||||
final int chunkX = chunkPos[0];
|
final int chunkZ = ChunkUtils.getChunkCoordZ(visibleChunk);
|
||||||
final int chunkZ = chunkPos[1];
|
|
||||||
if (chunk.getChunkX() == chunkX && chunk.getChunkZ() == chunkZ)
|
if (chunk.getChunkX() == chunkX && chunk.getChunkZ() == chunkZ)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user