Add dedicated `CachedPacket` for future network optimizations

Signed-off-by: TheMode <themode@outlook.fr>
This commit is contained in:
TheMode 2021-08-26 18:18:35 +02:00
parent b60b785dcd
commit f7cd0def20
2 changed files with 49 additions and 23 deletions

View File

@ -9,13 +9,13 @@ import net.minestom.server.entity.Player;
import net.minestom.server.entity.pathfinding.PFBlock;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.network.packet.CachedPacket;
import net.minestom.server.network.packet.FramedPacket;
import net.minestom.server.network.packet.server.play.ChunkDataPacket;
import net.minestom.server.network.packet.server.play.UpdateLightPacket;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.network.player.PlayerSocketConnection;
import net.minestom.server.utils.ArrayUtils;
import net.minestom.server.utils.PacketUtils;
import net.minestom.server.utils.chunk.ChunkUtils;
import net.minestom.server.world.biomes.Biome;
import org.jetbrains.annotations.NotNull;
@ -40,10 +40,8 @@ public class DynamicChunk extends Chunk {
protected final Int2ObjectOpenHashMap<Block> tickableMap = new Int2ObjectOpenHashMap<>();
private volatile long lastChangeTime;
private FramedPacket cachedChunkBuffer;
private FramedPacket cachedLightBuffer;
private long cachedPacketTime;
private final CachedPacket chunkCache = new CachedPacket(this::createChunkPacket);
private final CachedPacket lightCache = new CachedPacket(this::createLightPacket);
public DynamicChunk(@NotNull Instance instance, @Nullable Biome[] biomes, int chunkX, int chunkZ) {
super(instance, biomes, chunkX, chunkZ, true);
@ -126,34 +124,31 @@ public class DynamicChunk extends Chunk {
}
@Override
public synchronized void sendChunk(@NotNull Player player) {
public void sendChunk(@NotNull Player player) {
if (!isLoaded()) return;
final PlayerConnection connection = player.getPlayerConnection();
final long lastChange = getLastChangeTime();
final FramedPacket lightPacket = lightCache.retrieveFramedPacket(lastChange);
final FramedPacket chunkPacket = chunkCache.retrieveFramedPacket(lastChange);
if (connection instanceof PlayerSocketConnection) {
final long lastChange = getLastChangeTime();
var chunkPacket = cachedChunkBuffer;
var lightPacket = cachedLightBuffer;
if (lastChange > cachedPacketTime || (chunkPacket == null || lightPacket == null)) {
chunkPacket = PacketUtils.allocateTrimmedPacket(createChunkPacket());
lightPacket = PacketUtils.allocateTrimmedPacket(createLightPacket());
this.cachedChunkBuffer = chunkPacket;
this.cachedLightBuffer = lightPacket;
this.cachedPacketTime = lastChange;
}
PlayerSocketConnection socketConnection = (PlayerSocketConnection) connection;
socketConnection.write(lightPacket);
socketConnection.write(chunkPacket);
socketConnection.write(lightPacket.body());
socketConnection.write(chunkPacket.body());
} else {
connection.sendPacket(createLightPacket());
connection.sendPacket(createChunkPacket());
connection.sendPacket(lightPacket.packet());
connection.sendPacket(chunkPacket.packet());
}
}
@Override
public synchronized void sendChunk() {
public void sendChunk() {
if (!isLoaded()) return;
sendPacketToViewers(createLightPacket());
sendPacketToViewers(createChunkPacket());
if (getViewers().isEmpty()) return;
final long lastChange = getLastChangeTime();
final FramedPacket lightPacket = lightCache.retrieveFramedPacket(lastChange);
final FramedPacket chunkPacket = chunkCache.retrieveFramedPacket(lastChange);
sendPacketToViewers(lightPacket.packet());
sendPacketToViewers(chunkPacket.packet());
}
@NotNull

View File

@ -0,0 +1,31 @@
package net.minestom.server.network.packet;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.utils.PacketUtils;
import org.jetbrains.annotations.ApiStatus;
import java.lang.ref.SoftReference;
import java.util.function.Supplier;
@ApiStatus.Internal
public final class CachedPacket {
private final Supplier<ServerPacket> supplier;
private volatile long packetTimestamp;
private SoftReference<FramedPacket> packet;
public CachedPacket(Supplier<ServerPacket> supplier) {
this.supplier = supplier;
}
public FramedPacket retrieveFramedPacket(long lastChange) {
final long timestamp = packetTimestamp;
final var ref = packet;
FramedPacket cache = ref != null ? ref.get() : null;
if (cache == null || lastChange > timestamp) {
cache = PacketUtils.allocateTrimmedPacket(supplier.get());
this.packet = new SoftReference<>(cache);
this.packetTimestamp = lastChange;
}
return cache;
}
}