add cobblemon support(in test)

This commit is contained in:
mlus 2025-12-15 22:47:47 +08:00
parent 72d0255d48
commit e373b8c226
10 changed files with 345 additions and 2 deletions

View File

@ -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"

View File

@ -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(

View File

@ -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 <T extends PokemonStore<?>> void getStore$playerSync(Class<T> storeClass, UUID uuid, RegistryAccess registryAccess, Function1<? super UUID, ? extends T> constructor, CallbackInfoReturnable<T> 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();
}
}

View File

@ -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<InstancedPlayerData> codec = ((NbtBackedPlayerDataAccessor)this).getCodec();
DataResult<Tag> 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<InstancedPlayerData> 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<InstancedPlayerData> codec = ((NbtBackedPlayerDataAccessor)this).getCodec();
DataResult<InstancedPlayerData> 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);
}
}
}

View File

@ -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<CompoundTag> 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;
}
}

View File

@ -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<CompoundTag> 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;
}
}

View File

@ -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();
}

View File

@ -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<InstancedPlayerData> getCodec();
}

View File

@ -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"
}

View File

@ -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