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

Commit 2bcffc7

Browse files
committed
feat: refactor persistent player data handling and test plugin structure
- Removed `ServerboundPlayerPersistentDataContainerUpdatePacket` and its associated logic for simplified player data updates. - Reorganized test plugin structure: - Added `TestSpringApplication` in `test-core` module for Spring-based test applications. - Introduced `TestPpdcCommand` to enhance PPDC testing capabilities within `standalone` and `paper` modules. - Updated `RunningProtocols` to streamline persistent data request handling and improve codec consistency. - Enhanced shutdown handling with improved player disconnect management during network termination.
1 parent 4136747 commit 2bcffc7

File tree

34 files changed

+893
-440
lines changed

34 files changed

+893
-440
lines changed

settings.gradle.kts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,21 @@ include("surf-cloud-core:surf-cloud-core-client")
2727
findProject(":surf-cloud-core:surf-cloud-core-client")?.name = "surf-cloud-core-client"
2828

2929
include("surf-cloud-api:surf-cloud-api-client:surf-cloud-api-client-common")
30-
findProject(":surf-cloud-api:surf-cloud-api-client:surf-cloud-api-client-common")?.name = "surf-cloud-api-client-common"
30+
findProject(":surf-cloud-api:surf-cloud-api-client:surf-cloud-api-client-common")?.name =
31+
"surf-cloud-api-client-common"
3132

3233
include("surf-cloud-api:surf-cloud-api-client:surf-cloud-api-client-paper")
33-
findProject(":surf-cloud-api:surf-cloud-api-client:surf-cloud-api-client-paper")?.name = "surf-cloud-api-client-paper"
34+
findProject(":surf-cloud-api:surf-cloud-api-client:surf-cloud-api-client-paper")?.name =
35+
"surf-cloud-api-client-paper"
3436

3537
include("surf-cloud-api:surf-cloud-api-client:surf-cloud-api-client-velocity")
36-
findProject(":surf-cloud-api:surf-cloud-api-client:surf-cloud-api-client-velocity")?.name = "surf-cloud-api-client-velocity"
38+
findProject(":surf-cloud-api:surf-cloud-api-client:surf-cloud-api-client-velocity")?.name =
39+
"surf-cloud-api-client-velocity"
3740

3841
include("surf-cloud-bom")
3942

4043
if (!ci) {
4144
include(":surf-cloud-test-plugin:surf-cloud-test-standalone")
42-
}
45+
include(":surf-cloud-test-plugin:surf-cloud-test-core")
46+
include("surf-cloud-test-plugin:surf-cloud-test-paper")
47+
}

surf-cloud-api/surf-cloud-api-common/src/main/kotlin/dev/slne/surf/cloud/api/common/netty/network/codec/ByteBufCodecs.kt

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package dev.slne.surf.cloud.api.common.netty.network.codec
22

3-
import dev.slne.surf.cloud.api.common.internal.BinaryTagTypeProxy
43
import dev.slne.surf.cloud.api.common.netty.protocol.buffer.*
54
import dev.slne.surf.cloud.api.common.netty.protocol.buffer.types.Utf8String
65
import dev.slne.surf.cloud.api.common.util.ByIdMap
@@ -18,6 +17,7 @@ import net.kyori.adventure.key.Key
1817
import net.kyori.adventure.nbt.BinaryTag
1918
import net.kyori.adventure.nbt.BinaryTagIO
2019
import net.kyori.adventure.nbt.BinaryTagType
20+
import net.kyori.adventure.nbt.BinaryTagTypes
2121
import net.kyori.adventure.sound.Sound
2222
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer
2323
import java.io.ByteArrayInputStream
@@ -156,36 +156,83 @@ object ByteBufCodecs {
156156
BigDecimal(unscaledValue, scale, MathContext(precision))
157157
}
158158

159+
private val TAG_TYPES = arrayOf(
160+
BinaryTagTypes.END,
161+
BinaryTagTypes.BYTE,
162+
BinaryTagTypes.SHORT,
163+
BinaryTagTypes.INT,
164+
BinaryTagTypes.LONG,
165+
BinaryTagTypes.FLOAT,
166+
BinaryTagTypes.DOUBLE,
167+
BinaryTagTypes.BYTE_ARRAY,
168+
BinaryTagTypes.STRING,
169+
BinaryTagTypes.LIST,
170+
BinaryTagTypes.COMPOUND,
171+
BinaryTagTypes.INT_ARRAY,
172+
BinaryTagTypes.LONG_ARRAY,
173+
)
159174

160175
private val BINARY_TAG_BY_ID = ByIdMap.continuous(
161176
{ it.id().toInt() },
162-
BinaryTagTypeProxy.instance.getTypes().toTypedArray(),
177+
TAG_TYPES,
163178
OutOfBoundsStrategy.DECODE_ERROR
164179
)
165180

166181
val BINARY_TAG_CODEC: StreamCodec<ByteBuf, BinaryTag> = streamCodec({ buf, tag ->
167182
val type = tag.type() as BinaryTagType<BinaryTag>
168183
buf.writeByte(type.id().toInt())
169-
DataOutputStream(FastBufferedOutputStream(ByteBufOutputStream(buf))).use {
170-
type.write(tag, it)
184+
185+
val tmp = buf.alloc().buffer()
186+
try {
187+
DataOutputStream(FastBufferedOutputStream(ByteBufOutputStream(tmp))).use { out ->
188+
type.write(tag, out)
189+
}
190+
val length = tmp.readableBytes()
191+
buf.writeVarInt(length)
192+
buf.writeBytes(tmp, tmp.readerIndex(), length)
193+
} finally {
194+
tmp.release()
171195
}
196+
172197
}, { buf ->
173198
val type = BINARY_TAG_BY_ID(buf.readByte().toInt())
174-
DataInputStream(FastBufferedInputStream(ByteBufInputStream(buf))).use {
175-
type.read(it)
199+
val len = buf.readVarInt()
200+
val slice = buf.readRetainedSlice(len)
201+
202+
try {
203+
DataInputStream(FastBufferedInputStream(ByteBufInputStream(slice))).use { input ->
204+
type.read(input)
205+
}
206+
} finally {
207+
slice.release()
176208
}
177209
})
178210

179211
val BINARY_TAG_CODEC_COMPRESSED: StreamCodec<ByteBuf, BinaryTag> = streamCodec({ buf, tag ->
180212
val type = tag.type() as BinaryTagType<BinaryTag>
181213
buf.writeByte(type.id().toInt())
182-
DataOutputStream(FastBufferedOutputStream(GZIPOutputStream(ByteBufOutputStream(buf)))).use {
183-
type.write(tag, it)
214+
val temp = buf.alloc().buffer()
215+
216+
try {
217+
DataOutputStream(FastBufferedOutputStream(GZIPOutputStream(ByteBufOutputStream(temp)))).use {
218+
type.write(tag, it)
219+
}
220+
buf.writeVarInt(temp.readableBytes())
221+
buf.writeBytes(temp, temp.readerIndex(), temp.readableBytes())
222+
} finally {
223+
temp.release()
184224
}
185225
}, { buf ->
186226
val type = BINARY_TAG_BY_ID(buf.readByte().toInt())
187-
DataInputStream(FastBufferedInputStream(GZIPInputStream(ByteBufInputStream(buf)))).use {
188-
type.read(it)
227+
val length = buf.readVarInt()
228+
val slice = buf.readRetainedSlice(length)
229+
230+
try {
231+
DataInputStream(FastBufferedInputStream(GZIPInputStream(ByteBufInputStream(slice)))).use {
232+
type.read(it)
233+
}
234+
} finally {
235+
slice.release()
189236
}
190237
})
191238

surf-cloud-api/surf-cloud-api-common/src/main/kotlin/dev/slne/surf/cloud/api/common/player/ppdc/ListPersistentPlayerDataType.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ package dev.slne.surf.cloud.api.common.player.ppdc
66
* @param P The primitive type of the list elements.
77
* @param C The complex type of the list elements.
88
*/
9-
interface ListPersistentPlayerDataType<P : Any, C>: PersistentPlayerDataType<List<P>, C> {
9+
interface ListPersistentPlayerDataType<P : Any, C>: PersistentPlayerDataType<List<P>, List<C>> {
1010

1111
/**
1212
* The data type of the elements in the list.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package dev.slne.surf.cloud.api.common.player.ppdc
2+
3+
import com.google.common.collect.Lists
4+
5+
class ListPersistentPlayerDataTypeProvider {
6+
companion object {
7+
private val BYTE = ListPersistentPlayerDataTypeImpl.create(PersistentPlayerDataType.BYTE)
8+
private val SHORT = ListPersistentPlayerDataTypeImpl.create(PersistentPlayerDataType.SHORT)
9+
private val INT = ListPersistentPlayerDataTypeImpl.create(PersistentPlayerDataType.INT)
10+
private val LONG = ListPersistentPlayerDataTypeImpl.create(PersistentPlayerDataType.LONG)
11+
private val FLOAT = ListPersistentPlayerDataTypeImpl.create(PersistentPlayerDataType.FLOAT)
12+
private val DOUBLE =
13+
ListPersistentPlayerDataTypeImpl.create(PersistentPlayerDataType.DOUBLE)
14+
private val BOOLEAN =
15+
ListPersistentPlayerDataTypeImpl.create(PersistentPlayerDataType.BOOLEAN)
16+
private val STRING =
17+
ListPersistentPlayerDataTypeImpl.create(PersistentPlayerDataType.STRING)
18+
private val BYTE_ARRAY =
19+
ListPersistentPlayerDataTypeImpl.create(PersistentPlayerDataType.BYTE_ARRAY)
20+
private val INT_ARRAY =
21+
ListPersistentPlayerDataTypeImpl.create(PersistentPlayerDataType.INT_ARRAY)
22+
private val LONG_ARRAY =
23+
ListPersistentPlayerDataTypeImpl.create(PersistentPlayerDataType.LONG_ARRAY)
24+
private val DATA_CONTAINER =
25+
ListPersistentPlayerDataTypeImpl.create(PersistentPlayerDataType.TAG_CONTAINER)
26+
}
27+
28+
29+
fun bytes() = BYTE
30+
fun shorts() = SHORT
31+
fun ints() = INT
32+
fun longs() = LONG
33+
fun floats() = FLOAT
34+
fun doubles() = DOUBLE
35+
fun booleans() = BOOLEAN
36+
fun strings() = STRING
37+
fun byteArrays() = BYTE_ARRAY
38+
fun intArrays() = INT_ARRAY
39+
fun longArrays() = LONG_ARRAY
40+
fun dataContainers() = DATA_CONTAINER
41+
fun <P : Any, C> listTypeFrom(elementType: PersistentPlayerDataType<P, C>) =
42+
ListPersistentPlayerDataTypeImpl.create(elementType)
43+
44+
private class ListPersistentPlayerDataTypeImpl<P : Any, C>(
45+
override val elementType: PersistentPlayerDataType<P, C>
46+
) : ListPersistentPlayerDataType<P, C> {
47+
@Suppress("UNCHECKED_CAST")
48+
override val primitiveType = List::class.java as Class<List<P>>
49+
50+
override fun fromPrimitive(
51+
primitive: List<P>,
52+
context: PersistentPlayerDataAdapterContext
53+
): List<C> {
54+
return Lists.transform(primitive) { elementType.fromPrimitive(it, context) }
55+
}
56+
57+
override fun toPrimitive(
58+
complex: List<C>,
59+
context: PersistentPlayerDataAdapterContext
60+
): List<P> {
61+
return Lists.transform(complex) { elementType.toPrimitive(it, context) }
62+
}
63+
64+
companion object {
65+
fun <P : Any, C> create(elementType: PersistentPlayerDataType<P, C>): ListPersistentPlayerDataType<P, C> {
66+
return ListPersistentPlayerDataTypeImpl(elementType)
67+
}
68+
}
69+
}
70+
}

surf-cloud-api/surf-cloud-api-common/src/main/kotlin/dev/slne/surf/cloud/api/common/player/ppdc/PersistentPlayerDataContainer.kt

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,32 +24,17 @@ interface PersistentPlayerDataContainer: PersistentPlayerDataContainerView {
2424
fun <P : Any, C> set(key: Key, type: PersistentPlayerDataType<P, C>, value: C)
2525

2626
// region Primitive-specific set methods.
27-
fun setBoolean(key: Key, value: Boolean)
28-
fun setByte(key: Key, value: Byte)
29-
fun setShort(key: Key, value: Short)
30-
fun setInt(key: Key, value: Int)
31-
fun setLong(key: Key, value: Long)
32-
fun setFloat(key: Key, value: Float)
33-
fun setDouble(key: Key, value: Double)
34-
fun setString(key: Key, value: String)
35-
fun setByteArray(key: Key, value: ByteArray)
36-
fun setIntArray(key: Key, value: IntArray)
37-
fun setLongArray(key: Key, value: LongArray)
38-
// endregion
39-
40-
// region Primitive-specific get methods.
41-
fun getBoolean(key: Key): Boolean?
42-
fun getNumber(key: Key): Number?
43-
fun getByte(key: Key): Byte?
44-
fun getShort(key: Key): Short?
45-
fun getInt(key: Key): Int?
46-
fun getLong(key: Key): Long?
47-
fun getFloat(key: Key): Float?
48-
fun getDouble(key: Key): Double?
49-
fun getString(key: Key): String?
50-
fun getByteArray(key: Key): ByteArray?
51-
fun getIntArray(key: Key): IntArray?
52-
fun getLongArray(key: Key): LongArray?
27+
fun setBoolean(key: Key, value: Boolean?)
28+
fun setByte(key: Key, value: Byte?)
29+
fun setShort(key: Key, value: Short?)
30+
fun setInt(key: Key, value: Int?)
31+
fun setLong(key: Key, value: Long?)
32+
fun setFloat(key: Key, value: Float?)
33+
fun setDouble(key: Key, value: Double?)
34+
fun setString(key: Key, value: String?)
35+
fun setByteArray(key: Key, value: ByteArray?)
36+
fun setIntArray(key: Key, value: IntArray?)
37+
fun setLongArray(key: Key, value: LongArray?)
5338
// endregion
5439

5540
/**

surf-cloud-api/surf-cloud-api-common/src/main/kotlin/dev/slne/surf/cloud/api/common/player/ppdc/PersistentPlayerDataContainerView.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,21 @@ interface PersistentPlayerDataContainerView {
4343
*/
4444
fun <P : Any, C> get(key: Key, type: PersistentPlayerDataType<P, C>): C?
4545

46+
// region Primitive-specific get methods.
47+
fun getBoolean(key: Key): Boolean?
48+
fun getNumber(key: Key): Number?
49+
fun getByte(key: Key): Byte?
50+
fun getShort(key: Key): Short?
51+
fun getInt(key: Key): Int?
52+
fun getLong(key: Key): Long?
53+
fun getFloat(key: Key): Float?
54+
fun getDouble(key: Key): Double?
55+
fun getString(key: Key): String?
56+
fun getByteArray(key: Key): ByteArray?
57+
fun getIntArray(key: Key): IntArray?
58+
fun getLongArray(key: Key): LongArray?
59+
// endregion
60+
4661
/**
4762
* Retrieves all keys present in this container.
4863
*

surf-cloud-api/surf-cloud-api-common/src/main/kotlin/dev/slne/surf/cloud/api/common/player/ppdc/PersistentPlayerDataType.kt

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package dev.slne.surf.cloud.api.common.player.ppdc
22

3-
import kotlin.reflect.KClass
4-
53
/**
64
* Represents a data type that can be serialized and deserialized in a persistent player data container.
75
*
@@ -12,7 +10,7 @@ interface PersistentPlayerDataType<P : Any, C> {
1210
/**
1311
* The primitive type used for serialization.
1412
*/
15-
val primitiveType: KClass<P>
13+
val primitiveType: Class<P>
1614

1715
/**
1816
* Converts a primitive value to its complex representation.
@@ -31,4 +29,60 @@ interface PersistentPlayerDataType<P : Any, C> {
3129
* @return The primitive representation of the complex value.
3230
*/
3331
fun toPrimitive(complex: C, context: PersistentPlayerDataAdapterContext): P
32+
33+
companion object {
34+
val BYTE = PrimitivePersistentPlayerDataType<Byte>()
35+
val SHORT = PrimitivePersistentPlayerDataType<Short>()
36+
val INT = PrimitivePersistentPlayerDataType<Int>()
37+
val LONG = PrimitivePersistentPlayerDataType<Long>()
38+
val FLOAT = PrimitivePersistentPlayerDataType<Float>()
39+
val DOUBLE = PrimitivePersistentPlayerDataType<Double>()
40+
val BOOLEAN = BooleanPersistentPlayerDataType.create()
41+
val STRING = PrimitivePersistentPlayerDataType<String>()
42+
val BYTE_ARRAY = PrimitivePersistentPlayerDataType<ByteArray>()
43+
val INT_ARRAY = PrimitivePersistentPlayerDataType<IntArray>()
44+
val LONG_ARRAY = PrimitivePersistentPlayerDataType<LongArray>()
45+
val TAG_CONTAINER = PrimitivePersistentPlayerDataType<PersistentPlayerDataContainer>()
46+
val LIST by lazy { ListPersistentPlayerDataTypeProvider() }
47+
48+
49+
internal class PrimitivePersistentPlayerDataType<P : Any>(override val primitiveType: Class<P>) :
50+
PersistentPlayerDataType<P, P> {
51+
override fun fromPrimitive(
52+
primitive: P,
53+
context: PersistentPlayerDataAdapterContext
54+
): P = primitive
55+
56+
override fun toPrimitive(
57+
complex: P,
58+
context: PersistentPlayerDataAdapterContext
59+
): P = complex
60+
61+
companion object {
62+
internal inline operator fun <reified P : Any> invoke(): PersistentPlayerDataType<P, P> {
63+
return PrimitivePersistentPlayerDataType(P::class.java)
64+
}
65+
}
66+
}
67+
68+
internal class BooleanPersistentPlayerDataType :
69+
PersistentPlayerDataType<Byte, Boolean> {
70+
override val primitiveType: Class<Byte> = Byte::class.java
71+
72+
override fun fromPrimitive(
73+
primitive: Byte,
74+
context: PersistentPlayerDataAdapterContext
75+
): Boolean = primitive != 0.toByte()
76+
77+
override fun toPrimitive(
78+
complex: Boolean,
79+
context: PersistentPlayerDataAdapterContext
80+
): Byte = if (complex) 1 else 0
81+
82+
companion object {
83+
fun create(): PersistentPlayerDataType<Byte, Boolean> =
84+
BooleanPersistentPlayerDataType()
85+
}
86+
}
87+
}
3488
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ abstract class CommonClientCloudPlayerManagerImpl<Platform : Audience, P : Clien
6666
.fireAndAwaitOrThrow()
6767
.nbt
6868

69-
player.ppdcData = ppdcData.fast()
69+
player.overwritePpdc(ppdcData.fast())
7070
} catch (e: Exception) {
7171
log.atWarning()
7272
.withCause(e)

surf-cloud-core/surf-cloud-core-common/src/main/kotlin/dev/slne/surf/cloud/core/common/messages/MessageManager.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,17 @@ object MessageManager { // TODO: Add more messages
8282
)
8383
}
8484

85+
val networkShutdown = buildText {
86+
CommonComponents.renderDisconnectMessage(
87+
this,
88+
"DAS NETZWERK WURDE ABGESCHALTET",
89+
{
90+
error("Das Netzwerk wurde abgeschaltet.")
91+
},
92+
false
93+
)
94+
}
95+
8596
fun formatZonedDateTime(time: ZonedDateTime?) = buildText {
8697
if (time == null) {
8798
variableValue("N/A")

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -364,10 +364,6 @@ class ConnectionImpl(
364364
msg
365365
)
366366

367-
is ServerboundPlayerPersistentDataContainerUpdatePacket -> listener.handlePlayerPersistentDataContainerUpdate(
368-
msg
369-
)
370-
371367
is ServerboundConnectPlayerToServerPacket -> listener.handleConnectPlayerToServer(
372368
msg
373369
)

0 commit comments

Comments
 (0)