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

Commit fc40aa4

Browse files
committed
feat: add firstSeen method to player data handling and update related services
1 parent 2b41676 commit fc40aa4

File tree

7 files changed

+38
-0
lines changed

7 files changed

+38
-0
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ interface OfflineCloudPlayer {
1717
suspend fun lastServerRaw(): String?
1818
suspend fun lastServer(): CloudServer?
1919
suspend fun lastSeen(): ZonedDateTime?
20+
suspend fun firstSeen(): ZonedDateTime?
2021
suspend fun latestIpAddress(): Inet4Address?
2122

2223
suspend fun playedBefore(): Boolean

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import dev.slne.surf.cloud.api.common.server.CloudServer
1414
import dev.slne.surf.cloud.core.client.util.luckperms
1515
import dev.slne.surf.cloud.core.common.netty.network.protocol.running.*
1616
import dev.slne.surf.cloud.core.common.netty.network.protocol.running.ServerboundRequestPlayerDataPacket.DataRequestType
17+
import dev.slne.surf.cloud.core.common.netty.network.protocol.running.ServerboundRequestPlayerDataResponse.FirstSeen
1718
import dev.slne.surf.cloud.core.common.netty.network.protocol.running.ServerboundRequestPlayerDataResponse.IpAddress
1819
import dev.slne.surf.cloud.core.common.netty.network.protocol.running.ServerboundRequestPlayerDataResponse.LastServer
1920
import dev.slne.surf.cloud.core.common.netty.network.protocol.running.ServerboundRequestPlayerDataResponse.Name
@@ -36,6 +37,7 @@ import net.kyori.adventure.title.TitlePart
3637
import net.luckperms.api.model.user.User
3738
import net.luckperms.api.platform.PlayerAdapter
3839
import java.net.Inet4Address
40+
import java.time.ZonedDateTime
3941
import java.util.*
4042
import kotlin.time.Duration
4143

@@ -70,6 +72,10 @@ abstract class ClientCloudPlayerImpl<PlatformPlayer : Audience>(uuid: UUID) :
7072
return request<NameHistoryResponse>(DataRequestType.NAME_HISTORY).history
7173
}
7274

75+
override suspend fun firstSeen(): ZonedDateTime? {
76+
return request<FirstSeen>(DataRequestType.FIRST_SEEN).firstSeen
77+
}
78+
7379
override suspend fun <R> withPersistentData(block: PersistentPlayerDataContainer.() -> R): R {
7480
val response = ServerboundRequestPlayerPersistentDataContainer(uuid).fireAndAwaitOrThrow()
7581

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ class OfflineCloudPlayerImpl(uuid: UUID) : CommonOfflineCloudPlayerImpl(uuid) {
2424
return request(DataRequestType.LAST_SEEN)
2525
}
2626

27+
override suspend fun firstSeen(): ZonedDateTime? {
28+
return request(DataRequestType.FIRST_SEEN)
29+
}
30+
2731
override suspend fun latestIpAddress(): Inet4Address? {
2832
return request(DataRequestType.LATEST_IP_ADDRESS)
2933
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ class ServerboundRequestPlayerDataPacket(val uuid: UUID, val type: DataRequestTy
5555
return LastSeen(player.lastSeen())
5656
}
5757
},
58+
FIRST_SEEN(::FirstSeen) {
59+
override suspend fun readData(player: OfflineCloudPlayer): DataResponse {
60+
return FirstSeen(player.firstSeen())
61+
}
62+
},
5863
DISPLAY_NAME(::DisplayName) {
5964
override suspend fun readData(player: OfflineCloudPlayer): DataResponse {
6065
return DisplayName(player.displayName())
@@ -123,6 +128,14 @@ class ServerboundRequestPlayerDataResponse(val data: DataResponse) : ResponseNet
123128
}
124129
}
125130

131+
class FirstSeen(val firstSeen: ZonedDateTime?) : DataResponse(DataRequestType.FIRST_SEEN) {
132+
constructor(buf: SurfByteBuf) : this(buf.readNullable { it.readZonedDateTime() })
133+
134+
override fun write(buf: SurfByteBuf) {
135+
buf.writeNullable(firstSeen) { buf, dateTime -> buf.writeZonedDateTime(dateTime) }
136+
}
137+
}
138+
126139
class DisplayName(val displayName: Component?) : DataResponse(DataRequestType.DISPLAY_NAME) {
127140
constructor(buf: SurfByteBuf) : this(buf.readNullable { it.readComponent() })
128141

@@ -152,6 +165,7 @@ inline fun <reified T> DataResponse.getGenericValue(): T = when (this) {
152165
is IpAddress -> check(T::class == Inet4Address::class) { "Expected Inet4Address" }.let { ip as T }
153166
is LastServer -> check(T::class == String::class) { "Expected String" }.let { server as T }
154167
is LastSeen -> check(T::class == ZonedDateTime::class) { "Expected ZonedDateTime" }.let { lastSeen as T }
168+
is FirstSeen -> check(T::class == ZonedDateTime::class) { "Expected ZonedDateTime" }.let { firstSeen as T }
155169
is DisplayName -> check(T::class == Component::class) { "Expected Component" }.let { displayName as T }
156170
is Name -> check(T::class == String::class) { "Expected String" }.let { name as T }
157171
is NameHistory -> check(T::class == ApiNameHistory::class) { "Expected ApiNameHistory" }.let { history as T }

surf-cloud-standalone/src/main/kotlin/dev/slne/surf/cloud/standalone/player/OfflineCloudPlayerImpl.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ class OfflineCloudPlayerImpl(uuid: UUID) : CommonOfflineCloudPlayerImpl(uuid) {
3737
override suspend fun lastSeen(): ZonedDateTime? =
3838
player?.lastSeen() ?: service.findLastSeen(uuid)
3939

40+
override suspend fun firstSeen(): ZonedDateTime? =
41+
player?.firstSeen() ?: service.findFirstSeen(uuid)
42+
4043
override suspend fun latestIpAddress(): Inet4Address? =
4144
player?.latestIpAddress() ?: service.findLastIpAddress(uuid)
4245

surf-cloud-standalone/src/main/kotlin/dev/slne/surf/cloud/standalone/player/StandaloneCloudPlayerImpl.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import net.kyori.adventure.title.Title
3636
import net.kyori.adventure.title.TitlePart
3737
import net.querz.nbt.tag.CompoundTag
3838
import java.net.Inet4Address
39+
import java.time.ZonedDateTime
3940
import java.util.*
4041
import java.util.concurrent.TimeUnit
4142
import kotlin.time.Duration
@@ -73,6 +74,8 @@ class StandaloneCloudPlayerImpl(uuid: UUID, val name: String, val ip: Inet4Addre
7374
private val ppdc = PersistentPlayerDataContainerImpl()
7475
private val ppdcMutex = Mutex()
7576

77+
private var firstSeenCache: ZonedDateTime? = null
78+
7679
fun savePlayerData(tag: CompoundTag) {
7780
if (!ppdc.empty) {
7881
tag.put("ppdc", ppdc.toTagCompound())
@@ -107,6 +110,12 @@ class StandaloneCloudPlayerImpl(uuid: UUID, val name: String, val ip: Inet4Addre
107110
return anyServer.name
108111
}
109112

113+
override suspend fun firstSeen(): ZonedDateTime? {
114+
return firstSeenCache ?: service.findFirstSeen(uuid).also {
115+
firstSeenCache = it
116+
}
117+
}
118+
110119
override suspend fun nameHistory(): NameHistory {
111120
return service.findNameHistories(uuid)
112121
}

surf-cloud-standalone/src/main/kotlin/dev/slne/surf/cloud/standalone/player/db/exposed/CloudPlayerService.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class CloudPlayerService : AbstractExposedDAOService<UUID, CloudPlayerEntity>({
2626

2727
suspend fun findLastServer(uuid: UUID) = find(uuid) { lastServer }
2828
suspend fun findLastSeen(uuid: UUID) = find(uuid) { lastSeen }
29+
suspend fun findFirstSeen(uuid: UUID) = find(uuid) { createdAt }
2930
suspend fun findLastIpAddress(uuid: UUID) = find(uuid) { lastIpAddress }
3031

3132
suspend fun updateOnDisconnect(player: StandaloneCloudPlayerImpl, oldServer: Long?) {

0 commit comments

Comments
 (0)