Replaced player viewableChunks set interaction to the Chunk class (Viewable support)

This commit is contained in:
themode 2020-08-16 19:18:34 +02:00
parent 737cf24ace
commit 97a1141583
3 changed files with 49 additions and 62 deletions

View File

@ -40,8 +40,8 @@ import java.util.function.Consumer;
public abstract class Entity implements Viewable, EventHandler, DataContainer { public abstract class Entity implements Viewable, EventHandler, DataContainer {
private static Map<Integer, Entity> entityById = new ConcurrentHashMap<>(); private static final Map<Integer, Entity> entityById = new ConcurrentHashMap<>();
private static AtomicInteger lastEntityId = new AtomicInteger(); private static final AtomicInteger lastEntityId = new AtomicInteger();
// Metadata // Metadata
protected static final byte METADATA_BYTE = 0; protected static final byte METADATA_BYTE = 0;
@ -63,7 +63,8 @@ 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;
private int id; // Synchronization
private static final long SYNCHRONIZATION_DELAY = 1500; // In ms
private BoundingBox boundingBox; private BoundingBox boundingBox;
@ -74,22 +75,20 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
protected float eyeHeight; protected float eyeHeight;
private boolean autoViewable; private boolean autoViewable;
private Set<Player> viewers = new CopyOnWriteArraySet<>(); private final int id;
private Data data; private Data data;
private Set<Entity> passengers = new CopyOnWriteArraySet<>(); private final Set<Player> viewers = new CopyOnWriteArraySet<>();
protected UUID uuid; protected UUID uuid;
private boolean isActive; // False if entity has only been instanced without being added somewhere private boolean isActive; // False if entity has only been instanced without being added somewhere
private boolean removed; private boolean removed;
private boolean shouldRemove; private boolean shouldRemove;
private long scheduledRemoveTime; private long scheduledRemoveTime;
private EntityType entityType; private final Set<Entity> passengers = new CopyOnWriteArraySet<>();
private long lastUpdate; private long lastUpdate;
private Map<Class<? extends Event>, List<EventCallback>> eventCallbacks = new ConcurrentHashMap<>(); private final EntityType entityType;
protected long lastVelocityUpdateTime; // Reset velocity to 0 after countdown protected long lastVelocityUpdateTime; // Reset velocity to 0 after countdown
private final Map<Class<? extends Event>, List<EventCallback>> eventCallbacks = new ConcurrentHashMap<>();
// Synchronization
private long synchronizationDelay = 1500; // In ms
private long lastSynchronizationTime; private long lastSynchronizationTime;
// Metadata // Metadata
@ -215,9 +214,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
}; };
if (instance.hasEnabledAutoChunkLoad()) { if (instance.hasEnabledAutoChunkLoad()) {
instance.loadChunk(position, chunk -> { instance.loadChunk(position, chunk -> runnable.run());
runnable.run();
});
} else { } else {
runnable.run(); runnable.run();
} }
@ -289,7 +286,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
if (!result) if (!result)
return false; return false;
player.viewableEntities.add(this); player.viewableEntities.add(this);
return result; return true;
} }
@Override @Override
@ -497,7 +494,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
} }
// Scheduled synchronization // Scheduled synchronization
if (time - lastSynchronizationTime >= synchronizationDelay) { if (time - lastSynchronizationTime >= SYNCHRONIZATION_DELAY) {
lastSynchronizationTime = time; lastSynchronizationTime = time;
sendSynchronization(); sendSynchronization();
} }
@ -1210,9 +1207,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
protected void sendMetadataIndex(int index) { protected void sendMetadataIndex(int index) {
EntityMetaDataPacket metaDataPacket = new EntityMetaDataPacket(); EntityMetaDataPacket metaDataPacket = new EntityMetaDataPacket();
metaDataPacket.entityId = getEntityId(); metaDataPacket.entityId = getEntityId();
metaDataPacket.consumer = packet -> { metaDataPacket.consumer = packet -> fillMetadataIndex(packet, index);
fillMetadataIndex(packet, index);
};
sendPacketToViewersAndSelf(metaDataPacket); sendPacketToViewersAndSelf(metaDataPacket);
} }

View File

@ -61,7 +61,7 @@ public class Player extends LivingEntity implements CommandSender {
private String username; private String username;
protected PlayerConnection playerConnection; protected PlayerConnection playerConnection;
private ConcurrentLinkedQueue<ClientPlayPacket> packets = new ConcurrentLinkedQueue<>(); protected final Set<Entity> viewableEntities = new CopyOnWriteArraySet<>();
private int latency; private int latency;
private ColoredText displayName; private ColoredText displayName;
@ -69,19 +69,17 @@ public class Player extends LivingEntity implements CommandSender {
private DimensionType dimensionType; private DimensionType dimensionType;
private GameMode gameMode; private GameMode gameMode;
private LevelType levelType; protected final Set<Chunk> viewableChunks = new CopyOnWriteArraySet<>();
private int teleportId = 0; private int teleportId = 0;
protected boolean onGround; protected boolean onGround;
private final ConcurrentLinkedQueue<ClientPlayPacket> packets = new ConcurrentLinkedQueue<>();
protected Set<Entity> viewableEntities = new CopyOnWriteArraySet<>(); private final LevelType levelType;
protected Set<Chunk> viewableChunks = new CopyOnWriteArraySet<>(); private final PlayerSettings settings;
private PlayerSettings settings;
private float exp; private float exp;
private int level; private int level;
private PlayerInventory inventory; private final PlayerInventory inventory;
private Inventory openInventory; private Inventory openInventory;
// Used internally to allow the closing of inventory within the inventory listener // Used internally to allow the closing of inventory within the inventory listener
private boolean didCloseInventory; private boolean didCloseInventory;
@ -128,10 +126,10 @@ public class Player extends LivingEntity implements CommandSender {
private float walkingSpeed = 0.1f; private float walkingSpeed = 0.1f;
// Statistics // Statistics
private Map<PlayerStatistic, Integer> statisticValueMap = new Hashtable<>(); private final Map<PlayerStatistic, Integer> statisticValueMap = new Hashtable<>();
// Vehicle // Vehicle
private PlayerVehicleInformation vehicleInformation = new PlayerVehicleInformation(); private final PlayerVehicleInformation vehicleInformation = new PlayerVehicleInformation();
// Tick related // Tick related
private final PlayerTickEvent playerTickEvent = new PlayerTickEvent(this); private final PlayerTickEvent playerTickEvent = new PlayerTickEvent(this);
@ -364,7 +362,7 @@ public class Player extends LivingEntity implements CommandSender {
final boolean positionChanged = position.getX() != lastX || position.getY() != lastY || position.getZ() != lastZ; final boolean positionChanged = position.getX() != lastX || position.getY() != lastY || position.getZ() != lastZ;
final boolean viewChanged = position.getYaw() != lastYaw || position.getPitch() != lastPitch; final boolean viewChanged = position.getYaw() != lastYaw || position.getPitch() != lastPitch;
if (!getViewers().isEmpty() && (positionChanged || viewChanged)) { if (!getViewers().isEmpty() && (positionChanged || viewChanged)) {
ServerPacket updatePacket = null; ServerPacket updatePacket;
ServerPacket optionalUpdatePacket = null; ServerPacket optionalUpdatePacket = null;
if (positionChanged && viewChanged) { if (positionChanged && viewChanged) {
EntityPositionAndRotationPacket entityPositionAndRotationPacket = new EntityPositionAndRotationPacket(); EntityPositionAndRotationPacket entityPositionAndRotationPacket = new EntityPositionAndRotationPacket();
@ -393,7 +391,8 @@ public class Player extends LivingEntity implements CommandSender {
lastY = position.getY(); lastY = position.getY();
lastZ = position.getZ(); lastZ = position.getZ();
updatePacket = entityPositionPacket; updatePacket = entityPositionPacket;
} else if (viewChanged) { } else {
// View changed
EntityRotationPacket entityRotationPacket = new EntityRotationPacket(); EntityRotationPacket entityRotationPacket = new EntityRotationPacket();
entityRotationPacket.entityId = getEntityId(); entityRotationPacket.entityId = getEntityId();
entityRotationPacket.yaw = position.getYaw(); entityRotationPacket.yaw = position.getYaw();
@ -412,13 +411,13 @@ public class Player extends LivingEntity implements CommandSender {
optionalUpdatePacket = entityHeadLookPacket; optionalUpdatePacket = entityHeadLookPacket;
} }
if (updatePacket != null) { // Send the update packet
if (optionalUpdatePacket != null) { if (optionalUpdatePacket != null) {
sendPacketsToViewers(updatePacket, optionalUpdatePacket); sendPacketsToViewers(updatePacket, optionalUpdatePacket);
} else { } else {
sendPacketToViewers(updatePacket); sendPacketToViewers(updatePacket);
}
} }
} }
} }
@ -513,7 +512,7 @@ public class Player extends LivingEntity implements CommandSender {
PlayerConnection viewerConnection = player.getPlayerConnection(); PlayerConnection viewerConnection = player.getPlayerConnection();
showPlayer(viewerConnection); showPlayer(viewerConnection);
return result; return true;
} }
@Override @Override
@ -540,7 +539,6 @@ public class Player extends LivingEntity implements CommandSender {
for (Chunk viewableChunk : viewableChunks) { for (Chunk viewableChunk : viewableChunks) {
viewableChunk.removeViewer(this); viewableChunk.removeViewer(this);
} }
viewableChunks.clear();
if (this.instance != null) { if (this.instance != null) {
final DimensionType instanceDimensionType = instance.getDimensionType(); final DimensionType instanceDimensionType = instance.getDimensionType();
@ -552,13 +550,12 @@ public class Player extends LivingEntity implements CommandSender {
final int length = visibleChunks.length; final int length = visibleChunks.length;
AtomicInteger counter = new AtomicInteger(0); AtomicInteger counter = new AtomicInteger(0);
for (int i = 0; i < length; i++) { for (long visibleChunk : visibleChunks) {
final int[] chunkPos = ChunkUtils.getChunkCoord(visibleChunks[i]); final int[] chunkPos = ChunkUtils.getChunkCoord(visibleChunk);
final int chunkX = chunkPos[0]; final int chunkX = chunkPos[0];
final int chunkZ = chunkPos[1]; final int chunkZ = chunkPos[1];
Consumer<Chunk> callback = (chunk) -> { Consumer<Chunk> callback = (chunk) -> {
if (chunk != null) { if (chunk != null) {
viewableChunks.add(chunk);
chunk.addViewer(this); chunk.addViewer(this);
if (chunk.getChunkX() == Math.floorDiv((int) getPosition().getX(), 16) && chunk.getChunkZ() == Math.floorDiv((int) getPosition().getZ(), 16)) if (chunk.getChunkX() == Math.floorDiv((int) getPosition().getX(), 16) && chunk.getChunkZ() == Math.floorDiv((int) getPosition().getZ(), 16))
updateViewPosition(chunk); updateViewPosition(chunk);
@ -827,7 +824,7 @@ public class Player extends LivingEntity implements CommandSender {
/** /**
* Update the internal field and send the appropriate {@link EntityMetaDataPacket} * Update the internal field and send the appropriate {@link EntityMetaDataPacket}
* *
* @param additionalHearts the count of additional heartss * @param additionalHearts the count of additional hearts
*/ */
public void setAdditionalHearts(float additionalHearts) { public void setAdditionalHearts(float additionalHearts) {
this.additionalHearts = additionalHearts; this.additionalHearts = additionalHearts;
@ -958,7 +955,7 @@ public class Player extends LivingEntity implements CommandSender {
playerConnection.sendPacket(addPlayerPacket); playerConnection.sendPacket(addPlayerPacket);
for (Player viewer : getViewers()) { for (Player viewer : getViewers()) {
PlayerConnection connection = viewer.getPlayerConnection(); final PlayerConnection connection = viewer.getPlayerConnection();
connection.sendPacket(removePlayerPacket); connection.sendPacket(removePlayerPacket);
connection.sendPacket(destroyEntitiesPacket); connection.sendPacket(destroyEntitiesPacket);
@ -970,16 +967,6 @@ public class Player extends LivingEntity implements CommandSender {
teleport(getPosition()); teleport(getPosition());
} }
/**
* Used to update the internal skin field
*
* @param skin the player skin
* @see #setSkin(PlayerSkin) instead
*/
protected void refreshSkin(PlayerSkin skin) {
this.skin = skin;
}
/** /**
* Get if the player has the respawn screen enabled or disabled * Get if the player has the respawn screen enabled or disabled
* *
@ -1202,9 +1189,9 @@ public class Player extends LivingEntity implements CommandSender {
*/ */
protected void onChunkChange(Chunk newChunk) { protected void onChunkChange(Chunk newChunk) {
final long[] lastVisibleChunks = new long[viewableChunks.size()]; final long[] lastVisibleChunks = new long[viewableChunks.size()];
Chunk[] lastViewableChunks = viewableChunks.toArray(new Chunk[0]); final Chunk[] lastViewableChunks = viewableChunks.toArray(new Chunk[0]);
for (int i = 0; i < lastViewableChunks.length; i++) { for (int i = 0; i < lastViewableChunks.length; i++) {
Chunk lastViewableChunk = lastViewableChunks[i]; final Chunk lastViewableChunk = lastViewableChunks[i];
lastVisibleChunks[i] = ChunkUtils.getChunkIndex(lastViewableChunk.getChunkX(), lastViewableChunk.getChunkZ()); lastVisibleChunks[i] = ChunkUtils.getChunkIndex(lastViewableChunk.getChunkX(), lastViewableChunk.getChunkZ());
} }
final long[] updatedVisibleChunks = ChunkUtils.getChunksInRange(new Position(16 * newChunk.getChunkX(), 0, 16 * newChunk.getChunkZ()), getChunkRange()); final long[] updatedVisibleChunks = ChunkUtils.getChunksInRange(new Position(16 * newChunk.getChunkX(), 0, 16 * newChunk.getChunkZ()), getChunkRange());
@ -1219,8 +1206,7 @@ public class Player extends LivingEntity implements CommandSender {
unloadChunkPacket.chunkZ = chunkPos[1]; unloadChunkPacket.chunkZ = chunkPos[1];
playerConnection.sendPacket(unloadChunkPacket); playerConnection.sendPacket(unloadChunkPacket);
Chunk chunk = instance.getChunk(chunkPos[0], chunkPos[1]); final Chunk chunk = instance.getChunk(chunkPos[0], chunkPos[1]);
viewableChunks.remove(chunk);
if (chunk != null) if (chunk != null)
chunk.removeViewer(this); chunk.removeViewer(this);
} }
@ -1228,15 +1214,13 @@ public class Player extends LivingEntity implements CommandSender {
updateViewPosition(newChunk); updateViewPosition(newChunk);
// Load new chunks // Load new chunks
for (int i = 0; i < newChunks.length; i++) { for (int index : newChunks) {
final int index = newChunks[i];
final int[] chunkPos = ChunkUtils.getChunkCoord(updatedVisibleChunks[index]); final int[] chunkPos = ChunkUtils.getChunkCoord(updatedVisibleChunks[index]);
instance.loadOptionalChunk(chunkPos[0], chunkPos[1], chunk -> { instance.loadOptionalChunk(chunkPos[0], chunkPos[1], 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;
} }
this.viewableChunks.add(chunk);
chunk.addViewer(this); chunk.addViewer(this);
}); });
} }
@ -1541,11 +1525,14 @@ public class Player extends LivingEntity implements CommandSender {
/** /**
* Get the player viewable chunks * Get the player viewable chunks
* <p>
* WARNING: adding or removing a chunk there will not load/unload it,
* use {@link Chunk#addViewer(Player)} or {@link Chunk#removeViewer(Player)}
* *
* @return an unmodifiable {@link Set} containing all the chunks that the player sees * @return a {@link Set} containing all the chunks that the player sees
*/ */
public Set<Chunk> getViewableChunks() { public Set<Chunk> getViewableChunks() {
return Collections.unmodifiableSet(viewableChunks); return viewableChunks;
} }
/** /**

View File

@ -286,6 +286,8 @@ public abstract class Chunk implements Viewable {
// Send the chunk data & light packets to the player // Send the chunk data & light packets to the player
sendChunk(player); sendChunk(player);
// Add to the viewable chunks set
player.getViewableChunks().add(this);
PlayerChunkLoadEvent playerChunkLoadEvent = new PlayerChunkLoadEvent(player, chunkX, chunkZ); PlayerChunkLoadEvent playerChunkLoadEvent = new PlayerChunkLoadEvent(player, chunkX, chunkZ);
player.callEvent(PlayerChunkLoadEvent.class, playerChunkLoadEvent); player.callEvent(PlayerChunkLoadEvent.class, playerChunkLoadEvent);
@ -297,6 +299,9 @@ public abstract class Chunk implements Viewable {
public boolean removeViewer(Player player) { public boolean removeViewer(Player player) {
final boolean result = this.viewers.remove(player); final boolean result = this.viewers.remove(player);
// Remove from the viewable chunks set
player.getViewableChunks().remove(this);
PlayerChunkUnloadEvent playerChunkUnloadEvent = new PlayerChunkUnloadEvent(player, chunkX, chunkZ); PlayerChunkUnloadEvent playerChunkUnloadEvent = new PlayerChunkUnloadEvent(player, chunkX, chunkZ);
player.callEvent(PlayerChunkUnloadEvent.class, playerChunkUnloadEvent); player.callEvent(PlayerChunkUnloadEvent.class, playerChunkUnloadEvent);
return result; return result;