diff --git a/api/src/main/java/net/william278/husksync/bukkit/api/HuskSyncAPI.java b/api/src/main/java/net/william278/husksync/bukkit/api/HuskSyncAPI.java index 375f4ded..48a4df32 100644 --- a/api/src/main/java/net/william278/husksync/bukkit/api/HuskSyncAPI.java +++ b/api/src/main/java/net/william278/husksync/bukkit/api/HuskSyncAPI.java @@ -33,7 +33,7 @@ public class HuskSyncAPI { } /** - * (INTERNAL) Map of API requests that are processed by the bukkit plugin that implements the API. + * (Internal only) Map of API requests that are processed by the bukkit plugin that implements the API. */ public static HashMap> apiRequests = new HashMap<>(); @@ -47,7 +47,7 @@ public class HuskSyncAPI { public CompletableFuture getPlayerData(UUID playerUUID) throws IOException { // Create the request to be completed final UUID requestUUID = UUID.randomUUID(); - apiRequests.put(requestUUID, new CompletableFuture<>()); + apiRequests.put(requestUUID, new CompletableFuture<>()); // Remove the request from the map on completion apiRequests.get(requestUUID).whenComplete((playerData, throwable) -> apiRequests.remove(requestUUID)); diff --git a/bukkit/src/main/java/net/william278/husksync/HuskSyncBukkit.java b/bukkit/src/main/java/net/william278/husksync/HuskSyncBukkit.java index 164d07e9..4757bc31 100644 --- a/bukkit/src/main/java/net/william278/husksync/HuskSyncBukkit.java +++ b/bukkit/src/main/java/net/william278/husksync/HuskSyncBukkit.java @@ -144,7 +144,7 @@ public final class HuskSyncBukkit extends JavaPlugin { if (HuskSyncBukkit.handshakeCompleted && !HuskSyncBukkit.isMySqlPlayerDataBridgeInstalled && Bukkit.getOnlinePlayers().size() > 0) { getLogger().info("Saving data for remaining online players..."); for (Player player : Bukkit.getOnlinePlayers()) { - PlayerSetter.updatePlayerData(player); + PlayerSetter.updatePlayerData(player, false); } getLogger().info("Data save complete!"); } diff --git a/bukkit/src/main/java/net/william278/husksync/bukkit/config/ConfigLoader.java b/bukkit/src/main/java/net/william278/husksync/bukkit/config/ConfigLoader.java index 82a38d27..52d50cd7 100644 --- a/bukkit/src/main/java/net/william278/husksync/bukkit/config/ConfigLoader.java +++ b/bukkit/src/main/java/net/william278/husksync/bukkit/config/ConfigLoader.java @@ -27,6 +27,7 @@ public class ConfigLoader { Settings.syncFlight = config.getBoolean("synchronisation_settings.flight", false); Settings.useNativeImplementation = config.getBoolean("native_advancement_synchronization", false); + Settings.saveOnWorldSave = config.getBoolean("save_on_world_save", true); Settings.synchronizationTimeoutRetryDelay = config.getLong("synchronization_timeout_retry_delay", 15L); } diff --git a/bukkit/src/main/java/net/william278/husksync/bukkit/listener/BukkitEventListener.java b/bukkit/src/main/java/net/william278/husksync/bukkit/listener/BukkitEventListener.java index a823aeea..0f16ddb7 100644 --- a/bukkit/src/main/java/net/william278/husksync/bukkit/listener/BukkitEventListener.java +++ b/bukkit/src/main/java/net/william278/husksync/bukkit/listener/BukkitEventListener.java @@ -15,6 +15,7 @@ import org.bukkit.event.entity.EntityPickupItemEvent; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.inventory.InventoryOpenEvent; import org.bukkit.event.player.*; +import org.bukkit.event.world.WorldSaveEvent; import java.io.IOException; import java.util.logging.Level; @@ -38,7 +39,7 @@ public class BukkitEventListener implements Listener { return; // If the plugin has not been initialized correctly // Update the player's data - Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> PlayerSetter.updatePlayerData(player)); + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> PlayerSetter.updatePlayerData(player, true)); } @EventHandler(priority = EventPriority.LOWEST) @@ -145,4 +146,14 @@ public class BukkitEventListener implements Listener { event.setCancelled(true); // If the plugin / player has not been set } } + + @EventHandler(priority = EventPriority.NORMAL) + public void onWorldSave(WorldSaveEvent event) { + if (!plugin.isEnabled() || !HuskSyncBukkit.handshakeCompleted) { + return; + } + for (Player playerInWorld : event.getWorld().getPlayers()) { + PlayerSetter.updatePlayerData(playerInWorld, false); + } + } } diff --git a/bukkit/src/main/java/net/william278/husksync/bukkit/util/PlayerSetter.java b/bukkit/src/main/java/net/william278/husksync/bukkit/util/PlayerSetter.java index 00434b3d..ec819ed6 100644 --- a/bukkit/src/main/java/net/william278/husksync/bukkit/util/PlayerSetter.java +++ b/bukkit/src/main/java/net/william278/husksync/bukkit/util/PlayerSetter.java @@ -95,15 +95,16 @@ public class PlayerSetter { /** * Update a {@link Player}'s data, sending it to the proxy * - * @param player {@link Player} to send data to proxy + * @param player {@link Player} to send data to proxy + * @param bounceBack whether the plugin should bounce-back the updated data to the player (used for server switching) */ - public static void updatePlayerData(Player player) { + public static void updatePlayerData(Player player, boolean bounceBack) { // Send a redis message with the player's last updated PlayerData version UUID and their new PlayerData try { final String serializedPlayerData = getNewSerializedPlayerData(player); new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_UPDATE, new RedisMessage.MessageTarget(Settings.ServerType.PROXY, null, Settings.cluster), - serializedPlayerData).send(); + serializedPlayerData, Boolean.toString(bounceBack)).send(); } catch (IOException e) { plugin.getLogger().log(Level.SEVERE, "Failed to send a PlayerData update to the proxy", e); } @@ -280,7 +281,7 @@ public class PlayerSetter { final Object playerAdvancements = AdvancementUtils.getPlayerAdvancements(player); // Clear - AdvancementUtils.clearPlayerAdvancements(playerAdvancements); + AdvancementUtils.clearPlayerAdvancements(playerAdvancements); AdvancementUtils.clearVisibleAdvancements(playerAdvancements); advancementRecords.forEach(advancementRecord -> { diff --git a/bukkit/src/main/resources/config.yml b/bukkit/src/main/resources/config.yml index d0c7e7e2..1fb6a37b 100644 --- a/bukkit/src/main/resources/config.yml +++ b/bukkit/src/main/resources/config.yml @@ -18,4 +18,5 @@ synchronisation_settings: cluster_id: 'main' check_for_updates: true synchronization_timeout_retry_delay: 15 +save_on_world_save: true native_advancement_synchronization: false \ No newline at end of file diff --git a/bungeecord/src/main/java/net/william278/husksync/bungeecord/listener/BungeeRedisListener.java b/bungeecord/src/main/java/net/william278/husksync/bungeecord/listener/BungeeRedisListener.java index 377acb42..966726a3 100644 --- a/bungeecord/src/main/java/net/william278/husksync/bungeecord/listener/BungeeRedisListener.java +++ b/bungeecord/src/main/java/net/william278/husksync/bungeecord/listener/BungeeRedisListener.java @@ -92,7 +92,8 @@ public class BungeeRedisListener extends RedisListener { case PLAYER_DATA_UPDATE -> ProxyServer.getInstance().getScheduler().runAsync(plugin, () -> { // Deserialize the PlayerData received PlayerData playerData; - final String serializedPlayerData = message.getMessageData(); + final String serializedPlayerData = message.getMessageDataElements()[0]; + final boolean bounceBack = Boolean.parseBoolean(message.getMessageDataElements()[1]); try { playerData = (PlayerData) RedisMessage.deserialize(serializedPlayerData); } catch (IOException | ClassNotFoundException e) { @@ -110,7 +111,7 @@ public class BungeeRedisListener extends RedisListener { } // Reply with the player data if they are still online (switching server) - if (Settings.bounceBackSynchronisation) { + if (Settings.bounceBackSynchronisation && bounceBack) { try { ProxiedPlayer player = ProxyServer.getInstance().getPlayer(playerData.getPlayerUUID()); if (player != null) { diff --git a/common/src/main/java/net/william278/husksync/Settings.java b/common/src/main/java/net/william278/husksync/Settings.java index 7e0cea9c..19712f90 100644 --- a/common/src/main/java/net/william278/husksync/Settings.java +++ b/common/src/main/java/net/william278/husksync/Settings.java @@ -70,8 +70,8 @@ public class Settings { public static boolean syncAdvancements; public static boolean syncLocation; public static boolean syncFlight; - public static long synchronizationTimeoutRetryDelay; + public static boolean saveOnWorldSave; public static boolean useNativeImplementation; // This Cluster ID diff --git a/velocity/src/main/java/net/william278/husksync/velocity/listener/VelocityRedisListener.java b/velocity/src/main/java/net/william278/husksync/velocity/listener/VelocityRedisListener.java index 5ac95d91..e37eec47 100644 --- a/velocity/src/main/java/net/william278/husksync/velocity/listener/VelocityRedisListener.java +++ b/velocity/src/main/java/net/william278/husksync/velocity/listener/VelocityRedisListener.java @@ -89,7 +89,8 @@ public class VelocityRedisListener extends RedisListener { case PLAYER_DATA_UPDATE -> plugin.getProxyServer().getScheduler().buildTask(plugin, () -> { // Deserialize the PlayerData received PlayerData playerData; - final String serializedPlayerData = message.getMessageData(); + final String serializedPlayerData = message.getMessageDataElements()[0]; + final boolean bounceBack = Boolean.parseBoolean(message.getMessageDataElements()[1]); try { playerData = (PlayerData) RedisMessage.deserialize(serializedPlayerData); } catch (IOException | ClassNotFoundException e) { @@ -107,7 +108,7 @@ public class VelocityRedisListener extends RedisListener { } // Reply with the player data if they are still online (switching server) - if (Settings.bounceBackSynchronisation) { + if (Settings.bounceBackSynchronisation && bounceBack) { Optional updatingPlayer = plugin.getProxyServer().getPlayer(playerData.getPlayerUUID()); updatingPlayer.ifPresent(player -> { try {