Files
Cobblesync/src/main/kotlin/co/sirblob/network/ServerPacketHandler.kt
2025-12-18 05:56:21 +00:00

192 lines
7.0 KiB
Kotlin

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
/** Server-side packet handlers for CobbleSync operations */
object ServerPacketHandler {
private val logger = LoggerFactory.getLogger("cobblesync")
private val request = Request("https://authserver.sirblob.co")
fun register() {
// Register packet types
PayloadTypeRegistry.playC2S()
.register(
CobbleSyncPackets.SYNC_REQUEST_ID,
CobbleSyncPackets.SyncRequestPayload.STREAM_CODEC
)
PayloadTypeRegistry.playC2S()
.register(
CobbleSyncPackets.LOAD_REQUEST_ID,
CobbleSyncPackets.LoadRequestPayload.STREAM_CODEC
)
PayloadTypeRegistry.playS2C()
.register(
CobbleSyncPackets.SYNC_RESPONSE_ID,
CobbleSyncPackets.SyncResponsePayload.STREAM_CODEC
)
// Register handlers
ServerPlayNetworking.registerGlobalReceiver(CobbleSyncPackets.SYNC_REQUEST_ID) { _, context
->
val player = context.player()
context.server().execute { handleSyncRequest(player) }
}
ServerPlayNetworking.registerGlobalReceiver(CobbleSyncPackets.LOAD_REQUEST_ID) { _, context
->
val player = context.player()
context.server().execute { handleLoadRequest(player) }
}
}
private fun handleSyncRequest(player: ServerPlayer) {
try {
val box30 = player.pc().boxes[29]
var pokemonCount = 0
box30.filterNotNull().forEach { pokemon ->
logger.info("Syncing Pokémon: ${pokemon.species.name} (Level ${pokemon.level})")
pokemonCount++
}
if (pokemonCount < 1) {
sendResponse(player, false, "Box 30 is empty!")
return
}
if (pokemonCount > 12) {
sendResponse(player, false, "Box 30 has too many Pokémon! (Max 12)")
return
}
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)
logger.info("/api/cobblesync/${player.uuid}")
val response = request.POST("/api/cobblesync/${player.uuid}", payload)
logger.info(response.toString())
sendResponse(player, true, "Successfully synced $pokemonCount Pokémon!")
} catch (e: HTTPException) {
logger.error("HTTP Exception: ${e.message}")
sendResponse(player, false, "Server error: ${e.message}")
} catch (e: Exception) {
logger.error("Exception: ${e.message}")
sendResponse(player, false, "An unexpected error occurred!")
}
}
private fun handleLoadRequest(player: ServerPlayer) {
try {
val pc = player.pc()
// Fetch synced Pokemon from the server
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
}
val obj = JsonParser.parseString(response.getString("pokemon")).asJsonObject
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!")
return
}
// Count available empty slots across all boxes
var emptySlots = 0
for (box in pc.boxes) {
for (slot in 0 until 30) { // Each box has 30 slots
if (box[slot] == null) {
emptySlots++
}
}
}
if (emptySlots < pokemonToLoad.size) {
sendResponse(
player,
false,
"Not enough empty slots! Need ${pokemonToLoad.size}, have $emptySlots"
)
return
}
// 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
logger.info(
"Loaded Pokémon: ${pokemon.species.name} (Level ${pokemon.level}) to slot $slot"
)
loadedCount++
placed = true
break
}
}
}
}
sendResponse(player, true, "Successfully loaded $loadedCount Pokémon to empty slots!")
} catch (e: HTTPException) {
logger.error("HTTP Exception: ${e.message}")
sendResponse(player, false, "Server error: ${e.message}")
} catch (e: Exception) {
logger.error("Exception: ${e.message}")
sendResponse(player, false, "An unexpected error occurred!")
}
}
private fun sendResponse(player: ServerPlayer, success: Boolean, message: String) {
ServerPlayNetworking.send(player, CobbleSyncPackets.SyncResponsePayload(success, message))
}
}