Compare commits

...

9 Commits

Author SHA1 Message Date
mlus
c1fc137d9f 1.3.4 release 2024-10-11 17:54:16 +08:00
mlus
a2bee9f1d9 update sync 2024-09-14 14:43:49 +08:00
mlus
3a9bd966aa 1.3.0 update 2024-02-11 17:26:59 +08:00
mlus-Asuka
096ccea733 stupid sql 2023-09-29 20:07:52 +08:00
mlus-Asuka
80be4db008 bugs fix 2023-09-29 16:44:52 +08:00
mlus-Asuka
a60cd29ece back port to jdk 8 2023-09-28 19:22:47 +08:00
mlus-Asuka
e3f4aa888c update 1.2.0 2023-09-28 17:38:46 +08:00
mlus-Asuka
76836f680f 1.2.0 release 2023-08-09 16:00:09 +08:00
mlus-Asuka
e7836a37a4 init 1.18 2023-08-03 22:27:50 +08:00
11 changed files with 318 additions and 185 deletions

View File

@ -2,6 +2,7 @@
This is a Minecraft forge mod using Mysql backend to make player data synchronization between different servers. This is a Minecraft forge mod using Mysql backend to make player data synchronization between different servers.
Such as equipment,inventory,effects,experience,food level.Any other mods support is also possible. Such as equipment,inventory,effects,experience,food level.Any other mods support is also possible.
Support version now: Support version now:
1.20.1
1.19-1.19.3 1.19-1.19.3
1.18.2 1.18.2
1.16.5 1.16.5

View File

@ -4,16 +4,16 @@ plugins {
id 'net.minecraftforge.gradle' version '5.1.+' id 'net.minecraftforge.gradle' version '5.1.+'
} }
version = '1.2.0' version = mod_version
group = 'vip.fubuki.playersync' // http://maven.apache.org/guides/mini/guide-naming-conventions.html group = 'vip.fubuki.playersync' // http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = 'playersync' archivesBaseName = 'playersync'
java.toolchain.languageVersion = JavaLanguageVersion.of(17) java.toolchain.languageVersion = JavaLanguageVersion.of(8)
println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}" println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}"
minecraft { minecraft {
mappings channel: 'official', version: '1.19.2' 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') // Currently, this location cannot be changed from the default.
@ -116,20 +116,15 @@ repositories {
} }
dependencies { dependencies {
minecraft 'net.minecraftforge:forge:1.19.2-43.1.1' minecraft 'net.minecraftforge:forge:1.16.5-36.2.0'
jarJar("curse.maven:MySQL-561280:3685108") { jarJar("curse.maven:MySQL-561280:3685108") {
jarJar.ranged(it, '[1.0,)') jarJar.ranged(it, '[3685108,)')
} }
jarJar("com.zaxxer:HikariCP:3.4.5") { runtimeOnly fg.deobf("top.theillusivec4.curios:curios-forge:1.16.5-4.1.0.1")
jarJar.ranged(it, '[3.4.5,)') compileOnly fg.deobf("top.theillusivec4.curios:curios-forge:1.16.5-4.1.0.1:api")
}
runtimeOnly fg.deobf("top.theillusivec4.curios:curios-forge:1.19.2-5.1.1.0")
compileOnly fg.deobf("top.theillusivec4.curios:curios-forge:1.19.2-5.1.1.0:api")
implementation fg.deobf("curse.maven:MySQL-561280:3685108") implementation fg.deobf("curse.maven:MySQL-561280:3685108")
implementation group: 'com.zaxxer', name: 'HikariCP', version: '3.4.5'
} }
// Example for how to get properties into the manifest for reading at runtime. // Example for how to get properties into the manifest for reading at runtime.

View File

@ -1,4 +1,6 @@
# Sets default memory used for gradle commands. Can be overridden by user or command line properties. # Sets default memory used for gradle commands. Can be overridden by user or command line properties.
# This is required to provide enough memory for the Minecraft decompilation process. # This is required to provide enough memory for the Minecraft decompilation process.
org.gradle.jvmargs=-Xmx3G org.gradle.jvmargs=-Xmx3G
org.gradle.daemon=false org.gradle.daemon=false
mod_version=1.16.5-1.3.4

View File

@ -1,8 +1,6 @@
package vip.fubuki.playersync; package vip.fubuki.playersync;
import com.mojang.logging.LogUtils;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.server.ServerStartingEvent;
import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.ModList;
@ -10,20 +8,20 @@ import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.config.ModConfig; import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import org.slf4j.Logger;
import vip.fubuki.playersync.config.JdbcConfig; import vip.fubuki.playersync.config.JdbcConfig;
import vip.fubuki.playersync.sync.ChatSync; import vip.fubuki.playersync.sync.ChatSync;
import vip.fubuki.playersync.sync.VanillaSync; import vip.fubuki.playersync.sync.VanillaSync;
import vip.fubuki.playersync.util.JDBCsetUp; import vip.fubuki.playersync.util.JDBCsetUp;
import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
@Mod(PlayerSync.MODID) @Mod(PlayerSync.MODID)
public class PlayerSync public class PlayerSync
{ {
public static final String MODID = "playersync"; public static final String MODID = "playersync";
public static final Logger LOGGER = LogUtils.getLogger();
public PlayerSync() public PlayerSync()
{ {
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
@ -40,30 +38,38 @@ public class PlayerSync
} }
@SubscribeEvent @SubscribeEvent
public void onServerStarting(ServerStartingEvent event) throws SQLException { public void onServerStarting(FMLServerStartingEvent event) throws SQLException {
JDBCsetUp.executeUpdate("CREATE DATABASE IF NOT EXISTS "+JdbcConfig.DATABASE_NAME.get(),true); 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," + JDBCsetUp.executeUpdate("CREATE TABLE IF NOT EXISTS player_data (uuid CHAR(36) NOT NULL," +
"inventory MEDIUMBLOB,armor BLOB,advancements BLOB,enderchest MEDIUMBLOB,effects BLOB," + "inventory MEDIUMBLOB,armor BLOB,advancements BLOB,enderchest MEDIUMBLOB,effects BLOB,left_hand BLOB,cursors BLOB" +
"xp int,food_level int,score int,health int,online boolean, last_server int, PRIMARY KEY (uuid))"); "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(""" JDBCsetUp.QueryResult queryResult = JDBCsetUp.executeQuery("SELECT COUNT(*) AS column_count FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'player_data';");
CREATE TABLE IF NOT EXISTS server_info (
`id` INT NOT NULL, ResultSet resultSet = queryResult.getResultSet();
`enable` boolean NOT NULL, int columnCount = 0;
`last_update` BIGINT NOT NULL, if(resultSet.next()) {
PRIMARY KEY (`id`));"""); columnCount = resultSet.getInt("column_count");
}
if(columnCount<14){
JDBCsetUp.executeUpdate(" ALTER TABLE player_data ADD COLUMN left_hand blob, ADD COLUMN cursors blob; ");
}
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(); long current = System.currentTimeMillis();
JDBCsetUp.executeUpdate("INSERT INTO server_info(id,enable,last_update) " + JDBCsetUp.executeUpdate("INSERT INTO server_info(id,enable,last_update) " +
"VALUES(" + JdbcConfig.SERVER_ID.get() + ",true," + current + ") " + "VALUES(" + JdbcConfig.SERVER_ID.get() + ",true," + current + ") " +
"ON DUPLICATE KEY UPDATE id= " + JdbcConfig.SERVER_ID.get() +",enable = 1," + "ON DUPLICATE KEY UPDATE id= " + JdbcConfig.SERVER_ID.get() +",enable = 1," +
"last_update=" + current + ";"); "last_update=" + current + ";");
JDBCsetUp.executeUpdate("UPDATE server_info SET enable= 1 WHERE id= "+ JdbcConfig.SERVER_ID.get());
if(ModList.get().isLoaded("curios")) { if(ModList.get().isLoaded("curios")) {
JDBCsetUp.executeUpdate("CREATE TABLE IF NOT EXISTS curios (uuid CHAR(36) NOT NULL,curios_item BLOB, PRIMARY KEY (uuid))"); JDBCsetUp.executeUpdate("CREATE TABLE IF NOT EXISTS curios (uuid CHAR(36) NOT NULL,curios_item BLOB, PRIMARY KEY (uuid))");
} }
LOGGER.info("PlayerSync is ready!");
} }
} }

View File

@ -11,13 +11,16 @@ import java.util.Random;
public class JdbcConfig { public class JdbcConfig {
public static ForgeConfigSpec COMMON_CONFIG; public static ForgeConfigSpec COMMON_CONFIG;
public static ForgeConfigSpec.ConfigValue<String> HOST; public static ForgeConfigSpec.ConfigValue<String> HOST;
public static ForgeConfigSpec.ConfigValue<String> DATABASE_NAME;
public static ForgeConfigSpec.IntValue PORT; public static ForgeConfigSpec.IntValue PORT;
public static ForgeConfigSpec.ConfigValue<String> USERNAME; public static ForgeConfigSpec.ConfigValue<String> USERNAME;
public static ForgeConfigSpec.ConfigValue<String> PASSWORD; public static ForgeConfigSpec.ConfigValue<String> PASSWORD;
public static ForgeConfigSpec.ConfigValue<String> DATABASE_NAME;
public static ForgeConfigSpec.ConfigValue<List<String>> SYNC_WORLD; public static ForgeConfigSpec.ConfigValue<List<String>> SYNC_WORLD;
public static ForgeConfigSpec.BooleanValue USE_SSL; public static ForgeConfigSpec.BooleanValue USE_SSL;
public static ForgeConfigSpec.BooleanValue SYNC_CHAT; public static ForgeConfigSpec.BooleanValue SYNC_CHAT;
public static ForgeConfigSpec.BooleanValue IS_CHAT_SERVER;
public static ForgeConfigSpec.ConfigValue<String> CHAT_SERVER_IP;
public static ForgeConfigSpec.IntValue CHAT_SERVER_PORT;
public static ForgeConfigSpec.ConfigValue<Integer> SERVER_ID; public static ForgeConfigSpec.ConfigValue<Integer> SERVER_ID;
@ -26,14 +29,17 @@ public class JdbcConfig {
ForgeConfigSpec.Builder COMMON_BUILDER = new ForgeConfigSpec.Builder(); ForgeConfigSpec.Builder COMMON_BUILDER = new ForgeConfigSpec.Builder();
COMMON_BUILDER.comment("General settings").push("general"); COMMON_BUILDER.comment("General settings").push("general");
HOST=COMMON_BUILDER.comment("The host of the database").define("host", "localhost"); 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); PORT = COMMON_BUILDER.comment("database port").defineInRange("db_port", 3306, 0, 65535);
USE_SSL = COMMON_BUILDER.comment("whether use SSL").define("use_ssl", false); USE_SSL = COMMON_BUILDER.comment("whether use SSL").define("use_ssl", false);
USERNAME = COMMON_BUILDER.comment("username").define("user_name", "root"); USERNAME = COMMON_BUILDER.comment("username").define("user_name", "root");
PASSWORD = COMMON_BUILDER.comment("password").define("password", "password"); PASSWORD = COMMON_BUILDER.comment("password").define("password", "password");
SERVER_ID = COMMON_BUILDER.comment("the server id should be unique").define("Server_id", new Random().nextInt(1,Integer.MAX_VALUE-1)); DATABASE_NAME = COMMON_BUILDER.comment("database name").define("db_name","playersync");
SERVER_ID = COMMON_BUILDER.comment("the server id should be unique").define("Server_id", new Random().nextInt());
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_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); SYNC_CHAT= COMMON_BUILDER.comment("Whether synchronize chat").define("sync_chat", true);
IS_CHAT_SERVER = COMMON_BUILDER.comment("Whether recieve messages from other servers as host").define("IsChatServer",false);
CHAT_SERVER_IP = COMMON_BUILDER.define("ChatServerIP","127.0.0.1");
CHAT_SERVER_PORT = COMMON_BUILDER.defineInRange("ChatServerPort",7900,0,65535);
COMMON_BUILDER.pop(); COMMON_BUILDER.pop();
COMMON_CONFIG = COMMON_BUILDER.build(); COMMON_CONFIG = COMMON_BUILDER.build();
} }

View File

@ -1,44 +1,126 @@
package vip.fubuki.playersync.sync; package vip.fubuki.playersync.sync;
import net.minecraft.network.chat.Component; import net.minecraft.server.management.PlayerList;
import net.minecraft.server.players.PlayerList; import net.minecraft.util.text.ChatType;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import vip.fubuki.playersync.config.JdbcConfig;
import vip.fubuki.playersync.util.JDBCsetUp;
import java.sql.ResultSet; import java.io.IOException;
import java.sql.SQLException; import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Objects;
import java.util.Scanner;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Mod.EventBusSubscriber
public class ChatSync { public class ChatSync {
static int tick = 0;
static long current = System.currentTimeMillis();
public static void register(){}
@SubscribeEvent static PlayerList playerList;
public static void onPlayerChat(net.minecraftforge.event.ServerChatEvent event) throws SQLException {
JDBCsetUp.executeUpdate("INSERT INTO chat (player, message, timestamp) VALUES ('" + event.getUsername() + "', '" + event.getRawText() + "', '" + current + "')"); static ServerSocket serverSocket;
static Socket clientSocket;
static Set<Socket> SocketList;
static ExecutorService executorService = Executors.newCachedThreadPool();
public static void register(){
if(JdbcConfig.IS_CHAT_SERVER.get())
new Thread(ChatSync::ServerSocket).start();
ClientSocket();
MinecraftForge.EVENT_BUS.register(ChatSync.class);
} }
@SubscribeEvent
public static void Tick(net.minecraftforge.event.TickEvent.ServerTickEvent event) throws SQLException { private static void ServerSocket() {
tick++; try {
if(tick == 20) { serverSocket = new ServerSocket(JdbcConfig.CHAT_SERVER_PORT.get());
ReadMessage(event.getServer().getPlayerList()); while (true) {
Socket newSocket = serverSocket.accept();
SocketList.add(newSocket);
executorService.submit(() -> handleClient(newSocket));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
} }
} }
public static void ReadMessage(PlayerList playerList) throws SQLException { private static void handleClient(Socket socket) {
ResultSet resultSet= JDBCsetUp.executeQuery("SELECT * FROM chat WHERE timestamp > " + current); try (InputStream inputStream = socket.getInputStream()) {
current = System.currentTimeMillis(); byte[] buffer = new byte[1024];
tick = 0; int bytesRead;
while(resultSet.next()) { while ((bytesRead = inputStream.read(buffer)) != -1) {
String player = resultSet.getString("player"); String message = new String(buffer, 0, bytesRead);
String message = resultSet.getString("message"); broadcastMessage(socket, message);
Component textComponents = Component.literal(player+": "+message); }
playerList.broadcastSystemMessage(textComponents, true); } catch (IOException e) {
e.printStackTrace();
} finally {
SocketList.remove(socket);
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
} }
resultSet.close(); }
private static void broadcastMessage(Socket sender, String message) {
for (Socket socket : SocketList) {
if (!socket.equals(sender)) {
try {
OutputStream outputStream = socket.getOutputStream();
outputStream.write(message.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static void ClientSocket() {
try {
clientSocket = new Socket(JdbcConfig.CHAT_SERVER_IP.get(), JdbcConfig.CHAT_SERVER_PORT.get());
Scanner scanner = new Scanner(clientSocket.getInputStream());
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
playerList.broadcastMessage(ITextComponent.nullToEmpty(line), ChatType.CHAT, UUID.randomUUID());
}
} catch (IOException e) {
e.printStackTrace();
reconnectClient();
}
}
private static void reconnectClient() {
//TODO
}
@SubscribeEvent
public static void onPlayerChat(net.minecraftforge.event.ServerChatEvent event) throws IOException {
String message= event.getUsername()+":"+event.getMessage();
OutputStream outputStream = clientSocket.getOutputStream();
outputStream.write(message.getBytes());
}
@SubscribeEvent
public static void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event){
playerList= Objects.requireNonNull(event.getEntity().getServer()).getPlayerList();
}
@SubscribeEvent
public static void onPlayerLeave(PlayerEvent.PlayerLoggedOutEvent event){
playerList= Objects.requireNonNull(event.getEntity().getServer()).getPlayerList();
} }
} }

View File

@ -1,9 +1,9 @@
package vip.fubuki.playersync.sync; package vip.fubuki.playersync.sync;
import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.nbt.NbtUtils; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.world.entity.player.Player; import net.minecraft.item.ItemStack;
import net.minecraft.world.item.ItemStack; import net.minecraft.nbt.JsonToNBT;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.ModList;
import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.IItemHandlerModifiable;
@ -15,15 +15,17 @@ import java.sql.SQLException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@SuppressWarnings({"InstantiationOfUtilityClass", "AccessStaticViaInstance"})
public class ModsSupport { public class ModsSupport {
public void onPlayerJoin(Player player) throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException { public void onPlayerJoin(PlayerEntity player) throws SQLException {
if (ModList.get().isLoaded("curios")) { if (ModList.get().isLoaded("curios")) {
//TODO curios support /*
top.theillusivec4.curios.api.CuriosApi CuriosApi = new top.theillusivec4.curios.api.CuriosApi(); Curios Support
LazyOptional<IItemHandlerModifiable> itemHandler = CuriosApi.getCuriosHelper().getEquippedCurios(player); */
ResultSet resultSet = JDBCsetUp.executeQuery("SELECT curios_item FROM curios WHERE uuid = '"+player.getUUID()+"'"); 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()) { if(resultSet.next()) {
String curios_data=resultSet.getString("curios_item"); String curios_data=resultSet.getString("curios_item");
if(curios_data.length()>2) { if(curios_data.length()>2) {
@ -32,7 +34,7 @@ public class ModsSupport {
for (int i = 0; i < handler.getSlots(); i++) { for (int i = 0; i < handler.getSlots(); i++) {
try { try {
if (curios.get(i) == null) continue; if (curios.get(i) == null) continue;
handler.setStackInSlot(i, ItemStack.of(NbtUtils.snbtToStructure(curios.get(i).replace("|", ",")))); handler.setStackInSlot(i, ItemStack.of(JsonToNBT.parseTag(curios.get(i).replace("|", ",").replace("^","\"").replace("<","{").replace(">","}").replace("~", "'"))));
} catch (CommandSyntaxException e) { } catch (CommandSyntaxException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -40,26 +42,26 @@ public class ModsSupport {
}); });
} }
resultSet.close(); resultSet.close();
queryResult.getConnection().close();
}else{ }else{
StoreCurios(player,true); StoreCurios(player,true);
} }
} }
} }
public void onPlayerLeave(Player player) throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException { public void onPlayerLeave(PlayerEntity player) throws SQLException {
if (ModList.get().isLoaded("curios")) { if (ModList.get().isLoaded("curios")) {
StoreCurios(player, false); StoreCurios(player, false);
} }
} }
public void StoreCurios(Player player,boolean init) throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException { public void StoreCurios(PlayerEntity player,boolean init) throws SQLException {
top.theillusivec4.curios.api.CuriosApi CuriosApi = new top.theillusivec4.curios.api.CuriosApi(); LazyOptional<IItemHandlerModifiable> itemHandler = top.theillusivec4.curios.api.CuriosApi.getCuriosHelper().getEquippedCurios(player);
LazyOptional<IItemHandlerModifiable> itemHandler = CuriosApi.getCuriosHelper().getEquippedCurios(player);
Map<Integer, String> curios = new HashMap<>(); Map<Integer, String> curios = new HashMap<>();
itemHandler.ifPresent(handler -> { itemHandler.ifPresent(handler -> {
for (int i = 0; i < handler.getSlots(); i++) { for (int i = 0; i < handler.getSlots(); i++) {
if (!handler.getStackInSlot(i).isEmpty()) { if (!handler.getStackInSlot(i).isEmpty()) {
String sNBT= handler.getStackInSlot(i).serializeNBT().toString().replace(",", "|"); String sNBT= VanillaSync.serialize(handler.getStackInSlot(i).serializeNBT().toString());
curios.put(i, sNBT); curios.put(i, sNBT);
} }
} }

View File

@ -1,20 +1,22 @@
package vip.fubuki.playersync.sync; package vip.fubuki.playersync.sync;
import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.nbt.CompoundTag; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.NbtUtils; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.network.chat.Component; import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.item.ItemStack;
import net.minecraft.world.effect.MobEffect; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.nbt.JsonToNBT;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.potion.Effect;
import net.minecraft.world.entity.player.Player; import net.minecraft.potion.EffectInstance;
import net.minecraft.world.item.ItemStack; import net.minecraft.util.Hand;
import net.minecraft.util.text.StringTextComponent;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.event.server.ServerStoppedEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.server.FMLServerStoppedEvent;
import vip.fubuki.playersync.config.JdbcConfig; import vip.fubuki.playersync.config.JdbcConfig;
import vip.fubuki.playersync.util.JDBCsetUp; import vip.fubuki.playersync.util.JDBCsetUp;
import vip.fubuki.playersync.util.LocalJsonUtil; import vip.fubuki.playersync.util.LocalJsonUtil;
@ -39,38 +41,40 @@ public class VanillaSync {
static ExecutorService executorService = Executors.newCachedThreadPool(new PSThreadPoolFactory("PlayerSync")); static ExecutorService executorService = Executors.newCachedThreadPool(new PSThreadPoolFactory("PlayerSync"));
public static void doPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException, CommandSyntaxException, IOException { public static void doPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) throws SQLException, CommandSyntaxException, IOException {
String player_uuid = event.getEntity().getUUID().toString(); String player_uuid = event.getEntity().getUUID().toString();
ResultSet resultSet=JDBCsetUp.executeQuery("SELECT online, last_server FROM player_data WHERE uuid='"+player_uuid+"'"); JDBCsetUp.QueryResult queryResult=JDBCsetUp.executeQuery("SELECT online, last_server FROM player_data WHERE uuid='"+player_uuid+"';");
ServerPlayer serverPlayer = (ServerPlayer) event.getEntity(); ResultSet resultSet=queryResult.getResultSet();
ServerPlayerEntity serverPlayer = (ServerPlayerEntity) event.getEntity();
if(!resultSet.next()){ if(!resultSet.next()){
Store(event.getEntity(),true,Dist.CLIENT.isDedicatedServer()); store(event.getPlayer(),true,Dist.CLIENT.isDedicatedServer());
return; return;
} }
boolean online = resultSet.getBoolean("online"); boolean online = resultSet.getBoolean("online");
int lastServer = resultSet.getInt("last_server"); int lastServer = resultSet.getInt("last_server");
resultSet=JDBCsetUp.executeQuery("SELECT * FROM player_data WHERE uuid='"+player_uuid+"'"); queryResult=JDBCsetUp.executeQuery("SELECT * FROM player_data WHERE uuid='"+player_uuid+"'");
if(online) { resultSet= queryResult.getResultSet();
if(online && lastServer != JdbcConfig.SERVER_ID.get()) {
ResultSet getServerInfo = JDBCsetUp.executeQuery("SELECT last_update,enable FROM server_info WHERE id='"+lastServer+"'"); queryResult=JDBCsetUp.executeQuery("SELECT last_update,enable FROM server_info WHERE id='"+lastServer+"';");
ResultSet getServerInfo = queryResult.getResultSet();
if(getServerInfo.next()){ if(getServerInfo.next()){
long last_update = getServerInfo.getLong("last_update"); long last_update = getServerInfo.getLong("last_update");
boolean enable = getServerInfo.getBoolean("enable"); boolean enable = getServerInfo.getBoolean("enable");
if(enable && System.currentTimeMillis() < last_update + 300000.0){ if(enable && System.currentTimeMillis() < last_update + 300000.0){
event.getEntity().removeTag("player_synced"); event.getEntity().removeTag("player_synced");
serverPlayer.connection.disconnect(Component.translatable("playersync.already_online")); serverPlayer.connection.disconnect(new StringTextComponent("playersync.already_online"));
return; return;
} }
JDBCsetUp.executeUpdate("UPDATE server_info SET enable=false WHERE id=" + lastServer); JDBCsetUp.executeUpdate("UPDATE server_info SET enable= '0' WHERE id=" + lastServer);
} }
getServerInfo.close(); getServerInfo.close();
} }
JDBCsetUp.executeUpdate("UPDATE server_info SET last_update=" + System.currentTimeMillis() + " WHERE id=" + JdbcConfig.SERVER_ID.get()); 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+"'"); JDBCsetUp.executeUpdate("UPDATE player_data SET online= '1',last_server=" + JdbcConfig.SERVER_ID.get() + " WHERE uuid='"+player_uuid+"'");
if(resultSet.next()) { if(resultSet.next()) {
//Easy Part //Easy Part
serverPlayer.setHealth(resultSet.getInt("health")); serverPlayer.setHealth(resultSet.getInt("health"));
@ -80,23 +84,27 @@ public class VanillaSync {
serverPlayer.experienceProgress=0; serverPlayer.experienceProgress=0;
serverPlayer.giveExperiencePoints(resultSet.getInt("xp")); serverPlayer.giveExperiencePoints(resultSet.getInt("xp"));
serverPlayer.setScore(resultSet.getInt("score")); serverPlayer.setScore(resultSet.getInt("score"));
//Left Hand
serverPlayer.setItemInHand(Hand.OFF_HAND,ItemStack.of(JsonToNBT.parseTag(resultSet.getString("left_hand").replace("|",",").replace("^","\"").replace("<","{").replace(">","}").replace("~", "'"))));
//Cursor
serverPlayer.inventory.setCarried(ItemStack.of(JsonToNBT.parseTag(resultSet.getString("cursors").replace("|",",").replace("^","\"").replace("<","{").replace(">","}").replace("~", "'"))));
//Equipment //Equipment
String armor_data=resultSet.getString("armor"); String armor_data=resultSet.getString("armor");
if(armor_data.length()>2) { if(armor_data.length()>2) {
Map<Integer, String> equipment = LocalJsonUtil.StringToEntryMap(armor_data); Map<Integer, String> equipment = LocalJsonUtil.StringToEntryMap(armor_data);
for (Map.Entry<Integer, String> entry : equipment.entrySet()) { for (Map.Entry<Integer, String> entry : equipment.entrySet()) {
serverPlayer.getInventory().armor.set(entry.getKey(), Deserialize(entry)); serverPlayer.inventory.armor.set(entry.getKey(), deserialize(entry));
} }
} }
//Inventory //Inventory
Map<Integer,String> inventory = LocalJsonUtil.StringToEntryMap(resultSet.getString("inventory")); Map<Integer,String> inventory = LocalJsonUtil.StringToEntryMap(resultSet.getString("inventory"));
for (Map.Entry<Integer, String> entry : inventory.entrySet()) { for (Map.Entry<Integer, String> entry : inventory.entrySet()) {
serverPlayer.getInventory().setItem(entry.getKey(),Deserialize(entry)); serverPlayer.inventory.setItem(entry.getKey(),deserialize(entry));
} }
//Ender chest //Ender chest
Map<Integer,String> ender_chest = LocalJsonUtil.StringToEntryMap(resultSet.getString("enderchest")); Map<Integer,String> ender_chest = LocalJsonUtil.StringToEntryMap(resultSet.getString("enderchest"));
for (Map.Entry<Integer, String> entry : ender_chest.entrySet()) { for (Map.Entry<Integer, String> entry : ender_chest.entrySet()) {
serverPlayer.getEnderChestInventory().setItem(entry.getKey(),Deserialize(entry)); serverPlayer.getEnderChestInventory().setItem(entry.getKey(),deserialize(entry));
} }
//Effects //Effects
String effectData=resultSet.getString("effects"); String effectData=resultSet.getString("effects");
@ -104,9 +112,8 @@ public class VanillaSync {
serverPlayer.removeAllEffects(); serverPlayer.removeAllEffects();
Map<Integer, String> effects = LocalJsonUtil.StringToEntryMap(effectData); Map<Integer, String> effects = LocalJsonUtil.StringToEntryMap(effectData);
for (Map.Entry<Integer, String> entry : effects.entrySet()) { for (Map.Entry<Integer, String> entry : effects.entrySet()) {
CompoundTag effectTag = NbtUtils.snbtToStructure(entry.getValue().replace("|", ",")); CompoundNBT effectTag = JsonToNBT.parseTag(entry.getValue().replace("|", ","));
MobEffectInstance mobEffectInstance = MobEffectInstance.load(effectTag); EffectInstance mobEffectInstance = EffectInstance.load(effectTag);
assert mobEffectInstance != null;
serverPlayer.addEffect(mobEffectInstance); serverPlayer.addEffect(mobEffectInstance);
} }
} }
@ -120,7 +127,7 @@ public class VanillaSync {
byte [] bytes=resultSet.getString("advancements").getBytes(); byte [] bytes=resultSet.getString("advancements").getBytes();
Files.write(advancements.toPath(),bytes); Files.write(advancements.toPath(),bytes);
}else{ }else{
File[] files= ScanAdvancementsFile(player_uuid, gameDir); File[] files= scanAdvancementsFile(player_uuid, gameDir);
for (File file : files) { for (File file : files) {
if(file==null) continue; if(file==null) continue;
byte [] bytes=resultSet.getString("advancements").getBytes(); byte [] bytes=resultSet.getString("advancements").getBytes();
@ -137,7 +144,7 @@ public class VanillaSync {
} }
@SubscribeEvent @SubscribeEvent
public static void OnPlayerJoin(PlayerEvent.PlayerLoggedInEvent event){ public static void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event){
executorService.submit(()->{ executorService.submit(()->{
try { try {
doPlayerJoin(event); doPlayerJoin(event);
@ -148,19 +155,20 @@ public class VanillaSync {
} }
private static ItemStack Deserialize(Map.Entry<Integer, String> entry) throws CommandSyntaxException { public static ItemStack deserialize(Map.Entry<Integer, String> entry) throws CommandSyntaxException {
String nbt= entry.getValue().replace("|",",").replace("^","\"").replace("<","{").replace(">","}").replace("~", "'"); String nbt= entry.getValue().replace("|",",").replace("^","\"").replace("<","{").replace(">","}").replace("~", "'");
CompoundTag compoundTag = NbtUtils.snbtToStructure(nbt); CompoundNBT compoundTag = JsonToNBT.parseTag(nbt);
return ItemStack.of(compoundTag); return ItemStack.of(compoundTag);
} }
public static void doPlayerSaveToFile(PlayerEvent.SaveToFile event) throws SQLException, IOException, ClassNotFoundException, InstantiationException, IllegalAccessException { public static String serialize(String object){
return object.replace(",","|").replace("\"","^").replace("{","<").replace("}",">").replace("'","~");
}
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()); JDBCsetUp.executeUpdate("UPDATE server_info SET last_update=" + System.currentTimeMillis() + " WHERE id=" + JdbcConfig.SERVER_ID.get());
if(!event.getEntity().getTags().contains("player_synced")) return; if(!event.getEntity().getTags().contains("player_synced")) return;
Store(event.getEntity(),false,Dist.CLIENT.isDedicatedServer()); store(event.getPlayer(),false,Dist.CLIENT.isDedicatedServer());
//Mod support
ModsSupport modsSupport = new ModsSupport();
modsSupport.onPlayerLeave(event.getEntity());
} }
@SubscribeEvent @SubscribeEvent
@ -175,19 +183,18 @@ public class VanillaSync {
} }
@SubscribeEvent @SubscribeEvent
public static void onServerShutdown(ServerStoppedEvent event) throws SQLException { public static void onServerShutdown(FMLServerStoppedEvent event) throws SQLException {
JDBCsetUp.executeUpdate("UPDATE server_info SET enable=false WHERE id=" + JdbcConfig.SERVER_ID.get()); JDBCsetUp.executeUpdate("UPDATE server_info SET enable= '0' WHERE id=" + JdbcConfig.SERVER_ID.get()+";");
} }
public static void doPlayerLogout(PlayerEvent.PlayerLoggedOutEvent event) throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException, IOException { public static void doPlayerLogout(PlayerEvent.PlayerLoggedOutEvent event) throws SQLException, IOException {
if(!event.getEntity().getTags().contains("player_synced")) return; if(!event.getEntity().getTags().contains("player_synced")) return;
String player_uuid = event.getEntity().getUUID().toString(); String player_uuid = event.getEntity().getUUID().toString();
JDBCsetUp.executeUpdate("UPDATE player_data SET online=false WHERE uuid='"+player_uuid+"'"); JDBCsetUp.executeUpdate("UPDATE player_data SET online= '0' WHERE uuid='"+player_uuid+"';");
Store(event.getEntity(),false,Dist.CLIENT.isDedicatedServer()); store(event.getPlayer(),false,Dist.CLIENT.isDedicatedServer());
//Mod support //Mod support
ModsSupport modsSupport = new ModsSupport(); ModsSupport modsSupport = new ModsSupport();
modsSupport.onPlayerLeave(event.getEntity()); modsSupport.onPlayerLeave(event.getPlayer());
event.getEntity().removeTag("player_synced");
} }
@SubscribeEvent @SubscribeEvent
@ -202,39 +209,43 @@ public class VanillaSync {
} }
public static void Store(Player player, boolean init,boolean isServer) throws SQLException, IOException { public static void store(PlayerEntity player, boolean init, boolean isServer) throws SQLException, IOException {
String player_uuid = player.getUUID().toString(); String player_uuid = player.getUUID().toString();
//Easy part //Easy part
int XP = player.totalExperience; int XP = player.totalExperience;
int score=player.getScore(); int score=player.getScore();
int food_level=player.getFoodData().getFoodLevel(); int food_level=player.getFoodData().getFoodLevel();
int health=(int) player.getHealth(); int health=(int) player.getHealth();
//Left hand
String left_hand = serialize(player.getItemInHand(Hand.OFF_HAND).serializeNBT().toString());
//Cursor
String cursors = serialize(player.inventory.getCarried().serializeNBT().toString());
//Equipment //Equipment
Map<Integer,String> equipment =new HashMap<>() ; Map<Integer,String> equipment =new HashMap<>() ;
for (int i = 0; i < player.getInventory().armor.size(); i++) { for (int i = 0; i < player.inventory.armor.size(); i++) {
ItemStack itemStack = player.getInventory().armor.get(i); ItemStack itemStack = player.inventory.armor.get(i);
if(itemStack.isEmpty()) continue; if(itemStack.isEmpty()) continue;
equipment.put(i,itemStack.serializeNBT().toString().replace(",","|").replace("\"","^").replace("{","<").replace("}",">").replace("'","~")); equipment.put(i,serialize(itemStack.serializeNBT().toString()));
} }
//inventory //inventory
Inventory inventory = player.getInventory(); PlayerInventory inventory = player.inventory;
Map<Integer,String> inventoryMap=new HashMap<>(); Map<Integer,String> inventoryMap = new HashMap<>();
for (int i = 0; i < inventory.items.size(); i++) { for (int i = 0; i < inventory.items.size(); i++) {
CompoundTag itemNBT = inventory.items.get(i).serializeNBT(); CompoundNBT itemNBT = inventory.items.get(i).serializeNBT();
inventoryMap.put(i,itemNBT.toString().replace(",","|").replace("\"","^").replace("{","<").replace("}",">").replace("'","~")); inventoryMap.put(i,serialize(itemNBT.toString()));
} }
//EnderChest //EnderChest
Map<Integer, String> ender_chest=new HashMap<>(); Map<Integer, String> ender_chest = new HashMap<>();
for (int i=0;i< player.getEnderChestInventory().getContainerSize();i++) { for (int i=0;i< player.getEnderChestInventory().getContainerSize();i++) {
CompoundTag itemNBT = player.getEnderChestInventory().getItem(i).serializeNBT(); CompoundNBT itemNBT = player.getEnderChestInventory().getItem(i).serializeNBT();
ender_chest.put(i,itemNBT.toString().replace(",","|").replace("\"","^").replace("{","<").replace("}",">").replace("'","~")); ender_chest.put(i,serialize(itemNBT.toString()));
} }
//Effects //Effects
Map<MobEffect,MobEffectInstance> effects= player.getActiveEffectsMap(); Map<Effect, EffectInstance> effects= player.getActiveEffectsMap();
Map<Integer,String> effectMap=new HashMap<>(); Map<Integer,String> effectMap=new HashMap<>();
for (Map.Entry<MobEffect, MobEffectInstance> entry : effects.entrySet()) { for (Map.Entry<Effect, EffectInstance> entry : effects.entrySet()) {
CompoundTag effectTag= entry.getValue().save(new CompoundTag()); CompoundNBT effectTag= entry.getValue().save(new CompoundNBT());
effectMap.put(MobEffect.getId(entry.getKey()),effectTag.toString().replace(",","|")); effectMap.put(Effect.getId(entry.getKey()),effectTag.toString().replace(",","|"));
} }
//Advancements //Advancements
//File root = serverPlayer.getServer().getServerDirectory(); //File root = serverPlayer.getServer().getServerDirectory();
@ -244,7 +255,7 @@ public class VanillaSync {
advancements = new File(gameDir, JdbcConfig.SYNC_WORLD.get().get(0)+"/advancements"+"/"+player_uuid+".json"); advancements = new File(gameDir, JdbcConfig.SYNC_WORLD.get().get(0)+"/advancements"+"/"+player_uuid+".json");
}else{ }else{
// File gameDir = Minecraft.getInstance().gameDirectory; // File gameDir = Minecraft.getInstance().gameDirectory;
File[] files=ScanAdvancementsFile(player_uuid, gameDir); File[] files= scanAdvancementsFile(player_uuid, gameDir);
//Get LastModified //Get LastModified
long latestModifiedDate = 0; long latestModifiedDate = 0;
for (File file : files) { for (File file : files) {
@ -263,11 +274,11 @@ public class VanillaSync {
//SQL Operation //SQL Operation
if(init){ 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)"); JDBCsetUp.executeUpdate("INSERT INTO player_data (uuid,armor,inventory,enderchest,advancements,effects,xp,food_level,health,score,left_hand,cursors,online) VALUES ('"+player_uuid+"','"+equipment+"','"+inventoryMap+"','"+ender_chest+"','"+advancements+"','"+effectMap+"','"+XP+"','"+food_level+"','"+health+"','"+score+"','"+left_hand+"','"+cursors+"',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+"'"); }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+"',left_hand='"+left_hand+"',cursors='"+cursors+"' WHERE uuid = '"+player_uuid+"'");
} }
private static File[] ScanAdvancementsFile(String player_uuid, File gameDir) { private static File[] scanAdvancementsFile(String player_uuid, File gameDir) {
File[] files = new File[JdbcConfig.SYNC_WORLD.get().size()]; File[] files = new File[JdbcConfig.SYNC_WORLD.get().size()];
for (int i = 0; i < JdbcConfig.SYNC_WORLD.get().size(); i++) { 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"); File advanceFile=new File(gameDir, "saves/"+JdbcConfig.SYNC_WORLD.get().get(i)+"/advancements"+"/"+player_uuid+".json");
@ -277,15 +288,17 @@ public class VanillaSync {
return files; return files;
} }
// @SubscribeEvent static int tick = 0;
// public void RegisterCommand(RegisterCommandsEvent event){
// CommandDispatcher<CommandSourceStack> dispatcher=event.getDispatcher(); @SubscribeEvent
// LiteralCommandNode<CommandSourceStack> cmd = dispatcher.register( public static void onUpdate(TickEvent.ServerTickEvent event) throws SQLException {
// Commands.literal("serializeNBT").executes(context -> {context.getSource().sendSuccess(Component.literal(context.getSource().getPlayer().getItemInHand(InteractionHand.MAIN_HAND).serializeNBT().toString()),true); tick++;
// return 0; if(tick == 1800) {
// }) tick=0;
// ); long current = System.currentTimeMillis();
// } JDBCsetUp.executeUpdate("UPDATE server_info SET last_update ="+current+" WHERE id= "+ JdbcConfig.SERVER_ID.get());
}
}
} }

View File

@ -1,7 +1,5 @@
package vip.fubuki.playersync.util; package vip.fubuki.playersync.util;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import vip.fubuki.playersync.config.JdbcConfig; import vip.fubuki.playersync.config.JdbcConfig;
import java.sql.*; import java.sql.*;
@ -9,40 +7,73 @@ import java.sql.*;
public class JDBCsetUp { public class JDBCsetUp {
private static HikariDataSource dataSource;
public static void initDataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://"+JdbcConfig.HOST.get()+":"+JdbcConfig.PORT.get()+"?useUnicode=true&characterEncoding=utf-8&useSSL="+JdbcConfig.USE_SSL.get()+"&serverTimezone=UTC&allowPublicKeyRetrieval=true");
config.setUsername(JdbcConfig.USERNAME.get());
config.setPassword(JdbcConfig.PASSWORD.get());
dataSource = new HikariDataSource(config);
}
public static Connection getConnection() throws SQLException { public static Connection getConnection() throws SQLException {
if (dataSource == null) { String url= "jdbc:mysql://"+JdbcConfig.HOST.get()+":"+JdbcConfig.PORT.get()+"?useUnicode=true&characterEncoding=utf-8&useSSL="+JdbcConfig.USE_SSL.get()+"&serverTimezone=UTC&allowPublicKeyRetrieval=true";
initDataSource(); return DriverManager.getConnection(url, JdbcConfig.USERNAME.get(), JdbcConfig.PASSWORD.get());
}
return dataSource.getConnection();
} }
public static ResultSet executeQuery(String sql) throws SQLException{ public static QueryResult executeQuery(String sql) throws SQLException{
try (Connection connection = getConnection(); Connection connection = getConnection();
PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
return preparedStatement.executeQuery(); try (Statement useStatement = connection.createStatement()) {
useStatement.execute("USE " + JdbcConfig.DATABASE_NAME.get());
} }
PreparedStatement queryStatement = connection.prepareStatement(sql);
ResultSet resultSet = queryStatement.executeQuery();
return new QueryResult(connection,resultSet);
} }
public static void executeUpdate(String sql) throws SQLException{ public static void executeUpdate(String sql) throws SQLException{
executeUpdate(sql,false); try (Connection connection = getConnection()) {
try (Statement useStatement = connection.createStatement()) {
useStatement.execute("USE " + JdbcConfig.DATABASE_NAME.get());
}
try (PreparedStatement updateStatement = connection.prepareStatement(sql)) {
updateStatement.executeUpdate();
}
}
} }
public static void executeUpdate(String sql,boolean init) throws SQLException{ public static void update(String sql, String... argument) throws SQLException{
try (Connection connection = getConnection(); Connection connection = getConnection();
PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
if(!init) preparedStatement.executeUpdate("USE "+JdbcConfig.DATABASE_NAME.get()); try (Statement useStatement = connection.createStatement()) {
preparedStatement.executeUpdate(); useStatement.execute("USE " + JdbcConfig.DATABASE_NAME.get());
}
PreparedStatement updateStatement = connection.prepareStatement(sql);
for (int i = 1; i <= argument.length; i++) {
updateStatement.setString(i,argument[i]);
}
updateStatement.executeUpdate();
}
public static void executeUpdate(String sql, int i) throws SQLException{
try (Connection connection = getConnection()) {
try (PreparedStatement updateStatement = connection.prepareStatement(sql)) {
updateStatement.executeUpdate();
}
}
}
public static class QueryResult{
private final Connection connection;
private final ResultSet resultSet;
public QueryResult(Connection connection, ResultSet resultSet) {
this.connection = connection;
this.resultSet = resultSet;
}
public Connection getConnection() {
return connection;
}
public ResultSet getResultSet() {
return resultSet;
} }
} }
} }

View File

@ -1,7 +1,5 @@
package vip.fubuki.playersync.util; package vip.fubuki.playersync.util;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@ -14,7 +12,7 @@ public class PSThreadPoolFactory implements ThreadFactory {
threadNamePrefix = Prefix; threadNamePrefix = Prefix;
} }
@Override @Override
public Thread newThread(@NotNull Runnable runnable) { public Thread newThread(Runnable runnable) {
Thread thread = new Thread(runnable); Thread thread = new Thread(runnable);
thread.setName(threadNamePrefix + "-thread-" + threadIdx.getAndIncrement()); thread.setName(threadNamePrefix + "-thread-" + threadIdx.getAndIncrement());
return thread; return thread;

View File

@ -6,7 +6,7 @@
# The name of the mod loader type to load - for regular FML @Mod mods it should be javafml # The name of the mod loader type to load - for regular FML @Mod mods it should be javafml
modLoader="javafml" #mandatory modLoader="javafml" #mandatory
# A version range to match for said mod loader - for regular FML @Mod it will be the forge version # A version range to match for said mod loader - for regular FML @Mod it will be the forge version
loaderVersion="[43,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions. loaderVersion="[36,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions.
# The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties. # The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties.
# Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here. # Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here.
license="GPL-3.0 license" license="GPL-3.0 license"
@ -16,10 +16,7 @@ license="GPL-3.0 license"
[[mods]] #mandatory [[mods]] #mandatory
# The modid of the mod # The modid of the mod
modId="playersync" #mandatory modId="playersync" #mandatory
# The version number of the mod - there's a few well known ${} variables useable here or just hardcode it version="${file.jarVersion}" #mandatory
# ${file.jarVersion} will substitute the value of the Implementation-Version as read from the mod's JAR file metadata
# see the associated build.gradle script for how to populate this completely automatically during a build
version="1.2.0" #mandatory
# A display name for the mod # A display name for the mod
displayName="PlayerSync" #mandatory displayName="PlayerSync" #mandatory
# A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/ # A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/
@ -51,7 +48,7 @@ make multiserver players' data sync
# Does this dependency have to exist - if not, ordering below must be specified # Does this dependency have to exist - if not, ordering below must be specified
mandatory=true #mandatory mandatory=true #mandatory
# The version range of the dependency # The version range of the dependency
versionRange="[43,)" #mandatory versionRange="[36,37)" #mandatory
# An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory # An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory
ordering="NONE" ordering="NONE"
# Side this dependency is applied on - BOTH, CLIENT or SERVER # Side this dependency is applied on - BOTH, CLIENT or SERVER
@ -61,6 +58,6 @@ make multiserver players' data sync
modId="minecraft" modId="minecraft"
mandatory=true mandatory=true
# This version range declares a minimum of the current minecraft version up to but not including the next major version # This version range declares a minimum of the current minecraft version up to but not including the next major version
versionRange="[1.19.2,1.20)" versionRange="[1.16.5,1.17)"
ordering="NONE" ordering="NONE"
side="BOTH" side="BOTH"