mirror of
https://github.com/WiIIiam278/HuskSync.git
synced 2025-12-23 08:39:19 +00:00
TriumphGUI for menus, fix missing inv/echest view message, fix data saving despite no updates, close #42
This commit is contained in:
@@ -34,6 +34,7 @@ allprojects {
|
|||||||
maven { url 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' }
|
maven { url 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' }
|
||||||
maven { url 'https://repo.minebench.de/' }
|
maven { url 'https://repo.minebench.de/' }
|
||||||
maven { url 'https://repo.alessiodp.com/releases/' }
|
maven { url 'https://repo.alessiodp.com/releases/' }
|
||||||
|
maven { url 'https://repo.mattstudios.me/artifactory/public/' }
|
||||||
maven { url 'https://jitpack.io' }
|
maven { url 'https://jitpack.io' }
|
||||||
maven { url 'https://libraries.minecraft.net/' }
|
maven { url 'https://libraries.minecraft.net/' }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ dependencies {
|
|||||||
implementation 'net.william278:hsldataconverter:1.0'
|
implementation 'net.william278:hsldataconverter:1.0'
|
||||||
implementation 'me.lucko:commodore:2.2'
|
implementation 'me.lucko:commodore:2.2'
|
||||||
implementation 'net.kyori:adventure-platform-bukkit:4.1.2'
|
implementation 'net.kyori:adventure-platform-bukkit:4.1.2'
|
||||||
|
implementation 'dev.triumphteam:triumph-gui:3.1.3'
|
||||||
|
|
||||||
compileOnly 'org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT'
|
compileOnly 'org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT'
|
||||||
compileOnly 'commons-io:commons-io:2.11.0'
|
compileOnly 'commons-io:commons-io:2.11.0'
|
||||||
@@ -34,6 +35,7 @@ shadowJar {
|
|||||||
relocate 'me.lucko.commodore', 'net.william278.husksync.libraries.commodore'
|
relocate 'me.lucko.commodore', 'net.william278.husksync.libraries.commodore'
|
||||||
relocate 'net.byteflux.libby', 'net.william278.husksync.libraries.libby'
|
relocate 'net.byteflux.libby', 'net.william278.husksync.libraries.libby'
|
||||||
relocate 'org.bstats', 'net.william278.husksync.libraries.bstats'
|
relocate 'org.bstats', 'net.william278.husksync.libraries.bstats'
|
||||||
|
relocate 'dev.triumphteam.gui', 'net.william278.husksync.libraries.triumphgui'
|
||||||
relocate 'net.william278.mpdbconverter', 'net.william278.husksync.libraries.mpdbconverter'
|
relocate 'net.william278.mpdbconverter', 'net.william278.husksync.libraries.mpdbconverter'
|
||||||
relocate 'net.william278.hslmigrator', 'net.william278.husksync.libraries.hslconverter'
|
relocate 'net.william278.hslmigrator', 'net.william278.husksync.libraries.hslconverter'
|
||||||
relocate 'net.william278.annotaml', 'net.william278.husksync.libraries.annotaml'
|
relocate 'net.william278.annotaml', 'net.william278.husksync.libraries.annotaml'
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import net.william278.husksync.data.DataAdapter;
|
|||||||
import net.william278.husksync.data.JsonDataAdapter;
|
import net.william278.husksync.data.JsonDataAdapter;
|
||||||
import net.william278.husksync.database.Database;
|
import net.william278.husksync.database.Database;
|
||||||
import net.william278.husksync.database.MySqlDatabase;
|
import net.william278.husksync.database.MySqlDatabase;
|
||||||
import net.william278.husksync.editor.DataEditor;
|
|
||||||
import net.william278.husksync.event.BukkitEventCannon;
|
import net.william278.husksync.event.BukkitEventCannon;
|
||||||
import net.william278.husksync.event.EventCannon;
|
import net.william278.husksync.event.EventCannon;
|
||||||
import net.william278.husksync.hook.PlanHook;
|
import net.william278.husksync.hook.PlanHook;
|
||||||
@@ -59,7 +58,6 @@ public class BukkitHuskSync extends JavaPlugin implements HuskSync {
|
|||||||
private ResourceReader resourceReader;
|
private ResourceReader resourceReader;
|
||||||
private EventListener eventListener;
|
private EventListener eventListener;
|
||||||
private DataAdapter dataAdapter;
|
private DataAdapter dataAdapter;
|
||||||
private DataEditor dataEditor;
|
|
||||||
private EventCannon eventCannon;
|
private EventCannon eventCannon;
|
||||||
private Settings settings;
|
private Settings settings;
|
||||||
private Locales locales;
|
private Locales locales;
|
||||||
@@ -114,9 +112,6 @@ public class BukkitHuskSync extends JavaPlugin implements HuskSync {
|
|||||||
// Prepare event cannon
|
// Prepare event cannon
|
||||||
eventCannon = new BukkitEventCannon();
|
eventCannon = new BukkitEventCannon();
|
||||||
|
|
||||||
// Prepare data editor
|
|
||||||
dataEditor = new DataEditor(locales);
|
|
||||||
|
|
||||||
// Prepare migrators
|
// Prepare migrators
|
||||||
availableMigrators = new ArrayList<>();
|
availableMigrators = new ArrayList<>();
|
||||||
availableMigrators.add(new LegacyMigrator(this));
|
availableMigrators.add(new LegacyMigrator(this));
|
||||||
@@ -258,11 +253,6 @@ public class BukkitHuskSync extends JavaPlugin implements HuskSync {
|
|||||||
return dataAdapter;
|
return dataAdapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull DataEditor getDataEditor() {
|
|
||||||
return dataEditor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull EventCannon getEventCannon() {
|
public @NotNull EventCannon getEventCannon() {
|
||||||
return eventCannon;
|
return eventCannon;
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ public class BukkitSerializer {
|
|||||||
public static CompletableFuture<String> serializeItemStackArray(@NotNull ItemStack[] inventoryContents)
|
public static CompletableFuture<String> serializeItemStackArray(@NotNull ItemStack[] inventoryContents)
|
||||||
throws DataSerializationException {
|
throws DataSerializationException {
|
||||||
return CompletableFuture.supplyAsync(() -> {
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
BukkitHuskSync.getInstance().getLoggingAdapter().debug("[HS] Serializing inventory contents");
|
|
||||||
|
|
||||||
// Return an empty string if there is no inventory item data to serialize
|
// Return an empty string if there is no inventory item data to serialize
|
||||||
if (inventoryContents.length == 0) {
|
if (inventoryContents.length == 0) {
|
||||||
return "";
|
return "";
|
||||||
|
|||||||
@@ -3,9 +3,7 @@ package net.william278.husksync.listener;
|
|||||||
import net.william278.husksync.BukkitHuskSync;
|
import net.william278.husksync.BukkitHuskSync;
|
||||||
import net.william278.husksync.data.BukkitInventoryMap;
|
import net.william278.husksync.data.BukkitInventoryMap;
|
||||||
import net.william278.husksync.data.BukkitSerializer;
|
import net.william278.husksync.data.BukkitSerializer;
|
||||||
import net.william278.husksync.data.DataSerializationException;
|
|
||||||
import net.william278.husksync.data.ItemData;
|
import net.william278.husksync.data.ItemData;
|
||||||
import net.william278.husksync.editor.ItemEditorMenuType;
|
|
||||||
import net.william278.husksync.player.BukkitPlayer;
|
import net.william278.husksync.player.BukkitPlayer;
|
||||||
import net.william278.husksync.player.OnlineUser;
|
import net.william278.husksync.player.OnlineUser;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
@@ -18,8 +16,6 @@ import org.bukkit.event.block.BlockPlaceEvent;
|
|||||||
import org.bukkit.event.entity.EntityDamageEvent;
|
import org.bukkit.event.entity.EntityDamageEvent;
|
||||||
import org.bukkit.event.entity.EntityPickupItemEvent;
|
import org.bukkit.event.entity.EntityPickupItemEvent;
|
||||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
|
||||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
|
||||||
import org.bukkit.event.inventory.InventoryOpenEvent;
|
import org.bukkit.event.inventory.InventoryOpenEvent;
|
||||||
import org.bukkit.event.player.PlayerDropItemEvent;
|
import org.bukkit.event.player.PlayerDropItemEvent;
|
||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
@@ -29,9 +25,7 @@ import org.bukkit.event.world.WorldSaveEvent;
|
|||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class BukkitEventListener extends EventListener implements Listener {
|
public class BukkitEventListener extends EventListener implements Listener {
|
||||||
@@ -61,27 +55,6 @@ public class BukkitEventListener extends EventListener implements Listener {
|
|||||||
.collect(Collectors.toList())));
|
.collect(Collectors.toList())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(ignoreCancelled = true)
|
|
||||||
public void onInventoryClose(@NotNull InventoryCloseEvent event) {
|
|
||||||
CompletableFuture.runAsync(() -> {
|
|
||||||
if (event.getPlayer() instanceof Player player) {
|
|
||||||
final OnlineUser user = BukkitPlayer.adapt(player);
|
|
||||||
plugin.getDataEditor().getEditingInventoryData(user).ifPresent(menu -> {
|
|
||||||
try {
|
|
||||||
BukkitSerializer.serializeItemStackArray(Arrays.copyOf(event.getInventory().getContents(),
|
|
||||||
menu.itemEditorMenuType == ItemEditorMenuType.INVENTORY_VIEWER
|
|
||||||
? player.getInventory().getSize()
|
|
||||||
: player.getEnderChest().getSize())).thenAccept(
|
|
||||||
serializedInventory -> super.handleMenuClose(user, new ItemData(serializedInventory)));
|
|
||||||
} catch (DataSerializationException e) {
|
|
||||||
plugin.getLoggingAdapter().log(Level.SEVERE,
|
|
||||||
"Failed to serialize inventory data during menu close", e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(ignoreCancelled = true)
|
@EventHandler(ignoreCancelled = true)
|
||||||
public void onPlayerDeath(PlayerDeathEvent event) {
|
public void onPlayerDeath(PlayerDeathEvent event) {
|
||||||
final OnlineUser user = BukkitPlayer.adapt(event.getEntity());
|
final OnlineUser user = BukkitPlayer.adapt(event.getEntity());
|
||||||
@@ -137,13 +110,6 @@ public class BukkitEventListener extends EventListener implements Listener {
|
|||||||
event.setCancelled(cancelPlayerEvent(BukkitPlayer.adapt(event.getPlayer())));
|
event.setCancelled(cancelPlayerEvent(BukkitPlayer.adapt(event.getPlayer())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
|
||||||
public void onInventoryClick(@NotNull InventoryClickEvent event) {
|
|
||||||
if (event.getWhoClicked() instanceof Player player) {
|
|
||||||
event.setCancelled(cancelInventoryClick(BukkitPlayer.adapt(player)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||||
public void onInventoryOpen(@NotNull InventoryOpenEvent event) {
|
public void onInventoryOpen(@NotNull InventoryOpenEvent event) {
|
||||||
if (event.getPlayer() instanceof Player player) {
|
if (event.getPlayer() instanceof Player player) {
|
||||||
|
|||||||
@@ -2,12 +2,14 @@ package net.william278.husksync.player;
|
|||||||
|
|
||||||
import de.themoep.minedown.adventure.MineDown;
|
import de.themoep.minedown.adventure.MineDown;
|
||||||
import de.themoep.minedown.adventure.MineDownParser;
|
import de.themoep.minedown.adventure.MineDownParser;
|
||||||
|
import dev.triumphteam.gui.builder.gui.StorageBuilder;
|
||||||
|
import dev.triumphteam.gui.guis.Gui;
|
||||||
|
import dev.triumphteam.gui.guis.StorageGui;
|
||||||
import net.kyori.adventure.audience.Audience;
|
import net.kyori.adventure.audience.Audience;
|
||||||
import net.william278.desertwell.Version;
|
import net.william278.desertwell.Version;
|
||||||
import net.william278.husksync.BukkitHuskSync;
|
import net.william278.husksync.BukkitHuskSync;
|
||||||
import net.william278.husksync.config.Settings;
|
import net.william278.husksync.config.Settings;
|
||||||
import net.william278.husksync.data.*;
|
import net.william278.husksync.data.*;
|
||||||
import net.william278.husksync.editor.ItemEditorMenu;
|
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.advancement.Advancement;
|
import org.bukkit.advancement.Advancement;
|
||||||
import org.bukkit.advancement.AdvancementProgress;
|
import org.bukkit.advancement.AdvancementProgress;
|
||||||
@@ -15,7 +17,7 @@ import org.bukkit.attribute.Attribute;
|
|||||||
import org.bukkit.entity.EntityType;
|
import org.bukkit.entity.EntityType;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||||
import org.bukkit.inventory.Inventory;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.persistence.PersistentDataContainer;
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
import org.bukkit.potion.PotionEffect;
|
import org.bukkit.potion.PotionEffect;
|
||||||
@@ -565,16 +567,49 @@ public class BukkitPlayer extends OnlineUser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showMenu(@NotNull ItemEditorMenu menu) {
|
public CompletableFuture<Optional<ItemData>> showMenu(@NotNull ItemData itemData, boolean editable,
|
||||||
BukkitSerializer.deserializeItemStackArray(menu.itemData.serializedItems).thenAccept(inventoryContents -> {
|
int rows, @NotNull MineDown title) {
|
||||||
//todo show the inventory properly
|
final CompletableFuture<Optional<ItemData>> updatedData = new CompletableFuture<>();
|
||||||
/*final Inventory inventory = Bukkit.createInventory(player, menu.itemEditorMenuType.slotCount,
|
|
||||||
BaseComponent.toLegacyText(menu.menuTitle.toComponent()));*/
|
// Deserialize the item data to be shown and show it in a triumph GUI
|
||||||
final Inventory inventory = Bukkit.createInventory(player, menu.itemEditorMenuType.slotCount,
|
BukkitSerializer.deserializeItemStackArray(itemData.serializedItems).thenAccept(items -> {
|
||||||
menu.menuTitle.message());
|
try {
|
||||||
inventory.setContents(inventoryContents);
|
// Build the GUI and populate with items
|
||||||
Bukkit.getScheduler().runTask(BukkitHuskSync.getInstance(), () -> player.openInventory(inventory));
|
final int itemCount = items.length;
|
||||||
|
final StorageBuilder guiBuilder = Gui.storage().title(title.toComponent()).rows(rows).disableAllInteractions();
|
||||||
|
final StorageGui gui = editable ? guiBuilder.enableAllInteractions().create() : guiBuilder.create();
|
||||||
|
for (int i = 0; i < itemCount; i++) {
|
||||||
|
if (items[i] != null) {
|
||||||
|
gui.getInventory().setItem(i, items[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete the future with updated data (if editable) when the GUI is closed
|
||||||
|
gui.setCloseGuiAction(event -> {
|
||||||
|
if (!editable) {
|
||||||
|
updatedData.complete(Optional.empty());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get and save the updated items
|
||||||
|
final ItemStack[] updatedItems = Arrays.copyOf(event.getPlayer().getOpenInventory()
|
||||||
|
.getTopInventory().getContents().clone(), itemCount);
|
||||||
|
BukkitSerializer.serializeItemStackArray(updatedItems).thenAccept(serializedItems -> {
|
||||||
|
if (serializedItems.equals(itemData.serializedItems)) {
|
||||||
|
updatedData.complete(Optional.empty());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updatedData.complete(Optional.of(new ItemData(serializedItems)));
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Display the GUI (synchronously; on the main server thread)
|
||||||
|
Bukkit.getScheduler().runTask(BukkitHuskSync.getInstance(), () -> gui.open(player));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return updatedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import net.william278.desertwell.UpdateChecker;
|
|||||||
import net.william278.husksync.config.Locales;
|
import net.william278.husksync.config.Locales;
|
||||||
import net.william278.husksync.config.Settings;
|
import net.william278.husksync.config.Settings;
|
||||||
import net.william278.husksync.data.DataAdapter;
|
import net.william278.husksync.data.DataAdapter;
|
||||||
import net.william278.husksync.editor.DataEditor;
|
|
||||||
import net.william278.husksync.database.Database;
|
import net.william278.husksync.database.Database;
|
||||||
import net.william278.husksync.event.EventCannon;
|
import net.william278.husksync.event.EventCannon;
|
||||||
import net.william278.husksync.migrator.Migrator;
|
import net.william278.husksync.migrator.Migrator;
|
||||||
@@ -71,14 +70,6 @@ public interface HuskSync {
|
|||||||
@NotNull
|
@NotNull
|
||||||
DataAdapter getDataAdapter();
|
DataAdapter getDataAdapter();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the data editor implementation
|
|
||||||
*
|
|
||||||
* @return the {@link DataEditor} implementation
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
DataEditor getDataEditor();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the event firing cannon
|
* Returns the event firing cannon
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
package net.william278.husksync.command;
|
package net.william278.husksync.command;
|
||||||
|
|
||||||
|
import de.themoep.minedown.adventure.MineDown;
|
||||||
import net.william278.husksync.HuskSync;
|
import net.william278.husksync.HuskSync;
|
||||||
import net.william278.husksync.data.*;
|
import net.william278.husksync.data.DataSaveCause;
|
||||||
import net.william278.husksync.editor.ItemEditorMenu;
|
import net.william278.husksync.data.UserData;
|
||||||
|
import net.william278.husksync.data.UserDataBuilder;
|
||||||
|
import net.william278.husksync.data.UserDataSnapshot;
|
||||||
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.SimpleDateFormat;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
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;
|
import java.util.stream.Collectors;
|
||||||
@@ -53,37 +55,42 @@ public class EnderChestCommand extends CommandBase implements TabCompletable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void showEnderChestMenu(@NotNull OnlineUser player, @NotNull UserDataSnapshot userDataSnapshot,
|
private void showEnderChestMenu(@NotNull OnlineUser player, @NotNull UserDataSnapshot userDataSnapshot,
|
||||||
@NotNull User dataOwner, final boolean allowEdit) {
|
@NotNull User dataOwner, boolean allowEdit) {
|
||||||
CompletableFuture.runAsync(() -> {
|
CompletableFuture.runAsync(() -> {
|
||||||
final UserData data = userDataSnapshot.userData();
|
final UserData data = userDataSnapshot.userData();
|
||||||
final ItemEditorMenu menu = ItemEditorMenu.createEnderChestMenu(
|
data.getEnderChest().ifPresent(itemData -> {
|
||||||
data.getEnderChest().orElse(ItemData.empty()),
|
// Show message
|
||||||
dataOwner, player, plugin.getLocales(), allowEdit);
|
plugin.getLocales().getLocale("ender_chest_viewer_opened", dataOwner.username,
|
||||||
plugin.getLocales().getLocale("viewing_ender_chest_of", dataOwner.username,
|
new SimpleDateFormat("MMM dd yyyy, HH:mm:ss.sss")
|
||||||
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.getDefault())
|
|
||||||
.format(userDataSnapshot.versionTimestamp()))
|
.format(userDataSnapshot.versionTimestamp()))
|
||||||
.ifPresent(player::sendMessage);
|
.ifPresent(player::sendMessage);
|
||||||
plugin.getDataEditor().openItemEditorMenu(player, menu).thenAccept(enderChestDataOnClose -> {
|
|
||||||
if (!menu.canEdit) {
|
// Show inventory menu
|
||||||
|
player.showMenu(itemData, allowEdit, 3, plugin.getLocales()
|
||||||
|
.getLocale("ender_chest_viewer_menu_title", dataOwner.username)
|
||||||
|
.orElse(new MineDown("Ender Chest Viewer"))).thenAccept(dataOnClose -> {
|
||||||
|
if (dataOnClose.isEmpty() || !allowEdit) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create the updated data
|
||||||
final UserDataBuilder builder = UserData.builder(plugin.getMinecraftVersion());
|
final UserDataBuilder builder = UserData.builder(plugin.getMinecraftVersion());
|
||||||
data.getStatus().ifPresent(builder::setStatus);
|
data.getStatus().ifPresent(builder::setStatus);
|
||||||
data.getInventory().ifPresent(builder::setInventory);
|
|
||||||
data.getAdvancements().ifPresent(builder::setAdvancements);
|
data.getAdvancements().ifPresent(builder::setAdvancements);
|
||||||
data.getLocation().ifPresent(builder::setLocation);
|
data.getLocation().ifPresent(builder::setLocation);
|
||||||
data.getPersistentDataContainer().ifPresent(builder::setPersistentDataContainer);
|
data.getPersistentDataContainer().ifPresent(builder::setPersistentDataContainer);
|
||||||
data.getStatistics().ifPresent(builder::setStatistics);
|
data.getStatistics().ifPresent(builder::setStatistics);
|
||||||
data.getPotionEffects().ifPresent(builder::setPotionEffects);
|
data.getPotionEffects().ifPresent(builder::setPotionEffects);
|
||||||
builder.setEnderChest(enderChestDataOnClose);
|
data.getInventory().ifPresent(builder::setInventory);
|
||||||
final UserData updatedUserData = builder.build();
|
builder.setEnderChest(dataOnClose.get());
|
||||||
|
|
||||||
plugin.getDatabase().setUserData(dataOwner, updatedUserData, DataSaveCause.ENDERCHEST_COMMAND).join();
|
// Set the updated data
|
||||||
|
final UserData updatedUserData = builder.build();
|
||||||
|
plugin.getDatabase().setUserData(dataOwner, updatedUserData, DataSaveCause.INVENTORY_COMMAND).join();
|
||||||
plugin.getRedisManager().sendUserDataUpdate(dataOwner, updatedUserData).join();
|
plugin.getRedisManager().sendUserDataUpdate(dataOwner, updatedUserData).join();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
package net.william278.husksync.command;
|
package net.william278.husksync.command;
|
||||||
|
|
||||||
|
import de.themoep.minedown.adventure.MineDown;
|
||||||
import net.william278.husksync.HuskSync;
|
import net.william278.husksync.HuskSync;
|
||||||
import net.william278.husksync.data.*;
|
import net.william278.husksync.data.DataSaveCause;
|
||||||
import net.william278.husksync.editor.ItemEditorMenu;
|
import net.william278.husksync.data.UserData;
|
||||||
|
import net.william278.husksync.data.UserDataBuilder;
|
||||||
|
import net.william278.husksync.data.UserDataSnapshot;
|
||||||
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.SimpleDateFormat;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
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;
|
import java.util.stream.Collectors;
|
||||||
@@ -56,33 +58,42 @@ public class InventoryCommand extends CommandBase implements TabCompletable {
|
|||||||
@NotNull User dataOwner, boolean allowEdit) {
|
@NotNull User dataOwner, boolean allowEdit) {
|
||||||
CompletableFuture.runAsync(() -> {
|
CompletableFuture.runAsync(() -> {
|
||||||
final UserData data = userDataSnapshot.userData();
|
final UserData data = userDataSnapshot.userData();
|
||||||
final ItemEditorMenu menu = ItemEditorMenu.createInventoryMenu(
|
data.getInventory().ifPresent(itemData -> {
|
||||||
data.getInventory().orElse(ItemData.empty()),
|
// Show message
|
||||||
dataOwner, player, plugin.getLocales(), allowEdit);
|
plugin.getLocales().getLocale("inventory_viewer_opened", dataOwner.username,
|
||||||
plugin.getLocales().getLocale("viewing_inventory_of", dataOwner.username,
|
new SimpleDateFormat("MMM dd yyyy, HH:mm:ss.sss")
|
||||||
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.getDefault())
|
|
||||||
.format(userDataSnapshot.versionTimestamp()))
|
.format(userDataSnapshot.versionTimestamp()))
|
||||||
.ifPresent(player::sendMessage);
|
.ifPresent(player::sendMessage);
|
||||||
plugin.getDataEditor().openItemEditorMenu(player, menu).thenAccept(inventoryDataOnClose -> {
|
|
||||||
if (!menu.canEdit) {
|
// Show inventory menu
|
||||||
|
player.showMenu(itemData, allowEdit, 5, plugin.getLocales()
|
||||||
|
.getLocale("inventory_viewer_menu_title", dataOwner.username)
|
||||||
|
.orElse(new MineDown("Inventory Viewer")))
|
||||||
|
.thenAccept(dataOnClose -> {
|
||||||
|
if (dataOnClose.isEmpty() || !allowEdit) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
plugin.getLoggingAdapter().debug("Inventory data changed, updating user, etc!");
|
||||||
|
|
||||||
|
// Create the updated data
|
||||||
final UserDataBuilder builder = UserData.builder(plugin.getMinecraftVersion());
|
final UserDataBuilder builder = UserData.builder(plugin.getMinecraftVersion());
|
||||||
data.getStatus().ifPresent(builder::setStatus);
|
data.getStatus().ifPresent(builder::setStatus);
|
||||||
data.getEnderChest().ifPresent(builder::setEnderChest);
|
|
||||||
data.getAdvancements().ifPresent(builder::setAdvancements);
|
data.getAdvancements().ifPresent(builder::setAdvancements);
|
||||||
data.getLocation().ifPresent(builder::setLocation);
|
data.getLocation().ifPresent(builder::setLocation);
|
||||||
data.getPersistentDataContainer().ifPresent(builder::setPersistentDataContainer);
|
data.getPersistentDataContainer().ifPresent(builder::setPersistentDataContainer);
|
||||||
data.getStatistics().ifPresent(builder::setStatistics);
|
data.getStatistics().ifPresent(builder::setStatistics);
|
||||||
data.getPotionEffects().ifPresent(builder::setPotionEffects);
|
data.getPotionEffects().ifPresent(builder::setPotionEffects);
|
||||||
builder.setEnderChest(inventoryDataOnClose);
|
data.getEnderChest().ifPresent(builder::setEnderChest);
|
||||||
final UserData updatedUserData = builder.build();
|
builder.setInventory(dataOnClose.get());
|
||||||
|
|
||||||
|
// Set the updated data
|
||||||
|
final UserData updatedUserData = builder.build();
|
||||||
plugin.getDatabase().setUserData(dataOwner, updatedUserData, DataSaveCause.INVENTORY_COMMAND).join();
|
plugin.getDatabase().setUserData(dataOwner, updatedUserData, DataSaveCause.INVENTORY_COMMAND).join();
|
||||||
plugin.getRedisManager().sendUserDataUpdate(dataOwner, updatedUserData).join();
|
plugin.getRedisManager().sendUserDataUpdate(dataOwner, updatedUserData).join();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ 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.DataSaveCause;
|
||||||
import net.william278.husksync.data.UserData;
|
import net.william278.husksync.data.UserData;
|
||||||
|
import net.william278.husksync.util.DataSnapshotList;
|
||||||
import net.william278.husksync.player.OnlineUser;
|
import net.william278.husksync.player.OnlineUser;
|
||||||
import net.william278.husksync.util.DataDumper;
|
import net.william278.husksync.util.DataDumper;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -45,11 +46,12 @@ public class UserDataCommand extends CommandBase implements TabCompletable {
|
|||||||
if (args.length >= 3) {
|
if (args.length >= 3) {
|
||||||
try {
|
try {
|
||||||
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()
|
||||||
optionalUser -> optionalUser.ifPresentOrElse(
|
.getUserByName(username.toLowerCase())
|
||||||
user -> plugin.getDatabase().getUserData(user, versionUuid).thenAccept(data ->
|
.thenAccept(optionalUser -> optionalUser
|
||||||
data.ifPresentOrElse(userData -> plugin.getDataEditor()
|
.ifPresentOrElse(user -> plugin.getDatabase().getUserData(user, versionUuid)
|
||||||
.displayDataOverview(player, userData, user),
|
.thenAccept(data -> data.ifPresentOrElse(
|
||||||
|
userData -> userData.displayDataOverview(player, user, plugin.getLocales()),
|
||||||
() -> plugin.getLocales().getLocale("error_invalid_version_uuid")
|
() -> plugin.getLocales().getLocale("error_invalid_version_uuid")
|
||||||
.ifPresent(player::sendMessage))),
|
.ifPresent(player::sendMessage))),
|
||||||
() -> plugin.getLocales().getLocale("error_invalid_player")
|
() -> plugin.getLocales().getLocale("error_invalid_player")
|
||||||
@@ -60,12 +62,12 @@ public class UserDataCommand extends CommandBase implements TabCompletable {
|
|||||||
.ifPresent(player::sendMessage);
|
.ifPresent(player::sendMessage);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
CompletableFuture.runAsync(() -> plugin.getDatabase().getUserByName(username.toLowerCase()).thenAccept(
|
CompletableFuture.runAsync(() -> plugin.getDatabase()
|
||||||
optionalUser -> optionalUser.ifPresentOrElse(
|
.getUserByName(username.toLowerCase())
|
||||||
user -> plugin.getDatabase().getCurrentUserData(user).thenAccept(
|
.thenAccept(optionalUser -> optionalUser
|
||||||
latestData -> latestData.ifPresentOrElse(
|
.ifPresentOrElse(user -> plugin.getDatabase().getCurrentUserData(user)
|
||||||
userData -> plugin.getDataEditor()
|
.thenAccept(latestData -> latestData.ifPresentOrElse(
|
||||||
.displayDataOverview(player, userData, user),
|
userData -> userData.displayDataOverview(player, user, plugin.getLocales()),
|
||||||
() -> plugin.getLocales().getLocale("error_no_data_to_display")
|
() -> plugin.getLocales().getLocale("error_no_data_to_display")
|
||||||
.ifPresent(player::sendMessage))),
|
.ifPresent(player::sendMessage))),
|
||||||
() -> plugin.getLocales().getLocale("error_invalid_player")
|
() -> plugin.getLocales().getLocale("error_invalid_player")
|
||||||
@@ -84,8 +86,9 @@ public class UserDataCommand extends CommandBase implements TabCompletable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final String username = args[1];
|
final String username = args[1];
|
||||||
CompletableFuture.runAsync(() -> plugin.getDatabase().getUserByName(username.toLowerCase()).thenAccept(
|
CompletableFuture.runAsync(() -> plugin.getDatabase()
|
||||||
optionalUser -> optionalUser.ifPresentOrElse(
|
.getUserByName(username.toLowerCase())
|
||||||
|
.thenAccept(optionalUser -> optionalUser.ifPresentOrElse(
|
||||||
user -> plugin.getDatabase().getUserData(user).thenAccept(dataList -> {
|
user -> plugin.getDatabase().getUserData(user).thenAccept(dataList -> {
|
||||||
// Check if there is data to display
|
// Check if there is data to display
|
||||||
if (dataList.isEmpty()) {
|
if (dataList.isEmpty()) {
|
||||||
@@ -107,8 +110,9 @@ public class UserDataCommand extends CommandBase implements TabCompletable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show list
|
// Show the list to the player
|
||||||
plugin.getDataEditor().displayDataSnapshotList(player, dataList, user, page);
|
DataSnapshotList.create(dataList, user, plugin.getLocales())
|
||||||
|
.displayPage(player, page);
|
||||||
}),
|
}),
|
||||||
() -> plugin.getLocales().getLocale("error_invalid_player")
|
() -> plugin.getLocales().getLocale("error_invalid_player")
|
||||||
.ifPresent(player::sendMessage))));
|
.ifPresent(player::sendMessage))));
|
||||||
@@ -128,8 +132,9 @@ public class UserDataCommand extends CommandBase implements TabCompletable {
|
|||||||
final String username = args[1];
|
final String username = args[1];
|
||||||
try {
|
try {
|
||||||
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()
|
||||||
optionalUser -> optionalUser.ifPresentOrElse(
|
.getUserByName(username.toLowerCase())
|
||||||
|
.thenAccept(optionalUser -> optionalUser.ifPresentOrElse(
|
||||||
user -> plugin.getDatabase().deleteUserData(user, versionUuid).thenAccept(deleted -> {
|
user -> plugin.getDatabase().deleteUserData(user, versionUuid).thenAccept(deleted -> {
|
||||||
if (deleted) {
|
if (deleted) {
|
||||||
plugin.getLocales().getLocale("data_deleted",
|
plugin.getLocales().getLocale("data_deleted",
|
||||||
@@ -166,8 +171,9 @@ public class UserDataCommand extends CommandBase implements TabCompletable {
|
|||||||
final String username = args[1];
|
final String username = args[1];
|
||||||
try {
|
try {
|
||||||
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()
|
||||||
optionalUser -> optionalUser.ifPresentOrElse(
|
.getUserByName(username.toLowerCase())
|
||||||
|
.thenAccept(optionalUser -> optionalUser.ifPresentOrElse(
|
||||||
user -> plugin.getDatabase().getUserData(user, versionUuid).thenAccept(data -> {
|
user -> plugin.getDatabase().getUserData(user, versionUuid).thenAccept(data -> {
|
||||||
if (data.isEmpty()) {
|
if (data.isEmpty()) {
|
||||||
plugin.getLocales().getLocale("error_invalid_version_uuid")
|
plugin.getLocales().getLocale("error_invalid_version_uuid")
|
||||||
@@ -212,8 +218,9 @@ public class UserDataCommand extends CommandBase implements TabCompletable {
|
|||||||
final String username = args[1];
|
final String username = args[1];
|
||||||
try {
|
try {
|
||||||
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()
|
||||||
optionalUser -> optionalUser.ifPresentOrElse(
|
.getUserByName(username.toLowerCase())
|
||||||
|
.thenAccept(optionalUser -> optionalUser.ifPresentOrElse(
|
||||||
user -> plugin.getDatabase().getUserData(user, versionUuid).thenAccept(
|
user -> plugin.getDatabase().getUserData(user, versionUuid).thenAccept(
|
||||||
optionalUserData -> optionalUserData.ifPresentOrElse(userData -> {
|
optionalUserData -> optionalUserData.ifPresentOrElse(userData -> {
|
||||||
if (userData.pinned()) {
|
if (userData.pinned()) {
|
||||||
@@ -259,8 +266,9 @@ public class UserDataCommand extends CommandBase implements TabCompletable {
|
|||||||
final String username = args[1];
|
final String username = args[1];
|
||||||
try {
|
try {
|
||||||
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()
|
||||||
optionalUser -> optionalUser.ifPresentOrElse(
|
.getUserByName(username.toLowerCase())
|
||||||
|
.thenAccept(optionalUser -> optionalUser.ifPresentOrElse(
|
||||||
user -> plugin.getDatabase().getUserData(user, versionUuid).thenAccept(
|
user -> plugin.getDatabase().getUserData(user, versionUuid).thenAccept(
|
||||||
optionalUserData -> optionalUserData.ifPresentOrElse(userData -> {
|
optionalUserData -> optionalUserData.ifPresentOrElse(userData -> {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
package net.william278.husksync.data;
|
package net.william278.husksync.data;
|
||||||
|
|
||||||
|
import net.william278.husksync.command.Permission;
|
||||||
|
import net.william278.husksync.config.Locales;
|
||||||
|
import net.william278.husksync.player.OnlineUser;
|
||||||
|
import net.william278.husksync.player.User;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.StringJoiner;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,6 +39,82 @@ public record UserDataSnapshot(@NotNull UUID versionUUID, @NotNull Date versionT
|
|||||||
DataSaveCause.API, false, userData);
|
DataSaveCause.API, false, userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a menu in chat to an {@link OnlineUser} about this {@link UserDataSnapshot} for a {@link User dataOwner}
|
||||||
|
*
|
||||||
|
* @param user The {@link OnlineUser} to display the menu to
|
||||||
|
* @param dataOwner The {@link User} whose data this snapshot captures a state of
|
||||||
|
* @param locales The {@link Locales} to use for displaying the menu
|
||||||
|
*/
|
||||||
|
public void displayDataOverview(@NotNull OnlineUser user, @NotNull User dataOwner, @NotNull Locales locales) {
|
||||||
|
// Title message, timestamp, owner and cause.
|
||||||
|
locales.getLocale("data_manager_title", versionUUID().toString().split("-")[0],
|
||||||
|
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(versionTimestamp()))
|
||||||
|
.ifPresent(user::sendMessage);
|
||||||
|
if (pinned()) {
|
||||||
|
locales.getLocale("data_manager_pinned").ifPresent(user::sendMessage);
|
||||||
|
}
|
||||||
|
locales.getLocale("data_manager_cause", cause().name().toLowerCase().replaceAll("_", " "))
|
||||||
|
.ifPresent(user::sendMessage);
|
||||||
|
|
||||||
|
// User status data, if present in the snapshot
|
||||||
|
userData().getStatus()
|
||||||
|
.flatMap(statusData -> locales.getLocale("data_manager_status",
|
||||||
|
Integer.toString((int) statusData.health),
|
||||||
|
Integer.toString((int) statusData.maxHealth),
|
||||||
|
Integer.toString(statusData.hunger),
|
||||||
|
Integer.toString(statusData.expLevel),
|
||||||
|
statusData.gameMode.toLowerCase()))
|
||||||
|
.ifPresent(user::sendMessage);
|
||||||
|
|
||||||
|
// Advancement and statistic data, if both are present in the snapshot
|
||||||
|
userData().getAdvancements()
|
||||||
|
.flatMap(advancementData -> userData().getStatistics()
|
||||||
|
.flatMap(statisticsData -> locales.getLocale("data_manager_advancements_statistics",
|
||||||
|
Integer.toString(advancementData.size()),
|
||||||
|
generateAdvancementPreview(advancementData, locales),
|
||||||
|
String.format("%.2f", (((statisticsData.untypedStatistics.getOrDefault(
|
||||||
|
"PLAY_ONE_MINUTE", 0)) / 20d) / 60d) / 60d))))
|
||||||
|
.ifPresent(user::sendMessage);
|
||||||
|
|
||||||
|
if (user.hasPermission(Permission.COMMAND_INVENTORY.node)
|
||||||
|
&& user.hasPermission(Permission.COMMAND_ENDER_CHEST.node)) {
|
||||||
|
locales.getLocale("data_manager_item_buttons", dataOwner.username, versionUUID().toString())
|
||||||
|
.ifPresent(user::sendMessage);
|
||||||
|
}
|
||||||
|
if (user.hasPermission(Permission.COMMAND_USER_DATA_MANAGE.node)) {
|
||||||
|
locales.getLocale("data_manager_management_buttons", dataOwner.username, versionUUID().toString())
|
||||||
|
.ifPresent(user::sendMessage);
|
||||||
|
}
|
||||||
|
if (user.hasPermission(Permission.COMMAND_USER_DATA_DUMP.node)) {
|
||||||
|
locales.getLocale("data_manager_system_buttons", dataOwner.username, versionUUID().toString())
|
||||||
|
.ifPresent(user::sendMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private String generateAdvancementPreview(@NotNull List<AdvancementData> advancementData, @NotNull Locales locales) {
|
||||||
|
final StringJoiner joiner = new StringJoiner("\n");
|
||||||
|
final List<AdvancementData> advancementsToPreview = advancementData.stream().filter(dataItem ->
|
||||||
|
!dataItem.key.startsWith("minecraft:recipes/")).toList();
|
||||||
|
final int PREVIEW_SIZE = 8;
|
||||||
|
for (int i = 0; i < advancementsToPreview.size(); i++) {
|
||||||
|
joiner.add(advancementsToPreview.get(i).key);
|
||||||
|
if (i >= PREVIEW_SIZE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final int remainingAdvancements = advancementsToPreview.size() - PREVIEW_SIZE;
|
||||||
|
if (remainingAdvancements > 0) {
|
||||||
|
joiner.add(locales.getRawLocale("data_manager_advancements_preview_remaining",
|
||||||
|
Integer.toString(remainingAdvancements)).orElse("+" + remainingAdvancements + "…"));
|
||||||
|
}
|
||||||
|
return joiner.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare UserData by creation timestamp
|
* Compare UserData by creation timestamp
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,181 +0,0 @@
|
|||||||
package net.william278.husksync.editor;
|
|
||||||
|
|
||||||
import net.william278.husksync.command.Permission;
|
|
||||||
import net.william278.husksync.config.Locales;
|
|
||||||
import net.william278.husksync.data.AdvancementData;
|
|
||||||
import net.william278.husksync.data.ItemData;
|
|
||||||
import net.william278.husksync.data.UserDataSnapshot;
|
|
||||||
import net.william278.husksync.player.OnlineUser;
|
|
||||||
import net.william278.husksync.player.User;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides methods for displaying and editing user data
|
|
||||||
*/
|
|
||||||
public class DataEditor {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map of currently open inventory and ender chest data editors
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
protected final HashMap<UUID, ItemEditorMenu> openInventoryMenus;
|
|
||||||
|
|
||||||
private final Locales locales;
|
|
||||||
|
|
||||||
public DataEditor(@NotNull Locales locales) {
|
|
||||||
this.openInventoryMenus = new HashMap<>();
|
|
||||||
this.locales = locales;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open an inventory or ender chest editor menu
|
|
||||||
*
|
|
||||||
* @param user The online user to open the editor for
|
|
||||||
* @param itemEditorMenu The {@link ItemEditorMenu} to open
|
|
||||||
* @see ItemEditorMenu#createInventoryMenu(ItemData, User, OnlineUser, Locales, boolean)
|
|
||||||
* @see ItemEditorMenu#createEnderChestMenu(ItemData, User, OnlineUser, Locales, boolean)
|
|
||||||
*/
|
|
||||||
public CompletableFuture<ItemData> openItemEditorMenu(@NotNull OnlineUser user,
|
|
||||||
@NotNull ItemEditorMenu itemEditorMenu) {
|
|
||||||
this.openInventoryMenus.put(user.uuid, itemEditorMenu);
|
|
||||||
return itemEditorMenu.showInventory(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close an inventory or ender chest editor menu
|
|
||||||
*
|
|
||||||
* @param user The online user to close the editor for
|
|
||||||
* @param itemData the {@link ItemData} contained within the menu at the time of closing
|
|
||||||
*/
|
|
||||||
public void closeInventoryMenu(@NotNull OnlineUser user, @NotNull ItemData itemData) {
|
|
||||||
if (this.openInventoryMenus.containsKey(user.uuid)) {
|
|
||||||
this.openInventoryMenus.get(user.uuid).closeInventory(itemData);
|
|
||||||
}
|
|
||||||
this.openInventoryMenus.remove(user.uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether edits to the inventory or ender chest menu are allowed
|
|
||||||
*
|
|
||||||
* @param user The online user with an inventory open to check
|
|
||||||
* @return {@code true} if edits to the inventory or ender chest menu are allowed; {@code false} otherwise, including if they don't have an inventory open
|
|
||||||
*/
|
|
||||||
public boolean cancelMenuEdit(@NotNull OnlineUser user) {
|
|
||||||
if (this.openInventoryMenus.containsKey(user.uuid)) {
|
|
||||||
return !this.openInventoryMenus.get(user.uuid).canEdit;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display a chat menu detailing information about {@link UserDataSnapshot}
|
|
||||||
*
|
|
||||||
* @param user The online user to display the message to
|
|
||||||
* @param userData The {@link UserDataSnapshot} to display information about
|
|
||||||
* @param dataOwner The {@link User} who owns the {@link UserDataSnapshot}
|
|
||||||
*/
|
|
||||||
public void displayDataOverview(@NotNull OnlineUser user, @NotNull UserDataSnapshot userData,
|
|
||||||
@NotNull User dataOwner) {
|
|
||||||
// Title message, timestamp, owner and cause.
|
|
||||||
locales.getLocale("data_manager_title",
|
|
||||||
userData.versionUUID().toString().split("-")[0],
|
|
||||||
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);
|
|
||||||
if (userData.pinned()) {
|
|
||||||
locales.getLocale("data_manager_pinned").ifPresent(user::sendMessage);
|
|
||||||
}
|
|
||||||
locales.getLocale("data_manager_cause",
|
|
||||||
userData.cause().name().toLowerCase().replaceAll("_", " "))
|
|
||||||
.ifPresent(user::sendMessage);
|
|
||||||
|
|
||||||
// User status data, if present in the snapshot
|
|
||||||
userData.userData().getStatus()
|
|
||||||
.flatMap(statusData -> locales.getLocale("data_manager_status",
|
|
||||||
Integer.toString((int) statusData.health),
|
|
||||||
Integer.toString((int) statusData.maxHealth),
|
|
||||||
Integer.toString(statusData.hunger),
|
|
||||||
Integer.toString(statusData.expLevel),
|
|
||||||
statusData.gameMode.toLowerCase()))
|
|
||||||
.ifPresent(user::sendMessage);
|
|
||||||
|
|
||||||
// Advancement and statistic data, if both are present in the snapshot
|
|
||||||
userData.userData().getAdvancements()
|
|
||||||
.flatMap(advancementData -> userData.userData().getStatistics()
|
|
||||||
.flatMap(statisticsData -> locales.getLocale("data_manager_advancements_statistics",
|
|
||||||
Integer.toString(advancementData.size()),
|
|
||||||
generateAdvancementPreview(advancementData),
|
|
||||||
String.format("%.2f", (((statisticsData.untypedStatistics.getOrDefault(
|
|
||||||
"PLAY_ONE_MINUTE", 0)) / 20d) / 60d) / 60d))))
|
|
||||||
.ifPresent(user::sendMessage);
|
|
||||||
|
|
||||||
if (user.hasPermission(Permission.COMMAND_INVENTORY.node)
|
|
||||||
&& user.hasPermission(Permission.COMMAND_ENDER_CHEST.node)) {
|
|
||||||
locales.getLocale("data_manager_item_buttons",
|
|
||||||
dataOwner.username, userData.versionUUID().toString())
|
|
||||||
.ifPresent(user::sendMessage);
|
|
||||||
}
|
|
||||||
if (user.hasPermission(Permission.COMMAND_USER_DATA_MANAGE.node)) {
|
|
||||||
locales.getLocale("data_manager_management_buttons",
|
|
||||||
dataOwner.username, userData.versionUUID().toString())
|
|
||||||
.ifPresent(user::sendMessage);
|
|
||||||
}
|
|
||||||
if (user.hasPermission(Permission.COMMAND_USER_DATA_DUMP.node)) {
|
|
||||||
locales.getLocale("data_manager_system_buttons",
|
|
||||||
dataOwner.username, userData.versionUUID().toString())
|
|
||||||
.ifPresent(user::sendMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private String generateAdvancementPreview(@NotNull List<AdvancementData> advancementData) {
|
|
||||||
final StringJoiner joiner = new StringJoiner("\n");
|
|
||||||
final List<AdvancementData> advancementsToPreview = advancementData.stream().filter(dataItem ->
|
|
||||||
!dataItem.key.startsWith("minecraft:recipes/")).toList();
|
|
||||||
final int PREVIEW_SIZE = 8;
|
|
||||||
for (int i = 0; i < advancementsToPreview.size(); i++) {
|
|
||||||
joiner.add(advancementsToPreview.get(i).key);
|
|
||||||
if (i >= PREVIEW_SIZE) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final int remainingAdvancements = advancementsToPreview.size() - PREVIEW_SIZE;
|
|
||||||
if (remainingAdvancements > 0) {
|
|
||||||
joiner.add(locales.getRawLocale("data_manager_advancements_preview_remaining",
|
|
||||||
Integer.toString(remainingAdvancements)).orElse("+" + remainingAdvancements + "…"));
|
|
||||||
}
|
|
||||||
return joiner.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display a paginated chat list of {@link UserDataSnapshot}s
|
|
||||||
*
|
|
||||||
* @param user The online user to display the message to
|
|
||||||
* @param userDataList The list of {@link UserDataSnapshot}s to display
|
|
||||||
* @param dataOwner The {@link User} who owns the {@link UserDataSnapshot}s
|
|
||||||
* @param page The page of the list to display
|
|
||||||
*/
|
|
||||||
public void displayDataSnapshotList(@NotNull OnlineUser user, @NotNull List<UserDataSnapshot> userDataList,
|
|
||||||
@NotNull User dataOwner, final int page) {
|
|
||||||
DataSnapshotList.create(userDataList, dataOwner, locales).displayPage(user, page);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether the user has an inventory editor menu open
|
|
||||||
*
|
|
||||||
* @param user {@link OnlineUser} to check
|
|
||||||
* @return {@code true} if the user has an inventory editor open; {@code false} otherwise
|
|
||||||
*/
|
|
||||||
public Optional<ItemEditorMenu> getEditingInventoryData(@NotNull OnlineUser user) {
|
|
||||||
return this.openInventoryMenus.containsKey(user.uuid) ? Optional.of(this.openInventoryMenus.get(user.uuid))
|
|
||||||
: Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
package net.william278.husksync.editor;
|
|
||||||
|
|
||||||
import de.themoep.minedown.adventure.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 ItemEditorMenuType itemEditorMenuType;
|
|
||||||
public final MineDown menuTitle;
|
|
||||||
public final boolean canEdit;
|
|
||||||
|
|
||||||
private CompletableFuture<ItemData> inventoryDataCompletableFuture;
|
|
||||||
|
|
||||||
private ItemEditorMenu(@NotNull ItemData itemData, ItemEditorMenuType itemEditorMenuType,
|
|
||||||
@NotNull MineDown menuTitle, boolean canEdit) {
|
|
||||||
this.itemData = itemData;
|
|
||||||
this.menuTitle = menuTitle;
|
|
||||||
this.itemEditorMenuType = itemEditorMenuType;
|
|
||||||
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, ItemEditorMenuType.INVENTORY_VIEWER,
|
|
||||||
locales.getLocale(ItemEditorMenuType.INVENTORY_VIEWER.localeKey, 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, ItemEditorMenuType.ENDER_CHEST_VIEWER,
|
|
||||||
locales.getLocale(ItemEditorMenuType.ENDER_CHEST_VIEWER.localeKey, dataOwner.username).orElse(new MineDown("")),
|
|
||||||
viewer.hasPermission(Permission.COMMAND_ENDER_CHEST_EDIT.node) && canEdit);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package net.william278.husksync.editor;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
public enum ItemEditorMenuType {
|
|
||||||
INVENTORY_VIEWER(45, "inventory_viewer_menu_title"),
|
|
||||||
ENDER_CHEST_VIEWER(27, "ender_chest_viewer_menu_title");
|
|
||||||
|
|
||||||
public final int slotCount;
|
|
||||||
final String localeKey;
|
|
||||||
|
|
||||||
ItemEditorMenuType(int slotCount, @NotNull String localeKey) {
|
|
||||||
this.slotCount = slotCount;
|
|
||||||
this.localeKey = localeKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@ package net.william278.husksync.listener;
|
|||||||
import net.william278.husksync.HuskSync;
|
import net.william278.husksync.HuskSync;
|
||||||
import net.william278.husksync.data.DataSaveCause;
|
import net.william278.husksync.data.DataSaveCause;
|
||||||
import net.william278.husksync.data.ItemData;
|
import net.william278.husksync.data.ItemData;
|
||||||
import net.william278.husksync.editor.ItemEditorMenuType;
|
|
||||||
import net.william278.husksync.player.OnlineUser;
|
import net.william278.husksync.player.OnlineUser;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
@@ -194,30 +193,6 @@ public abstract class EventListener {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle an inventory menu closing
|
|
||||||
*
|
|
||||||
* @param user The user who closed the menu
|
|
||||||
* @param menuInventory Serialized {@link ItemData} containing the inventory contents
|
|
||||||
* @implNote The size of the serialized {@link ItemData} array is determined by the {@link ItemEditorMenuType} of the closed inventory
|
|
||||||
*/
|
|
||||||
protected final void handleMenuClose(@NotNull OnlineUser user, @NotNull ItemData menuInventory) {
|
|
||||||
if (disabling) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
plugin.getDataEditor().closeInventoryMenu(user, menuInventory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether an inventory click should be cancelled
|
|
||||||
*
|
|
||||||
* @param user {@link OnlineUser} performing the event
|
|
||||||
* @return Whether the event should be cancelled
|
|
||||||
*/
|
|
||||||
protected final boolean cancelInventoryClick(@NotNull OnlineUser user) {
|
|
||||||
return plugin.getDataEditor().cancelMenuEdit(user) || cancelPlayerEvent(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether a player event should be cancelled
|
* Determine whether a player event should be cancelled
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
package net.william278.husksync.player;
|
package net.william278.husksync.player;
|
||||||
|
|
||||||
import de.themoep.minedown.adventure.MineDown;
|
import de.themoep.minedown.adventure.MineDown;
|
||||||
|
import net.william278.desertwell.Version;
|
||||||
import net.william278.husksync.config.Settings;
|
import net.william278.husksync.config.Settings;
|
||||||
import net.william278.husksync.data.*;
|
import net.william278.husksync.data.*;
|
||||||
import net.william278.husksync.editor.ItemEditorMenu;
|
|
||||||
import net.william278.husksync.event.EventCannon;
|
import net.william278.husksync.event.EventCannon;
|
||||||
import net.william278.husksync.event.PreSyncEvent;
|
import net.william278.husksync.event.PreSyncEvent;
|
||||||
import net.william278.husksync.util.Logger;
|
import net.william278.husksync.util.Logger;
|
||||||
import net.william278.desertwell.Version;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -207,12 +206,8 @@ public abstract class OnlineUser extends User {
|
|||||||
*/
|
*/
|
||||||
public abstract boolean hasPermission(@NotNull String node);
|
public abstract boolean hasPermission(@NotNull String node);
|
||||||
|
|
||||||
/**
|
public abstract CompletableFuture<Optional<ItemData>> showMenu(@NotNull ItemData itemData, boolean editable,
|
||||||
* Show the player a {@link ItemEditorMenu} GUI
|
int rows, @NotNull MineDown title);
|
||||||
*
|
|
||||||
* @param menu The {@link ItemEditorMenu} interface to show
|
|
||||||
*/
|
|
||||||
public abstract void showMenu(@NotNull ItemEditorMenu menu);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the player is dead
|
* Returns true if the player is dead
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package net.william278.husksync.editor;
|
package net.william278.husksync.util;
|
||||||
|
|
||||||
import net.william278.husksync.config.Locales;
|
import net.william278.husksync.config.Locales;
|
||||||
import net.william278.husksync.data.UserDataSnapshot;
|
import net.william278.husksync.data.UserDataSnapshot;
|
||||||
@@ -7,9 +7,8 @@ import net.william278.husksync.player.User;
|
|||||||
import net.william278.paginedown.PaginatedList;
|
import net.william278.paginedown.PaginatedList;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,8 +28,8 @@ public class DataSnapshotList {
|
|||||||
this.paginatedList = PaginatedList.of(snapshots.stream()
|
this.paginatedList = PaginatedList.of(snapshots.stream()
|
||||||
.map(snapshot -> locales.getRawLocale("data_list_item",
|
.map(snapshot -> locales.getRawLocale("data_list_item",
|
||||||
getNumberIcon(snapshotNumber.getAndIncrement()),
|
getNumberIcon(snapshotNumber.getAndIncrement()),
|
||||||
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT,
|
new SimpleDateFormat("MMM dd yyyy, HH:mm:ss.sss")
|
||||||
Locale.getDefault()).format(snapshot.versionTimestamp()),
|
.format(snapshot.versionTimestamp()),
|
||||||
snapshot.versionUUID().toString().split("-")[0],
|
snapshot.versionUUID().toString().split("-")[0],
|
||||||
snapshot.versionUUID().toString(),
|
snapshot.versionUUID().toString(),
|
||||||
snapshot.cause().name().toLowerCase().replaceAll("_", " "),
|
snapshot.cause().name().toLowerCase().replaceAll("_", " "),
|
||||||
@@ -53,7 +52,7 @@ public class DataSnapshotList {
|
|||||||
* @param locales The {@link Locales} instance
|
* @param locales The {@link Locales} instance
|
||||||
* @return A new {@link DataSnapshotList}, to be viewed with {@link #displayPage(OnlineUser, int)}
|
* @return A new {@link DataSnapshotList}, to be viewed with {@link #displayPage(OnlineUser, int)}
|
||||||
*/
|
*/
|
||||||
protected static DataSnapshotList create(@NotNull List<UserDataSnapshot> snapshots, @NotNull User user,
|
public static DataSnapshotList create(@NotNull List<UserDataSnapshot> snapshots, @NotNull User user,
|
||||||
@NotNull Locales locales) {
|
@NotNull Locales locales) {
|
||||||
return new DataSnapshotList(snapshots, user, locales);
|
return new DataSnapshotList(snapshots, user, locales);
|
||||||
}
|
}
|
||||||
@@ -77,7 +76,7 @@ public class DataSnapshotList {
|
|||||||
* @param onlineUser The online user to display the message to
|
* @param onlineUser The online user to display the message to
|
||||||
* @param page The page number to display
|
* @param page The page number to display
|
||||||
*/
|
*/
|
||||||
protected void displayPage(@NotNull OnlineUser onlineUser, int page) {
|
public void displayPage(@NotNull OnlineUser onlineUser, int page) {
|
||||||
onlineUser.sendMessage(paginatedList.getNearestValidPage(page));
|
onlineUser.sendMessage(paginatedList.getNearestValidPage(page));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10,8 +10,8 @@ error_no_data_to_display: '[Error:](#ff3300) [Could not find any user data to di
|
|||||||
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'
|
||||||
ender_chest_viewer_menu_title: '&0%1%''s Ender Chest'
|
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_update_failed: '[🔔 Failed to update your data! Please contact an administrator.](#ff7e5e)'
|
data_update_failed: '[🔔 Failed to update your data! Please contact an administrator.](#ff7e5e)'
|
||||||
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](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [for](#00fb9a) [%3%](#00fb9a bold show_text=&7Player UUID:\n&8%4%)[:](#00fb9a)'
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ error_no_data_to_display: '[Error:](#ff3300) [Could not find any user data to di
|
|||||||
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'
|
||||||
ender_chest_viewer_menu_title: '&0%1%''s Ender Chest'
|
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_update_failed: '[🔔 Failed to update your data! Please contact an administrator.](#ff7e5e)'
|
data_update_failed: '[🔔 Failed to update your data! Please contact an administrator.](#ff7e5e)'
|
||||||
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](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [for](#00fb9a) [%3%](#00fb9a bold show_text=&7Player UUID:\n&8%4%)[:](#00fb9a)'
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ error_no_data_to_display: '[Error:](#ff3300) [Could not find any user data to di
|
|||||||
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'
|
||||||
ender_chest_viewer_menu_title: '&0%1%''s Ender Chest'
|
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_update_failed: '[🔔 Failed to update your data! Please contact an administrator.](#ff7e5e)'
|
data_update_failed: '[🔔 Failed to update your data! Please contact an administrator.](#ff7e5e)'
|
||||||
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](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [for](#00fb9a) [%3%](#00fb9a bold show_text=&7Player UUID:\n&8%4%)[:](#00fb9a)'
|
||||||
|
|||||||
@@ -3,14 +3,10 @@ package net.william278.husksync.player;
|
|||||||
import de.themoep.minedown.adventure.MineDown;
|
import de.themoep.minedown.adventure.MineDown;
|
||||||
import net.william278.husksync.config.Settings;
|
import net.william278.husksync.config.Settings;
|
||||||
import net.william278.husksync.data.*;
|
import net.william278.husksync.data.*;
|
||||||
import net.william278.husksync.editor.ItemEditorMenu;
|
|
||||||
import net.william278.desertwell.Version;
|
import net.william278.desertwell.Version;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
public class DummyPlayer extends OnlineUser {
|
public class DummyPlayer extends OnlineUser {
|
||||||
@@ -152,10 +148,13 @@ public class DummyPlayer extends OnlineUser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showMenu(@NotNull ItemEditorMenu menu) {
|
public CompletableFuture<Optional<ItemData>> showMenu(@NotNull ItemData itemData, boolean editable,
|
||||||
|
int rows, @NotNull MineDown title) {
|
||||||
// do nothing
|
// do nothing
|
||||||
|
return CompletableFuture.completedFuture(Optional.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDead() {
|
public boolean isDead() {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user