diff --git a/src/main/java/top/ellan/mahjong/table/render/TableRenderSnapshotFactory.java b/src/main/java/top/ellan/mahjong/table/render/TableRenderSnapshotFactory.java index f12695d..fb78207 100644 --- a/src/main/java/top/ellan/mahjong/table/render/TableRenderSnapshotFactory.java +++ b/src/main/java/top/ellan/mahjong/table/render/TableRenderSnapshotFactory.java @@ -4,19 +4,21 @@ import top.ellan.mahjong.render.TableRenderSubject; import top.ellan.mahjong.render.snapshot.TableRenderSnapshot; import top.ellan.mahjong.render.snapshot.TableSeatRenderSnapshot; +import java.util.Collections; import java.util.Comparator; import java.util.EnumMap; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; import java.util.UUID; import org.bukkit.Location; import org.bukkit.entity.Player; public final class TableRenderSnapshotFactory { + private static final Comparator SERIALIZED_VIEWER_ID_COMPARATOR = + Comparator.comparing(SerializedViewerId::serializedId); + public TableRenderSnapshot create(TableRenderSubject session, long version, long cancellationNonce) { Location tableCenter = session.center(); boolean started = session.isStarted(); @@ -24,12 +26,18 @@ public TableRenderSnapshot create(TableRenderSubject session, long version, long .map(Player::getUniqueId) .distinct() .map(viewerId -> new SerializedViewerId(viewerId, viewerId.toString())) - .sorted(Comparator.comparing(SerializedViewerId::serializedId)) + .sorted(SERIALIZED_VIEWER_ID_COMPARATOR) .toList(); List onlineViewerIds = serializedOnlineViewerIds.stream() .map(SerializedViewerId::id) .toList(); - Set onlineViewerIdSet = new HashSet<>(onlineViewerIds); + Map serializedOnlineViewersById = new HashMap<>( + Math.max(16, (int) (serializedOnlineViewerIds.size() / 0.75F) + 1) + ); + for (SerializedViewerId viewer : serializedOnlineViewerIds) { + serializedOnlineViewersById.put(viewer.id(), viewer); + } + StringBuilder viewerMembershipBuffer = this.viewerMembershipBuffer(serializedOnlineViewerIds); SeatWind[] seatWinds = SeatWind.values(); EnumMap seatPlayerIds = new EnumMap<>(SeatWind.class); for (SeatWind wind : seatWinds) { @@ -38,13 +46,28 @@ public TableRenderSnapshot create(TableRenderSubject session, long version, long Map viewerMembershipSignatures = new HashMap<>(); Map> viewerIdsExcluding = new HashMap<>(); for (UUID playerId : seatPlayerIds.values()) { - if (viewerMembershipSignatures.containsKey(playerId) - || playerId != null && !onlineViewerIdSet.contains(playerId)) { + if (viewerMembershipSignatures.containsKey(playerId)) { + continue; + } + SerializedViewerId excludedViewer = playerId == null + ? null + : serializedOnlineViewersById.get(playerId); + if (playerId != null && excludedViewer == null) { continue; } viewerMembershipSignatures.put( playerId, - this.viewerMembershipSignature(serializedOnlineViewerIds, playerId) + excludedViewer == null + ? viewerMembershipBuffer.toString() + : this.viewerMembershipSignature( + viewerMembershipBuffer, + excludedViewer, + Collections.binarySearch( + serializedOnlineViewerIds, + excludedViewer, + SERIALIZED_VIEWER_ID_COMPARATOR + ) + ) ); viewerIdsExcluding.put( playerId, @@ -59,7 +82,7 @@ public TableRenderSnapshot create(TableRenderSubject session, long version, long session, wind, seatPlayerIds.get(wind), - onlineViewerIdSet, + serializedOnlineViewersById, viewerMembershipSignatures, viewerIdsExcluding ) @@ -131,7 +154,7 @@ private TableSeatRenderSnapshot captureSeatSnapshot( TableRenderSubject session, SeatWind wind, UUID playerId, - Set onlineViewerIdSet, + Map serializedOnlineViewersById, Map viewerMembershipSignatures, Map> viewerIdsExcluding ) { @@ -145,7 +168,7 @@ private TableSeatRenderSnapshot captureSeatSnapshot( occupied && session.isRiichi(playerId), occupied && session.isReady(playerId), occupied && session.isQueuedToLeave(playerId), - occupied && onlineViewerIdSet.contains(playerId), + occupied && serializedOnlineViewersById.containsKey(playerId), viewerMembershipSignatures.getOrDefault(playerId, ""), occupied ? session.selectedHandTileIndex(playerId) : -1, occupied ? session.selectedHandTileIndices(playerId) : List.of(), @@ -160,14 +183,25 @@ private TableSeatRenderSnapshot captureSeatSnapshot( ); } - private String viewerMembershipSignature(List onlineViewerIds, UUID excludedPlayerId) { + private StringBuilder viewerMembershipBuffer(List onlineViewerIds) { StringBuilder builder = new StringBuilder(onlineViewerIds.size() * 36); for (SerializedViewerId viewer : onlineViewerIds) { - if (!viewer.id().equals(excludedPlayerId)) { - builder.append(viewer.serializedId()); - } + builder.append(viewer.serializedId()); } - return builder.toString(); + return builder; + } + + private String viewerMembershipSignature( + StringBuilder viewerMembershipBuffer, + SerializedViewerId excludedViewer, + int excludedViewerIndex + ) { + String serializedId = excludedViewer.serializedId(); + int start = excludedViewerIndex * serializedId.length(); + viewerMembershipBuffer.delete(start, start + serializedId.length()); + String signature = viewerMembershipBuffer.toString(); + viewerMembershipBuffer.insert(start, serializedId); + return signature; } private List viewerIdsExcluding(List onlineViewerIds, UUID excludedPlayerId) {