Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18813dfd1a | ||
|
|
b9f4736f2c | ||
|
|
5666f79c88 | ||
|
|
fcfd299807 | ||
|
|
e75a793abd | ||
|
|
7e3b6d43b3 | ||
|
|
226bc39185 | ||
|
|
d16e42c505 | ||
|
|
758bfc3d92 | ||
|
|
eea7aa97b0 | ||
|
|
db455ec911 | ||
|
|
5eb33c5928 | ||
|
|
f3a3bb9be0 | ||
|
|
2931022721 | ||
|
|
76836f680f | ||
|
|
e7836a37a4 |
42
.github/workflows/build-1.18.yml
vendored
Normal file
42
.github/workflows/build-1.18.yml
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
name: Build-1.18
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "1.18.2" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Make Gradle Wrapper Executable
|
||||||
|
run: chmod +x ./gradlew
|
||||||
|
working-directory: ${{ github.workspace }}
|
||||||
|
|
||||||
|
- name: Validate Gradle Wrapper
|
||||||
|
uses: gradle/wrapper-validation-action@v1
|
||||||
|
|
||||||
|
- name: Set up JDK 17
|
||||||
|
uses: actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
java-version: '17'
|
||||||
|
distribution: 'temurin'
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
id: build
|
||||||
|
uses: gradle/gradle-build-action@v2
|
||||||
|
with:
|
||||||
|
arguments: build
|
||||||
|
env:
|
||||||
|
SNAPSHOT: true
|
||||||
|
|
||||||
|
- name: Build Artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: Player_Sync
|
||||||
|
path: |
|
||||||
|
build/libs/
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
17
build.gradle
17
build.gradle
|
|
@ -4,7 +4,7 @@ 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'
|
||||||
|
|
||||||
|
|
@ -13,7 +13,7 @@ java.toolchain.languageVersion = JavaLanguageVersion.of(17)
|
||||||
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.18.2'
|
||||||
|
|
||||||
//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.18.2-40.1.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.18.2-5.0.7.1")
|
||||||
jarJar.ranged(it, '[3.4.5,)')
|
compileOnly fg.deobf("top.theillusivec4.curios:curios-forge:1.18.2-5.0.7.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.
|
||||||
|
|
|
||||||
|
|
@ -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.18.2-1.3.4
|
||||||
|
|
@ -17,6 +17,7 @@ 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)
|
||||||
|
|
@ -41,13 +42,47 @@ public class PlayerSync
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void onServerStarting(ServerStartingEvent event) throws SQLException {
|
public void onServerStarting(ServerStartingEvent 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,
|
||||||
|
`inventory` mediumblob,
|
||||||
|
`armor` blob,
|
||||||
|
`advancements` blob,
|
||||||
|
`enderchest` mediumblob,
|
||||||
|
`effects` blob,
|
||||||
|
`left_hand` blob,
|
||||||
|
`cursors` blob,
|
||||||
|
`xp` int DEFAULT NULL,
|
||||||
|
`food_level` int DEFAULT NULL,
|
||||||
|
`score` int DEFAULT NULL,
|
||||||
|
`health` int DEFAULT NULL,
|
||||||
|
`online` tinyint(1) DEFAULT NULL,
|
||||||
|
`last_server` int DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`uuid`)
|
||||||
|
);""");
|
||||||
|
|
||||||
|
JDBCsetUp.QueryResult queryResult = JDBCsetUp.executeQuery("""
|
||||||
|
SELECT COUNT(*) AS column_count
|
||||||
|
FROM INFORMATION_SCHEMA.COLUMNS
|
||||||
|
WHERE TABLE_NAME = 'player_data';
|
||||||
|
""");
|
||||||
|
|
||||||
|
ResultSet resultSet = queryResult.resultSet();
|
||||||
|
int columnCount = 0;
|
||||||
|
if(resultSet.next()) {
|
||||||
|
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 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("""
|
JDBCsetUp.executeUpdate("""
|
||||||
CREATE TABLE IF NOT EXISTS server_info (
|
CREATE TABLE IF NOT EXISTS server_info (
|
||||||
`id` INT NOT NULL,
|
`id` INT NOT NULL,
|
||||||
|
|
@ -59,6 +94,7 @@ public class PlayerSync
|
||||||
"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))");
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
|
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(1,Integer.MAX_VALUE-1));
|
SERVER_ID = COMMON_BUILDER.comment("the server id should be unique").define("Server_id", new Random().nextInt(1,Integer.MAX_VALUE-1));
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,44 +1,127 @@
|
||||||
package vip.fubuki.playersync.sync;
|
package vip.fubuki.playersync.sync;
|
||||||
|
|
||||||
|
import net.minecraft.network.chat.ChatType;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.server.players.PlayerList;
|
import net.minecraft.server.players.PlayerList;
|
||||||
|
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();
|
||||||
|
Component textComponents = Component.nullToEmpty(line);
|
||||||
|
playerList.broadcastMessage(textComponents, 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.getPlayer().getServer()).getPlayerList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void onPlayerLeave(PlayerEvent.PlayerLoggedOutEvent event){
|
||||||
|
playerList= Objects.requireNonNull(event.getPlayer().getServer()).getPlayerList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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(Player 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.resultSet();
|
||||||
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(NbtUtils.snbtToStructure(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.connection().close();
|
||||||
}else{
|
}else{
|
||||||
StoreCurios(player,true);
|
StoreCurios(player,true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPlayerLeave(Player player) throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException {
|
public void onPlayerLeave(Player 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(Player 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,16 @@ 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.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.NbtUtils;
|
import net.minecraft.nbt.NbtUtils;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.TranslatableComponent;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.effect.MobEffect;
|
import net.minecraft.world.effect.MobEffect;
|
||||||
import net.minecraft.world.effect.MobEffectInstance;
|
import net.minecraft.world.effect.MobEffectInstance;
|
||||||
import net.minecraft.world.entity.player.Inventory;
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
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.event.server.ServerStoppedEvent;
|
||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
|
|
@ -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+"'");
|
||||||
|
ResultSet resultSet=queryResult.resultSet();
|
||||||
ServerPlayer serverPlayer = (ServerPlayer) event.getEntity();
|
ServerPlayer serverPlayer = (ServerPlayer) 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.resultSet();
|
||||||
|
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.resultSet();
|
||||||
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 TranslatableComponent("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(InteractionHand.OFF_HAND,ItemStack.of(NbtUtils.snbtToStructure(resultSet.getString("left_hand").replace("|",",").replace("^","\"").replace("<","{").replace(">","}").replace("~", "'"))));
|
||||||
|
//Cursor
|
||||||
|
serverPlayer.containerMenu.setCarried(ItemStack.of(NbtUtils.snbtToStructure(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.getInventory().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.getInventory().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");
|
||||||
|
|
@ -120,7 +128,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 +145,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 +156,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);
|
CompoundTag compoundTag = NbtUtils.snbtToStructure(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
|
||||||
|
|
@ -176,22 +185,21 @@ public class VanillaSync {
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void onServerShutdown(ServerStoppedEvent event) throws SQLException {
|
public static void onServerShutdown(ServerStoppedEvent 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;
|
|
||||||
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
|
|
||||||
ModsSupport modsSupport = new ModsSupport();
|
|
||||||
modsSupport.onPlayerLeave(event.getEntity());
|
|
||||||
event.getEntity().removeTag("player_synced");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void onPlayerLogout(PlayerEvent.PlayerLoggedOutEvent event) {
|
public static void onPlayerLogout(PlayerEvent.PlayerLoggedOutEvent event) throws SQLException {
|
||||||
|
//Mod support
|
||||||
|
ModsSupport modsSupport = new ModsSupport();
|
||||||
|
modsSupport.onPlayerLeave(event.getPlayer());
|
||||||
executorService.submit(()->{
|
executorService.submit(()->{
|
||||||
try {
|
try {
|
||||||
doPlayerLogout(event);
|
doPlayerLogout(event);
|
||||||
|
|
@ -202,32 +210,36 @@ public class VanillaSync {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Store(Player player, boolean init,boolean isServer) throws SQLException, IOException {
|
public static void store(Player 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(InteractionHand.OFF_HAND).serializeNBT().toString());
|
||||||
|
//Cursor
|
||||||
|
String cursors = serialize(player.containerMenu.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.getInventory().armor.size(); i++) {
|
||||||
ItemStack itemStack = player.getInventory().armor.get(i);
|
ItemStack itemStack = player.getInventory().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();
|
Inventory inventory = player.getInventory();
|
||||||
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();
|
CompoundTag 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();
|
CompoundTag 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<MobEffect,MobEffectInstance> effects= player.getActiveEffectsMap();
|
||||||
|
|
@ -244,7 +256,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 +275,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 +289,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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,58 @@ 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()) {
|
||||||
}
|
|
||||||
|
|
||||||
public static void executeUpdate(String sql,boolean init) throws SQLException{
|
try (Statement useStatement = connection.createStatement()) {
|
||||||
try (Connection connection = getConnection();
|
useStatement.execute("USE " + JdbcConfig.DATABASE_NAME.get());
|
||||||
PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
|
}
|
||||||
if(!init) preparedStatement.executeUpdate("USE "+JdbcConfig.DATABASE_NAME.get());
|
|
||||||
preparedStatement.executeUpdate();
|
try (PreparedStatement updateStatement = connection.prepareStatement(sql)) {
|
||||||
|
updateStatement.executeUpdate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void update(String sql, String... argument) throws SQLException{
|
||||||
|
Connection connection = getConnection();
|
||||||
|
|
||||||
|
try (Statement useStatement = connection.createStatement()) {
|
||||||
|
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 record QueryResult(Connection connection, ResultSet resultSet) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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="[40,)" #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"
|
||||||
|
|
@ -19,7 +19,7 @@ modId="playersync" #mandatory
|
||||||
# The version number of the mod - there's a few well known ${} variables useable here or just hardcode it
|
# The version number of the mod - there's a few well known ${} variables useable here or just hardcode it
|
||||||
# ${file.jarVersion} will substitute the value of the Implementation-Version as read from the mod's JAR file metadata
|
# ${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
|
# see the associated build.gradle script for how to populate this completely automatically during a build
|
||||||
version="1.2.0" #mandatory
|
version="${file.jarVersion}" #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 +51,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="[40,)" #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 +61,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.18.2,)"
|
||||||
ordering="NONE"
|
ordering="NONE"
|
||||||
side="BOTH"
|
side="BOTH"
|
||||||
Loading…
Reference in New Issue
Block a user