diff --git a/server-common/src/main/java/org/figuramc/figura/server/FiguraServerConfig.java b/server-common/src/main/java/org/figuramc/figura/server/FiguraServerConfig.java index 83c292340..b4ac39832 100644 --- a/server-common/src/main/java/org/figuramc/figura/server/FiguraServerConfig.java +++ b/server-common/src/main/java/org/figuramc/figura/server/FiguraServerConfig.java @@ -41,7 +41,7 @@ public int garbageCollectionTicks() { return garbageCollectionTicks; } - public int maxOutcomingChunkSize() { + public int s2cChunkSize() { return maxOutcomingChunkSize; } } diff --git a/server-common/src/main/java/org/figuramc/figura/server/FiguraUser.java b/server-common/src/main/java/org/figuramc/figura/server/FiguraUser.java index ceb1f1c32..b264dc2ef 100644 --- a/server-common/src/main/java/org/figuramc/figura/server/FiguraUser.java +++ b/server-common/src/main/java/org/figuramc/figura/server/FiguraUser.java @@ -14,18 +14,20 @@ public final class FiguraUser { private final UUID player; - private boolean avatars; private boolean pings; + private boolean avatars; + private int s2cChunkSize; private final PingCounter pingCounter = new PingCounter(); private final BitSet prideBadges; private final HashMap equippedAvatars; private final HashMap ownedAvatars; - public FiguraUser(UUID player, boolean allowAvatars, boolean allowPings, BitSet prideBadges, HashMap equippedAvatars, HashMap ownedAvatars) { + public FiguraUser(UUID player, boolean allowPings, boolean allowAvatars, int s2cChunkSize, BitSet prideBadges, HashMap equippedAvatars, HashMap ownedAvatars) { this.player = player; - this.avatars = allowAvatars; this.pings = allowPings; + this.avatars = allowAvatars; + this.s2cChunkSize = s2cChunkSize; this.prideBadges = prideBadges; this.equippedAvatars = equippedAvatars; this.ownedAvatars = ownedAvatars; @@ -39,6 +41,10 @@ public boolean avatarsAllowed() { return avatars; } + public int s2cChunkSize() { + return s2cChunkSize; + } + public boolean pingsAllowed() { return pings; } @@ -90,18 +96,18 @@ public void save(IFriendlyByteBuf buf) { } } - public static FiguraUser load(UUID player, boolean pings, boolean avatars, Path playerFile) { + public static FiguraUser load(UUID player, boolean pings, boolean avatars, int s2cChunkSize, Path playerFile) { try (FileInputStream fis = new FileInputStream(playerFile.toFile())) { InputStreamByteBuf buf = new InputStreamByteBuf(fis); - return load(player, pings, avatars, buf); + return load(player, pings, avatars, s2cChunkSize, buf); } catch (FileNotFoundException e) { - return new FiguraUser(player, avatars, pings, new BitSet(), new HashMap<>(), new HashMap<>()); + return new FiguraUser(player, pings, avatars, s2cChunkSize, new BitSet(), new HashMap<>(), new HashMap<>()); } catch (IOException e) { throw new RuntimeException(e); } } - public static FiguraUser load(UUID player, boolean pings, boolean avatars, IFriendlyByteBuf buf) { + public static FiguraUser load(UUID player, boolean pings, boolean avatars, int s2cChunkSize, IFriendlyByteBuf buf) { BitSet prideBadges = BitSet.valueOf(buf.readByteArray(256)); int equippedAvatarsCount = buf.readVarInt(); HashMap equippedAvatars = new HashMap<>(); @@ -117,7 +123,7 @@ public static FiguraUser load(UUID player, boolean pings, boolean avatars, IFrie byte[] hash = buf.readHash(); ownedAvatars.put(id, hash); } - return new FiguraUser(player, avatars, pings, prideBadges, equippedAvatars, ownedAvatars); + return new FiguraUser(player, pings, avatars, s2cChunkSize, prideBadges, equippedAvatars, ownedAvatars); } public byte[] findEHash(byte[] hash) { diff --git a/server-common/src/main/java/org/figuramc/figura/server/FiguraUserManager.java b/server-common/src/main/java/org/figuramc/figura/server/FiguraUserManager.java index 2cce4654d..03d8a4b19 100644 --- a/server-common/src/main/java/org/figuramc/figura/server/FiguraUserManager.java +++ b/server-common/src/main/java/org/figuramc/figura/server/FiguraUserManager.java @@ -31,15 +31,15 @@ public void onPlayerJoin(UUID player) { )); } - public FiguraUser authorisePlayer(UUID player, boolean allowPings, boolean allowAvatars) { - return users.computeIfAbsent(player, (k) -> loadPlayerData(k, allowPings, allowAvatars)); + public FiguraUser authorisePlayer(UUID player, boolean allowPings, boolean allowAvatars, int s2cChunkSize) { + return users.computeIfAbsent(player, (k) -> loadPlayerData(k, allowPings, allowAvatars, s2cChunkSize)); } - private FiguraUser loadPlayerData(UUID player, boolean allowPings, boolean allowAvatars) { + private FiguraUser loadPlayerData(UUID player, boolean allowPings, boolean allowAvatars, int s2cChunkSize) { LoadPlayerDataEvent playerDataEvent = Events.call(new LoadPlayerDataEvent(player)); if (playerDataEvent.returned()) return playerDataEvent.returnValue(); Path dataFile = parent.getUserdataFile(player); - return FiguraUser.load(player, allowPings, allowAvatars, dataFile); + return FiguraUser.load(player, allowPings, allowAvatars, s2cChunkSize, dataFile); } public void onPlayerLeave(UUID player) { diff --git a/server-common/src/main/java/org/figuramc/figura/server/avatars/FiguraServerAvatarManager.java b/server-common/src/main/java/org/figuramc/figura/server/avatars/FiguraServerAvatarManager.java index 4bae8f598..43a9c6ac6 100644 --- a/server-common/src/main/java/org/figuramc/figura/server/avatars/FiguraServerAvatarManager.java +++ b/server-common/src/main/java/org/figuramc/figura/server/avatars/FiguraServerAvatarManager.java @@ -114,14 +114,23 @@ private AvatarOutcomingStream(UUID receiver, AvatarData source, int streamId, by this.ehash = ehash; } + private int getChunkSize() { + var inst = FiguraServer.getInstance(); + var user = inst.userManager().getUser(receiver); + int serverLimit = inst.config().s2cChunkSize(); + int maxServerLimit = serverLimit <= 0 ? AvatarDataPacket.MAX_CHUNK_SIZE : serverLimit; + int clientLimit = user.s2cChunkSize(); + int maxClientLimit = clientLimit <= 0 ? AvatarDataPacket.MAX_CHUNK_SIZE : clientLimit; + + return Math.min(maxClientLimit, maxServerLimit); + } + public void tick() { var inst = FiguraServer.getInstance(); if (streamPosition == 0) { inst.sendPacket(receiver, new S2CInitializeAvatarStreamPacket(streamId, ehash)); } - int maxOutcomingChunkSize = inst.config().maxOutcomingChunkSize(); - int chunkSize = maxOutcomingChunkSize > 0 ? Math.min(maxOutcomingChunkSize, AvatarDataPacket.MAX_CHUNK_SIZE) - : AvatarDataPacket.MAX_CHUNK_SIZE; + int chunkSize = getChunkSize(); byte[] data = source.data(); byte[] chunk = new byte[Math.min(chunkSize, data.length - streamPosition)]; System.arraycopy(source.data(), streamPosition, chunk, 0, chunk.length); diff --git a/server-common/src/main/java/org/figuramc/figura/server/packets/c2s/C2SBackendHandshakePacket.java b/server-common/src/main/java/org/figuramc/figura/server/packets/c2s/C2SBackendHandshakePacket.java index bed2b0ef5..36cd3e0b6 100644 --- a/server-common/src/main/java/org/figuramc/figura/server/packets/c2s/C2SBackendHandshakePacket.java +++ b/server-common/src/main/java/org/figuramc/figura/server/packets/c2s/C2SBackendHandshakePacket.java @@ -12,15 +12,18 @@ public class C2SBackendHandshakePacket implements Packet { private final boolean pings; private final boolean avatars; + private final int incomingChunkSize; - public C2SBackendHandshakePacket(boolean pings, boolean avatars) { + public C2SBackendHandshakePacket(boolean pings, boolean avatars, int incomingChunkSize) { this.pings = pings; this.avatars = avatars; + this.incomingChunkSize = incomingChunkSize; } public C2SBackendHandshakePacket(IFriendlyByteBuf byteBuf) { this.pings = byteBuf.readByte() != 0; this.avatars = byteBuf.readByte() != 0; + this.incomingChunkSize = this.avatars ? byteBuf.readInt() : 0; } /** @@ -39,10 +42,21 @@ public boolean avatars() { return avatars; } + /** + * Max incoming chunk size allowed by client, in case if it allows backend work with avatars. + * @return Max incoming chunk size + */ + public int maxAvatarChunkSize() { + return incomingChunkSize; + } + @Override public void write(IFriendlyByteBuf byteBuf) { byteBuf.writeByte(pings ? 1 : 0); byteBuf.writeByte(avatars ? 1 : 0); + if (avatars) { + byteBuf.writeInt(incomingChunkSize); + } } @Override