mirror of
https://github.com/WiIIiam278/HuskSync.git
synced 2025-12-21 15:49:20 +00:00
Implement data rollbacks and deletion
This commit is contained in:
@@ -455,12 +455,12 @@ public class BukkitPlayer extends OnlineUser {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendActionBar(@NotNull MineDown mineDown) {
|
public void sendActionBar(@NotNull MineDown mineDown) {
|
||||||
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, mineDown.toComponent());
|
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, mineDown.replace().toComponent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendMessage(@NotNull MineDown mineDown) {
|
public void sendMessage(@NotNull MineDown mineDown) {
|
||||||
player.spigot().sendMessage(mineDown.toComponent());
|
player.spigot().sendMessage(mineDown.replace().toComponent());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,22 +1,23 @@
|
|||||||
package net.william278.husksync.command;
|
package net.william278.husksync.command;
|
||||||
|
|
||||||
import net.william278.husksync.HuskSync;
|
import net.william278.husksync.HuskSync;
|
||||||
|
import net.william278.husksync.data.DataSaveCause;
|
||||||
import net.william278.husksync.data.ItemData;
|
import net.william278.husksync.data.ItemData;
|
||||||
import net.william278.husksync.data.UserData;
|
import net.william278.husksync.data.UserData;
|
||||||
import net.william278.husksync.data.VersionedUserData;
|
import net.william278.husksync.data.VersionedUserData;
|
||||||
import net.william278.husksync.data.DataSaveCause;
|
|
||||||
import net.william278.husksync.editor.ItemEditorMenu;
|
import net.william278.husksync.editor.ItemEditorMenu;
|
||||||
import net.william278.husksync.player.OnlineUser;
|
import net.william278.husksync.player.OnlineUser;
|
||||||
import net.william278.husksync.player.User;
|
import net.william278.husksync.player.User;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class EnderChestCommand extends CommandBase {
|
public class EnderChestCommand extends CommandBase implements TabCompletable {
|
||||||
|
|
||||||
public EnderChestCommand(@NotNull HuskSync implementor) {
|
public EnderChestCommand(@NotNull HuskSync implementor) {
|
||||||
super("enderchest", Permission.COMMAND_ENDER_CHEST, implementor, "echest", "openechest");
|
super("enderchest", Permission.COMMAND_ENDER_CHEST, implementor, "echest", "openechest");
|
||||||
@@ -35,12 +36,10 @@ public class EnderChestCommand extends CommandBase {
|
|||||||
// View user data by specified UUID
|
// View user data by specified UUID
|
||||||
try {
|
try {
|
||||||
final UUID versionUuid = UUID.fromString(args[1]);
|
final UUID versionUuid = UUID.fromString(args[1]);
|
||||||
plugin.getDatabase().getUserData(user).thenAccept(userDataList -> userDataList.stream()
|
plugin.getDatabase().getUserData(user, versionUuid).thenAccept(data -> data.ifPresentOrElse(
|
||||||
.filter(userData -> userData.versionUUID().equals(versionUuid)).findFirst().ifPresentOrElse(
|
userData -> showEnderChestMenu(player, userData, user, false),
|
||||||
userData -> showEnderChestMenu(player, userData, user, userDataList.stream().sorted().findFirst()
|
() -> plugin.getLocales().getLocale("error_invalid_version_uuid")
|
||||||
.map(VersionedUserData::versionUUID).orElse(UUID.randomUUID()).equals(versionUuid)),
|
.ifPresent(player::sendMessage)));
|
||||||
() -> plugin.getLocales().getLocale("error_invalid_version_uuid")
|
|
||||||
.ifPresent(player::sendMessage)));
|
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
plugin.getLocales().getLocale("error_invalid_syntax",
|
plugin.getLocales().getLocale("error_invalid_syntax",
|
||||||
"/enderchest <player> [version_uuid]").ifPresent(player::sendMessage);
|
"/enderchest <player> [version_uuid]").ifPresent(player::sendMessage);
|
||||||
@@ -77,6 +76,14 @@ public class EnderChestCommand extends CommandBase {
|
|||||||
plugin.getDatabase().setUserData(dataOwner, updatedUserData, DataSaveCause.ENDER_CHEST_COMMAND_EDIT).join();
|
plugin.getDatabase().setUserData(dataOwner, updatedUserData, DataSaveCause.ENDER_CHEST_COMMAND_EDIT).join();
|
||||||
plugin.getRedisManager().sendUserDataUpdate(dataOwner, updatedUserData).join();
|
plugin.getRedisManager().sendUserDataUpdate(dataOwner, updatedUserData).join();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> onTabComplete(@NotNull OnlineUser player, @NotNull String[] args) {
|
||||||
|
return plugin.getOnlineUsers().stream().map(user -> user.username)
|
||||||
|
.filter(argument -> argument.startsWith(args.length >= 1 ? args[1] : ""))
|
||||||
|
.sorted().collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ import net.william278.husksync.player.User;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class InventoryCommand extends CommandBase {
|
public class InventoryCommand extends CommandBase implements TabCompletable {
|
||||||
|
|
||||||
public InventoryCommand(@NotNull HuskSync implementor) {
|
public InventoryCommand(@NotNull HuskSync implementor) {
|
||||||
super("inventory", Permission.COMMAND_INVENTORY, implementor, "invsee", "openinv");
|
super("inventory", Permission.COMMAND_INVENTORY, implementor, "invsee", "openinv");
|
||||||
@@ -34,12 +36,10 @@ public class InventoryCommand extends CommandBase {
|
|||||||
// View user data by specified UUID
|
// View user data by specified UUID
|
||||||
try {
|
try {
|
||||||
final UUID versionUuid = UUID.fromString(args[1]);
|
final UUID versionUuid = UUID.fromString(args[1]);
|
||||||
plugin.getDatabase().getUserData(user).thenAccept(userDataList -> userDataList.stream()
|
plugin.getDatabase().getUserData(user, versionUuid).thenAccept(data -> data.ifPresentOrElse(
|
||||||
.filter(userData -> userData.versionUUID().equals(versionUuid)).findFirst().ifPresentOrElse(
|
userData -> showInventoryMenu(player, userData, user, false),
|
||||||
userData -> showInventoryMenu(player, userData, user, userDataList.stream().sorted().findFirst()
|
() -> plugin.getLocales().getLocale("error_invalid_version_uuid")
|
||||||
.map(VersionedUserData::versionUUID).orElse(UUID.randomUUID()).equals(versionUuid)),
|
.ifPresent(player::sendMessage)));
|
||||||
() -> plugin.getLocales().getLocale("error_invalid_version_uuid")
|
|
||||||
.ifPresent(player::sendMessage)));
|
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
plugin.getLocales().getLocale("error_invalid_syntax",
|
plugin.getLocales().getLocale("error_invalid_syntax",
|
||||||
"/inventory <player> [version_uuid]").ifPresent(player::sendMessage);
|
"/inventory <player> [version_uuid]").ifPresent(player::sendMessage);
|
||||||
@@ -78,4 +78,10 @@ public class InventoryCommand extends CommandBase {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> onTabComplete(@NotNull OnlineUser player, @NotNull String[] args) {
|
||||||
|
return plugin.getOnlineUsers().stream().map(user -> user.username)
|
||||||
|
.filter(argument -> argument.startsWith(args.length >= 1 ? args[1] : ""))
|
||||||
|
.sorted().collect(Collectors.toList());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package net.william278.husksync.command;
|
package net.william278.husksync.command;
|
||||||
|
|
||||||
import net.william278.husksync.HuskSync;
|
import net.william278.husksync.HuskSync;
|
||||||
|
import net.william278.husksync.data.DataSaveCause;
|
||||||
import net.william278.husksync.player.OnlineUser;
|
import net.william278.husksync.player.OnlineUser;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
@@ -41,14 +43,11 @@ public class UserDataCommand extends CommandBase implements TabCompletable {
|
|||||||
final UUID versionUuid = UUID.fromString(args[2]);
|
final UUID versionUuid = UUID.fromString(args[2]);
|
||||||
CompletableFuture.runAsync(() -> plugin.getDatabase().getUserByName(username.toLowerCase()).thenAccept(
|
CompletableFuture.runAsync(() -> plugin.getDatabase().getUserByName(username.toLowerCase()).thenAccept(
|
||||||
optionalUser -> optionalUser.ifPresentOrElse(
|
optionalUser -> optionalUser.ifPresentOrElse(
|
||||||
user -> plugin.getDatabase().getUserData(user).thenAccept(
|
user -> plugin.getDatabase().getUserData(user, versionUuid).thenAccept(data ->
|
||||||
userDataList -> userDataList.stream().filter(versionedUserData -> versionedUserData
|
data.ifPresentOrElse(userData -> plugin.getDataEditor()
|
||||||
.versionUUID().equals(versionUuid))
|
.displayDataOverview(player, userData, user),
|
||||||
.findFirst().ifPresentOrElse(userData ->
|
() -> plugin.getLocales().getLocale("error_invalid_version_uuid")
|
||||||
plugin.getDataEditor()
|
.ifPresent(player::sendMessage))),
|
||||||
.displayDataOverview(player, userData, user),
|
|
||||||
() -> plugin.getLocales().getLocale("error_invalid_version_uuid")
|
|
||||||
.ifPresent(player::sendMessage))),
|
|
||||||
() -> plugin.getLocales().getLocale("error_invalid_player")
|
() -> plugin.getLocales().getLocale("error_invalid_player")
|
||||||
.ifPresent(player::sendMessage))));
|
.ifPresent(player::sendMessage))));
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
@@ -91,18 +90,93 @@ public class UserDataCommand extends CommandBase implements TabCompletable {
|
|||||||
.ifPresent(player::sendMessage))));
|
.ifPresent(player::sendMessage))));
|
||||||
}
|
}
|
||||||
case "delete" -> {
|
case "delete" -> {
|
||||||
|
// Delete user data by specified UUID
|
||||||
|
if (args.length < 3) {
|
||||||
|
plugin.getLocales().getLocale("error_invalid_syntax",
|
||||||
|
"/userdata delete <username> <version_uuid>")
|
||||||
|
.ifPresent(player::sendMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final String username = args[1];
|
||||||
|
try {
|
||||||
|
final UUID versionUuid = UUID.fromString(args[2]);
|
||||||
|
CompletableFuture.runAsync(() -> plugin.getDatabase().getUserByName(username.toLowerCase()).thenAccept(
|
||||||
|
optionalUser -> optionalUser.ifPresentOrElse(
|
||||||
|
user -> plugin.getDatabase().deleteUserData(user, versionUuid).thenAccept(deleted -> {
|
||||||
|
if (deleted) {
|
||||||
|
plugin.getLocales().getLocale("data_deleted",
|
||||||
|
versionUuid.toString().split("-")[0],
|
||||||
|
versionUuid.toString(),
|
||||||
|
user.username,
|
||||||
|
user.uuid.toString())
|
||||||
|
.ifPresent(player::sendMessage);
|
||||||
|
} else {
|
||||||
|
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 delete <username> <version_uuid>")
|
||||||
|
.ifPresent(player::sendMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case "restore" -> {
|
case "restore" -> {
|
||||||
|
// Get user data by specified uuid and username
|
||||||
|
if (args.length < 3) {
|
||||||
|
plugin.getLocales().getLocale("error_invalid_syntax",
|
||||||
|
"/userdata restore <username> <version_uuid>")
|
||||||
|
.ifPresent(player::sendMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final String username = args[1];
|
||||||
|
try {
|
||||||
|
final UUID versionUuid = UUID.fromString(args[2]);
|
||||||
|
CompletableFuture.runAsync(() -> plugin.getDatabase().getUserByName(username.toLowerCase()).thenAccept(
|
||||||
|
optionalUser -> optionalUser.ifPresentOrElse(
|
||||||
|
user -> plugin.getDatabase().getUserData(user, versionUuid).thenAccept(data -> {
|
||||||
|
if (data.isEmpty()) {
|
||||||
|
plugin.getLocales().getLocale("error_invalid_version_uuid")
|
||||||
|
.ifPresent(player::sendMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
plugin.getDatabase().setUserData(user, data.get().userData(),
|
||||||
|
DataSaveCause.BACKUP_RESTORE);
|
||||||
|
plugin.getRedisManager().sendUserDataUpdate(user, data.get().userData()).join();
|
||||||
|
plugin.getLocales().getLocale("data_restored",
|
||||||
|
user.username,
|
||||||
|
user.uuid.toString(),
|
||||||
|
versionUuid.toString().split("-")[0],
|
||||||
|
versionUuid.toString())
|
||||||
|
.ifPresent(player::sendMessage);
|
||||||
|
}),
|
||||||
|
() -> plugin.getLocales().getLocale("error_invalid_player")
|
||||||
|
.ifPresent(player::sendMessage))));
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
plugin.getLocales().getLocale("error_invalid_syntax",
|
||||||
|
"/userdata restore <username> <version_uuid>")
|
||||||
|
.ifPresent(player::sendMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> onTabComplete(@NotNull OnlineUser player, @NotNull String[] args) {
|
public List<String> onTabComplete(@NotNull OnlineUser player, @NotNull String[] args) {
|
||||||
return Arrays.stream(COMMAND_ARGUMENTS)
|
switch (args.length) {
|
||||||
.filter(argument -> argument.startsWith(args.length >= 1 ? args[0] : ""))
|
case 0, 1 -> {
|
||||||
.sorted().collect(Collectors.toList());
|
return Arrays.stream(COMMAND_ARGUMENTS)
|
||||||
|
.filter(argument -> argument.startsWith(args.length >= 1 ? args[0] : ""))
|
||||||
|
.sorted().collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
case 2 -> {
|
||||||
|
return plugin.getOnlineUsers().stream().map(user -> user.username)
|
||||||
|
.filter(argument -> argument.startsWith(args[1]))
|
||||||
|
.sorted().collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public class Locales {
|
|||||||
*/
|
*/
|
||||||
public Optional<String> getRawLocale(@NotNull String localeId) {
|
public Optional<String> getRawLocale(@NotNull String localeId) {
|
||||||
if (rawLocales.containsKey(localeId)) {
|
if (rawLocales.containsKey(localeId)) {
|
||||||
return Optional.of(rawLocales.get(localeId));
|
return Optional.of(rawLocales.get(localeId).replaceAll(Pattern.quote("\\n"), "\n"));
|
||||||
}
|
}
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,12 +169,30 @@ public abstract class Database {
|
|||||||
public abstract CompletableFuture<List<VersionedUserData>> getUserData(@NotNull User user);
|
public abstract CompletableFuture<List<VersionedUserData>> getUserData(@NotNull User user);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <b>(Internal)</b> Prune user data records for a given user to the maximum value as configured
|
* Gets a specific {@link VersionedUserData} entry for a user from the database, by its UUID.
|
||||||
|
*
|
||||||
|
* @param user The user to get data for
|
||||||
|
* @param versionUuid The UUID of the {@link VersionedUserData} entry to get
|
||||||
|
* @return A future returning an optional containing the {@link VersionedUserData}, if it exists, or an empty optional if it does not
|
||||||
|
*/
|
||||||
|
public abstract CompletableFuture<Optional<VersionedUserData>> getUserData(@NotNull User user, @NotNull UUID versionUuid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>(Internal)</b> Prune user data for a given user to the maximum value as configured
|
||||||
*
|
*
|
||||||
* @param user The user to prune data for
|
* @param user The user to prune data for
|
||||||
* @return A future returning void when complete
|
* @return A future returning void when complete
|
||||||
*/
|
*/
|
||||||
protected abstract CompletableFuture<Void> pruneUserDataRecords(@NotNull User user);
|
protected abstract CompletableFuture<Void> pruneUserData(@NotNull User user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a specific {@link VersionedUserData} entry for a user from the database, by its UUID.
|
||||||
|
*
|
||||||
|
* @param user The user to get data for
|
||||||
|
* @param versionUuid The UUID of the {@link VersionedUserData} entry to delete
|
||||||
|
* @return A future returning void when complete
|
||||||
|
*/
|
||||||
|
public abstract CompletableFuture<Boolean> deleteUserData(@NotNull User user, @NotNull UUID versionUuid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save user data to the database<p>
|
* Save user data to the database<p>
|
||||||
|
|||||||
@@ -268,7 +268,38 @@ public class MySqlDatabase extends Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected CompletableFuture<Void> pruneUserDataRecords(@NotNull User user) {
|
public CompletableFuture<Optional<VersionedUserData>> getUserData(@NotNull User user, @NotNull UUID versionUuid) {
|
||||||
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
|
try (Connection connection = getConnection()) {
|
||||||
|
try (PreparedStatement statement = connection.prepareStatement(formatStatementTables("""
|
||||||
|
SELECT `version_uuid`, `timestamp`, `save_cause`, `data`
|
||||||
|
FROM `%data_table%`
|
||||||
|
WHERE `player_uuid`=? AND `version_uuid`=?
|
||||||
|
ORDER BY `timestamp` DESC
|
||||||
|
LIMIT 1;"""))) {
|
||||||
|
statement.setString(1, user.uuid.toString());
|
||||||
|
statement.setString(2, versionUuid.toString());
|
||||||
|
final ResultSet resultSet = statement.executeQuery();
|
||||||
|
if (resultSet.next()) {
|
||||||
|
final Blob blob = resultSet.getBlob("data");
|
||||||
|
final byte[] dataByteArray = blob.getBytes(1, (int) blob.length());
|
||||||
|
blob.free();
|
||||||
|
return Optional.of(new VersionedUserData(
|
||||||
|
UUID.fromString(resultSet.getString("version_uuid")),
|
||||||
|
Date.from(resultSet.getTimestamp("timestamp").toInstant()),
|
||||||
|
DataSaveCause.getCauseByName(resultSet.getString("save_cause")),
|
||||||
|
getDataAdapter().fromBytes(dataByteArray)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException | DataAdaptionException e) {
|
||||||
|
getLogger().log(Level.SEVERE, "Failed to fetch specific user data by UUID from the database", e);
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CompletableFuture<Void> pruneUserData(@NotNull User user) {
|
||||||
return CompletableFuture.runAsync(() -> getUserData(user).thenAccept(data -> {
|
return CompletableFuture.runAsync(() -> getUserData(user).thenAccept(data -> {
|
||||||
if (data.size() > maxUserDataRecords) {
|
if (data.size() > maxUserDataRecords) {
|
||||||
try (Connection connection = getConnection()) {
|
try (Connection connection = getConnection()) {
|
||||||
@@ -288,6 +319,25 @@ public class MySqlDatabase extends Database {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Boolean> deleteUserData(@NotNull User user, @NotNull UUID versionUuid) {
|
||||||
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
|
try (Connection connection = getConnection()) {
|
||||||
|
try (PreparedStatement statement = connection.prepareStatement(formatStatementTables("""
|
||||||
|
DELETE FROM `%data_table%`
|
||||||
|
WHERE `player_uuid`=? AND `version_uuid`=?
|
||||||
|
LIMIT 1;"""))) {
|
||||||
|
statement.setString(1, user.uuid.toString());
|
||||||
|
statement.setString(2, versionUuid.toString());
|
||||||
|
return statement.executeUpdate() > 0;
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
getLogger().log(Level.SEVERE, "Failed to delete specific user data from the database", e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> setUserData(@NotNull User user, @NotNull UserData userData,
|
public CompletableFuture<Void> setUserData(@NotNull User user, @NotNull UserData userData,
|
||||||
@NotNull DataSaveCause saveCause) {
|
@NotNull DataSaveCause saveCause) {
|
||||||
@@ -311,7 +361,7 @@ public class MySqlDatabase extends Database {
|
|||||||
getLogger().log(Level.SEVERE, "Failed to set user data in the database", e);
|
getLogger().log(Level.SEVERE, "Failed to set user data in the database", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).thenRun(() -> pruneUserDataRecords(user).join());
|
}).thenRun(() -> pruneUserData(user).join());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -82,18 +82,21 @@ public class DataEditor {
|
|||||||
public void displayDataOverview(@NotNull OnlineUser user, @NotNull VersionedUserData userData,
|
public void displayDataOverview(@NotNull OnlineUser user, @NotNull VersionedUserData userData,
|
||||||
@NotNull User dataOwner) {
|
@NotNull User dataOwner) {
|
||||||
locales.getLocale("data_manager_title",
|
locales.getLocale("data_manager_title",
|
||||||
dataOwner.username, dataOwner.uuid.toString())
|
|
||||||
.ifPresent(user::sendMessage);
|
|
||||||
locales.getLocale("data_manager_versioning",
|
|
||||||
new SimpleDateFormat("MMM dd yyyy, HH:mm:ss.sss").format(userData.versionTimestamp()),
|
|
||||||
userData.versionUUID().toString().split("-")[0],
|
userData.versionUUID().toString().split("-")[0],
|
||||||
userData.versionUUID().toString(),
|
userData.versionUUID().toString(),
|
||||||
|
dataOwner.username,
|
||||||
|
dataOwner.uuid.toString())
|
||||||
|
.ifPresent(user::sendMessage);
|
||||||
|
locales.getLocale("data_manager_timestamp",
|
||||||
|
new SimpleDateFormat("MMM dd yyyy, HH:mm:ss.sss").format(userData.versionTimestamp()))
|
||||||
|
.ifPresent(user::sendMessage);
|
||||||
|
locales.getLocale("data_manager_cause",
|
||||||
userData.cause().name().toLowerCase().replaceAll("_", " "))
|
userData.cause().name().toLowerCase().replaceAll("_", " "))
|
||||||
.ifPresent(user::sendMessage);
|
.ifPresent(user::sendMessage);
|
||||||
locales.getLocale("data_manager_status",
|
locales.getLocale("data_manager_status",
|
||||||
Double.toString(userData.userData().getStatusData().health),
|
Integer.toString((int) userData.userData().getStatusData().health),
|
||||||
Double.toString(userData.userData().getStatusData().maxHealth),
|
Integer.toString((int) userData.userData().getStatusData().maxHealth),
|
||||||
Double.toString(userData.userData().getStatusData().hunger),
|
Integer.toString(userData.userData().getStatusData().hunger),
|
||||||
Integer.toString(userData.userData().getStatusData().expLevel),
|
Integer.toString(userData.userData().getStatusData().expLevel),
|
||||||
userData.userData().getStatusData().gameMode.toLowerCase())
|
userData.userData().getStatusData().gameMode.toLowerCase())
|
||||||
.ifPresent(user::sendMessage);
|
.ifPresent(user::sendMessage);
|
||||||
@@ -146,7 +149,7 @@ public class DataEditor {
|
|||||||
dataOwner.username, dataOwner.uuid.toString())
|
dataOwner.username, dataOwner.uuid.toString())
|
||||||
.ifPresent(user::sendMessage);
|
.ifPresent(user::sendMessage);
|
||||||
|
|
||||||
final String[] numberedIcons = "①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳" .split("");
|
final String[] numberedIcons = "①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳".split("");
|
||||||
for (int i = 0; i < Math.min(20, userDataList.size()); i++) {
|
for (int i = 0; i < Math.min(20, userDataList.size()); i++) {
|
||||||
final VersionedUserData userData = userDataList.get(i);
|
final VersionedUserData userData = userDataList.get(i);
|
||||||
locales.getLocale("data_list_item",
|
locales.getLocale("data_list_item",
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package net.william278.husksync.util;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
@@ -13,7 +12,6 @@ import java.util.logging.Level;
|
|||||||
public class UpdateChecker {
|
public class UpdateChecker {
|
||||||
|
|
||||||
private final static int SPIGOT_PROJECT_ID = 97144;
|
private final static int SPIGOT_PROJECT_ID = 97144;
|
||||||
|
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
private final VersionUtils.Version currentVersion;
|
private final VersionUtils.Version currentVersion;
|
||||||
|
|
||||||
@@ -52,7 +50,7 @@ public class UpdateChecker {
|
|||||||
if (isUpdateAvailable(latestVersion)) {
|
if (isUpdateAvailable(latestVersion)) {
|
||||||
logger.log(Level.WARNING, "A new version of HuskSync is available: v" + latestVersion);
|
logger.log(Level.WARNING, "A new version of HuskSync is available: v" + latestVersion);
|
||||||
} else {
|
} else {
|
||||||
logger.log(Level.INFO, "HuskSync is up-to-date! (Running: v" + currentVersion + ")");
|
logger.log(Level.INFO, "HuskSync is up-to-date! (Running: v" + getCurrentVersion().toString() + ")");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ error_cannot_view_own_ender_chest: '[Error:](#ff3300) [You can''t access your ow
|
|||||||
error_console_command_only: '[Error:](#ff3300) [That command can only be run through the %1% console](#ff7e5e)'
|
error_console_command_only: '[Error:](#ff3300) [That command can only be run through the %1% console](#ff7e5e)'
|
||||||
error_no_servers_proxied: '[Error:](#ff3300) [Failed to process operation; no servers are online that have HuskSync installed. Please ensure HuskSync is installed on both the Proxy server and all servers you wish to synchronise data between.](#ff7e5e)'
|
error_no_servers_proxied: '[Error:](#ff3300) [Failed to process operation; no servers are online that have HuskSync installed. Please ensure HuskSync is installed on both the Proxy server and all servers you wish to synchronise data between.](#ff7e5e)'
|
||||||
error_invalid_cluster: '[Error:](#ff3300) [Please specify the ID of a valid cluster.](#ff7e5e)'
|
error_invalid_cluster: '[Error:](#ff3300) [Please specify the ID of a valid cluster.](#ff7e5e)'
|
||||||
|
|
||||||
error_no_data_to_display: '[Error:](#ff3300) [Could not find any user data to display.](#ff7e5e)'
|
error_no_data_to_display: '[Error:](#ff3300) [Could not find any user data to display.](#ff7e5e)'
|
||||||
error_invalid_version_uuid: '[Error:](#ff3300) [Could not find any user data for that version UUID.](#ff7e5e)'
|
error_invalid_version_uuid: '[Error:](#ff3300) [Could not find any user data for that version UUID.](#ff7e5e)'
|
||||||
inventory_viewer_menu_title: '&0%1%''s Inventory'
|
inventory_viewer_menu_title: '&0%1%''s Inventory'
|
||||||
@@ -18,14 +17,15 @@ ender_chest_viewer_menu_title: '&0%1%''s Ender Chest'
|
|||||||
inventory_viewer_opened: '[Viewing snapshot of](#00fb9a) [%1%](#00fb9a bold) [''s inventory as of ⌚ %2%](#00fb9a)'
|
inventory_viewer_opened: '[Viewing snapshot of](#00fb9a) [%1%](#00fb9a bold) [''s inventory as of ⌚ %2%](#00fb9a)'
|
||||||
ender_chest_viewer_opened: '[Viewing snapshot of](#00fb9a) [%1%](#00fb9a bold) [''s Ender Chest as of ⌚ %2%](#00fb9a)'
|
ender_chest_viewer_opened: '[Viewing snapshot of](#00fb9a) [%1%](#00fb9a bold) [''s Ender Chest as of ⌚ %2%](#00fb9a)'
|
||||||
data_update_complete: '[🔔 Your data has been updated!](#00fb9a)'
|
data_update_complete: '[🔔 Your data has been updated!](#00fb9a)'
|
||||||
|
data_manager_title: '[Viewing user data snapshot](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\\n&8%2%) [for](#00fb9a) [%3%](#00fb9a bold show_text=&7Player UUID:\\n&8%4%)[:](#00fb9a)'
|
||||||
data_manager_title: '[Viewing user data snapshot for](#00fb9a) [%1%](#00fb9a bold show_text=&7UUID: %2%)[:](#00fb9a)'
|
data_manager_timestamp: '[⌚ %1%](#ffc43b-#f5c962 show_text=&7Version timestamp:\\n&7When the data was saved)'
|
||||||
data_manager_versioning: '[⌚ %1%](gray show_text=&7Version timestamp: &7When the data was saved) [⚡ %2%](gray show_text=&7Version UUID: &7%3%) [⚑ %4%](gray show_text=&7Save cause: &7What caused the data to be saved)'
|
data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7Save cause:\\n&7What caused the data to be saved)\\n'
|
||||||
data_manager_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7Health points) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7Hunger points) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7XP level) [🏹 %5%](dark_aqua show_text=&7Game mode)'
|
data_manager_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7Health points) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7Hunger points) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7XP level) [🏹 %5%](dark_aqua show_text=&7Game mode)'
|
||||||
data_manager_advancements_statistics: '[⭐ Advancements: %1%](color=#ffc43b-#f5c962 show_text=&7%2%) [⌛ Play Time: %3%ʜʀs](color=#62a9f5-#7ab8fa show_text=&7⚠ Based on in-game statistics)'
|
data_manager_advancements_statistics: '[⭐ Advancements: %1%](color=#ffc43b-#f5c962 show_text=&7%2%) [⌛ Play Time: %3%ʜʀs](color=#62a9f5-#7ab8fa show_text=&7⚠ Based on in-game statistics)'
|
||||||
data_manager_item_buttons: '[[🪣 Inventory…]](color=#a17b5f-#f5b98c show_text=&7Click to view run_command=/inventory %1% %2%) [[⌀ Ender Chest…]](#b649c4-#d254ff show_text=&7Click to view run_command=/enderchest %1% %2%)'
|
data_manager_item_buttons: '[[🪣 Inventory…]](color=#a17b5f-#f5b98c show_text=&7Click to view run_command=/inventory %1% %2%) [[⌀ Ender Chest…]](#b649c4-#d254ff show_text=&7Click to view run_command=/enderchest %1% %2%)\\n'
|
||||||
data_manager_management_buttons: '[Manage:](gray) [[❌ Delete…]](#ff3300 show_text=&7Click to delete this user data run_command=/userdata delete %1% %2%) [[⏪ Restore…]](#00fb9a show_text=&7Click to restore this user data. &#ff3300&⚠ Warning: %1%''s current data will be overwritten! run_command=/userdata delete %1% %2%)'
|
data_manager_management_buttons: '[Manage:](gray) [[❌ Delete…]](#ff3300 show_text=&7Click to delete this user data run_command=/userdata restore %1% %2%) [[⏪ Restore…]](#00fb9a show_text=&7Click to restore this user data.\\n&#ff3300&⚠ Warning: %1%''s current data will be overwritten! run_command=/userdata delete %1% %2%)\\n'
|
||||||
data_manager_advancement_preview_remaining: '&7+%1% more…'
|
data_manager_advancement_preview_remaining: '&7+%1% more…'
|
||||||
|
data_list_title: '[List of](#00fb9a) [%1%](#00fb9a bold show_text=&7UUID: %2%)[''s user data snapshots:](#00fb9a)\\n'
|
||||||
data_list_title: '[List of](#00fb9a) [%1%](#00fb9a bold show_text=&7UUID: %2%)[''s user data snapshots:](#00fb9a)'
|
data_list_item: '[%1%](gray run_command=/userdata view %6% %4%) [%2%](color=#ffc43b-#f5c962 show_text=&7Version timestamp&7When the data was saved run_command=/userdata view %6% %4%) [⚡ %3%](color=#62a9f5-#7ab8fa show_text=&7Version UUID:&7%4% run_command=/userdata view %6% %4%) [⚑ %5%](#23a825-#36f539 show_text=&7Save cause&7What caused the data to be saved run_command=/userdata view %6% %4%)'
|
||||||
data_list_item: '[%1%](gray run_command=/userdata view %6% %4%) [⌚ %2%](color=#ffc43b-#f5c962 show_text=&7Version timestamp&7When the data was saved run_command=/userdata view %6% %4%) [⚡ %3%](color=#62a9f5-#7ab8fa show_text=&7Version UUID:&7%4% run_command=/userdata view %6% %4%) [⚑ %5%](#23a825-#36f539 show_text=&7Save cause&7What caused the data to be saved run_command=/userdata view %6% %4%)'
|
data_deleted: '[❌ Successfully deleted user data snapshot](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\\n&7%2%) [for](#00fb9a) [%3%.](#00fb9a show_text=&7Player UUID:\\n&7%4%)'
|
||||||
|
data_restored: '[⏪ Successfully restored](#00fb9a) [%1%](#00fb9a show_text=&7Player UUID:\\n&7%2%)[''s current user data from snapshot](#00fb9a) [%3%.](#00fb9a show_text=&7Version UUID:\\n&7%4%)'
|
||||||
Reference in New Issue
Block a user