mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-29 19:41:47 +01:00
Merge pull request #274 from Kebab11noel/position-cleanup
Chunk loading rework
This commit is contained in:
commit
d8274bbdf1
@ -683,8 +683,7 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer,
|
||||
* <i>(performed using {@link #synchronizePosition()})</i></li>
|
||||
* <li>{@link EntityPositionAndRotationPacket} if {@code positionChange && viewChange}</li>
|
||||
* <li>{@link EntityPositionPacket} if {@code positionChange}</li>
|
||||
* <li>{@link EntityRotationPacket} if {@code viewChange}
|
||||
* <i>(performed using {@link #setView(float, float)})</i></li>
|
||||
* <li>{@link EntityRotationPacket} and {@link EntityHeadLookPacket} if {@code viewChange}</li>
|
||||
* </ol>
|
||||
* In case of a player's position and/or view change an additional {@link PlayerPositionAndLookPacket}
|
||||
* is sent to self.
|
||||
|
@ -69,7 +69,6 @@ import net.minestom.server.utils.entity.EntityUtils;
|
||||
import net.minestom.server.utils.identity.NamedAndIdentified;
|
||||
import net.minestom.server.utils.instance.InstanceUtils;
|
||||
import net.minestom.server.utils.inventory.PlayerInventoryUtils;
|
||||
import net.minestom.server.utils.player.PlayerUtils;
|
||||
import net.minestom.server.utils.time.Cooldown;
|
||||
import net.minestom.server.utils.time.TimeUnit;
|
||||
import net.minestom.server.utils.time.UpdateOption;
|
||||
@ -609,19 +608,13 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
sendDimension(instanceDimensionType);
|
||||
}
|
||||
|
||||
// Load all the required chunks
|
||||
final long[] visibleChunks = ChunkUtils.getChunksInRange(spawnPosition, getChunkRange());
|
||||
// Only load the spawning chunk to speed up login, remaining chunks are loaded in #spawnPlayer
|
||||
final long[] visibleChunks = ChunkUtils.getChunksInRange(spawnPosition, 0);
|
||||
|
||||
final ChunkCallback endCallback = chunk -> {
|
||||
// This is the last chunk to be loaded , spawn player
|
||||
spawnPlayer(instance, spawnPosition, firstSpawn, true, dimensionChange);
|
||||
};
|
||||
|
||||
// Chunk 0;0 always needs to be loaded
|
||||
instance.loadChunk(0, 0, chunk ->
|
||||
// Load all the required chunks
|
||||
ChunkUtils.optionalLoadAll(instance, visibleChunks, null, endCallback));
|
||||
final ChunkCallback endCallback =
|
||||
chunk -> spawnPlayer(instance, spawnPosition, firstSpawn, dimensionChange, true);
|
||||
|
||||
ChunkUtils.optionalLoadAll(instance, visibleChunks, null, endCallback);
|
||||
} else {
|
||||
// The player already has the good version of all the chunks.
|
||||
// We just need to refresh his entity viewing list and add him to the instance
|
||||
@ -650,22 +643,20 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
*
|
||||
* @param spawnPosition the position to teleport the player
|
||||
* @param firstSpawn true if this is the player first spawn
|
||||
* @param updateChunks true if chunks should be refreshed, false if the new instance shares the same
|
||||
* chunks
|
||||
*/
|
||||
private void spawnPlayer(@NotNull Instance instance, @NotNull Position spawnPosition,
|
||||
boolean firstSpawn, boolean updateChunks, boolean dimensionChange) {
|
||||
// Clear previous instance elements
|
||||
boolean firstSpawn, boolean dimensionChange, boolean updateChunks) {
|
||||
if (!firstSpawn) {
|
||||
// Player instance changed, clear current viewable collections
|
||||
this.viewableChunks.forEach(chunk -> chunk.removeViewer(this));
|
||||
this.viewableEntities.forEach(entity -> entity.removeViewer(this));
|
||||
}
|
||||
|
||||
super.setInstance(instance, spawnPosition);
|
||||
|
||||
if (!position.isSimilar(spawnPosition) && !firstSpawn) {
|
||||
// Player changed instance at a different position
|
||||
teleport(spawnPosition);
|
||||
} else if (updateChunks) {
|
||||
// Send newly visible chunks to player once spawned in the instance
|
||||
if (updateChunks) {
|
||||
refreshVisibleChunks();
|
||||
}
|
||||
|
||||
@ -1556,27 +1547,25 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
final int[] oldChunks = ArrayUtils.getDifferencesBetweenArray(lastVisibleChunks, updatedVisibleChunks);
|
||||
final int[] newChunks = ArrayUtils.getDifferencesBetweenArray(updatedVisibleChunks, lastVisibleChunks);
|
||||
|
||||
// Update client render distance
|
||||
updateViewPosition(newChunk.getChunkX(), newChunk.getChunkZ());
|
||||
|
||||
// Unload old chunks
|
||||
for (int index : oldChunks) {
|
||||
final long chunkIndex = lastVisibleChunks[index];
|
||||
final int chunkX = ChunkUtils.getChunkCoordX(chunkIndex);
|
||||
final int chunkZ = ChunkUtils.getChunkCoordZ(chunkIndex);
|
||||
|
||||
// TODO prevent the client from getting lag spikes when re-loading large chunks
|
||||
// Probably by having a distinction between visible and loaded (cache) chunks
|
||||
/*UnloadChunkPacket unloadChunkPacket = new UnloadChunkPacket();
|
||||
final UnloadChunkPacket unloadChunkPacket = new UnloadChunkPacket();
|
||||
unloadChunkPacket.chunkX = chunkX;
|
||||
unloadChunkPacket.chunkZ = chunkZ;
|
||||
playerConnection.sendPacket(unloadChunkPacket);*/
|
||||
playerConnection.sendPacket(unloadChunkPacket);
|
||||
|
||||
final Chunk chunk = instance.getChunk(chunkX, chunkZ);
|
||||
if (chunk != null)
|
||||
chunk.removeViewer(this);
|
||||
}
|
||||
|
||||
// Update client render distance
|
||||
updateViewPosition(newChunk.getChunkX(), newChunk.getChunkZ());
|
||||
|
||||
// Load new chunks
|
||||
for (int index : newChunks) {
|
||||
final long chunkIndex = updatedVisibleChunks[index];
|
||||
@ -2372,17 +2361,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
* based on which one is the lowest
|
||||
*/
|
||||
public int getChunkRange() {
|
||||
final int playerRange = getSettings().viewDistance;
|
||||
if (playerRange < 1) {
|
||||
// Didn't receive settings packet yet (is the case on login)
|
||||
// In this case we send an arbitrary number of chunks
|
||||
// Will be updated in PlayerSettings#refresh.
|
||||
// Non-compliant clients might also be stuck with this view
|
||||
return 7;
|
||||
} else {
|
||||
final int serverRange = MinecraftServer.getChunkViewDistance();
|
||||
return Math.min(playerRange, serverRange);
|
||||
}
|
||||
return Math.min(getSettings().viewDistance, MinecraftServer.getChunkViewDistance());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2614,6 +2593,10 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
private byte displayedSkinParts;
|
||||
private MainHand mainHand;
|
||||
|
||||
public PlayerSettings() {
|
||||
viewDistance = 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* The player game language.
|
||||
*
|
||||
|
@ -161,18 +161,42 @@ public final class ChunkUtils {
|
||||
* @param range how far should it retrieves chunk
|
||||
* @return an array containing chunks index
|
||||
*/
|
||||
@NotNull
|
||||
public static long[] getChunksInRange(@NotNull 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(position.getX() + Chunk.CHUNK_SIZE_X * x);
|
||||
final int chunkZ = getChunkCoordinate(position.getZ() + Chunk.CHUNK_SIZE_Z * z);
|
||||
visibleChunks[counter++] = getChunkIndex(chunkX, chunkZ);
|
||||
public static @NotNull long[] getChunksInRange(@NotNull Position position, int range) {
|
||||
long[] visibleChunks = new long[MathUtils.square(range * 2 + 1)];
|
||||
int xDistance = 0;
|
||||
int xDirection = 1;
|
||||
int zDistance = 0;
|
||||
int zDirection = -1;
|
||||
int len = 1;
|
||||
int corner = 0;
|
||||
|
||||
for (int i = 0; i < visibleChunks.length; i++) {
|
||||
final int chunkX = getChunkCoordinate(xDistance * Chunk.CHUNK_SIZE_X + position.getX());
|
||||
final int chunkZ = getChunkCoordinate(zDistance * Chunk.CHUNK_SIZE_Z + position.getZ());
|
||||
visibleChunks[i] = getChunkIndex(chunkX, chunkZ);
|
||||
|
||||
if (corner % 2 == 0) {
|
||||
// step on X axis
|
||||
xDistance += xDirection;
|
||||
|
||||
if (Math.abs(xDistance) == len) {
|
||||
// hit corner
|
||||
corner++;
|
||||
xDirection = -xDirection;
|
||||
}
|
||||
} else {
|
||||
// step on Z axis
|
||||
zDistance += zDirection;
|
||||
|
||||
if (Math.abs(zDistance) == len) {
|
||||
// hit corner
|
||||
corner++;
|
||||
zDirection = -zDirection;
|
||||
|
||||
if (corner % 4 == 0) {
|
||||
len++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return visibleChunks;
|
||||
|
Loading…
Reference in New Issue
Block a user