From 67456b1097a466ab5d6d9947e8efd02952fe8720 Mon Sep 17 00:00:00 2001 From: default Date: Thu, 18 Dec 2025 05:56:21 +0000 Subject: [PATCH] CobbleSync Json Parser Fix --- .gitignore | 1 + src/main/kotlin/co/sirblob/CobbleSync.kt | 584 +++++++++--------- .../co/sirblob/network/ServerPacketHandler.kt | 30 +- 3 files changed, 327 insertions(+), 288 deletions(-) diff --git a/.gitignore b/.gitignore index 34d600a..e3ced66 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,4 @@ replay_*.log *.jfr remappedSrc/ +.kotlin/ \ No newline at end of file diff --git a/src/main/kotlin/co/sirblob/CobbleSync.kt b/src/main/kotlin/co/sirblob/CobbleSync.kt index 587b748..eb49b1d 100644 --- a/src/main/kotlin/co/sirblob/CobbleSync.kt +++ b/src/main/kotlin/co/sirblob/CobbleSync.kt @@ -4,6 +4,7 @@ import co.sirblob.network.ServerPacketHandler import com.cobblemon.mod.common.api.text.blue import com.cobblemon.mod.common.api.text.green import com.cobblemon.mod.common.api.text.red +import com.cobblemon.mod.common.pokemon.Pokemon import com.cobblemon.mod.common.util.pc import com.google.gson.JsonObject import com.google.gson.JsonParser @@ -14,318 +15,331 @@ import net.fabricmc.api.ModInitializer import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback import net.minecraft.commands.CommandSourceStack import net.minecraft.network.chat.Component +import net.minecraft.world.item.ItemStack import org.json.JSONObject import org.slf4j.LoggerFactory object CobbleSync : ModInitializer { - private val logger = LoggerFactory.getLogger("cobblesync") - private val request = Request("https://authserver.sirblob.co") + private val logger = LoggerFactory.getLogger("cobblesync") + private val request = Request("https://authserver.sirblob.co") - override fun onInitialize() { - logger.info("CobbleSync initializing...") + override fun onInitialize() { + logger.info("CobbleSync initializing...") - // Register network packet handlers for GUI communication - ServerPacketHandler.register() - logger.info("Registered CobbleSync network handlers") + // Register network packet handlers for GUI communication + ServerPacketHandler.register() + logger.info("Registered CobbleSync network handlers") - CommandRegistrationCallback.EVENT.register( - CommandRegistrationCallback { dispatcher, _, _ -> - dispatcher.register( - LiteralArgumentBuilder.literal("cobblesync") - .then( - LiteralArgumentBuilder.literal( - "sync" - ) - .executes( - Command { - context: - CommandContext< - CommandSourceStack> - -> - val player = - context.source - .playerOrException - player.sendSystemMessage( - Component.literal( - "Syncing box..." - ) - .red() - ) + CommandRegistrationCallback.EVENT.register( + CommandRegistrationCallback { dispatcher, _, _ -> + dispatcher.register( + LiteralArgumentBuilder.literal("cobblesync") + .then( + LiteralArgumentBuilder.literal( + "sync" + ) + .executes( + Command { + context: + CommandContext< + CommandSourceStack> + -> + val player = + context.source + .playerOrException + player.sendSystemMessage( + Component.literal( + "Syncing box..." + ) + .red() + ) - val box30 = - player.pc().boxes.get(29) - var pokemonCount = 0 + val box30 = + player.pc().boxes.get(29) + var pokemonCount = 0 - box30.filterNotNull().forEach { - pokemon -> - player.sendSystemMessage( - Component.literal( - "Syncing Pokémon: ${pokemon.species.name} (Level ${pokemon.level})" - ) - .blue() - ) - pokemonCount++ - } + box30.filterNotNull().forEach { + pokemon -> + player.sendSystemMessage( + Component.literal( + "Syncing Pokémon: ${pokemon.species.name} (Level ${pokemon.level})" + ) + .blue() + ) + pokemonCount++ + } - if (pokemonCount < 1) { - player.sendSystemMessage( - Component.literal( - "[Sync Failed] Box 1 is empty!" - ) - .red() - ) - return@Command 1 - } else if (pokemonCount > 12) { - player.sendSystemMessage( - Component.literal( - "[Sync Failed] Box 1 has too many pokemon!" - ) - .red() - ) - return@Command 1 - } + if (pokemonCount < 1) { + player.sendSystemMessage( + Component.literal( + "[Sync Failed] Box 1 is empty!" + ) + .red() + ) + return@Command 1 + } else if (pokemonCount > 12) { + player.sendSystemMessage( + Component.literal( + "[Sync Failed] Box 1 has too many pokemon!" + ) + .red() + ) + return@Command 1 + } - var obj = - box30.saveToJSON( - JsonObject(), - player.registryAccess() - ) + var obj = + box30.saveToJSON( + JsonObject(), + player.registryAccess() + ) - val payload = - JSONObject() - .put( - "pokemon", - obj.toString() - ) - .put( - "count", - pokemonCount - ) + // Remove held items from the JSON to prevent duping/transferring items + obj.entrySet().forEach { entry -> + if (entry.value.isJsonObject) { + entry.value.asJsonObject.remove("HeldItem") + } + } - logger.info( - "/api/cobblesync/" + - player.uuid - .toString() - ) + val payload = + JSONObject() + .put( + "pokemon", + obj.toString() + ) + .put( + "count", + pokemonCount + ) - try { - var response = - request.POST( - "/api/cobblesync/" + - player.uuid - .toString(), - payload - ) + logger.info( + "/api/cobblesync/" + + player.uuid + .toString() + ) - logger.info(response.toString()) + try { + var response = + request.POST( + "/api/cobblesync/" + + player.uuid + .toString(), + payload + ) - player.sendSystemMessage( - Component.literal( - "Box 30 synced successfully!" - ) - .green() - ) - } catch (e: HTTPException) { - logger.error( - "HTTP Exception: ${e.message}" - ) - player.sendSystemMessage( - Component.literal( - "Error syncing box 30!" - ) - .red() - ) - return@Command 1 - } catch (e: Exception) { - logger.error( - "Exception: ${e.message}" - ) - player.sendSystemMessage( - Component.literal( - "An unexpected error occurred!" - ) - .red() - ) - return@Command 1 - } + logger.info(response.toString()) - 1 - } - ) - ) - .then( - LiteralArgumentBuilder.literal( - "load" - ) - .executes( - Command { - context: - CommandContext< - CommandSourceStack> - -> - val player = - context.source - .playerOrException + player.sendSystemMessage( + Component.literal( + "Box 30 synced successfully!" + ) + .green() + ) + } catch (e: HTTPException) { + logger.error( + "HTTP Exception: ${e.message}" + ) + player.sendSystemMessage( + Component.literal( + "Error syncing box 30!" + ) + .red() + ) + return@Command 1 + } catch (e: Exception) { + logger.error( + "Exception: ${e.message}" + ) + player.sendSystemMessage( + Component.literal( + "An unexpected error occurred!" + ) + .red() + ) + return@Command 1 + } - val pc = player.pc() - player.sendSystemMessage( - Component.literal( - "Loading Pokémon..." - ) - .green() - ) + 1 + } + ) + ) + .then( + LiteralArgumentBuilder.literal( + "load" + ) + .executes( + Command { + context: + CommandContext< + CommandSourceStack> + -> + val player = + context.source + .playerOrException - try { - var response = - request.GET( - "/api/cobblesync/" + - player.uuid - .toString() - ) - logger.info(response.toString()) + val pc = player.pc() + player.sendSystemMessage( + Component.literal( + "Loading Pokémon..." + ) + .green() + ) - if (response.getInt("status") != - 200 - ) { - player.sendSystemMessage( - Component.literal( - "No saved Pokémon found!" - ) - .red() - ) - return@Command 1 - } + try { + var response = + request.GET( + "/api/cobblesync/" + + player.uuid + .toString() + ) + logger.info(response.toString()) - var obj = - JsonParser.parseString( - response.getString( - "pokemon" - ) - ) - .asJsonObject + if (response.getInt("status") == 403) { + player.sendSystemMessage( + Component.literal( + "Player already synced/loaded" + ) + .red() + ) + return@Command 1 + } - // Use a - // temporary - // box to - // parse the - // JSON - val tempBox = - pc.boxes[0] - .loadFromJSON( - obj, - player.registryAccess() - ) - val pokemonToLoad = - tempBox.pc - .filterNotNull() - .toMutableList() + if (response.getInt("status") != + 200 + ) { + player.sendSystemMessage( + Component.literal( + "No saved Pokémon found!" + ) + .red() + ) + return@Command 1 + } - if (pokemonToLoad.isEmpty()) { - player.sendSystemMessage( - Component.literal( - "No Pokémon to load!" - ) - .red() - ) - return@Command 1 - } + var obj = + JsonParser.parseString( + response.getString( + "pokemon" + ) + ) + .asJsonObject - // Count - // available - // empty - // slots - var emptySlots = 0 - for (box in pc.boxes) { - for (slot in 0 until 30) { - if (box[slot] == null) { - emptySlots++ - } - } - } + val pokemonToLoad = mutableListOf() + obj.entrySet().forEach { entry -> + if (entry.key.startsWith("Slot")) { + val pokemonJson = entry.value.asJsonObject + val pokemon = Pokemon.loadFromJSON(player.registryAccess()!!, pokemonJson) + if (pokemon != null) { + pokemonToLoad.add(pokemon) + } + } + } - if (emptySlots < - pokemonToLoad - .size - ) { - player.sendSystemMessage( - Component.literal( - "Not enough empty slots! Need ${pokemonToLoad.size}, have $emptySlots" - ) - .red() - ) - return@Command 1 - } + if (pokemonToLoad.isEmpty()) { + player.sendSystemMessage( + Component.literal( + "No Pokémon to load!" + ) + .red() + ) + return@Command 1 + } - // Add - // Pokemon - // to empty - // slots - // across - // all boxes - var loadedCount = 0 - for (pokemon in pokemonToLoad) { - var placed = false - for (box in pc.boxes) { - if (placed) break - for (slot in - 0 until 30) { - if (box[slot] == - null - ) { - box[slot] = - pokemon - player.sendSystemMessage( - Component - .literal( - "Received Pokémon: ${pokemon.species.name} (Level ${pokemon.level})" - ) - .blue() - ) - loadedCount++ - placed = true - break - } - } - } - } + // Count + // available + // empty + // slots + var emptySlots = 0 + for (box in pc.boxes) { + for (slot in 0 until 30) { + if (box[slot] == null) { + emptySlots++ + } + } + } - player.sendSystemMessage( - Component.literal( - "Successfully loaded $loadedCount Pokémon to empty slots!" - ) - .green() - ) - } catch (e: HTTPException) { - logger.error( - "HTTP Exception: ${e.message}" - ) - player.sendSystemMessage( - Component.literal( - "Error loading Pokémon!" - ) - .red() - ) - return@Command 1 - } catch (e: Exception) { - logger.error( - "Exception: ${e.message}" - ) - player.sendSystemMessage( - Component.literal( - "An unexpected error occurred!" - ) - .red() - ) - return@Command 1 - } + if (emptySlots < + pokemonToLoad + .size + ) { + player.sendSystemMessage( + Component.literal( + "Not enough empty slots! Need ${pokemonToLoad.size}, have $emptySlots" + ) + .red() + ) + return@Command 1 + } - 1 - } - ) - ) - ) - } - ) - } + // Add + // Pokemon + // to empty + // slots + // across + // all boxes + var loadedCount = 0 + for (pokemon in pokemonToLoad) { + var placed = false + for (box in pc.boxes) { + if (placed) break + for (slot in + 0 until 30) { + if (box[slot] == + null + ) { + box[slot] = + pokemon + player.sendSystemMessage( + Component + .literal( + "Received Pokémon: ${pokemon.species.name} (Level ${pokemon.level})" + ) + .blue() + ) + loadedCount++ + placed = true + break + } + } + } + } + + player.sendSystemMessage( + Component.literal( + "Successfully loaded $loadedCount Pokémon to empty slots!" + ) + .green() + ) + } catch (e: HTTPException) { + logger.error( + "HTTP Exception: ${e.message}" + ) + player.sendSystemMessage( + Component.literal( + "Error loading Pokémon!" + ) + .red() + ) + return@Command 1 + } catch (e: Exception) { + logger.error( + "Exception: ${e.message}" + ) + player.sendSystemMessage( + Component.literal( + "An unexpected error occurred!" + ) + .red() + ) + return@Command 1 + } + + 1 + } + ) + ) + ) + } + ) + } } diff --git a/src/main/kotlin/co/sirblob/network/ServerPacketHandler.kt b/src/main/kotlin/co/sirblob/network/ServerPacketHandler.kt index 719ac95..f948ec6 100644 --- a/src/main/kotlin/co/sirblob/network/ServerPacketHandler.kt +++ b/src/main/kotlin/co/sirblob/network/ServerPacketHandler.kt @@ -2,12 +2,17 @@ package co.sirblob.network import co.sirblob.HTTPException import co.sirblob.Request +import com.cobblemon.mod.common.api.text.red +import com.cobblemon.mod.common.pokemon.Pokemon import com.cobblemon.mod.common.util.pc import com.google.gson.JsonObject import com.google.gson.JsonParser import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking import net.minecraft.server.level.ServerPlayer +import net.minecraft.world.item.ItemStack +import net.minecraft.network.chat.Component +import com.cobblemon.mod.common.api.text.red import org.json.JSONObject import org.slf4j.LoggerFactory @@ -70,6 +75,13 @@ object ServerPacketHandler { } val obj = box30.saveToJSON(JsonObject(), player.registryAccess()) + + // Remove held items from the JSON to prevent duping/transferring items + obj.entrySet().forEach { entry -> + if (entry.value.isJsonObject) { + entry.value.asJsonObject.remove("HeldItem") + } + } val payload = JSONObject().put("pokemon", obj.toString()).put("count", pokemonCount) @@ -96,6 +108,11 @@ object ServerPacketHandler { val response = request.GET("/api/cobblesync/${player.uuid}") logger.info(response.toString()) + if (response.getInt("status") == 403) { + sendResponse(player, false, "Player already synced/loaded") + return + } + if (response.getInt("status") != 200) { sendResponse(player, false, "No saved Pokémon found!") return @@ -103,9 +120,16 @@ object ServerPacketHandler { val obj = JsonParser.parseString(response.getString("pokemon")).asJsonObject - // Use a temporary box to parse the JSON data - val tempBox = pc.boxes[0].loadFromJSON(obj, player.registryAccess()) - val pokemonToLoad = tempBox.pc.filterNotNull().toMutableList() + val pokemonToLoad = mutableListOf() + obj.entrySet().forEach { entry -> + if (entry.key.startsWith("Slot")) { + val pokemonJson = entry.value.asJsonObject + val pokemon = Pokemon.loadFromJSON(player.registryAccess()!!, pokemonJson) + if (pokemon != null) { + pokemonToLoad.add(pokemon) + } + } + } if (pokemonToLoad.isEmpty()) { sendResponse(player, false, "No Pokémon to load!")