For AstralSorcery and FTB

This commit is contained in:
mlus-Asuka 2024-01-04 22:07:20 +08:00
parent 096ccea733
commit 2e3694d7cb
12 changed files with 135 additions and 540 deletions

View File

@ -1,8 +1,22 @@
buildscript{
repositories{
mavenCentral()
maven { url = 'https://maven.minecraftforge.net' }
maven { url='https://repo.spongepowered.org/repository/maven-public' }
}
dependencies {
classpath group: 'org.spongepowered', name: 'mixingradle', version: '0.7-SNAPSHOT'
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+', changing: true
}
}
plugins {
id 'eclipse'
id 'maven-publish'
id 'net.minecraftforge.gradle' version '5.1.+'
}
apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'org.spongepowered.mixin'
version = mod_version
group = 'vip.fubuki.playersync' // http://maven.apache.org/guides/mini/guide-naming-conventions.html
@ -15,7 +29,7 @@ minecraft {
mappings channel: 'official', version: '1.16.5'
//accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') // Currently, this location cannot be changed from the default.
//accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
runs {
client {
@ -122,11 +136,19 @@ dependencies {
jarJar.ranged(it, '[3685108,)')
}
runtimeOnly fg.deobf("top.theillusivec4.curios:curios-forge:1.16.5-4.1.0.1")
compileOnly fg.deobf("top.theillusivec4.curios:curios-forge:1.16.5-4.1.0.1:api")
implementation fg.deobf("curse.maven:architectury-api-419699:4521290")
implementation fg.deobf("curse.maven:astral-sorcery-241721:3813365")
implementation fg.deobf("curse.maven:ftb-library-forge-404465:3553840")
implementation fg.deobf("curse.maven:ftb-quests-forge-289412:4297999")
implementation fg.deobf("curse.maven:MySQL-561280:3685108")
}
mixin {
add sourceSets.main, "playersync.refmap.json"
config 'playersync.mixin.json'
}
// Example for how to get properties into the manifest for reading at runtime.
jar {
manifest {
@ -137,7 +159,8 @@ jar {
"Implementation-Title" : project.name,
"Implementation-Version" : project.jar.archiveVersion,
"Implementation-Vendor" : "examplemodsareus",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
"MixinConfigs" : "playersync.mixin.json"
])
}
}

View File

@ -2,20 +2,11 @@ package vip.fubuki.playersync;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import vip.fubuki.playersync.config.JdbcConfig;
import vip.fubuki.playersync.sync.ChatSync;
import vip.fubuki.playersync.sync.VanillaSync;
import vip.fubuki.playersync.util.JDBCsetUp;
import java.sql.SQLException;
@Mod(PlayerSync.MODID)
public class PlayerSync
@ -25,36 +16,7 @@ public class PlayerSync
{
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, JdbcConfig.COMMON_CONFIG);
modEventBus.addListener(this::commonSetup);
MinecraftForge.EVENT_BUS.register(this);
}
private void commonSetup(final FMLCommonSetupEvent event) {
VanillaSync.register();
if(JdbcConfig.SYNC_CHAT.get()){
ChatSync.register();
}
}
@SubscribeEvent
public void onServerStarting(FMLServerStartingEvent event) throws SQLException {
JDBCsetUp.executeUpdate("CREATE DATABASE IF NOT EXISTS "+JdbcConfig.DATABASE_NAME.get()+";",1);
JDBCsetUp.executeUpdate("CREATE TABLE IF NOT EXISTS player_data (uuid CHAR(36) NOT NULL," +
"inventory MEDIUMBLOB,armor BLOB,advancements BLOB,enderchest MEDIUMBLOB,effects BLOB," +
"xp int,food_level int,score int,health int,online boolean, last_server int, PRIMARY KEY (uuid));");
JDBCsetUp.executeUpdate("CREATE TABLE IF NOT EXISTS chat (player CHAR(36) NOT NULL,message TEXT," +
"timestamp BIGINT);");
JDBCsetUp.executeUpdate("CREATE TABLE IF NOT EXISTS server_info (`id` INT NOT NULL,`enable` boolean NOT NULL,`last_update` BIGINT NOT NULL,PRIMARY KEY (`id`));");
long current = System.currentTimeMillis();
JDBCsetUp.executeUpdate("INSERT INTO server_info(id,enable,last_update) " +
"VALUES(" + JdbcConfig.SERVER_ID.get() + ",true," + current + ") " +
"ON DUPLICATE KEY UPDATE id= " + JdbcConfig.SERVER_ID.get() +",enable = 1," +
"last_update=" + current + ";");
if(ModList.get().isLoaded("curios")) {
JDBCsetUp.executeUpdate("CREATE TABLE IF NOT EXISTS curios (uuid CHAR(36) NOT NULL,curios_item BLOB, PRIMARY KEY (uuid));");
}
}
}

View File

@ -11,29 +11,20 @@ import java.util.Random;
public class JdbcConfig {
public static ForgeConfigSpec COMMON_CONFIG;
public static ForgeConfigSpec.ConfigValue<String> HOST;
public static ForgeConfigSpec.ConfigValue<String> DATABASE_NAME;
public static ForgeConfigSpec.IntValue PORT;
public static ForgeConfigSpec.ConfigValue<String> USERNAME;
public static ForgeConfigSpec.ConfigValue<String> PASSWORD;
public static ForgeConfigSpec.ConfigValue<List<String>> SYNC_WORLD;
public static ForgeConfigSpec.BooleanValue USE_SSL;
public static ForgeConfigSpec.BooleanValue SYNC_CHAT;
public static ForgeConfigSpec.ConfigValue<Integer> SERVER_ID;
static {
ForgeConfigSpec.Builder COMMON_BUILDER = new ForgeConfigSpec.Builder();
COMMON_BUILDER.comment("General settings").push("general");
HOST=COMMON_BUILDER.comment("The host of the database").define("host", "localhost");
DATABASE_NAME= COMMON_BUILDER.comment("Database name").define("database_name", "playersync");
PORT = COMMON_BUILDER.comment("database port").defineInRange("db_port", 3306, 0, 65535);
USE_SSL = COMMON_BUILDER.comment("whether use SSL").define("use_ssl", false);
USERNAME = COMMON_BUILDER.comment("username").define("user_name", "root");
PASSWORD = COMMON_BUILDER.comment("password").define("password", "password");
SERVER_ID = COMMON_BUILDER.comment("the server id should be unique").define("Server_id", (int) (Math.random()*Integer.MAX_VALUE));
SYNC_WORLD = COMMON_BUILDER.comment("The worlds that will be synchronized.If running in server it is supposed to have only one").define("sync_world", new ArrayList<>());
SYNC_CHAT= COMMON_BUILDER.comment("Whether synchronize chat").define("sync_chat", true);
COMMON_BUILDER.pop();
COMMON_CONFIG = COMMON_BUILDER.build();
}

View File

@ -0,0 +1,55 @@
package vip.fubuki.playersync.mixin;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import hellfirepvp.astralsorcery.common.data.research.PlayerProgress;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.JsonToNBT;
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.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import vip.fubuki.playersync.util.JDBCsetUp;
import java.sql.ResultSet;
import java.sql.SQLException;
@Mixin(PlayerProgress.class)
public abstract class MixinPlayerProgress {
@Shadow public abstract void load(CompoundNBT compound);
@ModifyArg(method = "store", at = @At(value = "INVOKE", target = "Lhellfirepvp/astralsorcery/common/data/research/PlayerPerkData;save(Lnet/minecraft/nbt/CompoundNBT;)V"))
private CompoundNBT save(CompoundNBT tag) {
tag.putBoolean("PlayerSync",false);
String nbt = tag.toString().replace(",","|").replace("\"","^").replace("{","<").replace("}",">").replace("'","~");
try {
JDBCsetUp.executeUpdate("INSERT INTO AstralSorcery(player,tag) VALUES('" + tag.getString("UUID") + "','" + nbt + "') ON DUPLICATE KEY UPDATE tag='" + tag + "';");
} catch (SQLException throwable) {
throwable.printStackTrace();
}
return tag;
}
@Inject(method = "load",at=@At(value="HEAD"), cancellable = true)
private void load(CompoundNBT compound, CallbackInfo ci){
if(compound.get("PlayerSync")==null || !compound.getBoolean("PlayerSync")){
compound.putBoolean("PlayerSync",true);
try {
ResultSet result= JDBCsetUp.executeQuery("SELECT * FROM AstralSorcery WHERE player='" + compound.getString("UUID") + "';").getResultSet();
if(result.next()){
String nbt = result.getString("tag").replace("|",",").replace("^","\"").replace("<","{").replace(">","}").replace("~", "'");
load(JsonToNBT.parseTag(nbt));
}
}catch (SQLException e){
e.printStackTrace();
} catch (CommandSyntaxException e) {
throw new RuntimeException(e);
}
ci.cancel();
}
}
}

View File

@ -0,0 +1,36 @@
package vip.fubuki.playersync.mixin;
import dev.ftb.mods.ftblibrary.snbt.SNBT;
import dev.ftb.mods.ftbquests.quest.ServerQuestFile;
import net.minecraft.server.MinecraftServer;
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.callback.CallbackInfo;
import java.nio.file.Path;
import java.util.Iterator;
import static dev.ftb.mods.ftbquests.quest.ServerQuestFile.FTBQUESTS_DATA;
@Mixin(ServerQuestFile.class)
public class MixinServerQuestFile {
@Shadow @Final public MinecraftServer server;
@Inject(method ="saveNow",at = @At("RETURN"))
private void saveNow(CallbackInfo ci){
Path path = this.server.getWorldPath(FTBQUESTS_DATA);
}
@Inject(method="load",at = @At("HEAD"))
private void load(CallbackInfo ci){
Path path = this.server.getWorldPath(FTBQUESTS_DATA);
// SNBT.write(path.resolve(data.uuid + ".snbt"), data.serializeNBT());
}
}

View File

@ -1,63 +0,0 @@
package vip.fubuki.playersync.sync;
import net.minecraft.server.management.PlayerList;
import net.minecraft.util.text.ChatType;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import vip.fubuki.playersync.util.JDBCsetUp;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Objects;
import java.util.UUID;
@Mod.EventBusSubscriber
public class ChatSync {
static int tick = 0;
static long current = System.currentTimeMillis();
static PlayerList playerList;
public static void register(){
}
@SubscribeEvent
public static void onPlayerChat(net.minecraftforge.event.ServerChatEvent event) throws SQLException {
JDBCsetUp.executeUpdate("INSERT INTO chat (player, message, timestamp) VALUES ('" + event.getUsername() + "', '" + event.getMessage() + "', '" + current + "');");
}
@SubscribeEvent
public static void Tick(net.minecraftforge.event.TickEvent.ServerTickEvent event) throws SQLException {
tick++;
if(tick == 20) {
ReadMessage(playerList);
}
}
@SubscribeEvent
public static void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event){
playerList= Objects.requireNonNull(event.getPlayer().getServer()).getPlayerList();
}
@SubscribeEvent
public static void onPlayerLeave(PlayerEvent.PlayerLoggedOutEvent event){
playerList= Objects.requireNonNull(event.getPlayer().getServer()).getPlayerList();
}
public static void ReadMessage(PlayerList playerList) throws SQLException {
JDBCsetUp.QueryResult queryResult=JDBCsetUp.executeQuery("SELECT * FROM chat WHERE timestamp > " + current+";");
ResultSet resultSet= queryResult.getResultSet();
current = System.currentTimeMillis();
tick = 0;
while(resultSet.next()) {
String player = resultSet.getString("player");
String message = resultSet.getString("message");
ITextComponent textComponents = ITextComponent.nullToEmpty(player+": "+message);
playerList.broadcastMessage(textComponents, ChatType.CHAT, UUID.nameUUIDFromBytes(player.getBytes()));
}
resultSet.close();
queryResult.getConnection().close();
}
}

View File

@ -1,75 +0,0 @@
package vip.fubuki.playersync.sync;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.JsonToNBT;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.items.IItemHandlerModifiable;
import vip.fubuki.playersync.util.JDBCsetUp;
import vip.fubuki.playersync.util.LocalJsonUtil;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
public class ModsSupport {
public void onPlayerJoin(PlayerEntity player) throws SQLException {
if (ModList.get().isLoaded("curios")) {
/*
Curios Support
*/
LazyOptional<IItemHandlerModifiable> itemHandler = top.theillusivec4.curios.api.CuriosApi.getCuriosHelper().getEquippedCurios(player);
JDBCsetUp.QueryResult queryResult=JDBCsetUp.executeQuery("SELECT curios_item FROM curios WHERE uuid = '"+player.getUUID()+"';");
ResultSet resultSet = queryResult.getResultSet();
if(resultSet.next()) {
String curios_data=resultSet.getString("curios_item");
if(curios_data.length()>2) {
Map<Integer, String> curios = LocalJsonUtil.StringToEntryMap(curios_data);
itemHandler.ifPresent(handler -> {
for (int i = 0; i < handler.getSlots(); i++) {
try {
if (curios.get(i) == null) continue;
handler.setStackInSlot(i, ItemStack.of(JsonToNBT.parseTag(curios.get(i).replace("|", ","))));
} catch (CommandSyntaxException e) {
throw new RuntimeException(e);
}
}
});
}
resultSet.close();
queryResult.getConnection().close();
}else{
StoreCurios(player,true);
}
}
}
public void onPlayerLeave(PlayerEntity player) throws SQLException {
if (ModList.get().isLoaded("curios")) {
StoreCurios(player, false);
}
}
public void StoreCurios(PlayerEntity player,boolean init) throws SQLException {
LazyOptional<IItemHandlerModifiable> itemHandler = top.theillusivec4.curios.api.CuriosApi.getCuriosHelper().getEquippedCurios(player);
Map<Integer, String> curios = new HashMap<>();
itemHandler.ifPresent(handler -> {
for (int i = 0; i < handler.getSlots(); i++) {
if (!handler.getStackInSlot(i).isEmpty()) {
String sNBT= handler.getStackInSlot(i).serializeNBT().toString().replace(",", "|");
curios.put(i, sNBT);
}
}
});
if(init) {
JDBCsetUp.executeUpdate("INSERT INTO curios (uuid,curios_item) VALUES ('"+player.getUUID()+"','"+ curios+"');");
} else {
JDBCsetUp.executeUpdate("UPDATE curios SET curios_item = '"+ curios+"' WHERE uuid = '"+player.getUUID()+"';");
}
}
}

View File

@ -1,292 +0,0 @@
package vip.fubuki.playersync.sync;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.JsonToNBT;
import net.minecraft.potion.Effect;
import net.minecraft.potion.EffectInstance;
import net.minecraft.util.text.StringTextComponent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.server.FMLServerStoppedEvent;
import vip.fubuki.playersync.config.JdbcConfig;
import vip.fubuki.playersync.util.JDBCsetUp;
import vip.fubuki.playersync.util.LocalJsonUtil;
import vip.fubuki.playersync.util.PSThreadPoolFactory;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Mod.EventBusSubscriber
public class VanillaSync {
public static void register(){}
static ExecutorService executorService = Executors.newCachedThreadPool(new PSThreadPoolFactory("PlayerSync"));
public static void doPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) throws SQLException, CommandSyntaxException, IOException {
String player_uuid = event.getEntity().getUUID().toString();
JDBCsetUp.QueryResult queryResult=JDBCsetUp.executeQuery("SELECT online, last_server FROM player_data WHERE uuid='"+player_uuid+"';");
ResultSet resultSet=queryResult.getResultSet();
ServerPlayerEntity serverPlayer = (ServerPlayerEntity) event.getEntity();
if(!resultSet.next()){
Store(event.getPlayer(),true,Dist.CLIENT.isDedicatedServer());
return;
}
boolean online = resultSet.getBoolean("online");
int lastServer = resultSet.getInt("last_server");
queryResult=JDBCsetUp.executeQuery("SELECT * FROM player_data WHERE uuid='"+player_uuid+"';");
resultSet= queryResult.getResultSet();
if(online) {
queryResult=JDBCsetUp.executeQuery("SELECT last_update,enable FROM server_info WHERE id='"+lastServer+"';");
ResultSet getServerInfo = queryResult.getResultSet();
if(getServerInfo.next()){
long last_update = getServerInfo.getLong("last_update");
boolean enable = getServerInfo.getBoolean("enable");
if(enable && System.currentTimeMillis() < last_update + 300000.0){
event.getEntity().removeTag("player_synced");
serverPlayer.connection.disconnect(new StringTextComponent("playersync.already_online"));
return;
}
JDBCsetUp.executeUpdate("UPDATE server_info SET enable=false WHERE id=" + lastServer+";");
}
getServerInfo.close();
}
JDBCsetUp.executeUpdate("UPDATE server_info SET last_update=" + System.currentTimeMillis() + " WHERE id=" + JdbcConfig.SERVER_ID.get()+";");
JDBCsetUp.executeUpdate("UPDATE player_data SET online=true,last_server=" + JdbcConfig.SERVER_ID.get() + " WHERE uuid='"+player_uuid+"';");
if(resultSet.next()) {
//Easy Part
serverPlayer.setHealth(resultSet.getInt("health"));
serverPlayer.getFoodData().setFoodLevel(resultSet.getInt("food_level"));
serverPlayer.totalExperience=0;
serverPlayer.experienceLevel=0;
serverPlayer.experienceProgress=0;
serverPlayer.giveExperiencePoints(resultSet.getInt("xp"));
serverPlayer.setScore(resultSet.getInt("score"));
//Equipment
String armor_data=resultSet.getString("armor");
if(armor_data.length()>2) {
Map<Integer, String> equipment = LocalJsonUtil.StringToEntryMap(armor_data);
for (Map.Entry<Integer, String> entry : equipment.entrySet()) {
serverPlayer.inventory.armor.set(entry.getKey(), Deserialize(entry));
}
}
//Inventory
Map<Integer,String> inventory = LocalJsonUtil.StringToEntryMap(resultSet.getString("inventory"));
for (Map.Entry<Integer, String> entry : inventory.entrySet()) {
serverPlayer.inventory.setItem(entry.getKey(),Deserialize(entry));
}
//Ender chest
Map<Integer,String> ender_chest = LocalJsonUtil.StringToEntryMap(resultSet.getString("enderchest"));
for (Map.Entry<Integer, String> entry : ender_chest.entrySet()) {
serverPlayer.getEnderChestInventory().setItem(entry.getKey(),Deserialize(entry));
}
//Effects
String effectData=resultSet.getString("effects");
if(effectData.length()>2) {
serverPlayer.removeAllEffects();
Map<Integer, String> effects = LocalJsonUtil.StringToEntryMap(effectData);
for (Map.Entry<Integer, String> entry : effects.entrySet()) {
CompoundNBT effectTag = JsonToNBT.parseTag(entry.getValue().replace("|", ","));
EffectInstance mobEffectInstance = EffectInstance.load(effectTag);
serverPlayer.addEffect(mobEffectInstance);
}
}
//Advancements
File gameDir = Objects.requireNonNull(serverPlayer.getServer()).getServerDirectory();
if(Dist.CLIENT.isDedicatedServer()){
File advancements = new File(gameDir, JdbcConfig.SYNC_WORLD.get().get(0)+"/advancements"+"/"+player_uuid+".json");
if (!advancements.exists()) {
advancements.createNewFile();
}
byte [] bytes=resultSet.getString("advancements").getBytes();
Files.write(advancements.toPath(),bytes);
}else{
File[] files= ScanAdvancementsFile(player_uuid, gameDir);
for (File file : files) {
if(file==null) continue;
byte [] bytes=resultSet.getString("advancements").getBytes();
Files.write(file.toPath(),bytes);
}
}
}
//Mod support
ModsSupport modsSupport = new ModsSupport();
modsSupport.onPlayerJoin(serverPlayer);
serverPlayer.addTag("player_synced");
resultSet.close();
}
@SubscribeEvent
public static void OnPlayerJoin(PlayerEvent.PlayerLoggedInEvent event){
executorService.submit(()->{
try {
doPlayerJoin(event);
} catch (Exception e) {
e.printStackTrace();
}
});
}
private static ItemStack Deserialize(Map.Entry<Integer, String> entry) throws CommandSyntaxException {
String nbt= entry.getValue().replace("|",",").replace("^","\"").replace("<","{").replace(">","}").replace("~", "'");
CompoundNBT compoundTag = JsonToNBT.parseTag(nbt);
return ItemStack.of(compoundTag);
}
public static void doPlayerSaveToFile(PlayerEvent.SaveToFile event) throws SQLException, IOException {
JDBCsetUp.executeUpdate("UPDATE server_info SET last_update=" + System.currentTimeMillis() + " WHERE id=" + JdbcConfig.SERVER_ID.get()+";");
if(!event.getEntity().getTags().contains("player_synced")) return;
Store(event.getPlayer(),false,Dist.CLIENT.isDedicatedServer());
//Mod support
ModsSupport modsSupport = new ModsSupport();
modsSupport.onPlayerLeave(event.getPlayer());
}
@SubscribeEvent
public static void onPlayerSaveToFile(PlayerEvent.SaveToFile event) {
executorService.submit(()->{
try {
doPlayerSaveToFile(event);
} catch (Exception e) {
e.printStackTrace();
}
});
}
@SubscribeEvent
public static void onServerShutdown(FMLServerStoppedEvent event) throws SQLException {
JDBCsetUp.executeUpdate("UPDATE server_info SET enable= false WHERE id=" + JdbcConfig.SERVER_ID.get()+";");
}
public static void doPlayerLogout(PlayerEvent.PlayerLoggedOutEvent event) throws SQLException, IOException {
if(!event.getEntity().getTags().contains("player_synced")) return;
String player_uuid = event.getEntity().getUUID().toString();
JDBCsetUp.executeUpdate("UPDATE player_data SET online= false WHERE uuid='"+player_uuid+"';");
Store(event.getPlayer(),false,Dist.CLIENT.isDedicatedServer());
//Mod support
ModsSupport modsSupport = new ModsSupport();
modsSupport.onPlayerLeave(event.getPlayer());
event.getEntity().removeTag("player_synced");
}
@SubscribeEvent
public static void onPlayerLogout(PlayerEvent.PlayerLoggedOutEvent event) {
executorService.submit(()->{
try {
doPlayerLogout(event);
} catch (Exception e) {
e.printStackTrace();
}
});
}
public static void Store(PlayerEntity player, boolean init, boolean isServer) throws SQLException, IOException {
String player_uuid = player.getUUID().toString();
//Easy part
int XP = player.totalExperience;
int score=player.getScore();
int food_level=player.getFoodData().getFoodLevel();
int health=(int) player.getHealth();
//Equipment
Map<Integer,String> equipment =new HashMap<>() ;
for (int i = 0; i < player.inventory.armor.size(); i++) {
ItemStack itemStack = player.inventory.armor.get(i);
if(itemStack.isEmpty()) continue;
equipment.put(i,itemStack.serializeNBT().toString().replace(",","|").replace("\"","^").replace("{","<").replace("}",">").replace("'","~"));
}
//inventory
PlayerInventory inventory = player.inventory;
Map<Integer,String> inventoryMap=new HashMap<>();
for (int i = 0; i < inventory.items.size(); i++) {
CompoundNBT itemNBT = inventory.items.get(i).serializeNBT();
inventoryMap.put(i,itemNBT.toString().replace(",","|").replace("\"","^").replace("{","<").replace("}",">").replace("'","~"));
}
//EnderChest
Map<Integer, String> ender_chest=new HashMap<>();
for (int i=0;i< player.getEnderChestInventory().getContainerSize();i++) {
CompoundNBT itemNBT = player.getEnderChestInventory().getItem(i).serializeNBT();
ender_chest.put(i,itemNBT.toString().replace(",","|").replace("\"","^").replace("{","<").replace("}",">").replace("'","~"));
}
//Effects
Map<Effect, EffectInstance> effects= player.getActiveEffectsMap();
Map<Integer,String> effectMap=new HashMap<>();
for (Map.Entry<Effect, EffectInstance> entry : effects.entrySet()) {
CompoundNBT effectTag= entry.getValue().save(new CompoundNBT());
effectMap.put(Effect.getId(entry.getKey()),effectTag.toString().replace(",","|"));
}
//Advancements
//File root = serverPlayer.getServer().getServerDirectory();
File advancements = null;
File gameDir = Objects.requireNonNull(player.getServer()).getServerDirectory();
if(isServer){
advancements = new File(gameDir, JdbcConfig.SYNC_WORLD.get().get(0)+"/advancements"+"/"+player_uuid+".json");
}else{
// File gameDir = Minecraft.getInstance().gameDirectory;
File[] files=ScanAdvancementsFile(player_uuid, gameDir);
//Get LastModified
long latestModifiedDate = 0;
for (File file : files) {
if(file==null) continue;
if (file.lastModified() > latestModifiedDate) {
latestModifiedDate = file.lastModified();
advancements = file;
}
}
}
byte[] bytes = new byte[0];
if (advancements != null) {
bytes = Files.readAllBytes(advancements.toPath());
}
String json = new String(bytes, StandardCharsets.UTF_8);
//SQL Operation
if(init){
JDBCsetUp.executeUpdate("INSERT INTO player_data (uuid,armor,inventory,enderchest,advancements,effects,xp,food_level,health,score,online) VALUES ('"+player_uuid+"','"+equipment+"','"+inventoryMap+"','"+ender_chest+"','"+advancements+"','"+effectMap+"','"+XP+"','"+food_level+"','"+health+"','"+score+"',online=true);");
}else JDBCsetUp.executeUpdate("UPDATE player_data SET inventory = '"+inventoryMap+"',armor='"+equipment+"' ,xp='"+XP+"',effects='"+effectMap+"',enderchest='"+ender_chest+"',score='"+score+"',food_level='"+food_level+"',health='"+health+"',advancements='"+json+"' WHERE uuid = '"+player_uuid+"';");
}
private static File[] ScanAdvancementsFile(String player_uuid, File gameDir) {
File[] files = new File[JdbcConfig.SYNC_WORLD.get().size()];
for (int i = 0; i < JdbcConfig.SYNC_WORLD.get().size(); i++) {
File advanceFile=new File(gameDir, "saves/"+JdbcConfig.SYNC_WORLD.get().get(i)+"/advancements"+"/"+player_uuid+".json");
if(!advanceFile.exists()) continue;
files[i] = advanceFile;
}
return files;
}
// @SubscribeEvent
// public void RegisterCommand(RegisterCommandsEvent event){
// CommandDispatcher<CommandSourceStack> dispatcher=event.getDispatcher();
// LiteralCommandNode<CommandSourceStack> cmd = dispatcher.register(
// Commands.literal("serializeNBT").executes(context -> {context.getSource().sendSuccess(Component.literal(context.getSource().getPlayer().getItemInHand(InteractionHand.MAIN_HAND).serializeNBT().toString()),true);
// return 0;
// })
// );
// }
}

View File

@ -1,8 +1,10 @@
package vip.fubuki.playersync.util;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import vip.fubuki.playersync.config.JdbcConfig;
import java.sql.*;
import java.util.Map;
public class JDBCsetUp {
@ -15,7 +17,7 @@ public class JDBCsetUp {
public static QueryResult executeQuery(String sql) throws SQLException{
Connection connection = getConnection();
PreparedStatement useStatement = connection.prepareStatement("USE " + JdbcConfig.DATABASE_NAME.get());
PreparedStatement useStatement = connection.prepareStatement("USE playersync");
useStatement.executeUpdate();
PreparedStatement queryStatement = connection.prepareStatement(sql);
@ -31,7 +33,7 @@ public class JDBCsetUp {
try (Connection connection = getConnection()) {
if(init==0){
sql="USE " + JdbcConfig.DATABASE_NAME.get() +";" + sql;
sql="USE playersync;" + sql;
}
try (PreparedStatement updateStatement = connection.prepareStatement(sql)) {

View File

@ -1,32 +0,0 @@
package vip.fubuki.playersync.util;
import java.util.HashMap;
import java.util.Map;
public class LocalJsonUtil {
public static Map<String,String> StringToMap(String param) {
Map<String,String> map = new HashMap<>();
String s1 = param.substring(1,param.length()-1);
String s2 = s1.trim();
String[] split = s2.split(",");
for (int i = split.length - 1; i >= 0; i--) {
String trim = split[i].trim();
String[] split1 = trim.split("=");
map.put(split1[0],split1[1]);
}
return map;
}
public static Map<Integer,String> StringToEntryMap(String param) {
Map<Integer,String> map = new HashMap<>();
String s1 = param.substring(1,param.length()-1);
String s2 = s1.trim();
String[] split = s2.split(",");
for (int i = split.length - 1; i >= 0; i--) {
String trim = split[i].trim();
String[] split1 = trim.split("=");
map.put(Integer.parseInt(split1[0]),split1[1]);
}
return map;
}
}

View File

@ -1,25 +0,0 @@
package vip.fubuki.playersync.util;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
public class PSThreadPoolFactory implements ThreadFactory {
private final AtomicInteger threadIdx = new AtomicInteger(0);
private final String threadNamePrefix;
public PSThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable runnable) {
Thread thread = new Thread(runnable);
thread.setName(threadNamePrefix + "-thread-" + threadIdx.getAndIncrement());
return thread;
}
}

View File

@ -0,0 +1,13 @@
{
"required": true,
"package": "vip.fubuki.playersync.mixin",
"compatibilityLevel": "JAVA_8",
"refmap": "thirst.refmap.json",
"mixins": [
"MixinPlayerProgress",
"MixinServerQuestFile"
],
"client": [
],
"minVersion": "0.8"
}