From 94433229b7f23512390d571c7c69e97704c3cfbb Mon Sep 17 00:00:00 2001 From: EoD <293499+EoD@users.noreply.github.com> Date: Sat, 26 Apr 2025 01:40:21 +0000 Subject: [PATCH 1/3] read level-name for servers from WorldData --- .../fubuki/playersync/config/JdbcConfig.java | 2 +- .../fubuki/playersync/sync/VanillaSync.java | 24 +++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/main/java/vip/fubuki/playersync/config/JdbcConfig.java b/src/main/java/vip/fubuki/playersync/config/JdbcConfig.java index da7f978..dbe3dad 100644 --- a/src/main/java/vip/fubuki/playersync/config/JdbcConfig.java +++ b/src/main/java/vip/fubuki/playersync/config/JdbcConfig.java @@ -36,7 +36,7 @@ public class JdbcConfig { PASSWORD = COMMON_BUILDER.comment("password").define("password", "pleaseChangeThisPassword"); 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)); - 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 on a server, leave array empty.").define("sync_world", new ArrayList<>()); 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"); diff --git a/src/main/java/vip/fubuki/playersync/sync/VanillaSync.java b/src/main/java/vip/fubuki/playersync/sync/VanillaSync.java index 1fb44a7..897db93 100644 --- a/src/main/java/vip/fubuki/playersync/sync/VanillaSync.java +++ b/src/main/java/vip/fubuki/playersync/sync/VanillaSync.java @@ -12,6 +12,7 @@ import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.storage.WorldData; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.entity.player.PlayerEvent; @@ -142,7 +143,7 @@ public class VanillaSync { // Restore Advancements File gameDir = Objects.requireNonNull(serverPlayer.getServer()).getServerDirectory(); if (Dist.CLIENT.isDedicatedServer()){ - File advancements = new File(gameDir, JdbcConfig.SYNC_WORLD.get().get(0) + "/advancements" + "/" + player_uuid + ".json"); + File advancements = new File(gameDir, getSyncWorldForServer() + "/advancements" + "/" + player_uuid + ".json"); if (!advancements.exists()) { advancements.createNewFile(); } @@ -319,7 +320,7 @@ public class VanillaSync { File advancements = null; File gameDir = Objects.requireNonNull(player.getServer()).getServerDirectory(); if (isServer) { - advancements = new File(gameDir, JdbcConfig.SYNC_WORLD.get().get(0) + "/advancements" + "/" + player_uuid + ".json"); + advancements = new File(gameDir, getSyncWorldForServer() + "/advancements" + "/" + player_uuid + ".json"); } else { File[] files = scanAdvancementsFile(player_uuid, gameDir); long latestModifiedDate = 0; @@ -345,6 +346,25 @@ public class VanillaSync { } } + private static String getSyncWorldForServer() { + if (!JdbcConfig.SYNC_WORLD.get().isEmpty()) { + PlayerSync.LOGGER.warn("Using configuration 'sync_world' on servers is deprecated. Please leave the array empty. Falling back to first entry."); + return JdbcConfig.SYNC_WORLD.get().get(0); + } + + final MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + if (server == null) { + PlayerSync.LOGGER.error("Unable to get current server. Assuming default level-name 'world'."); + return "world"; + } + + final WorldData worldData = server.getWorldData(); + final String levelName = worldData.getLevelName(); + PlayerSync.LOGGER.debug("Using server level-name: " + levelName); + + return levelName; + } + private static File[] scanAdvancementsFile(String player_uuid, File gameDir) { File[] files = new File[JdbcConfig.SYNC_WORLD.get().size()]; for (int i = 0; i < JdbcConfig.SYNC_WORLD.get().size(); i++) { From 37d0eb29315afcec64d9afa9d71d3f4526aaabf5 Mon Sep 17 00:00:00 2001 From: EoD <293499+EoD@users.noreply.github.com> Date: Sat, 26 Apr 2025 16:04:03 +0000 Subject: [PATCH 2/3] fix storing advancement json on dedicated servers --- .../fubuki/playersync/sync/VanillaSync.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/java/vip/fubuki/playersync/sync/VanillaSync.java b/src/main/java/vip/fubuki/playersync/sync/VanillaSync.java index 897db93..b71116f 100644 --- a/src/main/java/vip/fubuki/playersync/sync/VanillaSync.java +++ b/src/main/java/vip/fubuki/playersync/sync/VanillaSync.java @@ -53,7 +53,7 @@ public class VanillaSync { ResultSet rs1 = qr1.resultSet(); ServerPlayer serverPlayer = (ServerPlayer) event.getEntity(); if (!rs1.next()){ - store(event.getEntity(), true, Dist.CLIENT.isDedicatedServer()); + store(event.getEntity(), true); return; } boolean online = rs1.getBoolean("online"); @@ -233,7 +233,7 @@ public class VanillaSync { public static void doPlayerSaveToFile(PlayerEvent.SaveToFile event) throws SQLException, IOException { JDBCsetUp.executeUpdate("UPDATE server_info SET last_update=" + System.currentTimeMillis() + " WHERE id=" + JdbcConfig.SERVER_ID.get()); if (!event.getEntity().getTags().contains("player_synced")) return; - store(event.getEntity(), false, Dist.CLIENT.isDedicatedServer()); + store(event.getEntity(), false); } @SubscribeEvent @@ -255,7 +255,7 @@ public class VanillaSync { public static void doPlayerLogout(PlayerEvent.PlayerLoggedOutEvent event) throws SQLException, IOException { String player_uuid = event.getEntity().getUUID().toString(); JDBCsetUp.executeUpdate("UPDATE player_data SET online= '0' WHERE uuid='" + player_uuid + "'"); - store(event.getEntity(), false, Dist.CLIENT.isDedicatedServer()); + store(event.getEntity(), false); } @SubscribeEvent @@ -272,7 +272,7 @@ public class VanillaSync { }); } - public static void store(Player player, boolean init, boolean isServer) throws SQLException, IOException { + public static void store(Player player, boolean init) throws SQLException, IOException { String player_uuid = player.getUUID().toString(); PlayerSync.LOGGER.info("Storing data for player " + player_uuid + " (init=" + init + ")"); @@ -319,9 +319,12 @@ public class VanillaSync { // Advancements File advancements = null; File gameDir = Objects.requireNonNull(player.getServer()).getServerDirectory(); - if (isServer) { + final MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + if (server != null && server.isDedicatedServer() ) { + PlayerSync.LOGGER.trace("Reading dedicated server advancements"); advancements = new File(gameDir, getSyncWorldForServer() + "/advancements" + "/" + player_uuid + ".json"); } else { + PlayerSync.LOGGER.debug("Reading non-dedicated server advancements"); File[] files = scanAdvancementsFile(player_uuid, gameDir); long latestModifiedDate = 0; for (File file : files) { @@ -334,9 +337,13 @@ public class VanillaSync { } byte[] bytes = new byte[0]; if (advancements != null) { + PlayerSync.LOGGER.debug("Storing advancements for " + player_uuid + " from " + advancements.toPath()); bytes = Files.readAllBytes(advancements.toPath()); + } else { + PlayerSync.LOGGER.error("Unable to save advancements for player " + player_uuid); } String json = new String(bytes, StandardCharsets.UTF_8); + PlayerSync.LOGGER.trace("Storing advancements for player " + player_uuid + ": " + json); // SQL Operation for player data if (init) { @@ -408,7 +415,7 @@ public class VanillaSync { executorService.submit(() -> { try { // Call the same store method used in logout and file save events. - store(player, false, server.isDedicatedServer()); + store(player, false); } catch (Exception e) { PlayerSync.LOGGER.error("Error auto-saving player " + player.getUUID(), e); } From 7ece81435700128f22aa2764edc620826d95b941 Mon Sep 17 00:00:00 2001 From: EoD <293499+EoD@users.noreply.github.com> Date: Sat, 26 Apr 2025 16:39:04 +0000 Subject: [PATCH 3/3] fix advancement json restore Previously, the json was written too late and never reloaded. This commit moves the advancement restoration from the PlayerLoggedInEvent to the earlier onDatapackSyncEvent. At the same time, it forces a reload of the json files, making sure the client is informed about the update advancements. --- .../fubuki/playersync/sync/VanillaSync.java | 84 +++++++++++++++---- 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/src/main/java/vip/fubuki/playersync/sync/VanillaSync.java b/src/main/java/vip/fubuki/playersync/sync/VanillaSync.java index b71116f..2598880 100644 --- a/src/main/java/vip/fubuki/playersync/sync/VanillaSync.java +++ b/src/main/java/vip/fubuki/playersync/sync/VanillaSync.java @@ -5,6 +5,7 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.PlayerAdvancements; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.effect.MobEffect; @@ -14,6 +15,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.storage.WorldData; import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.event.OnDatapackSyncEvent; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.event.server.ServerStoppedEvent; @@ -44,6 +46,70 @@ public class VanillaSync { static ExecutorService executorService = Executors.newCachedThreadPool(new PSThreadPoolFactory("PlayerSync")); + @SubscribeEvent + public static void onDataPackSyncEvent(OnDatapackSyncEvent event) throws SQLException, IOException { + final ServerPlayer serverPlayer = event.getPlayer(); + if (serverPlayer == null) { + PlayerSync.LOGGER.debug("No player joining"); + return; + } + + final String player_uuid = serverPlayer.getUUID().toString(); + PlayerSync.LOGGER.info("Player entity joining level " + player_uuid); + + JDBCsetUp.QueryResult advancementsQuery = JDBCsetUp + .executeQuery("SELECT advancements FROM player_data WHERE uuid='" + player_uuid + "'"); + ResultSet advancementsResultSet = advancementsQuery.resultSet(); + + if (!advancementsResultSet.next()) { + PlayerSync.LOGGER.debug("No advancements found for player " + player_uuid); + advancementsResultSet.close(); + return; + } + + // Restore Advancements + File gameDir = Objects.requireNonNull(serverPlayer.getServer()).getServerDirectory(); + + final MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + if (server != null && server.isDedicatedServer()) { + PlayerSync.LOGGER.debug("Attempting to write dedicated server advancement file"); + File advancements = new File(gameDir, + getSyncWorldForServer() + "/advancements" + "/" + player_uuid + ".json"); + byte[] bytes = advancementsResultSet.getString("advancements").getBytes(); + advancementsResultSet.close(); + + // only create advancements file if at least "{}" has been stored in the field + if (bytes.length < 2) { + PlayerSync.LOGGER.debug("Skip writing advancements for player " + player_uuid); + return; + } + + if (!advancements.exists()) { + advancements.createNewFile(); + PlayerSync.LOGGER.info("Creating new advancement file for player " + player_uuid); + } + PlayerSync.LOGGER.debug("Writing advancement file " + advancements.toPath() + " for player " + player_uuid); + PlayerSync.LOGGER.trace("Writing advancement file for player " + player_uuid + ": " + + new String(bytes, StandardCharsets.UTF_8)); + Files.write(advancements.toPath(), bytes); + + // reload the json files on the server after updating them + PlayerAdvancements playeradvancements = serverPlayer.getAdvancements(); + playeradvancements.reload(server.getAdvancements()); + + } else { + PlayerSync.LOGGER.debug("Writing non-dedicated server advancement files"); + File[] files = scanAdvancementsFile(player_uuid, gameDir); + for (File file : files) { + if (file == null) + continue; + byte[] bytes = advancementsResultSet.getString("advancements").getBytes(); + Files.write(file.toPath(), bytes); + } + advancementsResultSet.close(); + } + } + public static void doPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) throws SQLException, CommandSyntaxException, IOException { String player_uuid = event.getEntity().getUUID().toString(); PlayerSync.LOGGER.info("Starting synchronization for player " + player_uuid); @@ -139,24 +205,6 @@ public class VanillaSync { } } } - - // Restore Advancements - File gameDir = Objects.requireNonNull(serverPlayer.getServer()).getServerDirectory(); - if (Dist.CLIENT.isDedicatedServer()){ - File advancements = new File(gameDir, getSyncWorldForServer() + "/advancements" + "/" + player_uuid + ".json"); - if (!advancements.exists()) { - advancements.createNewFile(); - } - byte[] bytes = rs2.getString("advancements").getBytes(); - Files.write(advancements.toPath(), bytes); - } else { - File[] files = scanAdvancementsFile(player_uuid, gameDir); - for (File file : files) { - if (file == null) continue; - byte[] bytes = rs2.getString("advancements").getBytes(); - Files.write(file.toPath(), bytes); - } - } } // Mod support