CobbleSync Json Parser Fix

This commit is contained in:
2025-12-18 05:56:21 +00:00
parent 88c155d239
commit 67456b1097
3 changed files with 327 additions and 288 deletions

1
.gitignore vendored
View File

@@ -40,3 +40,4 @@ replay_*.log
*.jfr
remappedSrc/
.kotlin/

View File

@@ -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<CommandSourceStack>("cobblesync")
.then(
LiteralArgumentBuilder.literal<CommandSourceStack>(
"sync"
)
.executes(
Command<CommandSourceStack> {
context:
CommandContext<
CommandSourceStack>
->
val player =
context.source
.playerOrException
player.sendSystemMessage(
Component.literal(
"Syncing box..."
)
.red()
)
CommandRegistrationCallback.EVENT.register(
CommandRegistrationCallback { dispatcher, _, _ ->
dispatcher.register(
LiteralArgumentBuilder.literal<CommandSourceStack>("cobblesync")
.then(
LiteralArgumentBuilder.literal<CommandSourceStack>(
"sync"
)
.executes(
Command<CommandSourceStack> {
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<CommandSourceStack>(
"load"
)
.executes(
Command<CommandSourceStack> {
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<CommandSourceStack>(
"load"
)
.executes(
Command<CommandSourceStack> {
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<Pokemon>()
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
}
)
)
)
}
)
}
}

View File

@@ -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<Pokemon>()
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!")