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 *.jfr
remappedSrc/ 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.blue
import com.cobblemon.mod.common.api.text.green import com.cobblemon.mod.common.api.text.green
import com.cobblemon.mod.common.api.text.red import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.pc import com.cobblemon.mod.common.util.pc
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.google.gson.JsonParser import com.google.gson.JsonParser
@@ -14,318 +15,331 @@ import net.fabricmc.api.ModInitializer
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback
import net.minecraft.commands.CommandSourceStack import net.minecraft.commands.CommandSourceStack
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.world.item.ItemStack
import org.json.JSONObject import org.json.JSONObject
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
object CobbleSync : ModInitializer { object CobbleSync : ModInitializer {
private val logger = LoggerFactory.getLogger("cobblesync") private val logger = LoggerFactory.getLogger("cobblesync")
private val request = Request("https://authserver.sirblob.co") private val request = Request("https://authserver.sirblob.co")
override fun onInitialize() { override fun onInitialize() {
logger.info("CobbleSync initializing...") logger.info("CobbleSync initializing...")
// Register network packet handlers for GUI communication // Register network packet handlers for GUI communication
ServerPacketHandler.register() ServerPacketHandler.register()
logger.info("Registered CobbleSync network handlers") logger.info("Registered CobbleSync network handlers")
CommandRegistrationCallback.EVENT.register( CommandRegistrationCallback.EVENT.register(
CommandRegistrationCallback { dispatcher, _, _ -> CommandRegistrationCallback { dispatcher, _, _ ->
dispatcher.register( dispatcher.register(
LiteralArgumentBuilder.literal<CommandSourceStack>("cobblesync") LiteralArgumentBuilder.literal<CommandSourceStack>("cobblesync")
.then( .then(
LiteralArgumentBuilder.literal<CommandSourceStack>( LiteralArgumentBuilder.literal<CommandSourceStack>(
"sync" "sync"
) )
.executes( .executes(
Command<CommandSourceStack> { Command<CommandSourceStack> {
context: context:
CommandContext< CommandContext<
CommandSourceStack> CommandSourceStack>
-> ->
val player = val player =
context.source context.source
.playerOrException .playerOrException
player.sendSystemMessage( player.sendSystemMessage(
Component.literal( Component.literal(
"Syncing box..." "Syncing box..."
) )
.red() .red()
) )
val box30 = val box30 =
player.pc().boxes.get(29) player.pc().boxes.get(29)
var pokemonCount = 0 var pokemonCount = 0
box30.filterNotNull().forEach { box30.filterNotNull().forEach {
pokemon -> pokemon ->
player.sendSystemMessage( player.sendSystemMessage(
Component.literal( Component.literal(
"Syncing Pokémon: ${pokemon.species.name} (Level ${pokemon.level})" "Syncing Pokémon: ${pokemon.species.name} (Level ${pokemon.level})"
) )
.blue() .blue()
) )
pokemonCount++ pokemonCount++
} }
if (pokemonCount < 1) { if (pokemonCount < 1) {
player.sendSystemMessage( player.sendSystemMessage(
Component.literal( Component.literal(
"[Sync Failed] Box 1 is empty!" "[Sync Failed] Box 1 is empty!"
) )
.red() .red()
) )
return@Command 1 return@Command 1
} else if (pokemonCount > 12) { } else if (pokemonCount > 12) {
player.sendSystemMessage( player.sendSystemMessage(
Component.literal( Component.literal(
"[Sync Failed] Box 1 has too many pokemon!" "[Sync Failed] Box 1 has too many pokemon!"
) )
.red() .red()
) )
return@Command 1 return@Command 1
} }
var obj = var obj =
box30.saveToJSON( box30.saveToJSON(
JsonObject(), JsonObject(),
player.registryAccess() player.registryAccess()
) )
val payload = // Remove held items from the JSON to prevent duping/transferring items
JSONObject() obj.entrySet().forEach { entry ->
.put( if (entry.value.isJsonObject) {
"pokemon", entry.value.asJsonObject.remove("HeldItem")
obj.toString() }
) }
.put(
"count",
pokemonCount
)
logger.info( val payload =
"/api/cobblesync/" + JSONObject()
player.uuid .put(
.toString() "pokemon",
) obj.toString()
)
.put(
"count",
pokemonCount
)
try { logger.info(
var response = "/api/cobblesync/" +
request.POST( player.uuid
"/api/cobblesync/" + .toString()
player.uuid )
.toString(),
payload
)
logger.info(response.toString()) try {
var response =
request.POST(
"/api/cobblesync/" +
player.uuid
.toString(),
payload
)
player.sendSystemMessage( logger.info(response.toString())
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
}
1 player.sendSystemMessage(
} Component.literal(
) "Box 30 synced successfully!"
) )
.then( .green()
LiteralArgumentBuilder.literal<CommandSourceStack>( )
"load" } catch (e: HTTPException) {
) logger.error(
.executes( "HTTP Exception: ${e.message}"
Command<CommandSourceStack> { )
context: player.sendSystemMessage(
CommandContext< Component.literal(
CommandSourceStack> "Error syncing box 30!"
-> )
val player = .red()
context.source )
.playerOrException 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() 1
player.sendSystemMessage( }
Component.literal( )
"Loading Pokémon..." )
) .then(
.green() LiteralArgumentBuilder.literal<CommandSourceStack>(
) "load"
)
.executes(
Command<CommandSourceStack> {
context:
CommandContext<
CommandSourceStack>
->
val player =
context.source
.playerOrException
try { val pc = player.pc()
var response = player.sendSystemMessage(
request.GET( Component.literal(
"/api/cobblesync/" + "Loading Pokémon..."
player.uuid )
.toString() .green()
) )
logger.info(response.toString())
if (response.getInt("status") != try {
200 var response =
) { request.GET(
player.sendSystemMessage( "/api/cobblesync/" +
Component.literal( player.uuid
"No saved Pokémon found!" .toString()
) )
.red() logger.info(response.toString())
)
return@Command 1
}
var obj = if (response.getInt("status") == 403) {
JsonParser.parseString( player.sendSystemMessage(
response.getString( Component.literal(
"pokemon" "Player already synced/loaded"
) )
) .red()
.asJsonObject )
return@Command 1
}
// Use a if (response.getInt("status") !=
// temporary 200
// box to ) {
// parse the player.sendSystemMessage(
// JSON Component.literal(
val tempBox = "No saved Pokémon found!"
pc.boxes[0] )
.loadFromJSON( .red()
obj, )
player.registryAccess() return@Command 1
) }
val pokemonToLoad =
tempBox.pc
.filterNotNull()
.toMutableList()
if (pokemonToLoad.isEmpty()) { var obj =
player.sendSystemMessage( JsonParser.parseString(
Component.literal( response.getString(
"No Pokémon to load!" "pokemon"
) )
.red() )
) .asJsonObject
return@Command 1
}
// Count val pokemonToLoad = mutableListOf<Pokemon>()
// available obj.entrySet().forEach { entry ->
// empty if (entry.key.startsWith("Slot")) {
// slots val pokemonJson = entry.value.asJsonObject
var emptySlots = 0 val pokemon = Pokemon.loadFromJSON(player.registryAccess()!!, pokemonJson)
for (box in pc.boxes) { if (pokemon != null) {
for (slot in 0 until 30) { pokemonToLoad.add(pokemon)
if (box[slot] == null) { }
emptySlots++ }
} }
}
}
if (emptySlots < if (pokemonToLoad.isEmpty()) {
pokemonToLoad player.sendSystemMessage(
.size Component.literal(
) { "No Pokémon to load!"
player.sendSystemMessage( )
Component.literal( .red()
"Not enough empty slots! Need ${pokemonToLoad.size}, have $emptySlots" )
) return@Command 1
.red() }
)
return@Command 1
}
// Add // Count
// Pokemon // available
// to empty // empty
// slots // slots
// across var emptySlots = 0
// all boxes for (box in pc.boxes) {
var loadedCount = 0 for (slot in 0 until 30) {
for (pokemon in pokemonToLoad) { if (box[slot] == null) {
var placed = false emptySlots++
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( if (emptySlots <
Component.literal( pokemonToLoad
"Successfully loaded $loadedCount Pokémon to empty slots!" .size
) ) {
.green() player.sendSystemMessage(
) Component.literal(
} catch (e: HTTPException) { "Not enough empty slots! Need ${pokemonToLoad.size}, have $emptySlots"
logger.error( )
"HTTP Exception: ${e.message}" .red()
) )
player.sendSystemMessage( return@Command 1
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 // 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.HTTPException
import co.sirblob.Request 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.cobblemon.mod.common.util.pc
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.google.gson.JsonParser import com.google.gson.JsonParser
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking
import net.minecraft.server.level.ServerPlayer 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.json.JSONObject
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
@@ -71,6 +76,13 @@ object ServerPacketHandler {
val obj = box30.saveToJSON(JsonObject(), player.registryAccess()) 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) val payload = JSONObject().put("pokemon", obj.toString()).put("count", pokemonCount)
logger.info("/api/cobblesync/${player.uuid}") logger.info("/api/cobblesync/${player.uuid}")
@@ -96,6 +108,11 @@ object ServerPacketHandler {
val response = request.GET("/api/cobblesync/${player.uuid}") val response = request.GET("/api/cobblesync/${player.uuid}")
logger.info(response.toString()) logger.info(response.toString())
if (response.getInt("status") == 403) {
sendResponse(player, false, "Player already synced/loaded")
return
}
if (response.getInt("status") != 200) { if (response.getInt("status") != 200) {
sendResponse(player, false, "No saved Pokémon found!") sendResponse(player, false, "No saved Pokémon found!")
return return
@@ -103,9 +120,16 @@ object ServerPacketHandler {
val obj = JsonParser.parseString(response.getString("pokemon")).asJsonObject val obj = JsonParser.parseString(response.getString("pokemon")).asJsonObject
// Use a temporary box to parse the JSON data val pokemonToLoad = mutableListOf<Pokemon>()
val tempBox = pc.boxes[0].loadFromJSON(obj, player.registryAccess()) obj.entrySet().forEach { entry ->
val pokemonToLoad = tempBox.pc.filterNotNull().toMutableList() 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()) { if (pokemonToLoad.isEmpty()) {
sendResponse(player, false, "No Pokémon to load!") sendResponse(player, false, "No Pokémon to load!")