forked from public-mirrors/HuskSync
Userdata command, API expansion, editor interfaces
parent
1c9d74f925
commit
b7709f2d6c
@ -0,0 +1,137 @@
|
||||
package net.william278.husksync.api;
|
||||
|
||||
import net.william278.husksync.HuskSync;
|
||||
import net.william278.husksync.data.DataSaveCause;
|
||||
import net.william278.husksync.data.UserData;
|
||||
import net.william278.husksync.data.VersionedUserData;
|
||||
import net.william278.husksync.player.OnlineUser;
|
||||
import net.william278.husksync.player.User;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* The base implementation of the HuskSync API, containing cross-platform API calls.
|
||||
* </p>
|
||||
* This class should not be used directly, but rather through platform-specific extending API classes.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class BaseHuskSyncAPI {
|
||||
|
||||
/**
|
||||
* <b>(Internal use only)</b> - Instance of the implementing plugin.
|
||||
*/
|
||||
protected final HuskSync plugin;
|
||||
|
||||
protected BaseHuskSyncAPI(@NotNull HuskSync plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link User} by the given player's account {@link UUID}, if they exist.
|
||||
*
|
||||
* @param uuid the unique id of the player to get the {@link User} instance for
|
||||
* @return future returning the {@link User} instance for the given player's unique id if they exist, otherwise an empty {@link Optional}
|
||||
* @apiNote The player does not have to be online
|
||||
* @since 2.0
|
||||
*/
|
||||
public final CompletableFuture<Optional<User>> getUser(@NotNull UUID uuid) {
|
||||
return plugin.getDatabase().getUser(uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link User} by the given player's username (case-insensitive), if they exist.
|
||||
*
|
||||
* @param username the username of the {@link User} instance for
|
||||
* @return future returning the {@link User} instance for the given player's username if they exist,
|
||||
* otherwise an empty {@link Optional}
|
||||
* @apiNote The player does not have to be online, though their username has to be the username
|
||||
* they had when they last joined the server.
|
||||
* @since 2.0
|
||||
*/
|
||||
public final CompletableFuture<Optional<User>> getUser(@NotNull String username) {
|
||||
return plugin.getDatabase().getUserByName(username);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link User}'s current {@link UserData}
|
||||
*
|
||||
* @param user the {@link User} to get the {@link UserData} for
|
||||
* @return future returning the {@link UserData} for the given {@link User} if they exist, otherwise an empty {@link Optional}
|
||||
* @apiNote If the user is not online on the implementing bukkit server,
|
||||
* the {@link UserData} returned will be their last database-saved UserData.
|
||||
* </p>
|
||||
* Because of this, if the user is online on another server on the network,
|
||||
* then the {@link UserData} returned by this method will <i>not necessarily reflective of
|
||||
* their current state</i>
|
||||
* @since 2.0
|
||||
*/
|
||||
public final CompletableFuture<Optional<UserData>> getUserData(@NotNull User user) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
if (user instanceof OnlineUser) {
|
||||
return Optional.of(((OnlineUser) user).getUserData().join());
|
||||
} else {
|
||||
return plugin.getDatabase().getCurrentUserData(user).join().map(VersionedUserData::userData);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link UserData} to the database for the given {@link User}.
|
||||
* </p>
|
||||
* If the user is online and on the same cluster, their data will be updated in game.
|
||||
*
|
||||
* @param user the {@link User} to set the {@link UserData} for
|
||||
* @param userData the {@link UserData} to set for the given {@link User}
|
||||
* @return future returning void when complete
|
||||
* @since 2.0
|
||||
*/
|
||||
public final CompletableFuture<Void> setUserData(@NotNull User user, @NotNull UserData userData) {
|
||||
return CompletableFuture.runAsync(() ->
|
||||
plugin.getDatabase().setUserData(user, userData, DataSaveCause.API)
|
||||
.thenRun(() -> plugin.getRedisManager().sendUserDataUpdate(user, userData).join()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the {@link UserData} of an {@link OnlineUser} to the database
|
||||
*
|
||||
* @param user the {@link OnlineUser} to save the {@link UserData} of
|
||||
* @return future returning void when complete
|
||||
* @since 2.0
|
||||
*/
|
||||
public final CompletableFuture<Void> saveUserData(@NotNull OnlineUser user) {
|
||||
return CompletableFuture.runAsync(() -> user.getUserData().thenAccept(userData ->
|
||||
plugin.getDatabase().setUserData(user, userData, DataSaveCause.API).join()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the saved {@link VersionedUserData} records for the given {@link User}
|
||||
*
|
||||
* @param user the {@link User} to get the {@link VersionedUserData} for
|
||||
* @return future returning a list {@link VersionedUserData} for the given {@link User} if they exist,
|
||||
* otherwise an empty {@link Optional}
|
||||
* @apiNote The length of the list of VersionedUserData will correspond to the configured
|
||||
* {@code max_user_data_records} config option
|
||||
* @since 2.0
|
||||
*/
|
||||
public final CompletableFuture<List<VersionedUserData>> getSavedUserData(@NotNull User user) {
|
||||
return CompletableFuture.supplyAsync(() -> plugin.getDatabase().getUserData(user).join());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JSON string representation of the given {@link UserData}
|
||||
*
|
||||
* @param userData the {@link UserData} to get the JSON string representation of
|
||||
* @param prettyPrint whether to pretty print the JSON string
|
||||
* @return the JSON string representation of the given {@link UserData}
|
||||
* @since 2.0
|
||||
*/
|
||||
@NotNull
|
||||
public final String getUserDataJson(@NotNull UserData userData, boolean prettyPrint) {
|
||||
return plugin.getDataAdapter().toJson(userData, prettyPrint);
|
||||
}
|
||||
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
package net.william278.husksync.command;
|
||||
|
||||
import net.william278.husksync.HuskSync;
|
||||
import net.william278.husksync.data.UserData;
|
||||
import net.william278.husksync.data.VersionedUserData;
|
||||
import net.william278.husksync.data.DataSaveCause;
|
||||
import net.william278.husksync.editor.InventoryEditorMenu;
|
||||
import net.william278.husksync.player.OnlineUser;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class EchestCommand extends CommandBase {
|
||||
|
||||
public EchestCommand(@NotNull HuskSync implementor) {
|
||||
super("echest", Permission.COMMAND_VIEW_INVENTORIES, implementor, "openechest");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecute(@NotNull OnlineUser player, @NotNull String[] args) {
|
||||
if (args.length == 0 || args.length > 2) {
|
||||
plugin.getLocales().getLocale("error_invalid_syntax", "/echest <player>")
|
||||
.ifPresent(player::sendMessage);
|
||||
return;
|
||||
}
|
||||
plugin.getDatabase().getUserByName(args[0].toLowerCase()).thenAcceptAsync(optionalUser ->
|
||||
optionalUser.ifPresentOrElse(user -> {
|
||||
List<VersionedUserData> userData = plugin.getDatabase().getUserData(user).join();
|
||||
Optional<VersionedUserData> dataToView;
|
||||
if (args.length == 2) {
|
||||
try {
|
||||
final UUID version = UUID.fromString(args[1]);
|
||||
dataToView = userData.stream().filter(data -> data.versionUUID().equals(version)).findFirst();
|
||||
} catch (IllegalArgumentException e) {
|
||||
plugin.getLocales().getLocale("error_invalid_syntax",
|
||||
"/echest <player> [version_uuid]").ifPresent(player::sendMessage);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
dataToView = userData.stream().sorted().findFirst();
|
||||
}
|
||||
dataToView.ifPresentOrElse(versionedUserData -> {
|
||||
final UserData data = versionedUserData.userData();
|
||||
final InventoryEditorMenu menu = InventoryEditorMenu.createEnderChestMenu(
|
||||
data.getEnderChestData(), user, player);
|
||||
plugin.getLocales().getLocale("viewing_ender_chest_of", user.username)
|
||||
.ifPresent(player::sendMessage);
|
||||
plugin.getDataEditor().openInventoryMenu(player, menu).thenAcceptAsync(inventoryDataOnClose -> {
|
||||
if (!menu.canEdit) {
|
||||
return;
|
||||
}
|
||||
final UserData updatedUserData = new UserData(data.getStatusData(),
|
||||
data.getInventoryData(), inventoryDataOnClose,
|
||||
data.getPotionEffectsData(), data.getAdvancementData(),
|
||||
data.getStatisticsData(), data.getLocationData(),
|
||||
data.getPersistentDataContainerData());
|
||||
plugin.getDatabase().setUserData(user, updatedUserData, DataSaveCause.ECHEST_COMMAND_EDIT).join();
|
||||
});
|
||||
}, () -> plugin.getLocales().getLocale(args.length == 2 ? "error_invalid_version_uuid"
|
||||
: "error_no_data_to_display").ifPresent(player::sendMessage));
|
||||
}, () -> plugin.getLocales().getLocale("error_invalid_player").ifPresent(player::sendMessage)));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package net.william278.husksync.command;
|
||||
|
||||
import net.william278.husksync.HuskSync;
|
||||
import net.william278.husksync.data.ItemData;
|
||||
import net.william278.husksync.data.UserData;
|
||||
import net.william278.husksync.data.VersionedUserData;
|
||||
import net.william278.husksync.data.DataSaveCause;
|
||||
import net.william278.husksync.editor.ItemEditorMenu;
|
||||
import net.william278.husksync.player.OnlineUser;
|
||||
import net.william278.husksync.player.User;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class EnderChestCommand extends CommandBase {
|
||||
|
||||
public EnderChestCommand(@NotNull HuskSync implementor) {
|
||||
super("enderchest", Permission.COMMAND_ENDER_CHEST, implementor, "echest", "openechest");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecute(@NotNull OnlineUser player, @NotNull String[] args) {
|
||||
if (args.length == 0 || args.length > 2) {
|
||||
plugin.getLocales().getLocale("error_invalid_syntax", "/enderchest <player>")
|
||||
.ifPresent(player::sendMessage);
|
||||
return;
|
||||
}
|
||||
plugin.getDatabase().getUserByName(args[0].toLowerCase()).thenAccept(optionalUser ->
|
||||
optionalUser.ifPresentOrElse(user -> {
|
||||
if (args.length == 2) {
|
||||
// View user data by specified UUID
|
||||
try {
|
||||
final UUID versionUuid = UUID.fromString(args[1]);
|
||||
plugin.getDatabase().getUserData(user).thenAccept(userDataList -> userDataList.stream()
|
||||
.filter(userData -> userData.versionUUID().equals(versionUuid)).findFirst().ifPresentOrElse(
|
||||
userData -> showEnderChestMenu(player, userData, user, userDataList.stream().sorted().findFirst()
|
||||
.map(VersionedUserData::versionUUID).orElse(UUID.randomUUID()).equals(versionUuid)),
|
||||
() -> plugin.getLocales().getLocale("error_invalid_version_uuid")
|
||||
.ifPresent(player::sendMessage)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
plugin.getLocales().getLocale("error_invalid_syntax",
|
||||
"/enderchest <player> [version_uuid]").ifPresent(player::sendMessage);
|
||||
}
|
||||
} else {
|
||||
// View latest user data
|
||||
plugin.getDatabase().getCurrentUserData(user).thenAccept(optionalData -> optionalData.ifPresentOrElse(
|
||||
versionedUserData -> showEnderChestMenu(player, versionedUserData, user, true),
|
||||
() -> plugin.getLocales().getLocale("error_no_data_to_display")
|
||||
.ifPresent(player::sendMessage)));
|
||||
}
|
||||
}, () -> plugin.getLocales().getLocale("error_invalid_player")
|
||||
.ifPresent(player::sendMessage)));
|
||||
}
|
||||
|
||||
private void showEnderChestMenu(@NotNull OnlineUser player, @NotNull VersionedUserData versionedUserData,
|
||||
@NotNull User dataOwner, final boolean allowEdit) {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
final UserData data = versionedUserData.userData();
|
||||
final ItemEditorMenu menu = ItemEditorMenu.createEnderChestMenu(data.getEnderChestData(),
|
||||
dataOwner, player, plugin.getLocales(), allowEdit);
|
||||
plugin.getLocales().getLocale("viewing_ender_chest_of", dataOwner.username,
|
||||
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.getDefault())
|
||||
.format(versionedUserData.versionTimestamp()))
|
||||
.ifPresent(player::sendMessage);
|
||||
final ItemData enderChestDataOnClose = plugin.getDataEditor().openItemEditorMenu(player, menu).join();
|
||||
if (!menu.canEdit) {
|
||||
return;
|
||||
}
|
||||
final UserData updatedUserData = new UserData(data.getStatusData(), data.getInventoryData(),
|
||||
enderChestDataOnClose, data.getPotionEffectsData(), data.getAdvancementData(),
|
||||
data.getStatisticsData(), data.getLocationData(),
|
||||
data.getPersistentDataContainerData());
|
||||
plugin.getDatabase().setUserData(dataOwner, updatedUserData, DataSaveCause.ENDER_CHEST_COMMAND_EDIT).join();
|
||||
plugin.getRedisManager().sendUserDataUpdate(dataOwner, updatedUserData).join();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package net.william278.husksync.command;
|
||||
|
||||
import net.william278.husksync.HuskSync;
|
||||
import net.william278.husksync.data.DataSaveCause;
|
||||
import net.william278.husksync.data.ItemData;
|
||||
import net.william278.husksync.data.UserData;
|
||||
import net.william278.husksync.data.VersionedUserData;
|
||||
import net.william278.husksync.editor.ItemEditorMenu;
|
||||
import net.william278.husksync.player.OnlineUser;
|
||||
import net.william278.husksync.player.User;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class InventoryCommand extends CommandBase {
|
||||
|
||||
public InventoryCommand(@NotNull HuskSync implementor) {
|
||||
super("inventory", Permission.COMMAND_INVENTORY, implementor, "invsee", "openinv");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecute(@NotNull OnlineUser player, @NotNull String[] args) {
|
||||
if (args.length == 0 || args.length > 2) {
|
||||
plugin.getLocales().getLocale("error_invalid_syntax", "/inventory <player>")
|
||||
.ifPresent(player::sendMessage);
|
||||
return;
|
||||
}
|
||||
plugin.getDatabase().getUserByName(args[0].toLowerCase()).thenAccept(optionalUser ->
|
||||
optionalUser.ifPresentOrElse(user -> {
|
||||
if (args.length == 2) {
|
||||
// View user data by specified UUID
|
||||
try {
|
||||
final UUID versionUuid = UUID.fromString(args[1]);
|
||||
plugin.getDatabase().getUserData(user).thenAccept(userDataList -> userDataList.stream()
|
||||
.filter(userData -> userData.versionUUID().equals(versionUuid)).findFirst().ifPresentOrElse(
|
||||
userData -> showInventoryMenu(player, userData, user, userDataList.stream().sorted().findFirst()
|
||||
.map(VersionedUserData::versionUUID).orElse(UUID.randomUUID()).equals(versionUuid)),
|
||||
() -> plugin.getLocales().getLocale("error_invalid_version_uuid")
|
||||
.ifPresent(player::sendMessage)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
plugin.getLocales().getLocale("error_invalid_syntax",
|
||||
"/inventory <player> [version_uuid]").ifPresent(player::sendMessage);
|
||||
}
|
||||
} else {
|
||||
// View latest user data
|
||||
plugin.getDatabase().getCurrentUserData(user).thenAccept(optionalData -> optionalData.ifPresentOrElse(
|
||||
versionedUserData -> showInventoryMenu(player, versionedUserData, user, true),
|
||||
() -> plugin.getLocales().getLocale("error_no_data_to_display")
|
||||
.ifPresent(player::sendMessage)));
|
||||
}
|
||||
}, () -> plugin.getLocales().getLocale("error_invalid_player")
|
||||
.ifPresent(player::sendMessage)));
|
||||
}
|
||||
|
||||
private void showInventoryMenu(@NotNull OnlineUser player, @NotNull VersionedUserData versionedUserData,
|
||||
@NotNull User dataOwner, boolean allowEdit) {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
final UserData data = versionedUserData.userData();
|
||||
final ItemEditorMenu menu = ItemEditorMenu.createInventoryMenu(data.getInventoryData(),
|
||||
dataOwner, player, plugin.getLocales(), allowEdit);
|
||||
plugin.getLocales().getLocale("viewing_inventory_of", dataOwner.username,
|
||||
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.getDefault())
|
||||
.format(versionedUserData.versionTimestamp()))
|
||||
.ifPresent(player::sendMessage);
|
||||
final ItemData inventoryDataOnClose = plugin.getDataEditor().openItemEditorMenu(player, menu).join();
|
||||
if (!menu.canEdit) {
|
||||
return;
|
||||
}
|
||||
final UserData updatedUserData = new UserData(data.getStatusData(), inventoryDataOnClose,
|
||||
data.getEnderChestData(), data.getPotionEffectsData(), data.getAdvancementData(),
|
||||
data.getStatisticsData(), data.getLocationData(),
|
||||
data.getPersistentDataContainerData());
|
||||
plugin.getDatabase().setUserData(dataOwner, updatedUserData, DataSaveCause.INVENTORY_COMMAND_EDIT).join();
|
||||
plugin.getRedisManager().sendUserDataUpdate(dataOwner, updatedUserData).join();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
package net.william278.husksync.command;
|
||||
|
||||
import net.william278.husksync.HuskSync;
|
||||
import net.william278.husksync.data.UserData;
|
||||
import net.william278.husksync.data.VersionedUserData;
|
||||
import net.william278.husksync.data.DataSaveCause;
|
||||
import net.william278.husksync.editor.InventoryEditorMenu;
|
||||
import net.william278.husksync.player.OnlineUser;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class InvseeCommand extends CommandBase {
|
||||
|
||||
public InvseeCommand(@NotNull HuskSync implementor) {
|
||||
super("invsee", Permission.COMMAND_VIEW_INVENTORIES, implementor, "openinv");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecute(@NotNull OnlineUser player, @NotNull String[] args) {
|
||||
if (args.length == 0 || args.length > 2) {
|
||||
plugin.getLocales().getLocale("error_invalid_syntax", "/invsee <player>")
|
||||
.ifPresent(player::sendMessage);
|
||||
return;
|
||||
}
|
||||
plugin.getDatabase().getUserByName(args[0].toLowerCase()).thenAcceptAsync(optionalUser ->
|
||||
optionalUser.ifPresentOrElse(user -> {
|
||||
List<VersionedUserData> userData = plugin.getDatabase().getUserData(user).join();
|
||||
Optional<VersionedUserData> dataToView;
|
||||
if (args.length == 2) {
|
||||
try {
|
||||
final UUID version = UUID.fromString(args[1]);
|
||||
dataToView = userData.stream().filter(data -> data.versionUUID().equals(version)).findFirst();
|
||||
} catch (IllegalArgumentException e) {
|
||||
plugin.getLocales().getLocale("error_invalid_syntax",
|
||||
"/invsee <player> [version_uuid]").ifPresent(player::sendMessage);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
dataToView = userData.stream().sorted().findFirst();
|
||||
}
|
||||
dataToView.ifPresentOrElse(versionedUserData -> {
|
||||
final UserData data = versionedUserData.userData();
|
||||
final InventoryEditorMenu menu = InventoryEditorMenu.createInventoryMenu(
|
||||
data.getInventoryData(), user, player);
|
||||
plugin.getLocales().getLocale("viewing_inventory_of", user.username)
|
||||
.ifPresent(player::sendMessage);
|
||||
plugin.getDataEditor().openInventoryMenu(player, menu).thenAcceptAsync(inventoryDataOnClose -> {
|
||||
if (!menu.canEdit) {
|
||||
return;
|
||||
}
|
||||
final UserData updatedUserData = new UserData(data.getStatusData(),
|
||||
inventoryDataOnClose,
|
||||
data.getEnderChestData(), data.getPotionEffectsData(), data.getAdvancementData(),
|
||||
data.getStatisticsData(), data.getLocationData(),
|
||||
data.getPersistentDataContainerData());
|
||||
plugin.getDatabase().setUserData(user, updatedUserData, DataSaveCause.INVSEE_COMMAND_EDIT).join();
|
||||
});
|
||||
}, () -> plugin.getLocales().getLocale(args.length == 2 ? "error_invalid_version_uuid"
|
||||
: "error_no_data_to_display").ifPresent(player::sendMessage));
|
||||
}, () -> plugin.getLocales().getLocale("error_invalid_player").ifPresent(player::sendMessage)));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
package net.william278.husksync.command;
|
||||
|
||||
import net.william278.husksync.HuskSync;
|
||||
import net.william278.husksync.player.OnlineUser;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class UserDataCommand extends CommandBase implements TabCompletable {
|
||||
|
||||
private final String[] COMMAND_ARGUMENTS = {"view", "list", "delete", "restore"};
|
||||
|
||||
public UserDataCommand(@NotNull HuskSync implementor) {
|
||||
super("userdata", Permission.COMMAND_USER_DATA, implementor, "playerdata");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecute(@NotNull OnlineUser player, @NotNull String[] args) {
|
||||
if (args.length < 1) {
|
||||
plugin.getLocales().getLocale("error_invalid_syntax",
|
||||
"/userdata <view|list|delete|restore> <username> [version_uuid]")
|
||||
.ifPresent(player::sendMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (args[0].toLowerCase()) {
|
||||
case "view" -> {
|
||||
if (args.length < 2) {
|
||||
plugin.getLocales().getLocale("error_invalid_syntax",
|
||||
"/userdata view <username> [version_uuid]")
|
||||
.ifPresent(player::sendMessage);
|
||||
return;
|
||||
}
|
||||
final String username = args[1];
|
||||
if (args.length >= 3) {
|
||||
try {
|
||||
final UUID versionUuid = UUID.fromString(args[2]);
|
||||
CompletableFuture.runAsync(() -> plugin.getDatabase().getUserByName(username.toLowerCase()).thenAccept(
|
||||
optionalUser -> optionalUser.ifPresentOrElse(
|
||||
user -> plugin.getDatabase().getUserData(user).thenAccept(
|
||||
userDataList -> userDataList.stream().filter(versionedUserData -> versionedUserData
|
||||
.versionUUID().equals(versionUuid))
|
||||
.findFirst().ifPresentOrElse(userData ->
|
||||
plugin.getDataEditor()
|
||||
.displayDataOverview(player, userData, user),
|
||||
() -> plugin.getLocales().getLocale("error_invalid_version_uuid")
|
||||
.ifPresent(player::sendMessage))),
|
||||
() -> plugin.getLocales().getLocale("error_invalid_player")
|
||||
.ifPresent(player::sendMessage))));
|
||||
} catch (IllegalArgumentException e) {
|
||||
plugin.getLocales().getLocale("error_invalid_syntax",
|
||||
"/userdata view <username> [version_uuid]")
|
||||
.ifPresent(player::sendMessage);
|
||||
}
|
||||
} else {
|
||||
CompletableFuture.runAsync(() -> plugin.getDatabase().getUserByName(username.toLowerCase()).thenAccept(
|
||||
optionalUser -> optionalUser.ifPresentOrElse(
|
||||
user -> plugin.getDatabase().getCurrentUserData(user).thenAccept(
|
||||
latestData -> latestData.ifPresentOrElse(
|
||||
userData -> plugin.getDataEditor()
|
||||
.displayDataOverview(player, userData, user),
|
||||
() -> plugin.getLocales().getLocale("error_no_data_to_display")
|
||||
.ifPresent(player::sendMessage))),
|
||||
() -> plugin.getLocales().getLocale("error_invalid_player")
|
||||
.ifPresent(player::sendMessage))));
|
||||
}
|
||||
}
|
||||
case "list" -> {
|
||||
if (args.length < 2) {
|
||||
plugin.getLocales().getLocale("error_invalid_syntax",
|
||||
"/userdata list <username>")
|
||||
.ifPresent(player::sendMessage);
|
||||
return;
|
||||
}
|
||||
final String username = args[1];
|
||||
CompletableFuture.runAsync(() -> plugin.getDatabase().getUserByName(username.toLowerCase()).thenAccept(
|
||||
optionalUser -> optionalUser.ifPresentOrElse(
|
||||
user -> plugin.getDatabase().getUserData(user).thenAccept(dataList -> {
|
||||
if (dataList.isEmpty()) {
|
||||
plugin.getLocales().getLocale("error_no_data_to_display")
|
||||
.ifPresent(player::sendMessage);
|
||||
return;
|
||||
}
|
||||
plugin.getDataEditor().displayDataList(player, dataList, user);
|
||||
}),
|
||||
() -> plugin.getLocales().getLocale("error_invalid_player")
|
||||
.ifPresent(player::sendMessage))));
|
||||
}
|
||||
case "delete" -> {
|
||||
|
||||
}
|
||||
case "restore" -> {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(@NotNull OnlineUser player, @NotNull String[] args) {
|
||||
return Arrays.stream(COMMAND_ARGUMENTS)
|
||||
.filter(argument -> argument.startsWith(args.length >= 1 ? args[0] : ""))
|
||||
.sorted().collect(Collectors.toList());
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package net.william278.husksync.data;
|
||||
|
||||
/**
|
||||
* Indicates an error occurred during base-64 serialization and deserialization of data.
|
||||
* </p>
|
||||
* For example, an exception deserializing {@link ItemData} item stack or {@link PotionEffectData} potion effect arrays
|
||||
*/
|
||||
public class DataDeserializationException extends RuntimeException {
|
||||
protected DataDeserializationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package net.william278.husksync.data;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Indicates an error occurred during Base-64 serialization and deserialization of data.
|
||||
* </p>
|
||||
* For example, an exception deserializing {@link ItemData} item stack or {@link PotionEffectData} potion effect arrays
|
||||
*/
|
||||
public class DataSerializationException extends RuntimeException {
|
||||
protected DataSerializationException(@NotNull String message, @NotNull Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
package net.william278.husksync.editor;
|
||||
|
||||
import de.themoep.minedown.MineDown;
|
||||
import net.william278.husksync.command.Permission;
|
||||
import net.william278.husksync.data.ItemData;
|
||||
import net.william278.husksync.player.OnlineUser;
|
||||
import net.william278.husksync.player.User;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class InventoryEditorMenu {
|
||||
|
||||
public final ItemData itemData;
|
||||
public final int slotCount;
|
||||
public final MineDown menuTitle;
|
||||
public final boolean canEdit;
|
||||
|
||||
private CompletableFuture<ItemData> inventoryDataCompletableFuture;
|
||||
|
||||
private InventoryEditorMenu(@NotNull ItemData itemData, int slotCount,
|
||||
@NotNull MineDown menuTitle, boolean canEdit) {
|
||||
this.itemData = itemData;
|
||||
this.menuTitle = menuTitle;
|
||||
this.slotCount = slotCount;
|
||||
this.canEdit = canEdit;
|
||||
}
|
||||
|
||||
public CompletableFuture<ItemData> showInventory(@NotNull OnlineUser user) {
|
||||
inventoryDataCompletableFuture = new CompletableFuture<>();
|
||||
user.showMenu(this);
|
||||
return inventoryDataCompletableFuture;
|
||||
}
|
||||
|
||||
public void closeInventory(@NotNull ItemData itemData) {
|
||||
inventoryDataCompletableFuture.completeAsync(() -> itemData);
|
||||
}
|
||||
|
||||
public static InventoryEditorMenu createInventoryMenu(@NotNull ItemData itemData, @NotNull User dataOwner,
|
||||
@NotNull OnlineUser viewer) {
|
||||
return new InventoryEditorMenu(itemData, 45,
|
||||
new MineDown(dataOwner.username + "'s Inventory"),
|
||||
viewer.hasPermission(Permission.COMMAND_EDIT_INVENTORIES.node));
|
||||
}
|
||||
|
||||
public static InventoryEditorMenu createEnderChestMenu(@NotNull ItemData itemData, @NotNull User dataOwner,
|
||||
@NotNull OnlineUser viewer) {
|
||||
return new InventoryEditorMenu(itemData, 27,
|
||||
new MineDown(dataOwner.username + "'s Ender Chest"),
|
||||
viewer.hasPermission(Permission.COMMAND_EDIT_ENDER_CHESTS.node));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package net.william278.husksync.editor;
|
||||
|
||||
import de.themoep.minedown.MineDown;
|
||||
import net.william278.husksync.command.Permission;
|
||||
import net.william278.husksync.config.Locales;
|
||||
import net.william278.husksync.data.ItemData;
|
||||
import net.william278.husksync.player.OnlineUser;
|
||||
import net.william278.husksync.player.User;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class ItemEditorMenu {
|
||||
|
||||
public final ItemData itemData;
|
||||
public final int slotCount;
|
||||
public final MineDown menuTitle;
|
||||
public boolean canEdit;
|
||||
|
||||
private CompletableFuture<ItemData> inventoryDataCompletableFuture;
|
||||
|
||||
private ItemEditorMenu(@NotNull ItemData itemData, int slotCount,
|
||||
@NotNull MineDown menuTitle, boolean canEdit) {
|
||||
this.itemData = itemData;
|
||||
this.menuTitle = menuTitle;
|
||||
this.slotCount = slotCount;
|
||||
this.canEdit = canEdit;
|
||||
}
|
||||
|
||||
public CompletableFuture<ItemData> showInventory(@NotNull OnlineUser user) {
|
||||
inventoryDataCompletableFuture = new CompletableFuture<>();
|
||||
user.showMenu(this);
|
||||
return inventoryDataCompletableFuture;
|
||||
}
|
||||
|
||||
public void closeInventory(@NotNull ItemData itemData) {
|
||||
inventoryDataCompletableFuture.complete(itemData);
|
||||
}
|
||||
|
||||
public static ItemEditorMenu createInventoryMenu(@NotNull ItemData itemData, @NotNull User dataOwner,
|
||||
@NotNull OnlineUser viewer, @NotNull Locales locales,
|
||||
boolean canEdit) {
|
||||
return new ItemEditorMenu(itemData, 45,
|
||||
locales.getLocale("inventory_viewer_menu_title", dataOwner.username).orElse(new MineDown("")),
|
||||
viewer.hasPermission(Permission.COMMAND_INVENTORY_EDIT.node) && canEdit);
|
||||
}
|
||||
|
||||
public static ItemEditorMenu createEnderChestMenu(@NotNull ItemData itemData, @NotNull User dataOwner,
|
||||
@NotNull OnlineUser viewer, @NotNull Locales locales,
|
||||
boolean canEdit) {
|
||||
return new ItemEditorMenu(itemData, 27,
|
||||
locales.getLocale("ender_chest_viewer_menu_title", dataOwner.username).orElse(new MineDown("")),
|
||||
viewer.hasPermission(Permission.COMMAND_ENDER_CHEST_EDIT.node) && canEdit);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package net.william278.husksync.redis;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public enum RedisKeyType {
|
||||
CACHE(60 * 60 * 24),
|
||||
DATA_UPDATE(10),
|
||||
SERVER_SWITCH(10);
|
||||
|
||||
public final int timeToLive;
|
||||
|
||||
RedisKeyType(int timeToLive) {
|
||||
this.timeToLive = timeToLive;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getKeyPrefix() {
|
||||
return RedisManager.KEY_NAMESPACE.toLowerCase() + ":" + RedisManager.clusterId.toLowerCase() + ":" + name().toLowerCase();
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package net.william278.husksync.redis;
|
||||
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class RedisMessage {
|
||||
|
||||
public UUID targetUserUuid;
|
||||
public byte[] data;
|
||||
|
||||
public RedisMessage(@NotNull UUID targetUserUuid, byte[] message) {
|
||||
this.targetUserUuid = targetUserUuid;
|
||||
this.data = message;
|
||||
}
|
||||
|
||||
public RedisMessage() {
|
||||
}
|
||||
|
||||
public void dispatch(@NotNull RedisManager redisManager, @NotNull RedisMessageType type) {
|
||||
CompletableFuture.runAsync(() -> redisManager.sendMessage(type.getMessageChannel(),
|
||||
new GsonBuilder().create().toJson(this)));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static RedisMessage fromJson(@NotNull String json) throws JsonSyntaxException {
|
||||
return new GsonBuilder().create().fromJson(json, RedisMessage.class);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package net.william278.husksync.redis;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
public enum RedisMessageType {
|
||||
|
||||
UPDATE_USER_DATA;
|
||||
|
||||
@NotNull
|
||||
public String getMessageChannel() {
|
||||
return RedisManager.KEY_NAMESPACE.toLowerCase() + ":" + RedisManager.clusterId.toLowerCase()
|
||||
+ ":" + name().toLowerCase();
|
||||
}
|
||||
|
||||
public static Optional<RedisMessageType> getTypeFromChannel(@NotNull String messageChannel) {
|
||||
return Arrays.stream(values()).filter(messageType -> messageType.getMessageChannel()
|
||||
.equalsIgnoreCase(messageChannel)).findFirst();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue