diff --git a/common/src/main/java/net/william278/husksync/api/BaseHuskSyncAPI.java b/common/src/main/java/net/william278/husksync/api/BaseHuskSyncAPI.java
index fe1fc24f..3827e8c6 100644
--- a/common/src/main/java/net/william278/husksync/api/BaseHuskSyncAPI.java
+++ b/common/src/main/java/net/william278/husksync/api/BaseHuskSyncAPI.java
@@ -72,7 +72,7 @@ public abstract class BaseHuskSyncAPI {
public final CompletableFuture> getUserData(@NotNull User user) {
return CompletableFuture.supplyAsync(() -> {
if (user instanceof OnlineUser) {
- return Optional.of(((OnlineUser) user).getUserData().join());
+ return ((OnlineUser) user).getUserData(plugin.getLoggingAdapter()).join();
} else {
return plugin.getDatabase().getCurrentUserData(user).join().map(UserDataSnapshot::userData);
}
@@ -103,8 +103,8 @@ public abstract class BaseHuskSyncAPI {
* @since 2.0
*/
public final CompletableFuture saveUserData(@NotNull OnlineUser user) {
- return CompletableFuture.runAsync(() -> user.getUserData().thenAccept(userData ->
- plugin.getDatabase().setUserData(user, userData, DataSaveCause.API).join()));
+ return CompletableFuture.runAsync(() -> user.getUserData(plugin.getLoggingAdapter()).thenAccept(optionalUserData -> optionalUserData.ifPresent(
+ userData -> plugin.getDatabase().setUserData(user, userData, DataSaveCause.API).join())));
}
/**
diff --git a/common/src/main/java/net/william278/husksync/listener/EventListener.java b/common/src/main/java/net/william278/husksync/listener/EventListener.java
index 3d55888b..5c0f98d6 100644
--- a/common/src/main/java/net/william278/husksync/listener/EventListener.java
+++ b/common/src/main/java/net/william278/husksync/listener/EventListener.java
@@ -148,9 +148,10 @@ public abstract class EventListener {
if (usersAwaitingSync.contains(user.uuid)) {
return;
}
- plugin.getRedisManager().setUserServerSwitch(user).thenRun(() -> user.getUserData().thenAccept(
- userData -> plugin.getRedisManager().setUserData(user, userData).thenRun(
- () -> plugin.getDatabase().setUserData(user, userData, DataSaveCause.DISCONNECT).join())));
+ plugin.getRedisManager().setUserServerSwitch(user).thenRun(() -> user.getUserData(plugin.getLoggingAdapter()).thenAccept(
+ optionalUserData -> optionalUserData.ifPresent(
+ userData -> plugin.getRedisManager().setUserData(user, userData).thenRun(
+ () -> plugin.getDatabase().setUserData(user, userData, DataSaveCause.DISCONNECT).join()))));
usersAwaitingSync.remove(user.uuid);
}
@@ -163,8 +164,8 @@ public abstract class EventListener {
if (disabling || !plugin.getSettings().getBooleanValue(Settings.ConfigOption.SYNCHRONIZATION_SAVE_ON_WORLD_SAVE)) {
return;
}
- usersInWorld.forEach(user -> plugin.getDatabase().setUserData(user, user.getUserData().join(),
- DataSaveCause.WORLD_SAVE).join());
+ usersInWorld.forEach(user -> user.getUserData(plugin.getLoggingAdapter()).join().ifPresent(
+ userData -> plugin.getDatabase().setUserData(user, userData, DataSaveCause.WORLD_SAVE).join()));
}
/**
@@ -207,8 +208,9 @@ public abstract class EventListener {
public final void handlePluginDisable() {
disabling = true;
- plugin.getOnlineUsers().stream().filter(user -> !usersAwaitingSync.contains(user.uuid)).forEach(user ->
- plugin.getDatabase().setUserData(user, user.getUserData().join(), DataSaveCause.SERVER_SHUTDOWN).join());
+ plugin.getOnlineUsers().stream().filter(user -> !usersAwaitingSync.contains(user.uuid)).forEach(
+ user -> user.getUserData(plugin.getLoggingAdapter()).join().ifPresent(
+ userData -> plugin.getDatabase().setUserData(user, userData, DataSaveCause.SERVER_SHUTDOWN).join()));
plugin.getDatabase().close();
plugin.getRedisManager().close();
diff --git a/common/src/main/java/net/william278/husksync/player/OnlineUser.java b/common/src/main/java/net/william278/husksync/player/OnlineUser.java
index c9007828..26a63935 100644
--- a/common/src/main/java/net/william278/husksync/player/OnlineUser.java
+++ b/common/src/main/java/net/william278/husksync/player/OnlineUser.java
@@ -12,6 +12,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
@@ -258,16 +259,23 @@ public abstract class OnlineUser extends User {
public abstract void showMenu(@NotNull ItemEditorMenu menu);
/**
- * Get the player's current {@link UserData}
+ * Get the player's current {@link UserData} in an {@link Optional}
+ *
+ * If the user data could not be returned due to an exception, the optional will return empty
*
- * @return the player's current {@link UserData}
+ * @param logger The logger to use for handling exceptions
+ * @return the player's current {@link UserData} in an optional; empty if an exception occurs
*/
- public final CompletableFuture getUserData() {
- return CompletableFuture.supplyAsync(
- () -> new UserData(getStatus().join(), getInventory().join(),
+ public final CompletableFuture> getUserData(@NotNull Logger logger) {
+ return CompletableFuture.supplyAsync(() -> Optional.of(new UserData(getStatus().join(), getInventory().join(),
getEnderChest().join(), getPotionEffects().join(), getAdvancements().join(),
getStatistics().join(), getLocation().join(), getPersistentDataContainer().join(),
- getMinecraftVersion().toString()));
+ getMinecraftVersion().toString())))
+ .exceptionally(exception -> {
+ logger.log(Level.SEVERE, "Failed to fetch user data for online player " + username + " (" + exception.getMessage() + ")");
+ exception.printStackTrace();
+ return Optional.empty();
+ });
}
}