Player#setInstance can now take an optional Position parameter

This commit is contained in:
Felix Cravic 2020-11-25 12:12:58 +01:00
parent edf22fcb66
commit ab73b0fa3e
4 changed files with 62 additions and 60 deletions

View File

@ -1122,34 +1122,6 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
this.eyeHeight = eyeHeight;
}
/**
* Gets if this entity is in the same chunk as the specified position.
*
* @param position the checked position chunk
* @return true if the entity is in the same chunk as {@code position}
*/
public boolean sameChunk(@NotNull Position position) {
Check.notNull(position, "Position cannot be null");
final Position pos = getPosition();
final int chunkX1 = ChunkUtils.getChunkCoordinate((int) Math.floor(pos.getX()));
final int chunkZ1 = ChunkUtils.getChunkCoordinate((int) Math.floor(pos.getZ()));
final int chunkX2 = ChunkUtils.getChunkCoordinate((int) Math.floor(position.getX()));
final int chunkZ2 = ChunkUtils.getChunkCoordinate((int) Math.floor(position.getZ()));
return chunkX1 == chunkX2 && chunkZ1 == chunkZ2;
}
/**
* Gets if the entity is in the same chunk as another.
*
* @param entity the entity to check
* @return true if both entities are in the same chunk, false otherwise
*/
public boolean sameChunk(@NotNull Entity entity) {
return sameChunk(entity.getPosition());
}
/**
* Removes the entity from the server immediately.
* <p>

View File

@ -66,6 +66,7 @@ public final class EntityManager {
waitingPlayer.init();
// Spawn the player at Player#getRespawnPoint during the next instance tick
spawningInstance.scheduleNextTick(waitingPlayer::setInstance);
}
}

View File

@ -683,22 +683,19 @@ public class Player extends LivingEntity implements CommandSender {
* <p>
* Be aware that because chunk operations are expensive,
* it is possible for this method to be non-blocking when retrieving chunks is required.
* <p>
* When this method is called for the first time (during player login), the player will be teleport at {@link #getRespawnPoint()}.
*
* @param instance the new instance of the player
* @param instance the new player instance
*/
@Override
public void setInstance(@NotNull Instance instance) {
public void setInstance(@NotNull Instance instance, @NotNull Position spawnPosition) {
Check.notNull(instance, "instance cannot be null!");
Check.argCondition(this.instance == instance, "Instance should be different than the current one");
final boolean firstSpawn = this.instance == null; // TODO: Handle player reconnections, must be false in that case too
// true if the chunks need to be sent to the client, can be false if the instances share the same chunks (eg SharedInstance)
final boolean needWorldRefresh = !InstanceUtils.areLinked(this.instance, instance);
if (needWorldRefresh) {
final boolean firstSpawn = this.instance == null; // TODO: Handle player reconnections, must be false in that case too
// Remove all previous viewable chunks (from the previous instance)
for (Chunk viewableChunk : viewableChunks) {
viewableChunk.removeViewer(this);
@ -712,13 +709,12 @@ public class Player extends LivingEntity implements CommandSender {
}
// Load all the required chunks
final Position pos = firstSpawn ? getRespawnPoint() : position;
final long[] visibleChunks = ChunkUtils.getChunksInRange(pos, getChunkRange());
final long[] visibleChunks = ChunkUtils.getChunksInRange(spawnPosition, getChunkRange());
final ChunkCallback eachCallback = chunk -> {
if (chunk != null) {
final int chunkX = ChunkUtils.getChunkCoordinate((int) pos.getX());
final int chunkZ = ChunkUtils.getChunkCoordinate((int) pos.getZ());
final int chunkX = ChunkUtils.getChunkCoordinate((int) spawnPosition.getX());
final int chunkZ = ChunkUtils.getChunkCoordinate((int) spawnPosition.getZ());
if (chunk.getChunkX() == chunkX &&
chunk.getChunkZ() == chunkZ) {
updateViewPosition(chunkX, chunkZ);
@ -728,7 +724,7 @@ public class Player extends LivingEntity implements CommandSender {
final ChunkCallback endCallback = chunk -> {
// This is the last chunk to be loaded , spawn player
spawnPlayer(instance, firstSpawn);
spawnPlayer(instance, spawnPosition, firstSpawn);
};
// Chunk 0;0 always needs to be loaded
@ -739,26 +735,40 @@ public class Player extends LivingEntity implements CommandSender {
} 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
spawnPlayer(instance, false);
spawnPlayer(instance, spawnPosition, false);
}
}
/**
* Changes the player instance without changing its position (defaulted to {@link #getRespawnPoint()}
* if the player is not in any instance.
*
* @param instance the new player instance
* @see #setInstance(Instance, Position)
*/
@Override
public void setInstance(@NotNull Instance instance) {
setInstance(instance, this.instance != null ? getPosition() : getRespawnPoint());
}
/**
* Used to spawn the player once the client has all the required chunks.
* <p>
* Does add the player to {@code instance}, remove all viewable entities and call {@link PlayerSpawnEvent}.
* <p>
* UNSAFE: only called with {@link #setInstance(Instance)}.
* UNSAFE: only called with {@link #setInstance(Instance, Position)}.
*
* @param firstSpawn true if this is the player first spawn
* @param spawnPosition the position to teleport the player
* @param firstSpawn true if this is the player first spawn
*/
private void spawnPlayer(@NotNull Instance instance, boolean firstSpawn) {
private void spawnPlayer(@NotNull Instance instance, @Nullable Position spawnPosition, boolean firstSpawn) {
this.viewableEntities.forEach(entity -> entity.removeViewer(this));
super.setInstance(instance);
if (firstSpawn) {
teleport(getRespawnPoint());
if (spawnPosition != null && !position.isSimilar(spawnPosition)) {
teleport(spawnPosition,
position.inSameChunk(spawnPosition) ? () -> refreshVisibleChunks(getChunk()) : null);
} else {
refreshVisibleChunks(getChunk());
}
@ -1519,7 +1529,7 @@ public class Player extends LivingEntity implements CommandSender {
// New chunks indexes
final long[] updatedVisibleChunks = ChunkUtils.getChunksInRange(newChunk.toPosition(), getChunkRange());
// Find the difference between the two arrays¬
// Find the difference between the two arrays
final int[] oldChunks = ArrayUtils.getDifferencesBetweenArray(lastVisibleChunks, updatedVisibleChunks);
final int[] newChunks = ArrayUtils.getDifferencesBetweenArray(updatedVisibleChunks, lastVisibleChunks);

View File

@ -1,5 +1,8 @@
package net.minestom.server.utils;
import net.minestom.server.utils.chunk.ChunkUtils;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
/**
@ -72,8 +75,8 @@ public class Position {
/**
* Gets the distance between 2 positions.
* In cases where performance matters, {@link #getDistanceSquared(Position)} should be used
* as it does not perform the expensive Math.sqrt method.
* In cases where performance matters, {@link #getDistanceSquared(Position)} should be used
* as it does not perform the expensive Math.sqrt method.
*
* @param position the second position
* @return the distance between {@code this} and {@code position}
@ -86,15 +89,15 @@ public class Position {
/**
* Gets the square distance to another position.
*
* @param position the second position
* @return the squared distance between {@code this} and {@code position}
*/
public float getDistanceSquared(Position position) {
return MathUtils.square(getX() - position.getX()) +
MathUtils.square(getY() - position.getY()) +
MathUtils.square(getZ() - position.getZ());
}
*
* @param position the second position
* @return the squared distance between {@code this} and {@code position}
*/
public float getDistanceSquared(Position position) {
return MathUtils.square(getX() - position.getX()) +
MathUtils.square(getY() - position.getY()) +
MathUtils.square(getZ() - position.getZ());
}
/**
* Gets a unit-vector pointing in the direction that this Location is
@ -209,7 +212,7 @@ public class Position {
* @param position the position to compare
* @return true if the two positions are similar
*/
public boolean isSimilar(Position position) {
public boolean isSimilar(@NotNull Position position) {
return Float.compare(position.x, x) == 0 &&
Float.compare(position.y, y) == 0 &&
Float.compare(position.z, z) == 0;
@ -221,11 +224,27 @@ public class Position {
* @param position the position to compare
* @return true if the two positions have the same view
*/
public boolean hasSimilarView(Position position) {
public boolean hasSimilarView(@NotNull Position position) {
return Float.compare(position.yaw, yaw) == 0 &&
Float.compare(position.pitch, pitch) == 0;
}
/**
* Gets if two positions are in the same chunk.
*
* @param position the checked position chunk
* @return true if 'this' is in the same chunk as {@code position}
*/
public boolean inSameChunk(@NotNull Position position) {
final int chunkX1 = ChunkUtils.getChunkCoordinate((int) Math.floor(getX()));
final int chunkZ1 = ChunkUtils.getChunkCoordinate((int) Math.floor(getZ()));
final int chunkX2 = ChunkUtils.getChunkCoordinate((int) Math.floor(position.getX()));
final int chunkZ2 = ChunkUtils.getChunkCoordinate((int) Math.floor(position.getZ()));
return chunkX1 == chunkX2 && chunkZ1 == chunkZ2;
}
@Override
public int hashCode() {
return Objects.hash(x, y, z, yaw, pitch);