From e373b8c226f8b31a5b7ed1a01150b4e6c14bc5df Mon Sep 17 00:00:00 2001 From: mlus <1319237806@qq.com> Date: Mon, 15 Dec 2025 22:47:47 +0800 Subject: [PATCH] add cobblemon support(in test) --- build.gradle | 13 +++ .../vip/fubuki/playersync/PlayerSync.java | 14 +++ .../MixinFileBackedPokemonStoreFactory.java | 62 +++++++++++++ .../cobblemon/MixinNbtBackedPlayerData.java | 92 +++++++++++++++++++ .../mixin/cobblemon/MixinPCStore.java | 58 ++++++++++++ .../mixin/cobblemon/MixinPartyStore.java | 58 ++++++++++++ ...leBasedPlayerDataStoreBackendAccessor.java | 12 +++ .../accessor/NbtBackedPlayerDataAccessor.java | 14 +++ src/main/resources/playersync.mixins.json | 20 ++++ .../templates/META-INF/neoforge.mods.toml | 4 +- 10 files changed, 345 insertions(+), 2 deletions(-) create mode 100644 src/main/java/vip/fubuki/playersync/mixin/cobblemon/MixinFileBackedPokemonStoreFactory.java create mode 100644 src/main/java/vip/fubuki/playersync/mixin/cobblemon/MixinNbtBackedPlayerData.java create mode 100644 src/main/java/vip/fubuki/playersync/mixin/cobblemon/MixinPCStore.java create mode 100644 src/main/java/vip/fubuki/playersync/mixin/cobblemon/MixinPartyStore.java create mode 100644 src/main/java/vip/fubuki/playersync/mixin/cobblemon/accessor/FileBasedPlayerDataStoreBackendAccessor.java create mode 100644 src/main/java/vip/fubuki/playersync/mixin/cobblemon/accessor/NbtBackedPlayerDataAccessor.java create mode 100644 src/main/resources/playersync.mixins.json diff --git a/build.gradle b/build.gradle index 8df8b4a..04b374b 100644 --- a/build.gradle +++ b/build.gradle @@ -4,6 +4,11 @@ plugins { id 'maven-publish' // id 'net.neoforged.gradle.userdev' version '7.0.170' id 'net.neoforged.moddev' + + // Adds the Kotlin Gradle plugin + id 'org.jetbrains.kotlin.jvm' version '2.2.20' + // OPTIONAL Kotlin Serialization plugin + id 'org.jetbrains.kotlin.plugin.serialization' version '2.2.20' } tasks.named('wrapper', Wrapper).configure { @@ -41,6 +46,11 @@ repositories { includeGroup "curse.maven" } } + + maven { + name = 'Kotlin for Forge' + url = 'https://thedarkcolour.github.io/KotlinForForge/' + } } base { @@ -108,6 +118,9 @@ dependencies { compileOnly "curse.maven:sophisticated-backpacks-422301:7169832" compileOnly "curse.maven:sophisticated-core-618298:7168230" + compileOnly "thedarkcolour:kotlinforforge:5.10.0" + compileOnly "curse.maven:cobblemon-687131:7273151" + runtimeOnly "curse.maven:curios-309927:6529130" runtimeOnly "curse.maven:sophisticated-backpacks-422301:7169832" runtimeOnly "curse.maven:sophisticated-core-618298:7168230" diff --git a/src/main/java/vip/fubuki/playersync/PlayerSync.java b/src/main/java/vip/fubuki/playersync/PlayerSync.java index f9d5efc..f3cab1b 100644 --- a/src/main/java/vip/fubuki/playersync/PlayerSync.java +++ b/src/main/java/vip/fubuki/playersync/PlayerSync.java @@ -133,6 +133,20 @@ public class PlayerSync { ); } + // Create Cobblemon table + if(ModList.get().isLoaded("cobblemon")){ + JDBCsetUp.executeUpdate( + "CREATE TABLE IF NOT EXISTS " + dbName + ".cobblemon(" + + "uuid CHAR(36) NOT NULL," + + "inv BLOB," + + "pokedex BLOB," + + "pc BLOB," + + "general BLOB," + + "PRIMARY KEY (uuid)" + + ")" + ); + } + // Create backpack_data table if (ModList.get().isLoaded("sophisticatedbackpacks")) { JDBCsetUp.executeUpdate( diff --git a/src/main/java/vip/fubuki/playersync/mixin/cobblemon/MixinFileBackedPokemonStoreFactory.java b/src/main/java/vip/fubuki/playersync/mixin/cobblemon/MixinFileBackedPokemonStoreFactory.java new file mode 100644 index 0000000..03a6d3c --- /dev/null +++ b/src/main/java/vip/fubuki/playersync/mixin/cobblemon/MixinFileBackedPokemonStoreFactory.java @@ -0,0 +1,62 @@ +package vip.fubuki.playersync.mixin.cobblemon; + +import com.cobblemon.mod.common.api.storage.PokemonStore; +import com.cobblemon.mod.common.api.storage.factory.FileBackedPokemonStoreFactory; +import com.cobblemon.mod.common.api.storage.party.PartyStore; +import com.cobblemon.mod.common.api.storage.pc.PCStore; +import kotlin.jvm.functions.Function1; +import net.minecraft.core.RegistryAccess; +import net.minecraft.nbt.CompoundTag; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import vip.fubuki.playersync.util.JDBCsetUp; + +import java.sql.ResultSet; +import java.util.UUID; + +@Mixin(FileBackedPokemonStoreFactory.class) +public class MixinFileBackedPokemonStoreFactory { + @Unique + RegistryAccess playerSync$registryAccess; + + @Inject(method = "getStore", at = @At("HEAD")) + private > void getStore$playerSync(Class storeClass, UUID uuid, RegistryAccess registryAccess, Function1 constructor, CallbackInfoReturnable cir){ + this.playerSync$registryAccess = registryAccess; + } + + @Redirect(method = "getStore", at = @At(value = "INVOKE", target = "Lcom/cobblemon/mod/common/api/storage/PokemonStore;initialize()V")) + private void getStore$playerSync(PokemonStore instance) { + + String column; + if(instance instanceof PCStore){ + column = "pc"; + } else if(instance instanceof PartyStore){ + column = "inv"; + }else { + instance.initialize(); + return; + } + + String sql = "SELECT " + column + " FROM cobblemon WHERE uuid = '" + instance.getUuid() + "'"; + + try { + JDBCsetUp.QueryResult qr = vip.fubuki.playersync.util.JDBCsetUp.executeQuery(sql); + ResultSet rs = qr.resultSet(); + if (rs.next() && rs.getString(column) != null) { + CompoundTag compoundTag = new CompoundTag(); + instance.loadFromNBT(compoundTag, playerSync$registryAccess); + } + + rs.close(); + qr.close(); + } catch (java.sql.SQLException e) { + throw new RuntimeException(e); + } + + instance.initialize(); + } +} diff --git a/src/main/java/vip/fubuki/playersync/mixin/cobblemon/MixinNbtBackedPlayerData.java b/src/main/java/vip/fubuki/playersync/mixin/cobblemon/MixinNbtBackedPlayerData.java new file mode 100644 index 0000000..1f40ec4 --- /dev/null +++ b/src/main/java/vip/fubuki/playersync/mixin/cobblemon/MixinNbtBackedPlayerData.java @@ -0,0 +1,92 @@ +package vip.fubuki.playersync.mixin.cobblemon; + +import com.cobblemon.mod.common.Cobblemon; +import com.cobblemon.mod.common.api.pokedex.PokedexManager; +import com.cobblemon.mod.common.api.storage.player.InstancedPlayerData; +import com.cobblemon.mod.common.api.storage.player.adapter.NbtBackedPlayerData; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.nbt.Tag; +import net.minecraft.resources.ResourceLocation; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import vip.fubuki.playersync.mixin.cobblemon.accessor.FileBasedPlayerDataStoreBackendAccessor; +import vip.fubuki.playersync.mixin.cobblemon.accessor.NbtBackedPlayerDataAccessor; +import vip.fubuki.playersync.util.JDBCsetUp; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +@Mixin(NbtBackedPlayerData.class) +public class MixinNbtBackedPlayerData { + + @Inject(method = "save", at = @org.spongepowered.asm.mixin.injection.At("HEAD")) + private void save$playerSync(InstancedPlayerData playerData, CallbackInfo ci) { + if(playerData instanceof PokedexManager){ + Codec codec = ((NbtBackedPlayerDataAccessor)this).getCodec(); + DataResult encodeResult = codec.encodeStart( + NbtOps.INSTANCE, + playerData + ); + + CompoundTag nbt = (CompoundTag) encodeResult.result().orElseThrow(); + + String serializedData = nbt.toString(); + String sql = "INSERT INTO cobblemon (uuid, pokedex) VALUES ('" + playerData.getUuid() + "', '" + serializedData + "') " + + "ON DUPLICATE KEY UPDATE pokedex = '" + serializedData + "'"; + try { + JDBCsetUp.executeUpdate(sql); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + } + + @Inject(method = "load", at = @org.spongepowered.asm.mixin.injection.At("HEAD"), cancellable = true) + private void load$playerSync(UUID uuid, CallbackInfoReturnable cir){ + if(!((FileBasedPlayerDataStoreBackendAccessor) this).getType().getId().equals(ResourceLocation.fromNamespaceAndPath("cobblemon", "pokedex"))){ + return; + } + + String sql = "SELECT pokedex FROM cobblemon WHERE uuid = '" + uuid + "'"; + CompoundTag loadedNbt; + try { + JDBCsetUp.QueryResult qr = JDBCsetUp.executeQuery(sql); + ResultSet rs = qr.resultSet(); + if (rs.next()) { + String serializedData = rs.getString("pokedex"); + + if(serializedData == null){ + rs.close(); + qr.close(); + return; + } + + loadedNbt = NbtUtils.snbtToStructure(serializedData); + + if(!loadedNbt.isEmpty()){ + Codec codec = ((NbtBackedPlayerDataAccessor)this).getCodec(); + DataResult decodeResult = codec.parse( + NbtOps.INSTANCE, + loadedNbt + ); + InstancedPlayerData playerData = decodeResult.result().orElseThrow(); + cir.setReturnValue(playerData); + } + } + + rs.close(); + qr.close(); + } catch (SQLException | CommandSyntaxException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/java/vip/fubuki/playersync/mixin/cobblemon/MixinPCStore.java b/src/main/java/vip/fubuki/playersync/mixin/cobblemon/MixinPCStore.java new file mode 100644 index 0000000..41ad349 --- /dev/null +++ b/src/main/java/vip/fubuki/playersync/mixin/cobblemon/MixinPCStore.java @@ -0,0 +1,58 @@ +package vip.fubuki.playersync.mixin.cobblemon; + +import com.cobblemon.mod.common.api.storage.pc.PCStore; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.minecraft.core.RegistryAccess; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import vip.fubuki.playersync.util.JDBCsetUp; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +@Mixin(PCStore.class) +public class MixinPCStore { + @Final + @Shadow + private UUID uuid; + + @Inject(method = "saveToNBT",at = @At("TAIL")) + private void saveToNBT$playerSync(CompoundTag nbt, RegistryAccess registryAccess, CallbackInfoReturnable cir) { + String serializedData = nbt.toString(); + String sql = "INSERT INTO cobblemon (uuid, pc) VALUES ('" + this.uuid.toString() + "', '" + serializedData + "') " + + "ON DUPLICATE KEY UPDATE pc = '" + serializedData + "'"; + try { + JDBCsetUp.executeUpdate(sql); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @ModifyVariable(method = "loadFromNBT", at = @At("HEAD"), argsOnly = true, name = "arg1") + private CompoundTag loadFromNBT$playerSync(CompoundTag value) { + String sql = "SELECT pc FROM cobblemon WHERE uuid = '" + this.uuid.toString() + "'"; + CompoundTag loadedNbt = value; + try { + JDBCsetUp.QueryResult qr = JDBCsetUp.executeQuery(sql); + ResultSet rs = qr.resultSet(); + if (rs.next()) { + String serializedData = rs.getString("pc"); + loadedNbt = NbtUtils.snbtToStructure(serializedData); + } + + rs.close(); + qr.close(); + } catch (SQLException | CommandSyntaxException e) { + throw new RuntimeException(e); + } + return loadedNbt; + } +} diff --git a/src/main/java/vip/fubuki/playersync/mixin/cobblemon/MixinPartyStore.java b/src/main/java/vip/fubuki/playersync/mixin/cobblemon/MixinPartyStore.java new file mode 100644 index 0000000..bc11c73 --- /dev/null +++ b/src/main/java/vip/fubuki/playersync/mixin/cobblemon/MixinPartyStore.java @@ -0,0 +1,58 @@ +package vip.fubuki.playersync.mixin.cobblemon; + +import com.cobblemon.mod.common.api.storage.party.PartyStore; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.minecraft.core.RegistryAccess; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import vip.fubuki.playersync.util.JDBCsetUp; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +@Mixin(PartyStore.class) +public class MixinPartyStore { + @Final + @Shadow + private UUID uuid; + + @Inject(method = "saveToNBT",at = @At("TAIL")) + private void saveToNBT$playerSync(CompoundTag nbt, RegistryAccess registryAccess, CallbackInfoReturnable cir) { + String serializedData = nbt.toString(); + String sql = "INSERT INTO cobblemon (uuid, inv) VALUES ('" + this.uuid.toString() + "', '" + serializedData + "') " + + "ON DUPLICATE KEY UPDATE inv = '" + serializedData + "'"; + try { + JDBCsetUp.executeUpdate(sql); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @ModifyVariable(method = "loadFromNBT*", at = @At("HEAD"), argsOnly = true, name = "arg1") + private CompoundTag loadFromNBT$playerSync(CompoundTag value) { + String sql = "SELECT inv FROM cobblemon WHERE uuid = '" + this.uuid.toString() + "'"; + CompoundTag loadedNbt = value; + try { + JDBCsetUp.QueryResult qr = JDBCsetUp.executeQuery(sql); + ResultSet rs = qr.resultSet(); + if (rs.next()) { + String serializedData = rs.getString("inv"); + loadedNbt = NbtUtils.snbtToStructure(serializedData); + } + + rs.close(); + qr.close(); + } catch (SQLException | CommandSyntaxException e) { + throw new RuntimeException(e); + } + return loadedNbt; + } +} diff --git a/src/main/java/vip/fubuki/playersync/mixin/cobblemon/accessor/FileBasedPlayerDataStoreBackendAccessor.java b/src/main/java/vip/fubuki/playersync/mixin/cobblemon/accessor/FileBasedPlayerDataStoreBackendAccessor.java new file mode 100644 index 0000000..31ce33c --- /dev/null +++ b/src/main/java/vip/fubuki/playersync/mixin/cobblemon/accessor/FileBasedPlayerDataStoreBackendAccessor.java @@ -0,0 +1,12 @@ +package vip.fubuki.playersync.mixin.cobblemon.accessor; + +import com.cobblemon.mod.common.api.storage.player.PlayerInstancedDataStoreType; +import com.cobblemon.mod.common.api.storage.player.adapter.FileBasedPlayerDataStoreBackend; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(FileBasedPlayerDataStoreBackend.class) +public interface FileBasedPlayerDataStoreBackendAccessor { + @Accessor + PlayerInstancedDataStoreType getType(); +} diff --git a/src/main/java/vip/fubuki/playersync/mixin/cobblemon/accessor/NbtBackedPlayerDataAccessor.java b/src/main/java/vip/fubuki/playersync/mixin/cobblemon/accessor/NbtBackedPlayerDataAccessor.java new file mode 100644 index 0000000..65f1d2b --- /dev/null +++ b/src/main/java/vip/fubuki/playersync/mixin/cobblemon/accessor/NbtBackedPlayerDataAccessor.java @@ -0,0 +1,14 @@ +package vip.fubuki.playersync.mixin.cobblemon.accessor; + +import com.cobblemon.mod.common.api.storage.player.InstancedPlayerData; +import com.cobblemon.mod.common.api.storage.player.adapter.DexDataNbtBackend; +import com.mojang.serialization.Codec; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(DexDataNbtBackend.class) +public interface NbtBackedPlayerDataAccessor { + @Accessor("codec") + Codec getCodec(); + +} diff --git a/src/main/resources/playersync.mixins.json b/src/main/resources/playersync.mixins.json new file mode 100644 index 0000000..c5db030 --- /dev/null +++ b/src/main/resources/playersync.mixins.json @@ -0,0 +1,20 @@ +{ + "required": true, + "package": "vip.fubuki.playersync.mixin", + "compatibilityLevel": "JAVA_21", + "refmap": "thirst.refmap.json", + "mixins": [ + "cobblemon.MixinFileBackedPokemonStoreFactory", + "cobblemon.MixinNbtBackedPlayerData", + "cobblemon.MixinPartyStore", + "cobblemon.MixinPCStore", + "cobblemon.accessor.FileBasedPlayerDataStoreBackendAccessor", + "cobblemon.accessor.NbtBackedPlayerDataAccessor" + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + }, + "minVersion": "0.8.4" +} diff --git a/src/main/templates/META-INF/neoforge.mods.toml b/src/main/templates/META-INF/neoforge.mods.toml index 5049468..100de66 100644 --- a/src/main/templates/META-INF/neoforge.mods.toml +++ b/src/main/templates/META-INF/neoforge.mods.toml @@ -39,8 +39,8 @@ authors="${mod_authors}" #optional description='''${mod_description}''' # The [[mixins]] block allows you to declare your mixin config to FML so that it gets loaded. -#[[mixins]] -#config="${mod_id}.mixins.json" +[[mixins]] +config="${mod_id}.mixins.json" # The [[accessTransformers]] block allows you to declare where your AT file is. # If this block is omitted, a fallback attempt will be made to load an AT from META-INF/accesstransformer.cfg