A Minecraft Fabric mod that connects the game with ATProtocol ⛏️
at main 250 lines 7.6 kB view raw
1package com.jollywhoppers.atproto.examples 2 3import com.jollywhoppers.atproto.AtProtoSessionManager 4import kotlinx.serialization.Serializable 5import kotlinx.serialization.encodeToString 6import kotlinx.serialization.json.Json 7import kotlinx.serialization.json.JsonElement 8import kotlinx.serialization.json.encodeToJsonElement 9import java.util.* 10 11/** 12 * Example showing how to create records in a player's AT Protocol repository. 13 * This demonstrates the foundation for syncing Minecraft data to AT Protocol. 14 */ 15class RecordCreationExample( 16 private val sessionManager: AtProtoSessionManager 17) { 18 private val json = Json { prettyPrint = false } 19 20 /** 21 * Example: Create a player stats record 22 */ 23 suspend fun createPlayerStatsRecord( 24 playerUuid: UUID, 25 statistics: List<Statistic>, 26 playtimeMinutes: Int, 27 level: Int 28 ): Result<String> = runCatching { 29 // Get the player's session (will auto-refresh if needed) 30 val session = sessionManager.getSession(playerUuid).getOrThrow() 31 32 // Build the record according to our lexicon 33 val record = PlayerStatsRecord( 34 `$type` = "com.jollywhoppers.minecraft.player.stats", 35 player = PlayerReference( 36 uuid = playerUuid.toString(), 37 username = "ExamplePlayer" // Would come from Minecraft player object 38 ), 39 server = ServerReference( 40 serverId = "example-server-id", 41 serverName = "Example Server" 42 ), 43 statistics = statistics, 44 playtimeMinutes = playtimeMinutes, 45 level = level, 46 gamemode = "survival", 47 syncedAt = java.time.Instant.now().toString() 48 ) 49 50 // Create the record via XRPC 51 val requestBody = CreateRecordRequest( 52 repo = session.did, 53 collection = "com.jollywhoppers.minecraft.player.stats", 54 record = json.encodeToJsonElement(record) 55 ) 56 57 val response = sessionManager.makeAuthenticatedRequest( 58 uuid = playerUuid, 59 method = "POST", 60 endpoint = "com.atproto.repo.createRecord", 61 body = json.encodeToString(requestBody) 62 ).getOrThrow() 63 64 response 65 } 66 67 /** 68 * Example: Create a player profile record 69 */ 70 suspend fun createPlayerProfileRecord( 71 playerUuid: UUID, 72 displayName: String?, 73 bio: String?, 74 publicStats: Boolean = true 75 ): Result<String> = runCatching { 76 val session = sessionManager.getSession(playerUuid).getOrThrow() 77 78 val record = PlayerProfileRecord( 79 `$type` = "com.jollywhoppers.minecraft.player.profile", 80 player = PlayerReference( 81 uuid = playerUuid.toString(), 82 username = "ExamplePlayer" 83 ), 84 displayName = displayName, 85 bio = bio, 86 createdAt = java.time.Instant.now().toString(), 87 publicStats = publicStats, 88 publicSessions = true 89 ) 90 91 // For profile, we use rkey "self" since there's only one per account 92 val requestBody = CreateRecordRequestWithRkey( 93 repo = session.did, 94 collection = "com.jollywhoppers.minecraft.player.profile", 95 rkey = "self", 96 record = json.encodeToJsonElement(record) 97 ) 98 99 sessionManager.makeAuthenticatedRequest( 100 uuid = playerUuid, 101 method = "POST", 102 endpoint = "com.atproto.repo.putRecord", 103 body = json.encodeToString(requestBody) 104 ).getOrThrow() 105 } 106 107 /** 108 * Example: Create an achievement record 109 */ 110 suspend fun createAchievementRecord( 111 playerUuid: UUID, 112 achievementId: String, 113 achievementName: String, 114 achievementDescription: String, 115 category: String, 116 isChallenge: Boolean = false 117 ): Result<String> = runCatching { 118 val session = sessionManager.getSession(playerUuid).getOrThrow() 119 120 val record = AchievementRecord( 121 `$type` = "com.jollywhoppers.minecraft.achievement", 122 player = PlayerReference( 123 uuid = playerUuid.toString(), 124 username = "ExamplePlayer" 125 ), 126 server = ServerReference( 127 serverId = "example-server-id", 128 serverName = "Example Server" 129 ), 130 achievementId = achievementId, 131 achievementName = achievementName, 132 achievementDescription = achievementDescription, 133 achievedAt = java.time.Instant.now().toString(), 134 category = category, 135 isChallenge = isChallenge 136 ) 137 138 val requestBody = CreateRecordRequest( 139 repo = session.did, 140 collection = "com.jollywhoppers.minecraft.achievement", 141 record = json.encodeToJsonElement(record) 142 ) 143 144 sessionManager.makeAuthenticatedRequest( 145 uuid = playerUuid, 146 method = "POST", 147 endpoint = "com.atproto.repo.createRecord", 148 body = json.encodeToString(requestBody) 149 ).getOrThrow() 150 } 151 152 // Data classes matching our lexicon schemas 153 154 @Serializable 155 data class PlayerReference( 156 val uuid: String, 157 val username: String 158 ) 159 160 @Serializable 161 data class ServerReference( 162 val serverId: String, 163 val serverName: String 164 ) 165 166 @Serializable 167 data class Statistic( 168 val key: String, 169 val value: Int, 170 val category: String? = null 171 ) 172 173 @Serializable 174 data class PlayerStatsRecord( 175 val `$type`: String, 176 val player: PlayerReference, 177 val server: ServerReference, 178 val statistics: List<Statistic>, 179 val playtimeMinutes: Int, 180 val level: Int, 181 val gamemode: String, 182 val dimension: String? = null, 183 val syncedAt: String 184 ) 185 186 @Serializable 187 data class PlayerProfileRecord( 188 val `$type`: String, 189 val player: PlayerReference, 190 val displayName: String?, 191 val bio: String?, 192 val createdAt: String, 193 val updatedAt: String? = null, 194 val publicStats: Boolean, 195 val publicSessions: Boolean 196 ) 197 198 @Serializable 199 data class AchievementRecord( 200 val `$type`: String, 201 val player: PlayerReference, 202 val server: ServerReference, 203 val achievementId: String, 204 val achievementName: String, 205 val achievementDescription: String, 206 val achievedAt: String, 207 val category: String, 208 val isChallenge: Boolean 209 ) 210 211 @Serializable 212 data class CreateRecordRequest( 213 val repo: String, 214 val collection: String, 215 val record: JsonElement 216 ) 217 218 @Serializable 219 data class CreateRecordRequestWithRkey( 220 val repo: String, 221 val collection: String, 222 val rkey: String, 223 val record: JsonElement 224 ) 225} 226 227/** 228 * Usage example: 229 * 230 * ```kotlin 231 * val example = RecordCreationExample(sessionManager) 232 * 233 * // Create a stats snapshot 234 * val stats = listOf( 235 * Statistic("minecraft:killed.minecraft.zombie", 42, "killed"), 236 * Statistic("minecraft:mined.minecraft.diamond_ore", 15, "mined") 237 * ) 238 * 239 * example.createPlayerStatsRecord( 240 * playerUuid = player.uuid, 241 * statistics = stats, 242 * playtimeMinutes = 180, 243 * level = 25 244 * ).onSuccess { response -> 245 * logger.info("Stats synced successfully!") 246 * }.onFailure { error -> 247 * logger.error("Failed to sync stats", error) 248 * } 249 * ``` 250 */