Per instance thread is now the default, added a configurable cooldown for player position refresh

This commit is contained in:
themode 2020-11-18 05:13:49 +01:00
parent 2405b7ae6f
commit 553a280993
5 changed files with 44 additions and 31 deletions

View File

@ -3,7 +3,7 @@ package net.minestom.server;
import net.minestom.server.entity.EntityManager; import net.minestom.server.entity.EntityManager;
import net.minestom.server.instance.Instance; import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceManager; import net.minestom.server.instance.InstanceManager;
import net.minestom.server.thread.PerGroupChunkProvider; import net.minestom.server.thread.PerInstanceThreadProvider;
import net.minestom.server.thread.ThreadProvider; import net.minestom.server.thread.ThreadProvider;
import net.minestom.server.utils.thread.MinestomThread; import net.minestom.server.utils.thread.MinestomThread;
import net.minestom.server.utils.validate.Check; import net.minestom.server.utils.validate.Check;
@ -33,7 +33,8 @@ public final class UpdateManager {
{ {
// DEFAULT THREAD PROVIDER // DEFAULT THREAD PROVIDER
threadProvider = new PerGroupChunkProvider(); //threadProvider = new PerGroupChunkProvider();
threadProvider = new PerInstanceThreadProvider();
} }
/** /**

View File

@ -31,7 +31,9 @@ import net.minestom.server.utils.callback.OptionalCallback;
import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.utils.chunk.ChunkUtils;
import net.minestom.server.utils.entity.EntityUtils; import net.minestom.server.utils.entity.EntityUtils;
import net.minestom.server.utils.player.PlayerUtils; import net.minestom.server.utils.player.PlayerUtils;
import net.minestom.server.utils.time.CooldownUtils;
import net.minestom.server.utils.time.TimeUnit; import net.minestom.server.utils.time.TimeUnit;
import net.minestom.server.utils.time.UpdateOption;
import net.minestom.server.utils.validate.Check; import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -103,9 +105,9 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
private long lastUpdate; private long lastUpdate;
private final EntityType entityType; private final EntityType entityType;
// Network synchronization // Network synchronization, send the absolute position of the entity each X milliseconds
private static final long SYNCHRONIZATION_DELAY = 1500; // In ms private static final UpdateOption SYNCHRONIZATION_COOLDOWN = new UpdateOption(1500, TimeUnit.MILLISECOND);
private long lastSynchronizationTime; private long lastAbsoluteSynchronizationTime;
// Events // Events
private final Map<Class<? extends Event>, Collection<EventCallback>> eventCallbacks = new ConcurrentHashMap<>(); private final Map<Class<? extends Event>, Collection<EventCallback>> eventCallbacks = new ConcurrentHashMap<>();
@ -543,8 +545,8 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
} }
// Scheduled synchronization // Scheduled synchronization
if (time - lastSynchronizationTime >= SYNCHRONIZATION_DELAY) { if (!CooldownUtils.hasCooldown(time, lastAbsoluteSynchronizationTime, SYNCHRONIZATION_COOLDOWN)) {
lastSynchronizationTime = time; this.lastAbsoluteSynchronizationTime = time;
sendSynchronization(); sendSynchronization();
} }
@ -672,7 +674,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
*/ */
@Nullable @Nullable
public Chunk getChunk() { public Chunk getChunk() {
return instance.getChunkAt(lastX, lastZ); return instance.getChunkAt(position.getX(), position.getZ());
} }
/** /**
@ -1354,7 +1356,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
* Asks for a synchronization (position) to happen during next entity tick. * Asks for a synchronization (position) to happen during next entity tick.
*/ */
public void askSynchronization() { public void askSynchronization() {
this.lastSynchronizationTime = 0; this.lastAbsoluteSynchronizationTime = 0;
} }
private boolean shouldUpdate(long time) { private boolean shouldUpdate(long time) {

View File

@ -1,5 +1,6 @@
package net.minestom.server.entity; package net.minestom.server.entity;
import io.netty.channel.Channel;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.advancements.AdvancementTab; import net.minestom.server.advancements.AdvancementTab;
import net.minestom.server.attribute.Attribute; import net.minestom.server.attribute.Attribute;
@ -131,6 +132,11 @@ public class Player extends LivingEntity implements CommandSender {
private byte targetStage; // The current stage of the target block, only if multi player breaking is disabled private byte targetStage; // The current stage of the target block, only if multi player breaking is disabled
private final Set<Player> targetBreakers = new HashSet<>(1); // Only used if multi player breaking is disabled, contains only this player private final Set<Player> targetBreakers = new HashSet<>(1); // Only used if multi player breaking is disabled, contains only this player
// Position synchronization with viewers
protected UpdateOption playerSynchronizationCooldown = new UpdateOption(2, TimeUnit.TICK);
private long lastPlayerSynchronizationTime;
private float lastPlayerSyncX, lastPlayerSyncY, lastPlayerSyncZ, lastPlayerSyncYaw, lastPlayerSyncPitch;
// Experience orb pickup // Experience orb pickup
protected UpdateOption experiencePickupCooldown = new UpdateOption(10, TimeUnit.TICK); protected UpdateOption experiencePickupCooldown = new UpdateOption(10, TimeUnit.TICK);
private long lastExperiencePickupCheckTime; private long lastExperiencePickupCheckTime;
@ -301,7 +307,8 @@ public class Player extends LivingEntity implements CommandSender {
// Flush all pending packets // Flush all pending packets
if (PlayerUtils.isNettyClient(this)) { if (PlayerUtils.isNettyClient(this)) {
((NettyPlayerConnection) playerConnection).getChannel().flush(); Channel channel = ((NettyPlayerConnection) playerConnection).getChannel();
channel.eventLoop().execute(() -> channel.flush());
} }
// Network tick verification // Network tick verification
@ -412,9 +419,11 @@ public class Player extends LivingEntity implements CommandSender {
callEvent(PlayerTickEvent.class, playerTickEvent); callEvent(PlayerTickEvent.class, playerTickEvent);
// Multiplayer sync // Multiplayer sync
final boolean positionChanged = position.getX() != lastX || position.getY() != lastY || position.getZ() != lastZ; final boolean positionChanged = position.getX() != lastPlayerSyncX || position.getY() != lastPlayerSyncY || position.getZ() != lastPlayerSyncZ;
final boolean viewChanged = position.getYaw() != lastYaw || position.getPitch() != lastPitch; final boolean viewChanged = position.getYaw() != lastPlayerSyncYaw || position.getPitch() != lastPlayerSyncPitch;
if (!viewers.isEmpty()) { if (!viewers.isEmpty() && !CooldownUtils.hasCooldown(time, lastPlayerSynchronizationTime, playerSynchronizationCooldown)) {
this.lastPlayerSynchronizationTime = time;
if (positionChanged || viewChanged) { if (positionChanged || viewChanged) {
// Player moved since last time // Player moved since last time
@ -423,9 +432,9 @@ public class Player extends LivingEntity implements CommandSender {
if (positionChanged && viewChanged) { if (positionChanged && viewChanged) {
EntityPositionAndRotationPacket entityPositionAndRotationPacket = new EntityPositionAndRotationPacket(); EntityPositionAndRotationPacket entityPositionAndRotationPacket = new EntityPositionAndRotationPacket();
entityPositionAndRotationPacket.entityId = getEntityId(); entityPositionAndRotationPacket.entityId = getEntityId();
entityPositionAndRotationPacket.deltaX = (short) ((position.getX() * 32 - lastX * 32) * 128); entityPositionAndRotationPacket.deltaX = (short) ((position.getX() * 32 - lastPlayerSyncX * 32) * 128);
entityPositionAndRotationPacket.deltaY = (short) ((position.getY() * 32 - lastY * 32) * 128); entityPositionAndRotationPacket.deltaY = (short) ((position.getY() * 32 - lastPlayerSyncY * 32) * 128);
entityPositionAndRotationPacket.deltaZ = (short) ((position.getZ() * 32 - lastZ * 32) * 128); entityPositionAndRotationPacket.deltaZ = (short) ((position.getZ() * 32 - lastPlayerSyncZ * 32) * 128);
entityPositionAndRotationPacket.yaw = position.getYaw(); entityPositionAndRotationPacket.yaw = position.getYaw();
entityPositionAndRotationPacket.pitch = position.getPitch(); entityPositionAndRotationPacket.pitch = position.getPitch();
entityPositionAndRotationPacket.onGround = onGround; entityPositionAndRotationPacket.onGround = onGround;
@ -434,9 +443,9 @@ public class Player extends LivingEntity implements CommandSender {
} else if (positionChanged) { } else if (positionChanged) {
EntityPositionPacket entityPositionPacket = new EntityPositionPacket(); EntityPositionPacket entityPositionPacket = new EntityPositionPacket();
entityPositionPacket.entityId = getEntityId(); entityPositionPacket.entityId = getEntityId();
entityPositionPacket.deltaX = (short) ((position.getX() * 32 - lastX * 32) * 128); entityPositionPacket.deltaX = (short) ((position.getX() * 32 - lastPlayerSyncX * 32) * 128);
entityPositionPacket.deltaY = (short) ((position.getY() * 32 - lastY * 32) * 128); entityPositionPacket.deltaY = (short) ((position.getY() * 32 - lastPlayerSyncY * 32) * 128);
entityPositionPacket.deltaZ = (short) ((position.getZ() * 32 - lastZ * 32) * 128); entityPositionPacket.deltaZ = (short) ((position.getZ() * 32 - lastPlayerSyncZ * 32) * 128);
entityPositionPacket.onGround = onGround; entityPositionPacket.onGround = onGround;
updatePacket = entityPositionPacket; updatePacket = entityPositionPacket;
@ -472,16 +481,17 @@ public class Player extends LivingEntity implements CommandSender {
entityMovementPacket.entityId = getEntityId(); entityMovementPacket.entityId = getEntityId();
sendPacketToViewers(entityMovementPacket); sendPacketToViewers(entityMovementPacket);
} }
}
// Update sync data
if (positionChanged) { if (positionChanged) {
lastX = position.getX(); lastPlayerSyncX = position.getX();
lastY = position.getY(); lastPlayerSyncY = position.getY();
lastZ = position.getZ(); lastPlayerSyncZ = position.getZ();
} }
if (viewChanged) { if (viewChanged) {
lastYaw = position.getYaw(); lastPlayerSyncYaw = position.getYaw();
lastPitch = position.getPitch(); lastPlayerSyncPitch = position.getPitch();
}
} }
} }

View File

@ -33,7 +33,7 @@ public class PacketCompressor extends ByteToMessageCodec<ByteBuf> {
private final byte[] buffer = new byte[8192]; private final byte[] buffer = new byte[8192];
private final Deflater deflater = new Deflater(3); private final Deflater deflater = new Deflater();
private final Inflater inflater = new Inflater(); private final Inflater inflater = new Inflater();
public PacketCompressor(int threshold) { public PacketCompressor(int threshold) {

View File

@ -57,7 +57,7 @@ public class NettyPlayerConnection extends PlayerConnection {
} }
/** /**
* Sets the encryption key and add the channels to the pipeline. * Sets the encryption key and add the codecs to the pipeline.
* *
* @param secretKey the secret key to use in the encryption * @param secretKey the secret key to use in the encryption
* @throws IllegalStateException if encryption is already enabled for this connection * @throws IllegalStateException if encryption is already enabled for this connection
@ -70,7 +70,7 @@ public class NettyPlayerConnection extends PlayerConnection {
} }
/** /**
* Enables compression and add a new channel to the pipeline. * Enables compression and add a new codec to the pipeline.
* *
* @param threshold the threshold for a packet to be compressible * @param threshold the threshold for a packet to be compressible
* @throws IllegalStateException if encryption is already enabled for this connection * @throws IllegalStateException if encryption is already enabled for this connection