Skip to content
This repository was archived by the owner on Dec 10, 2025. It is now read-only.

Commit 795db6d

Browse files
committed
feat: streamline player data management and update protocol version
- Updated `RespondingNettyPacket` to utilize weak references for response connections, enhancing memory management. - Introduced `overwritePpdc` in `ClientCloudPlayerImpl` for efficient persistent player data updates. - Enhanced `PlayerConnectedToServerPacket` and `PlayerConnectToServerPacket` with `StreamCodec` for seamless serialization. - Refined `PrePlayerJoinTask.Result` to support clean serialization and type distinction. - Updated netty protocol to version `2` and adjusted related codec registrations for consistency.
1 parent dbd36fb commit 795db6d

File tree

10 files changed

+147
-31
lines changed

10 files changed

+147
-31
lines changed

surf-cloud-api/surf-cloud-api-common/src/main/kotlin/dev/slne/surf/cloud/api/common/netty/packet/RespondingNettyPacket.kt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import kotlinx.coroutines.CompletableDeferred
1010
import kotlinx.coroutines.TimeoutCancellationException
1111
import kotlinx.coroutines.withTimeout
1212
import kotlinx.coroutines.withTimeoutOrNull
13+
import java.lang.ref.WeakReference
1314
import java.util.*
15+
import kotlin.properties.Delegates
1416
import kotlin.time.Duration
1517
import kotlin.time.Duration.Companion.seconds
1618

@@ -42,8 +44,12 @@ abstract class RespondingNettyPacket<P : ResponseNettyPacket> : NettyPacket() {
4244
* The connection through which the response will be sent.
4345
*/
4446
@InternalApi
45-
lateinit var responseConnection: Connection
47+
private var responseConnection by Delegates.notNull<WeakReference<Connection>>()
4648

49+
@InternalApi
50+
fun initResponseConnection(connection: Connection) {
51+
responseConnection = WeakReference(connection)
52+
}
4753

4854
/**
4955
* Fires the packet and awaits its response within the specified timeout.
@@ -109,6 +115,14 @@ abstract class RespondingNettyPacket<P : ResponseNettyPacket> : NettyPacket() {
109115
fun respond(packet: P) {
110116
packet.responseTo = uniqueSessionId
111117
?: error("Responding packet has no session id. Are you sure it was sent?")
118+
119+
val responseConnection = responseConnection.get()
120+
if (responseConnection == null) {
121+
log.atWarning()
122+
.log("Cannot respond to packet ${this::class.simpleName} with session ID $uniqueSessionId: original connection has been garbage collected")
123+
return
124+
}
125+
112126
responseConnection.send(packet)
113127
}
114128

surf-cloud-api/surf-cloud-api-common/src/main/kotlin/dev/slne/surf/cloud/api/common/player/task/PrePlayerJoinTask.kt

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,64 @@
11
package dev.slne.surf.cloud.api.common.player.task
22

3+
import dev.slne.surf.cloud.api.common.netty.network.codec.ByteBufCodecs
4+
import dev.slne.surf.cloud.api.common.netty.network.codec.StreamCodec
5+
import dev.slne.surf.cloud.api.common.netty.network.codec.streamCodecUnitSimple
36
import dev.slne.surf.cloud.api.common.player.OfflineCloudPlayer
47
import dev.slne.surf.cloud.api.common.util.annotation.InternalApi
8+
import dev.slne.surf.cloud.api.common.util.int2ObjectMapOf
9+
import io.netty.handler.codec.DecoderException
510
import kotlinx.serialization.Contextual
6-
import kotlinx.serialization.Serializable
711
import net.kyori.adventure.text.Component
812

913
interface PrePlayerJoinTask {
1014
suspend fun preJoin(player: OfflineCloudPlayer): Result
1115

12-
@Serializable
1316
sealed interface Result {
17+
val type: Type
1418

15-
@Serializable
16-
data object ALLOWED: Result
19+
data object ALLOWED : Result {
20+
val TYPE = Type(0)
21+
val STREAM_CODEC = streamCodecUnitSimple(this)
22+
override val type = TYPE
23+
}
1724

18-
@Serializable
19-
data class DENIED(val reason: @Contextual Component): Result
25+
data class DENIED(val reason: @Contextual Component) : Result {
26+
override val type = TYPE
2027

21-
@Serializable
22-
data object ERROR: Result
28+
companion object {
29+
val TYPE = Type(1)
30+
val STREAM_CODEC = StreamCodec.composite(
31+
ByteBufCodecs.COMPONENT_CODEC,
32+
DENIED::reason,
33+
::DENIED
34+
)
35+
}
36+
}
37+
38+
data object ERROR : Result {
39+
val TYPE = Type(2)
40+
val STREAM_CODEC = streamCodecUnitSimple(this)
41+
override val type = TYPE
42+
}
43+
44+
@JvmInline
45+
value class Type(val id: Int)
46+
47+
companion object {
48+
private val TYPES = int2ObjectMapOf(
49+
ALLOWED.TYPE.id to ALLOWED.STREAM_CODEC,
50+
DENIED.TYPE.id to DENIED.STREAM_CODEC,
51+
ERROR.TYPE.id to ERROR.STREAM_CODEC
52+
)
53+
54+
val STREAM_CODEC = ByteBufCodecs.VAR_INT_CODEC.dispatch(
55+
{ it.type.id },
56+
{
57+
TYPES.get(it)
58+
?: throw DecoderException("Unknown PrePlayerJoinTask.Result type id: $it")
59+
}
60+
)
61+
}
2362
}
2463

2564
@InternalApi

surf-cloud-core/surf-cloud-core-client/src/main/kotlin/dev/slne/surf/cloud/core/client/netty/network/ClientRunningPacketListenerImpl.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,16 @@ class ClientRunningPacketListenerImpl(
4646
private val log = logger()
4747

4848
override suspend fun handlePlayerConnectedToServer(packet: PlayerConnectedToServerPacket) {
49-
playerManagerImpl.updateOrCreatePlayer(
49+
commonPlayerManagerImpl.updateOrCreatePlayer(
5050
packet.uuid,
5151
packet.name,
5252
packet.proxy,
5353
packet.playerIp,
5454
packet.serverName,
5555
false
56-
)
56+
) {
57+
overwritePpdc(packet.pdc)
58+
}
5759
}
5860

5961
override suspend fun handlePlayerDisconnectFromServer(packet: PlayerDisconnectFromServerPacket) {

surf-cloud-core/surf-cloud-core-client/src/main/kotlin/dev/slne/surf/cloud/core/client/player/ClientCloudPlayerImpl.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import net.kyori.adventure.audience.MessageType
3131
import net.kyori.adventure.bossbar.BossBar
3232
import net.kyori.adventure.identity.Identity
3333
import net.kyori.adventure.inventory.Book
34+
import net.kyori.adventure.nbt.CompoundBinaryTag
3435
import net.kyori.adventure.resource.ResourcePackRequest
3536
import net.kyori.adventure.sound.Sound
3637
import net.kyori.adventure.sound.Sound.Emitter
@@ -80,6 +81,12 @@ abstract class ClientCloudPlayerImpl<PlatformPlayer : Audience>(
8081
}
8182
}
8283

84+
fun overwritePpdc(tag: CompoundBinaryTag) {
85+
ppdcReentrantLock.write {
86+
ppdc.fromTagCompound(tag)
87+
}
88+
}
89+
8390
override fun <R> editPdc(block: PersistentPlayerDataContainer.() -> R): R {
8491
val (result, patch) = editPdc0(true, block)
8592
if (!patch.empty) {

surf-cloud-core/surf-cloud-core-common/src/main/kotlin/dev/slne/surf/cloud/core/common/netty/network/RespondingPacketSendHandler.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class RespondingPacketSendHandler : UnifiedReadOnlyChannelHandler<NettyPacket>()
3232
}
3333

3434
if (msg is RespondingNettyPacket<*>) {
35-
msg.responseConnection = ctx.channel().attr(ConnectionImpl.CHANNEL_ATTRIBUTE_KEY).get()
35+
msg.initResponseConnection(ctx.channel().attr(ConnectionImpl.CHANNEL_ATTRIBUTE_KEY).get())
3636
}
3737

3838
if (msg is ResponseNettyPacket) {

surf-cloud-core/surf-cloud-core-common/src/main/kotlin/dev/slne/surf/cloud/core/common/netty/network/protocol/handshake/ServerboundHandshakePacket.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import dev.slne.surf.cloud.api.common.netty.packet.NettyPacket
88
import dev.slne.surf.cloud.api.common.netty.packet.packetCodec
99
import dev.slne.surf.cloud.api.common.netty.protocol.buffer.SurfByteBuf
1010

11-
const val PROTOCOL_VERSION = 1
11+
const val PROTOCOL_VERSION = 2
1212

1313
/**
1414
* First packet sent by the client to the cloud server. It is used to establish a connection to the cloud server.

surf-cloud-core/surf-cloud-core-common/src/main/kotlin/dev/slne/surf/cloud/core/common/netty/network/protocol/running/ClientboundRunPrePlayerJoinTasksPacket.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package dev.slne.surf.cloud.core.common.netty.network.protocol.running
22

33
import dev.slne.surf.cloud.api.common.meta.SurfNettyPacket
4+
import dev.slne.surf.cloud.api.common.netty.network.codec.StreamCodec
45
import dev.slne.surf.cloud.api.common.netty.network.protocol.PacketFlow
56
import dev.slne.surf.cloud.api.common.netty.packet.RespondingNettyPacket
67
import dev.slne.surf.cloud.api.common.netty.packet.ResponseNettyPacket
@@ -15,5 +16,13 @@ class ClientboundRunPrePlayerJoinTasksPacket(val uuid: @Contextual UUID) :
1516
RespondingNettyPacket<RunPrePlayerJoinTasksResultPacket>()
1617

1718
@SurfNettyPacket("cloud:response:run_pre_player_join_tasks", PacketFlow.SERVERBOUND)
18-
@Serializable
19-
class RunPrePlayerJoinTasksResultPacket(val result: PrePlayerJoinTask.Result) : ResponseNettyPacket()
19+
class RunPrePlayerJoinTasksResultPacket(val result: PrePlayerJoinTask.Result) :
20+
ResponseNettyPacket() {
21+
companion object {
22+
val STREAM_CODEC = StreamCodec.composite(
23+
PrePlayerJoinTask.Result.STREAM_CODEC,
24+
RunPrePlayerJoinTasksResultPacket::result,
25+
::RunPrePlayerJoinTasksResultPacket
26+
)
27+
}
28+
}

surf-cloud-core/surf-cloud-core-common/src/main/kotlin/dev/slne/surf/cloud/core/common/netty/network/protocol/running/PlayerConnectToServerPacket.kt

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ package dev.slne.surf.cloud.core.common.netty.network.protocol.running
22

33
import dev.slne.surf.cloud.api.common.meta.DefaultIds
44
import dev.slne.surf.cloud.api.common.meta.SurfNettyPacket
5+
import dev.slne.surf.cloud.api.common.netty.network.codec.ByteBufCodecs
6+
import dev.slne.surf.cloud.api.common.netty.network.codec.StreamCodec
7+
import dev.slne.surf.cloud.api.common.netty.network.codec.composite
58
import dev.slne.surf.cloud.api.common.netty.network.protocol.PacketFlow
69
import dev.slne.surf.cloud.api.common.netty.packet.NettyPacket
710
import dev.slne.surf.cloud.api.common.netty.packet.RespondingNettyPacket
811
import dev.slne.surf.cloud.api.common.netty.packet.ResponseNettyPacket
912
import dev.slne.surf.cloud.api.common.player.task.PrePlayerJoinTask
10-
import kotlinx.serialization.Contextual
11-
import kotlinx.serialization.Serializable
13+
import net.kyori.adventure.nbt.CompoundBinaryTag
1214
import java.net.Inet4Address
1315
import java.util.*
1416

@@ -23,25 +25,66 @@ import java.util.*
2325
* @param proxy If the server is a proxy
2426
*/
2527
@SurfNettyPacket(DefaultIds.PLAYER_CONNECT_TO_SERVER_PACKET, PacketFlow.SERVERBOUND)
26-
@Serializable
2728
data class PlayerConnectToServerPacket(
28-
val uuid: @Contextual UUID,
29+
val uuid: UUID,
2930
val name: String,
3031
val serverName: String,
3132
val proxy: Boolean,
32-
val playerIp: @Contextual Inet4Address,
33-
) : RespondingNettyPacket<PlayerConnectToServerResponsePacket>()
33+
val playerIp: Inet4Address
34+
) : RespondingNettyPacket<PlayerConnectToServerResponsePacket>() {
35+
companion object {
36+
val STREAM_CODEC = StreamCodec.composite(
37+
ByteBufCodecs.UUID_CODEC,
38+
PlayerConnectToServerPacket::uuid,
39+
ByteBufCodecs.STRING_CODEC,
40+
PlayerConnectToServerPacket::name,
41+
ByteBufCodecs.STRING_CODEC,
42+
PlayerConnectToServerPacket::serverName,
43+
ByteBufCodecs.BOOLEAN_CODEC,
44+
PlayerConnectToServerPacket::proxy,
45+
ByteBufCodecs.INET_4_ADDRESS_CODEC,
46+
PlayerConnectToServerPacket::playerIp,
47+
::PlayerConnectToServerPacket
48+
)
49+
}
50+
}
3451

3552
@SurfNettyPacket(DefaultIds.PLAYER_CONNECTED_TO_SERVER_PACKET, PacketFlow.CLIENTBOUND)
36-
@Serializable
3753
data class PlayerConnectedToServerPacket(
38-
val uuid: @Contextual UUID,
54+
val uuid: UUID,
3955
val name: String,
4056
val serverName: String,
4157
val proxy: Boolean,
42-
val playerIp: @Contextual Inet4Address,
43-
) : NettyPacket()
58+
val playerIp: Inet4Address,
59+
val pdc: CompoundBinaryTag
60+
) : NettyPacket() {
61+
companion object {
62+
val STREAM_CODEC = StreamCodec.composite(
63+
ByteBufCodecs.UUID_CODEC,
64+
PlayerConnectedToServerPacket::uuid,
65+
ByteBufCodecs.STRING_CODEC,
66+
PlayerConnectedToServerPacket::name,
67+
ByteBufCodecs.STRING_CODEC,
68+
PlayerConnectedToServerPacket::serverName,
69+
ByteBufCodecs.BOOLEAN_CODEC,
70+
PlayerConnectedToServerPacket::proxy,
71+
ByteBufCodecs.INET_4_ADDRESS_CODEC,
72+
PlayerConnectedToServerPacket::playerIp,
73+
ByteBufCodecs.COMPOUND_TAG_CODEC,
74+
PlayerConnectedToServerPacket::pdc,
75+
::PlayerConnectedToServerPacket
76+
)
77+
}
78+
}
4479

4580
@SurfNettyPacket("cloud:response:connect_to_server", PacketFlow.BIDIRECTIONAL)
46-
@Serializable
47-
class PlayerConnectToServerResponsePacket(val result: PrePlayerJoinTask.Result) : ResponseNettyPacket()
81+
class PlayerConnectToServerResponsePacket(val result: PrePlayerJoinTask.Result) :
82+
ResponseNettyPacket() {
83+
companion object {
84+
val STREAM_CODEC = StreamCodec.composite(
85+
PrePlayerJoinTask.Result.STREAM_CODEC,
86+
PlayerConnectToServerResponsePacket::result,
87+
::PlayerConnectToServerResponsePacket
88+
)
89+
}
90+
}

surf-cloud-core/surf-cloud-core-common/src/main/kotlin/dev/slne/surf/cloud/core/common/netty/network/protocol/running/RunningProtocols.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ object RunningProtocols {
3131
.addPacket(ClientboundSendResourcePacksPacket.STREAM_CODEC)
3232
.addPacket(ClientboundRemoveResourcePacksPacket.STREAM_CODEC)
3333
.addPacket(ClientboundClearResourcePacksPacket.STREAM_CODEC)
34-
.addPacket(PlayerConnectedToServerPacket::class.createCodec())
34+
.addPacket(PlayerConnectedToServerPacket.STREAM_CODEC)
3535
.addPacket(PlayerConnectToServerResponsePacket::class.createCodec())
3636
.addPacket(PlayerDisconnectFromServerPacket.STREAM_CODEC)
3737
.addPacket(ClientboundRequestDisplayNamePacket.STREAM_CODEC)
@@ -102,7 +102,7 @@ object RunningProtocols {
102102
.addPacket(ServerboundBroadcastPacket.STREAM_CODEC)
103103
.addPacket(ServerboundClientInformationPacket.STREAM_CODEC)
104104
.addPacket(ServerboundPingRequestPacket.STREAM_CODEC)
105-
.addPacket(PlayerConnectToServerPacket::class.createCodec())
105+
.addPacket(PlayerConnectToServerPacket.STREAM_CODEC)
106106
.addPacket(PlayerConnectToServerResponsePacket::class.createCodec())
107107
.addPacket(PlayerDisconnectFromServerPacket.STREAM_CODEC)
108108
.addPacket(ServerboundRequestDisplayNamePacket.STREAM_CODEC)
@@ -122,7 +122,7 @@ object RunningProtocols {
122122
.addPacket(ServerboundPullPlayersToGroupPacket::class.createCodec())
123123
.addPacket(SilentDisconnectPlayerPacket::class.createCodec())
124124
.addPacket(TeleportPlayerToPlayerPacket::class.createCodec())
125-
.addPacket(RunPrePlayerJoinTasksResultPacket::class.createCodec())
125+
.addPacket(RunPrePlayerJoinTasksResultPacket.STREAM_CODEC)
126126
.addPacket(ServerboundGeneratePunishmentIdPacket::class.createCodec())
127127
.addPacket(ServerboundCreateKickPacket::class.createCodec())
128128
.addPacket(ServerboundCreateWarnPacket::class.createCodec())

surf-cloud-core/surf-cloud-core-common/src/main/kotlin/dev/slne/surf/cloud/core/common/player/CloudPlayerManagerImpl.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ abstract class CloudPlayerManagerImpl<P : CommonCloudPlayerImpl> : CloudPlayerMa
7777
proxy: Boolean,
7878
ip: Inet4Address,
7979
serverName: String,
80-
runPreJoinTasks: Boolean
80+
runPreJoinTasks: Boolean,
81+
extraInit: P.() -> Unit = {}
8182
): PrePlayerJoinTask.Result {
8283
val existing = playerCache.getOrNull(uuid)
8384
if (existing != null) {
@@ -93,6 +94,7 @@ abstract class CloudPlayerManagerImpl<P : CommonCloudPlayerImpl> : CloudPlayerMa
9394
return try {
9495
playerCache.get(uuid) {
9596
val newPlayer = createPlayer(uuid, name, proxy, ip, serverName)
97+
newPlayer.extraInit()
9698

9799
if (runPreJoinTasks) {
98100
val pre = preJoin(newPlayer)

0 commit comments

Comments
 (0)