mirror of
https://github.com/plexusorg/Plex.git
synced 2026-07-14 21:44:55 +00:00
Updater improvements, toggle pvp, Dialog API
This commit is contained in:
@@ -3,6 +3,7 @@ import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
val paperApiVersion = "26.1.2"
|
||||
val supportedMinecraftVersions = listOf("26.1", "26.1.1", "26.1.2", "26.2")
|
||||
|
||||
plugins {
|
||||
java
|
||||
@@ -132,7 +133,7 @@ tasks {
|
||||
property("buildNumber", if (System.getenv("BUILD_NUMBER") != null) System.getenv("BUILD_NUMBER") else getBuildNumber())
|
||||
property("date", SimpleDateFormat("MM/dd/yyyy '<light_purple>at<gold>' hh:mm:ss a z").format(Date()))
|
||||
property("gitCommit", indraGit.commit().get().name)
|
||||
property("minecraftVersion", paperApiVersion)
|
||||
property("minecraftVersion", supportedMinecraftVersions.joinToString(","))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import dev.plex.command.ServerCommand;
|
||||
import dev.plex.command.ServerCommandContext;
|
||||
import dev.plex.command.exception.CommandFailException;
|
||||
import dev.plex.menu.impl.MaterialMenu;
|
||||
import dev.plex.menu.dialog.MaterialDialog;
|
||||
import dev.plex.util.GameRuleUtil;
|
||||
import dev.plex.util.PlexLog;
|
||||
|
||||
@@ -126,7 +126,7 @@ public class DebugCMD extends ServerCommand
|
||||
{
|
||||
return context.messageComponent("noPermissionConsole");
|
||||
}
|
||||
new MaterialMenu().open(playerSender);
|
||||
new MaterialDialog().open(playerSender);
|
||||
return null;
|
||||
}
|
||||
return context.usage();
|
||||
|
||||
@@ -10,6 +10,7 @@ import dev.plex.util.BuildInfo;
|
||||
import dev.plex.util.PlexLog;
|
||||
import dev.plex.util.PlexUtils;
|
||||
import dev.plex.util.TimeUtils;
|
||||
import dev.plex.util.UpdateChecker;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -18,6 +19,7 @@ import io.papermc.paper.command.brigadier.CommandSourceStack;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PlexCMD extends ServerCommand
|
||||
@@ -69,7 +71,7 @@ public class PlexCMD extends ServerCommand
|
||||
context.send(sender, context.mmString("<light_purple>Authors: <gold>Telesphoreo, Taahh"));
|
||||
context.send(sender, context.mmString("<light_purple>Built by: <gold>" + BuildInfo.getAuthor() + " <light_purple>on <gold>" + BuildInfo.getDate()));
|
||||
context.send(sender, context.mmString("<light_purple>Run <gold>/plex modules <light_purple>to see a list of modules."));
|
||||
plugin.getUpdateChecker().getUpdateStatusMessage(sender, true, 2);
|
||||
plugin.getApi().scheduler().runAsync(() -> plugin.getUpdateChecker().getUpdateStatusMessage(sender, true, 2));
|
||||
return null;
|
||||
}
|
||||
if (args[0].equalsIgnoreCase("reload"))
|
||||
@@ -111,12 +113,19 @@ public class PlexCMD extends ServerCommand
|
||||
else if (args[1].equalsIgnoreCase("update"))
|
||||
{
|
||||
context.checkPermission(sender, "plex.modules.update");
|
||||
plugin.getApi().scheduler().runAsync(() ->
|
||||
{
|
||||
for (PlexModule module : plugin.getModuleManager().getModules())
|
||||
{
|
||||
plugin.getUpdateChecker().updateModuleJar(sender, module);
|
||||
}
|
||||
plugin.getApi().scheduler().runGlobal(() ->
|
||||
{
|
||||
plugin.getModuleManager().reloadModules();
|
||||
return context.mmString("<green>All modules updated and reloaded!");
|
||||
sender.sendMessage(context.mmString("<green>All modules updated and reloaded!"));
|
||||
});
|
||||
});
|
||||
return null;
|
||||
}
|
||||
else if (args[1].equalsIgnoreCase("install"))
|
||||
{
|
||||
@@ -126,7 +135,7 @@ public class PlexCMD extends ServerCommand
|
||||
return context.usage();
|
||||
}
|
||||
String moduleName = args[2];
|
||||
plugin.getUpdateChecker().installModuleJar(sender, moduleName);
|
||||
plugin.getApi().scheduler().runAsync(() -> plugin.getUpdateChecker().installModuleJar(sender, moduleName));
|
||||
return context.mmString("<green>Installing module <yellow>" + moduleName + "<green>...");
|
||||
}
|
||||
else if (args[1].equalsIgnoreCase("uninstall"))
|
||||
@@ -154,12 +163,22 @@ public class PlexCMD extends ServerCommand
|
||||
else if (args[0].equalsIgnoreCase("update"))
|
||||
{
|
||||
context.checkPermission(sender, "plex.update");
|
||||
if (!plugin.getUpdateChecker().getUpdateStatusMessage(sender, false, 0))
|
||||
plugin.getApi().scheduler().runAsync(() ->
|
||||
{
|
||||
return context.mmString("<red>Plex is already up to date!");
|
||||
UpdateChecker.UpdateCheckResult result = plugin.getUpdateChecker().checkForUpdates(false);
|
||||
if (result.status() == UpdateChecker.UpdateCheckStatus.UPDATE_AVAILABLE)
|
||||
{
|
||||
plugin.getUpdateChecker().updateJar(sender, result.metadata(), () -> sendMessage(sender, context.mmString("<red>Alert: Restart the server for the new JAR file to be applied.")));
|
||||
return;
|
||||
}
|
||||
plugin.getUpdateChecker().updateJar(sender, "Plex", false);
|
||||
return context.mmString("<red>Alert: Restart the server for the new JAR file to be applied.");
|
||||
if (result.status() == UpdateChecker.UpdateCheckStatus.UP_TO_DATE)
|
||||
{
|
||||
sendMessage(sender, context.mmString("<red>Plex is already up to date!"));
|
||||
return;
|
||||
}
|
||||
plugin.getUpdateChecker().sendResultMessage(sender, result, 2);
|
||||
});
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -167,4 +186,14 @@ public class PlexCMD extends ServerCommand
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void sendMessage(CommandSender sender, Component message)
|
||||
{
|
||||
if (sender instanceof Player player)
|
||||
{
|
||||
plugin.getApi().scheduler().runEntity(player, () -> sender.sendMessage(message));
|
||||
return;
|
||||
}
|
||||
plugin.getApi().scheduler().runGlobal(() -> sender.sendMessage(message));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,7 @@ import dev.plex.command.ServerCommand;
|
||||
import dev.plex.command.ServerCommandContext;
|
||||
import dev.plex.command.exception.PlayerNotFoundException;
|
||||
import dev.plex.command.source.RequiredCommandSource;
|
||||
import dev.plex.menu.impl.PunishedPlayerMenu;
|
||||
import dev.plex.menu.impl.PunishmentMenu;
|
||||
import dev.plex.menu.dialog.PunishmentDialog;
|
||||
import dev.plex.player.PlexPlayer;
|
||||
|
||||
|
||||
@@ -45,9 +44,10 @@ public class PunishmentsCMD extends ServerCommand
|
||||
CommandSender sender = context.sender();
|
||||
Player playerSender = context.player();
|
||||
String[] args = context.args();
|
||||
PunishmentDialog dialog = new PunishmentDialog(plugin.getPlayerService());
|
||||
if (args.length == 0)
|
||||
{
|
||||
new PunishmentMenu(plugin.getPlayerService()).open(playerSender);
|
||||
dialog.open(playerSender);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -59,7 +59,7 @@ public class PunishmentsCMD extends ServerCommand
|
||||
final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(args[0]);
|
||||
final PlexPlayer player = offlinePlayer.isOnline() ? context.getOnlinePlexPlayer(args[0]) : context.getOfflinePlexPlayer(offlinePlayer.getUniqueId());
|
||||
|
||||
new PunishedPlayerMenu(player, plugin.getPlayerService()).open(playerSender);
|
||||
dialog.open(playerSender, player);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -3,7 +3,7 @@ package dev.plex.command.impl;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import dev.plex.command.ServerCommand;
|
||||
import dev.plex.command.ServerCommandContext;
|
||||
import dev.plex.menu.impl.ToggleMenu;
|
||||
import dev.plex.menu.dialog.ToggleDialog;
|
||||
import dev.plex.util.PlexUtils;
|
||||
|
||||
|
||||
@@ -47,19 +47,8 @@ public class ToggleCMD extends ServerCommand
|
||||
CommandSender sender = context.sender();
|
||||
Player playerSender = context.player();
|
||||
String[] args = context.args();
|
||||
if (context.isConsole(sender) || playerSender == null)
|
||||
if (args.length > 0)
|
||||
{
|
||||
if (args.length == 0)
|
||||
{
|
||||
sender.sendMessage(context.messageComponent("toggleAvailable"));
|
||||
sender.sendMessage(toggleListItem(context, "toggleExplosions", "explosions"));
|
||||
sender.sendMessage(toggleListItem(context, "toggleFluidSpread", "fluidspread"));
|
||||
sender.sendMessage(toggleListItem(context, "toggleDrops", "drops"));
|
||||
sender.sendMessage(toggleListItem(context, "toggleRedstone", "redstone"));
|
||||
sender.sendMessage(toggleListItem(context, "togglePvp", "pvp"));
|
||||
sender.sendMessage(toggleListItem(context, "toggleChat", "chat"));
|
||||
return null;
|
||||
}
|
||||
switch (args[0].toLowerCase())
|
||||
{
|
||||
case "explosions" ->
|
||||
@@ -93,7 +82,18 @@ public class ToggleCMD extends ServerCommand
|
||||
}
|
||||
}
|
||||
}
|
||||
new ToggleMenu(plugin).open(playerSender);
|
||||
if (context.isConsole(sender) || playerSender == null)
|
||||
{
|
||||
sender.sendMessage(context.messageComponent("toggleAvailable"));
|
||||
sender.sendMessage(toggleListItem(context, "toggleExplosions", "explosions"));
|
||||
sender.sendMessage(toggleListItem(context, "toggleFluidSpread", "fluidspread"));
|
||||
sender.sendMessage(toggleListItem(context, "toggleDrops", "drops"));
|
||||
sender.sendMessage(toggleListItem(context, "toggleRedstone", "redstone"));
|
||||
sender.sendMessage(toggleListItem(context, "togglePvp", "pvp"));
|
||||
sender.sendMessage(toggleListItem(context, "toggleChat", "chat"));
|
||||
return null;
|
||||
}
|
||||
new ToggleDialog(plugin).open(playerSender);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import dev.plex.listener.impl.CommandListener;
|
||||
import dev.plex.listener.impl.DropListener;
|
||||
import dev.plex.listener.impl.FreezeListener;
|
||||
import dev.plex.listener.impl.GameModeListener;
|
||||
import dev.plex.listener.impl.MenuListener;
|
||||
import dev.plex.listener.impl.MobListener;
|
||||
import dev.plex.listener.impl.MuteListener;
|
||||
import dev.plex.listener.impl.PlayerListener;
|
||||
@@ -50,7 +49,6 @@ public class ListenerHandler
|
||||
register(() -> new DropListener(plugin));
|
||||
register(() -> new FreezeListener(plugin));
|
||||
register(() -> new GameModeListener(plugin));
|
||||
register(() -> new MenuListener(plugin));
|
||||
register(() -> new MobListener(plugin));
|
||||
register(() -> new MuteListener(plugin));
|
||||
register(() -> new PlayerListener(plugin));
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
package dev.plex.listener.impl;
|
||||
|
||||
import dev.plex.Plex;
|
||||
import dev.plex.listener.ServerListenerBase;
|
||||
import dev.plex.menu.AbstractMenu;
|
||||
import dev.plex.menu.pagination.PageableMenu;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
/**
|
||||
* @author Taah
|
||||
* @since 7:01 AM [02-09-2023]
|
||||
*/
|
||||
public class MenuListener extends ServerListenerBase
|
||||
{
|
||||
public MenuListener(Plex plugin)
|
||||
{
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onClick(InventoryClickEvent event)
|
||||
{
|
||||
if (event.getClickedInventory() == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getCurrentItem() == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(event.getWhoClicked() instanceof Player player))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AbstractMenu.INVENTORIES.entrySet().stream().filter(entry -> entry.getKey().equals(event.getView().title()))
|
||||
.findFirst()
|
||||
.ifPresent(entry ->
|
||||
{
|
||||
if (entry.getValue() instanceof PageableMenu.Page page)
|
||||
{
|
||||
final ItemMeta meta = event.getCurrentItem().getItemMeta();
|
||||
if (meta != null && meta.displayName() != null)
|
||||
{
|
||||
if (meta.displayName().equals(PageableMenu.previousItem().getItemMeta().displayName()))
|
||||
{
|
||||
page.parent().currentPage(page.parent().currentPage() - 1);
|
||||
page.parent().open(player, page.parent().currentPage());
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
else if (meta.displayName().equals(PageableMenu.nextItem().getItemMeta().displayName()))
|
||||
{
|
||||
page.parent().currentPage(page.parent().currentPage() + 1);
|
||||
page.parent().open(player, page.parent().currentPage());
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
else if (meta.displayName().equals(PageableMenu.closeItem().getItemMeta().displayName()))
|
||||
{
|
||||
player.closeInventory();
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
event.setCancelled(entry.getValue().onClick(event.getView(), event.getClickedInventory(), player, event.getCurrentItem()));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package dev.plex.menu;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import dev.plex.util.minimessage.SafeMiniMessage;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
@Getter
|
||||
@Accessors(fluent = true)
|
||||
public abstract class AbstractMenu
|
||||
{
|
||||
public static final Map<Component, AbstractMenu> INVENTORIES = Maps.newHashMap();
|
||||
private final Component name;
|
||||
private final Inventory inventory;
|
||||
|
||||
public AbstractMenu(Component name, Rows rows)
|
||||
{
|
||||
this.name = name;
|
||||
this.inventory = Bukkit.createInventory(null, rows.slots, name);
|
||||
|
||||
INVENTORIES.put(name, this);
|
||||
}
|
||||
|
||||
public AbstractMenu(String name, Rows rows)
|
||||
{
|
||||
this(SafeMiniMessage.mmDeserializeWithoutEvents(name), rows);
|
||||
}
|
||||
|
||||
public abstract boolean onClick(InventoryView view, Inventory inventory, Player player, ItemStack clicked);
|
||||
|
||||
public void open(Player player)
|
||||
{
|
||||
player.openInventory(this.inventory);
|
||||
}
|
||||
|
||||
public enum Rows
|
||||
{
|
||||
ONE(9), TWO(18), THREE(27), FOUR(36), FIVE(45), SIX(54);
|
||||
|
||||
private final int slots;
|
||||
|
||||
Rows(int slots)
|
||||
{
|
||||
this.slots = slots;
|
||||
}
|
||||
|
||||
public int slots()
|
||||
{
|
||||
return this.slots;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package dev.plex.menu.dialog;
|
||||
|
||||
import io.papermc.paper.dialog.Dialog;
|
||||
import io.papermc.paper.registry.data.dialog.ActionButton;
|
||||
import io.papermc.paper.registry.data.dialog.DialogBase;
|
||||
import io.papermc.paper.registry.data.dialog.action.DialogAction;
|
||||
import io.papermc.paper.registry.data.dialog.body.DialogBody;
|
||||
import io.papermc.paper.registry.data.dialog.type.DialogType;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickCallback;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class MaterialDialog
|
||||
{
|
||||
private static final int PAGE_SIZE = 40;
|
||||
private static final ClickCallback.Options CALLBACK_OPTIONS = ClickCallback.Options.builder()
|
||||
.uses(1)
|
||||
.lifetime(Duration.ofMinutes(5))
|
||||
.build();
|
||||
|
||||
private final List<Material> materials = Arrays.stream(Material.values())
|
||||
.filter(material -> !material.isAir())
|
||||
.toList();
|
||||
|
||||
public void open(Player player)
|
||||
{
|
||||
open(player, 0);
|
||||
}
|
||||
|
||||
private void open(Player player, int page)
|
||||
{
|
||||
player.showDialog(create(page));
|
||||
}
|
||||
|
||||
private Dialog create(int page)
|
||||
{
|
||||
int pageCount = Math.max(1, (int) Math.ceil(materials.size() / (double) PAGE_SIZE));
|
||||
int currentPage = Math.max(0, Math.min(page, pageCount - 1));
|
||||
int fromIndex = currentPage * PAGE_SIZE;
|
||||
int toIndex = Math.min(fromIndex + PAGE_SIZE, materials.size());
|
||||
List<ActionButton> actions = new ArrayList<>(materials.subList(fromIndex, toIndex).stream()
|
||||
.map(material -> materialButton(material, currentPage))
|
||||
.toList());
|
||||
if (currentPage > 0)
|
||||
{
|
||||
actions.add(pageButton("Previous Page", currentPage - 1));
|
||||
}
|
||||
if (currentPage + 1 < pageCount)
|
||||
{
|
||||
actions.add(pageButton("Next Page", currentPage + 1));
|
||||
}
|
||||
|
||||
return Dialog.create(builder -> builder.empty()
|
||||
.base(DialogBase.builder(Component.text("Materials"))
|
||||
.canCloseWithEscape(true)
|
||||
.pause(false)
|
||||
.afterAction(DialogBase.DialogAfterAction.WAIT_FOR_RESPONSE)
|
||||
.body(List.of(DialogBody.plainMessage(Component.text("Page " + (currentPage + 1) + " of " + pageCount))))
|
||||
.build())
|
||||
.type(DialogType.multiAction(actions, closeButton(), 4)));
|
||||
}
|
||||
|
||||
private ActionButton materialButton(Material material, int page)
|
||||
{
|
||||
return ActionButton.builder(Component.text(material.name()))
|
||||
.width(120)
|
||||
.action(DialogAction.customClick((response, audience) ->
|
||||
{
|
||||
if (audience instanceof Player player)
|
||||
{
|
||||
player.sendMessage(Component.text(material.name()));
|
||||
open(player, page);
|
||||
}
|
||||
}, CALLBACK_OPTIONS))
|
||||
.build();
|
||||
}
|
||||
|
||||
private ActionButton pageButton(String label, int page)
|
||||
{
|
||||
return ActionButton.builder(Component.text(label))
|
||||
.width(150)
|
||||
.action(DialogAction.customClick((response, audience) ->
|
||||
{
|
||||
if (audience instanceof Player player)
|
||||
{
|
||||
open(player, page);
|
||||
}
|
||||
}, CALLBACK_OPTIONS))
|
||||
.build();
|
||||
}
|
||||
|
||||
private ActionButton closeButton()
|
||||
{
|
||||
return ActionButton.builder(Component.text("Close"))
|
||||
.width(150)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package dev.plex.menu.dialog;
|
||||
|
||||
import dev.plex.player.PlayerService;
|
||||
import dev.plex.player.PlexPlayer;
|
||||
import dev.plex.punishment.Punishment;
|
||||
import dev.plex.util.PlexUtils;
|
||||
import dev.plex.util.TimeUtils;
|
||||
import io.papermc.paper.dialog.Dialog;
|
||||
import io.papermc.paper.registry.data.dialog.ActionButton;
|
||||
import io.papermc.paper.registry.data.dialog.DialogBase;
|
||||
import io.papermc.paper.registry.data.dialog.action.DialogAction;
|
||||
import io.papermc.paper.registry.data.dialog.body.DialogBody;
|
||||
import io.papermc.paper.registry.data.dialog.type.DialogType;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickCallback;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class PunishmentDialog
|
||||
{
|
||||
private static final ClickCallback.Options CALLBACK_OPTIONS = ClickCallback.Options.builder()
|
||||
.uses(1)
|
||||
.lifetime(Duration.ofMinutes(5))
|
||||
.build();
|
||||
|
||||
private final PlayerService playerService;
|
||||
|
||||
public PunishmentDialog(PlayerService playerService)
|
||||
{
|
||||
this.playerService = playerService;
|
||||
}
|
||||
|
||||
public void open(Player player)
|
||||
{
|
||||
player.showDialog(playerListDialog());
|
||||
}
|
||||
|
||||
public void open(Player viewer, PlexPlayer punishedPlayer)
|
||||
{
|
||||
viewer.showDialog(playerPunishmentsDialog(punishedPlayer));
|
||||
}
|
||||
|
||||
private Dialog playerListDialog()
|
||||
{
|
||||
List<ActionButton> actions = Bukkit.getOnlinePlayers().stream()
|
||||
.map(this::playerButton)
|
||||
.toList();
|
||||
|
||||
return Dialog.create(builder -> builder.empty()
|
||||
.base(DialogBase.builder(PlexUtils.messageComponent("punishmentMenuTitle"))
|
||||
.canCloseWithEscape(true)
|
||||
.pause(false)
|
||||
.afterAction(DialogBase.DialogAfterAction.WAIT_FOR_RESPONSE)
|
||||
.body(List.of(DialogBody.plainMessage(Component.text("Select an online player to view their punishments."))))
|
||||
.build())
|
||||
.type(DialogType.multiAction(actions, closeButton(), 2)));
|
||||
}
|
||||
|
||||
private Dialog playerPunishmentsDialog(PlexPlayer punishedPlayer)
|
||||
{
|
||||
List<DialogBody> body = new ArrayList<>();
|
||||
List<Punishment> punishments = punishedPlayer.getPunishments();
|
||||
|
||||
if (punishments.isEmpty())
|
||||
{
|
||||
body.add(DialogBody.plainMessage(Component.text("No punishments found.")));
|
||||
}
|
||||
else
|
||||
{
|
||||
punishments.forEach(punishment -> body.add(DialogBody.plainMessage(punishmentSummary(punishment), 320)));
|
||||
}
|
||||
|
||||
return Dialog.create(builder -> builder.empty()
|
||||
.base(DialogBase.builder(PlexUtils.messageComponent("punishedPlayerMenuTitle", punishedPlayer.getName()))
|
||||
.canCloseWithEscape(true)
|
||||
.pause(false)
|
||||
.afterAction(DialogBase.DialogAfterAction.WAIT_FOR_RESPONSE)
|
||||
.body(body)
|
||||
.build())
|
||||
.type(DialogType.multiAction(List.of(backButton()), closeButton(), 2)));
|
||||
}
|
||||
|
||||
private ActionButton playerButton(Player player)
|
||||
{
|
||||
return ActionButton.builder(Component.text(player.getName()))
|
||||
.width(150)
|
||||
.action(DialogAction.customClick((response, audience) -> openPunishments(audience, player), CALLBACK_OPTIONS))
|
||||
.build();
|
||||
}
|
||||
|
||||
private ActionButton backButton()
|
||||
{
|
||||
return ActionButton.builder(Component.text("Back"))
|
||||
.width(150)
|
||||
.action(DialogAction.customClick((response, audience) ->
|
||||
{
|
||||
if (audience instanceof Player player)
|
||||
{
|
||||
open(player);
|
||||
}
|
||||
}, CALLBACK_OPTIONS))
|
||||
.build();
|
||||
}
|
||||
|
||||
private ActionButton closeButton()
|
||||
{
|
||||
return ActionButton.builder(Component.text("Close"))
|
||||
.width(150)
|
||||
.build();
|
||||
}
|
||||
|
||||
private void openPunishments(Audience audience, OfflinePlayer selectedPlayer)
|
||||
{
|
||||
if (!(audience instanceof Player viewer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PlexPlayer punishedPlayer = playerService.getPlayer(selectedPlayer.getUniqueId());
|
||||
if (punishedPlayer == null)
|
||||
{
|
||||
viewer.sendMessage(PlexUtils.messageComponent("punishmentPlayerNotFound"));
|
||||
return;
|
||||
}
|
||||
open(viewer, punishedPlayer);
|
||||
}
|
||||
|
||||
private Component punishmentSummary(Punishment punishment)
|
||||
{
|
||||
String punisher = punishment.getPunisher() == null ? "CONSOLE" : playerService.getNameByUUID(punishment.getPunisher());
|
||||
return Component.text(punishment.getType().name() + "\n"
|
||||
+ "By: " + punisher + "\n"
|
||||
+ "Issued: " + TimeUtils.useTimezone(punishment.getIssueDate()) + "\n"
|
||||
+ "Expire(d/s): " + TimeUtils.useTimezone(punishment.getEndDate()) + "\n"
|
||||
+ "Reason: " + punishment.getReason());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package dev.plex.menu.dialog;
|
||||
|
||||
import dev.plex.Plex;
|
||||
import dev.plex.util.PlexUtils;
|
||||
import io.papermc.paper.dialog.Dialog;
|
||||
import io.papermc.paper.registry.data.dialog.ActionButton;
|
||||
import io.papermc.paper.registry.data.dialog.DialogBase;
|
||||
import io.papermc.paper.registry.data.dialog.action.DialogAction;
|
||||
import io.papermc.paper.registry.data.dialog.body.DialogBody;
|
||||
import io.papermc.paper.registry.data.dialog.type.DialogType;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickCallback;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class ToggleDialog
|
||||
{
|
||||
private static final ClickCallback.Options CALLBACK_OPTIONS = ClickCallback.Options.builder()
|
||||
.uses(1)
|
||||
.lifetime(Duration.ofMinutes(5))
|
||||
.build();
|
||||
|
||||
private final Plex plugin;
|
||||
|
||||
public ToggleDialog(Plex plugin)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void open(Player player)
|
||||
{
|
||||
player.showDialog(create());
|
||||
}
|
||||
|
||||
private Dialog create()
|
||||
{
|
||||
return Dialog.create(builder -> builder.empty()
|
||||
.base(DialogBase.builder(PlexUtils.messageComponent("toggleMenuTitle"))
|
||||
.canCloseWithEscape(true)
|
||||
.pause(false)
|
||||
.afterAction(DialogBase.DialogAfterAction.WAIT_FOR_RESPONSE)
|
||||
.body(List.of(
|
||||
DialogBody.plainMessage(statusLine("toggleExplosions", "explosions", true)),
|
||||
DialogBody.plainMessage(statusLine("toggleFluidSpread", "fluidspread", false)),
|
||||
DialogBody.plainMessage(statusLine("toggleDrops", "drops", false)),
|
||||
DialogBody.plainMessage(statusLine("toggleRedstone", "redstone", false)),
|
||||
DialogBody.plainMessage(statusLine("togglePvp", "pvp", false)),
|
||||
DialogBody.plainMessage(Component.text(PlexUtils.messageString("toggleChat") + ": " + PlexUtils.messageString(plugin.toggles.getBoolean("chat") ? "stateOn" : "stateOff")))))
|
||||
.build())
|
||||
.type(DialogType.multiAction(List.of(
|
||||
toggleButton("toggleExplosions", "toggleExplosionsLower", "explosions"),
|
||||
toggleButton("toggleFluidSpread", "toggleFluidSpreadLower", "fluidspread"),
|
||||
toggleButton("toggleDrops", "toggleDropsLower", "drops"),
|
||||
toggleButton("toggleRedstone", "toggleRedstoneLower", "redstone"),
|
||||
toggleButton("togglePvp", "togglePvpLower", "pvp"),
|
||||
toggleButton("toggleChat", "toggleChatLower", "chat")),
|
||||
closeButton(), 2)));
|
||||
}
|
||||
|
||||
private ActionButton toggleButton(String nameKey, String lowerNameKey, String toggle)
|
||||
{
|
||||
return ActionButton.builder(Component.text(PlexUtils.messageString(nameKey)))
|
||||
.tooltip(Component.text(PlexUtils.messageString(plugin.toggles.getBoolean(toggle) ? "stateEnabled" : "stateDisabled")))
|
||||
.width(150)
|
||||
.action(DialogAction.customClick((response, audience) -> toggle(audience, lowerNameKey, toggle), CALLBACK_OPTIONS))
|
||||
.build();
|
||||
}
|
||||
|
||||
private ActionButton closeButton()
|
||||
{
|
||||
return ActionButton.builder(Component.text("Close"))
|
||||
.width(150)
|
||||
.build();
|
||||
}
|
||||
|
||||
private void toggle(Audience audience, String lowerNameKey, String toggle)
|
||||
{
|
||||
if (!(audience instanceof Player player) || !player.hasPermission("plex.toggle"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
plugin.toggles.set(toggle, !plugin.toggles.getBoolean(toggle));
|
||||
if ("chat".equals(toggle))
|
||||
{
|
||||
PlexUtils.broadcast(PlexUtils.messageComponent("chatToggled", player.getName(), PlexUtils.messageString(plugin.toggles.getBoolean("chat") ? "stateOn" : "stateOff")));
|
||||
}
|
||||
player.sendMessage(PlexUtils.messageComponent("toggleToggled", PlexUtils.messageString(lowerNameKey)));
|
||||
open(player);
|
||||
}
|
||||
|
||||
private Component statusLine(String nameKey, String toggle, boolean enabledIsUnsafe)
|
||||
{
|
||||
return Component.text(PlexUtils.messageString(nameKey) + ": " + status(toggle, enabledIsUnsafe));
|
||||
}
|
||||
|
||||
private String status(String toggle, boolean enabledIsUnsafe)
|
||||
{
|
||||
if (enabledIsUnsafe)
|
||||
{
|
||||
return PlexUtils.messageString(plugin.toggles.getBoolean(toggle) ? "stateEnabledUnsafe" : "stateDisabledSafe");
|
||||
}
|
||||
return PlexUtils.messageString(plugin.toggles.getBoolean(toggle) ? "stateEnabled" : "stateDisabled");
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package dev.plex.menu.impl;
|
||||
|
||||
import dev.plex.menu.AbstractMenu;
|
||||
import dev.plex.menu.pagination.PageableMenu;
|
||||
import dev.plex.util.item.ItemBuilder;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class MaterialMenu extends PageableMenu<Material>
|
||||
{
|
||||
public MaterialMenu()
|
||||
{
|
||||
super("<dark_aqua><bold>Materials", AbstractMenu.Rows.SIX);
|
||||
onClick((inventoryView, inventory, player, itemStack) ->
|
||||
{
|
||||
player.sendMessage(itemStack.displayName());
|
||||
return true;
|
||||
});
|
||||
this.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStack toItem(Material object)
|
||||
{
|
||||
return new ItemBuilder(object).displayName("<blue>" + object.name()).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Material> list()
|
||||
{
|
||||
return Arrays.stream(Material.values()).filter(material -> !material.isAir()).toList();
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package dev.plex.menu.impl;
|
||||
|
||||
import dev.plex.menu.AbstractMenu;
|
||||
import dev.plex.menu.pagination.PageableMenu;
|
||||
import dev.plex.player.PlayerService;
|
||||
import dev.plex.player.PlexPlayer;
|
||||
import dev.plex.punishment.Punishment;
|
||||
import dev.plex.util.PlexUtils;
|
||||
import dev.plex.util.TimeUtils;
|
||||
import dev.plex.util.item.ItemBuilder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class PunishedPlayerMenu extends PageableMenu<Punishment>
|
||||
{
|
||||
private final PlexPlayer punishedPlayer;
|
||||
private final PlayerService playerService;
|
||||
|
||||
public PunishedPlayerMenu(PlexPlayer player, PlayerService playerService)
|
||||
{
|
||||
super(PlexUtils.messageComponent("punishedPlayerMenuTitle", player.getName()), AbstractMenu.Rows.SIX);
|
||||
this.punishedPlayer = player;
|
||||
this.playerService = playerService;
|
||||
onClick((inventoryView, itemStacks, player1, itemStack) -> true);
|
||||
this.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStack toItem(Punishment object)
|
||||
{
|
||||
return new ItemBuilder(Material.PAPER)
|
||||
.displayName(PlexUtils.messageComponent("punishmentItemTitle", object.getType().name()))
|
||||
.lore(PlexUtils.messageComponent("punishmentItemPunisher", object.getPunisher() == null ? "CONSOLE" : playerService.getNameByUUID(object.getPunisher())),
|
||||
PlexUtils.messageComponent("punishmentItemIssued", TimeUtils.useTimezone(object.getIssueDate())),
|
||||
PlexUtils.messageComponent("punishmentItemExpires", TimeUtils.useTimezone(object.getEndDate())),
|
||||
PlexUtils.messageComponent("punishmentItemReason", object.getReason()))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Punishment> list()
|
||||
{
|
||||
return this.punishedPlayer.getPunishments();
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package dev.plex.menu.impl;
|
||||
|
||||
import dev.plex.menu.AbstractMenu;
|
||||
import dev.plex.menu.pagination.PageableMenu;
|
||||
import dev.plex.player.PlayerService;
|
||||
import dev.plex.player.PlexPlayer;
|
||||
import dev.plex.util.PlexLog;
|
||||
import dev.plex.util.PlexUtils;
|
||||
import dev.plex.util.item.ItemBuilder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
|
||||
public class PunishmentMenu extends PageableMenu<Player>
|
||||
{
|
||||
private final PlayerService playerService;
|
||||
|
||||
public PunishmentMenu(PlayerService playerService)
|
||||
{
|
||||
super(PlexUtils.messageComponent("punishmentMenuTitle"), AbstractMenu.Rows.SIX);
|
||||
this.playerService = playerService;
|
||||
PlexLog.debug("list: {0}", list().size());
|
||||
onClick((inventoryView, itemStacks, player, itemStack) ->
|
||||
{
|
||||
if (itemStack.getType() != Material.PLAYER_HEAD)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
final SkullMeta meta = (SkullMeta) itemStack.getItemMeta();
|
||||
if (meta.getOwningPlayer() == null)
|
||||
{
|
||||
meta.setOwningPlayer(Bukkit.getOfflinePlayer("markbyron"));
|
||||
}
|
||||
PlexPlayer punishedPlayer = playerService.getPlayer(meta.getOwningPlayer().getUniqueId());
|
||||
if (punishedPlayer == null)
|
||||
{
|
||||
player.sendMessage(PlexUtils.messageComponent("punishmentPlayerNotFound"));
|
||||
player.closeInventory();
|
||||
return true;
|
||||
}
|
||||
new PunishedPlayerMenu(punishedPlayer, playerService).open(player);
|
||||
return true;
|
||||
});
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStack toItem(Player object)
|
||||
{
|
||||
return new ItemBuilder(Material.PLAYER_HEAD).owner(object).displayName(PlexUtils.messageComponent("punishmentPlayerItem", object.getName())).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Player> list()
|
||||
{
|
||||
return Bukkit.getOnlinePlayers().stream().map(OfflinePlayer::getPlayer).toList();
|
||||
}
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
package dev.plex.menu.impl;
|
||||
|
||||
import dev.plex.Plex;
|
||||
import dev.plex.menu.AbstractMenu;
|
||||
import dev.plex.util.PlexUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
public class ToggleMenu extends AbstractMenu
|
||||
{
|
||||
private final Plex plugin;
|
||||
|
||||
public ToggleMenu(Plex plugin)
|
||||
{
|
||||
super(PlexUtils.messageComponent("toggleMenuTitle"), Rows.ONE);
|
||||
this.plugin = plugin;
|
||||
resetExplosionItem(this.inventory());
|
||||
resetFluidspreadItem(this.inventory());
|
||||
resetDropsItem(this.inventory());
|
||||
resetRedstoneItem(this.inventory());
|
||||
resetPVPItem(this.inventory());
|
||||
resetChatItem(this.inventory());
|
||||
}
|
||||
|
||||
private void resetExplosionItem(Inventory inventory)
|
||||
{
|
||||
ItemStack explosions = new ItemStack(Material.TNT);
|
||||
ItemMeta explosionsItemMeta = explosions.getItemMeta();
|
||||
explosionsItemMeta.displayName(PlexUtils.messageComponent("toggleMenuExplosionsName"));
|
||||
explosionsItemMeta.lore(List.of(PlexUtils.messageComponent("toggleMenuExplosionsLore", status("explosions", true))));
|
||||
explosions.setItemMeta(explosionsItemMeta);
|
||||
inventory.setItem(0, explosions);
|
||||
}
|
||||
|
||||
private void resetFluidspreadItem(Inventory inventory)
|
||||
{
|
||||
ItemStack water = new ItemStack(Material.WATER_BUCKET);
|
||||
ItemMeta waterItemMeta = water.getItemMeta();
|
||||
waterItemMeta.displayName(PlexUtils.messageComponent("toggleMenuFluidSpreadName"));
|
||||
waterItemMeta.lore(List.of(PlexUtils.messageComponent("toggleMenuFluidSpreadLore", status("fluidspread", false))));
|
||||
water.setItemMeta(waterItemMeta);
|
||||
inventory.setItem(1, water);
|
||||
}
|
||||
|
||||
private void resetDropsItem(Inventory inventory)
|
||||
{
|
||||
ItemStack feather = new ItemStack(Material.FEATHER);
|
||||
ItemMeta featherItemMeta = feather.getItemMeta();
|
||||
featherItemMeta.displayName(PlexUtils.messageComponent("toggleMenuDropsName"));
|
||||
featherItemMeta.lore(List.of(PlexUtils.messageComponent("toggleMenuDropsLore", status("drops", false))));
|
||||
feather.setItemMeta(featherItemMeta);
|
||||
inventory.setItem(2, feather);
|
||||
}
|
||||
|
||||
private void resetRedstoneItem(Inventory inventory)
|
||||
{
|
||||
ItemStack redstone = new ItemStack(Material.REDSTONE);
|
||||
ItemMeta redstoneItemMeta = redstone.getItemMeta();
|
||||
redstoneItemMeta.displayName(PlexUtils.messageComponent("toggleMenuRedstoneName"));
|
||||
redstoneItemMeta.lore(List.of(PlexUtils.messageComponent("toggleMenuRedstoneLore", status("redstone", false))));
|
||||
redstone.setItemMeta(redstoneItemMeta);
|
||||
inventory.setItem(3, redstone);
|
||||
}
|
||||
|
||||
private void resetPVPItem(Inventory inventory)
|
||||
{
|
||||
ItemStack pvp = new ItemStack(Material.IRON_SWORD);
|
||||
ItemMeta pvpItemMeta = pvp.getItemMeta();
|
||||
pvpItemMeta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES);
|
||||
pvpItemMeta.displayName(PlexUtils.messageComponent("toggleMenuPvpName"));
|
||||
pvpItemMeta.lore(List.of(PlexUtils.messageComponent("toggleMenuPvpLore", status("pvp", false))));
|
||||
pvp.setItemMeta(pvpItemMeta);
|
||||
inventory.setItem(4, pvp);
|
||||
}
|
||||
|
||||
private void resetChatItem(Inventory inventory)
|
||||
{
|
||||
ItemStack chat = new ItemStack(Material.OAK_SIGN);
|
||||
ItemMeta chatItemMeta = chat.getItemMeta();
|
||||
chatItemMeta.displayName(PlexUtils.messageComponent("toggleMenuChatName"));
|
||||
chatItemMeta.lore(List.of(PlexUtils.messageComponent("toggleMenuChatLore", PlexUtils.messageString(plugin.toggles.getBoolean("chat") ? "stateOn" : "stateOff"))));
|
||||
chat.setItemMeta(chatItemMeta);
|
||||
inventory.setItem(5, chat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onClick(InventoryView view, Inventory inventory, Player player, ItemStack clicked)
|
||||
{
|
||||
if (!player.hasPermission("plex.toggle"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (clicked.getType() == Material.TNT)
|
||||
{
|
||||
plugin.toggles.set("explosions", !plugin.toggles.getBoolean("explosions"));
|
||||
resetExplosionItem(inventory);
|
||||
player.sendMessage(PlexUtils.messageComponent("toggleToggled", PlexUtils.messageString("toggleExplosionsLower")));
|
||||
}
|
||||
if (clicked.getType() == Material.WATER_BUCKET)
|
||||
{
|
||||
plugin.toggles.set("fluidspread", !plugin.toggles.getBoolean("fluidspread"));
|
||||
resetFluidspreadItem(inventory);
|
||||
player.sendMessage(PlexUtils.messageComponent("toggleToggled", PlexUtils.messageString("toggleFluidSpreadLower")));
|
||||
}
|
||||
if (clicked.getType() == Material.FEATHER)
|
||||
{
|
||||
plugin.toggles.set("drops", !plugin.toggles.getBoolean("drops"));
|
||||
resetDropsItem(inventory);
|
||||
player.sendMessage(PlexUtils.messageComponent("toggleToggled", PlexUtils.messageString("toggleDropsLower")));
|
||||
}
|
||||
if (clicked.getType() == Material.REDSTONE)
|
||||
{
|
||||
plugin.toggles.set("redstone", !plugin.toggles.getBoolean("redstone"));
|
||||
resetRedstoneItem(inventory);
|
||||
player.sendMessage(PlexUtils.messageComponent("toggleToggled", PlexUtils.messageString("toggleRedstoneLower")));
|
||||
}
|
||||
if (clicked.getType() == Material.IRON_SWORD)
|
||||
{
|
||||
plugin.toggles.set("pvp", !plugin.toggles.getBoolean("pvp"));
|
||||
resetPVPItem(inventory);
|
||||
player.sendMessage(PlexUtils.messageComponent("toggleToggled", PlexUtils.messageString("togglePvpLower")));
|
||||
}
|
||||
if (clicked.getType() == Material.OAK_SIGN)
|
||||
{
|
||||
plugin.toggles.set("chat", !plugin.toggles.getBoolean("chat"));
|
||||
PlexUtils.broadcast(PlexUtils.messageComponent("chatToggled", player.getName(), PlexUtils.messageString(plugin.toggles.getBoolean("chat") ? "stateOn" : "stateOff")));
|
||||
resetChatItem(inventory);
|
||||
player.sendMessage(PlexUtils.messageComponent("toggleToggled", PlexUtils.messageString("toggleChatLower")));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private String status(String toggle, boolean enabledIsUnsafe)
|
||||
{
|
||||
if (enabledIsUnsafe)
|
||||
{
|
||||
return PlexUtils.messageString(plugin.toggles.getBoolean(toggle) ? "stateEnabledUnsafe" : "stateDisabledSafe");
|
||||
}
|
||||
return PlexUtils.messageString(plugin.toggles.getBoolean(toggle) ? "stateEnabled" : "stateDisabled");
|
||||
}
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
package dev.plex.menu.pagination;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import dev.plex.menu.AbstractMenu;
|
||||
import dev.plex.util.PlexUtils;
|
||||
import dev.plex.util.function.ConditionalQuadConsumer;
|
||||
import dev.plex.util.item.ItemBuilder;
|
||||
import dev.plex.util.minimessage.SafeMiniMessage;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(fluent = true)
|
||||
public abstract class PageableMenu<T>
|
||||
{
|
||||
protected final Map<Integer, Page> pages = Maps.newHashMap();
|
||||
private final Component name;
|
||||
private final AbstractMenu.Rows rows;
|
||||
private final Inventory inventory;
|
||||
private int currentPage;
|
||||
private boolean initialized;
|
||||
|
||||
@Setter(AccessLevel.NONE)
|
||||
private ConditionalQuadConsumer<InventoryView, Inventory, Player, ItemStack> onClick;
|
||||
|
||||
public PageableMenu(Component name, AbstractMenu.Rows rows)
|
||||
{
|
||||
this.name = name;
|
||||
this.rows = rows;
|
||||
this.inventory = Bukkit.createInventory(null, rows.slots(), name);
|
||||
|
||||
if (rows.slots() < AbstractMenu.Rows.TWO.slots())
|
||||
{
|
||||
throw new RuntimeException("A pageable menu must have at least two rows to compensate for the navigation!");
|
||||
}
|
||||
}
|
||||
|
||||
protected void init()
|
||||
{
|
||||
this.initialized = true;
|
||||
// Preload all needed pages, a better solution is probably just to dynamically create the pages as they go but no!
|
||||
if (list().size() < (rows.slots() - 9))
|
||||
{
|
||||
final Page page = new Page(name.append(Component.space()).append(PlexUtils.mmDeserialize("(1)")), rows);
|
||||
page.parent = this;
|
||||
page.inventory().setItem(rows.slots() - 5, closeItem());
|
||||
this.pages.put(0, page);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < Math.ceil(list().size() / (double) (rows.slots() - 9)); i++)
|
||||
{
|
||||
final Page page = new Page(name.append(Component.space()).append(PlexUtils.mmDeserialize("(" + (i + 1) + ")")), rows);
|
||||
page.parent = this;
|
||||
if (i > 0) // If not first page set previous page button
|
||||
{
|
||||
page.inventory().setItem(rows.slots() - 6, previousItem());
|
||||
}
|
||||
page.inventory().setItem(rows.slots() - 5, closeItem());
|
||||
if (i < (list().size() / (rows.slots() - 9)) - 1) // If not last page set next page button
|
||||
{
|
||||
page.inventory().setItem(rows.slots() - 4, nextItem());
|
||||
}
|
||||
this.pages.put(i, page);
|
||||
}
|
||||
}
|
||||
|
||||
int currentSlotIndex = 0;
|
||||
int currentPageIndex = 0;
|
||||
int currentIndex = 0;
|
||||
while (currentSlotIndex < rows.slots() - 9 && currentIndex < list().size())
|
||||
{
|
||||
final Page page = this.pages.get(currentPageIndex);
|
||||
if (page == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
page.inventory().setItem(currentSlotIndex, toItem(list().get(currentIndex)));
|
||||
currentIndex++;
|
||||
currentSlotIndex++;
|
||||
if (currentSlotIndex == rows.slots() - 9)
|
||||
{
|
||||
currentSlotIndex = 0;
|
||||
currentPageIndex++;
|
||||
}
|
||||
}
|
||||
if (onClick != null) // To make sure this wasn't declared already
|
||||
{
|
||||
this.pages.forEach((integer, page) -> page.onClick(this.onClick));
|
||||
}
|
||||
}
|
||||
|
||||
public PageableMenu(String name, AbstractMenu.Rows rows)
|
||||
{
|
||||
this(SafeMiniMessage.mmDeserializeWithoutEvents(name), rows);
|
||||
}
|
||||
|
||||
protected abstract ItemStack toItem(T object);
|
||||
|
||||
protected abstract List<T> list();
|
||||
|
||||
public void open(Player player)
|
||||
{
|
||||
open(player, 0);
|
||||
}
|
||||
|
||||
public void open(Player player, int pageNum)
|
||||
{
|
||||
if (!this.initialized)
|
||||
{
|
||||
player.sendMessage(PlexUtils.messageComponent("pageableNotInitialized"));
|
||||
return;
|
||||
}
|
||||
final Page page = this.pages.get(pageNum);
|
||||
if (page == null)
|
||||
{
|
||||
player.sendMessage(PlexUtils.messageComponent("pageNotFound"));
|
||||
return;
|
||||
}
|
||||
player.openInventory(page.inventory());
|
||||
}
|
||||
|
||||
public void onClick(ConditionalQuadConsumer<InventoryView, Inventory, Player, ItemStack> onClick)
|
||||
{
|
||||
this.onClick = onClick;
|
||||
this.pages.forEach((integer, page) -> page.onClick(this.onClick));
|
||||
}
|
||||
|
||||
public static ItemStack nextItem()
|
||||
{
|
||||
return new ItemBuilder(Material.FEATHER).displayName(PlexUtils.messageComponent("pageNext")).build();
|
||||
}
|
||||
|
||||
public static ItemStack previousItem()
|
||||
{
|
||||
return new ItemBuilder(Material.FEATHER).displayName(PlexUtils.messageComponent("pagePrevious")).build();
|
||||
}
|
||||
|
||||
public static ItemStack closeItem()
|
||||
{
|
||||
return new ItemBuilder(Material.BARRIER).displayName(PlexUtils.messageComponent("pageClose")).build();
|
||||
}
|
||||
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(fluent = true)
|
||||
public static class Page extends AbstractMenu
|
||||
{
|
||||
private ConditionalQuadConsumer<InventoryView, Inventory, Player, ItemStack> onClick;
|
||||
private PageableMenu<?> parent;
|
||||
|
||||
private Page(Component name, Rows rows)
|
||||
{
|
||||
super(name, rows);
|
||||
}
|
||||
|
||||
private Page(String name, AbstractMenu.Rows rows)
|
||||
{
|
||||
this(SafeMiniMessage.mmDeserializeWithoutEvents(name), rows);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onClick(InventoryView view, Inventory inventory, Player player, ItemStack clicked)
|
||||
{
|
||||
return onClick.accept(view, inventory, player, clicked);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,13 @@ package dev.plex.services.impl;
|
||||
|
||||
import dev.plex.Plex;
|
||||
import dev.plex.services.AbstractService;
|
||||
import dev.plex.util.UpdateChecker;
|
||||
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class UpdateCheckerService extends AbstractService
|
||||
{
|
||||
private boolean newVersion = false;
|
||||
private boolean notified = false;
|
||||
|
||||
public UpdateCheckerService(Plex plugin)
|
||||
{
|
||||
@@ -17,11 +18,16 @@ public class UpdateCheckerService extends AbstractService
|
||||
@Override
|
||||
public void run(ScheduledTask task)
|
||||
{
|
||||
if (!newVersion)
|
||||
if (!notified)
|
||||
{
|
||||
if (plugin.getUpdateChecker().getUpdateStatusMessage(Bukkit.getConsoleSender(), false, 1))
|
||||
UpdateChecker.UpdateCheckResult result = plugin.getUpdateChecker().checkForUpdates(false);
|
||||
plugin.getUpdateChecker().sendResultMessage(Bukkit.getConsoleSender(), result, 1);
|
||||
if (result.status() == UpdateChecker.UpdateCheckStatus.UPDATE_AVAILABLE
|
||||
|| result.status() == UpdateChecker.UpdateCheckStatus.MINECRAFT_TOO_OLD
|
||||
|| result.status() == UpdateChecker.UpdateCheckStatus.MINECRAFT_TOO_NEW
|
||||
|| result.status() == UpdateChecker.UpdateCheckStatus.MINECRAFT_UNLISTED)
|
||||
{
|
||||
newVersion = true;
|
||||
notified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,12 @@ public final class ArtifactMetadata
|
||||
return publishedAt;
|
||||
}
|
||||
|
||||
public Optional<String> validatePlex(UpdateChannel requestedChannel, String minecraftVersion)
|
||||
public List<String> minecraftVersions()
|
||||
{
|
||||
return minecraftVersions == null ? List.of() : List.copyOf(minecraftVersions);
|
||||
}
|
||||
|
||||
public Optional<String> validatePlex(UpdateChannel requestedChannel)
|
||||
{
|
||||
Optional<String> commonError = validateCommon(requestedChannel);
|
||||
if (commonError.isPresent())
|
||||
@@ -84,9 +89,9 @@ public final class ArtifactMetadata
|
||||
{
|
||||
return Optional.of("Plex metadata has unexpected artifact name " + name);
|
||||
}
|
||||
if (minecraftVersions == null || !minecraftVersions.contains(minecraftVersion))
|
||||
if (minecraftVersions == null || minecraftVersions.isEmpty())
|
||||
{
|
||||
return Optional.of("metadata does not include Minecraft version " + minecraftVersion);
|
||||
return Optional.of("Plex metadata is missing minecraftVersions");
|
||||
}
|
||||
if (apiCompatibility == null)
|
||||
{
|
||||
@@ -95,6 +100,20 @@ public final class ArtifactMetadata
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public Optional<String> validatePlex(UpdateChannel requestedChannel, String minecraftVersion)
|
||||
{
|
||||
Optional<String> plexError = validatePlex(requestedChannel);
|
||||
if (plexError.isPresent())
|
||||
{
|
||||
return plexError;
|
||||
}
|
||||
if (!supportsMinecraftVersion(minecraftVersion))
|
||||
{
|
||||
return Optional.of("metadata does not include Minecraft version " + minecraftVersion);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public Optional<String> validateModule(UpdateChannel requestedChannel, String moduleName, int apiCompatibility)
|
||||
{
|
||||
Optional<String> commonError = validateCommon(requestedChannel);
|
||||
@@ -185,6 +204,11 @@ public final class ArtifactMetadata
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private boolean supportsMinecraftVersion(String minecraftVersion)
|
||||
{
|
||||
return minecraftVersions != null && minecraftVersions.contains(minecraftVersion);
|
||||
}
|
||||
|
||||
private static boolean isBlank(String value)
|
||||
{
|
||||
return value == null || value.isBlank();
|
||||
|
||||
@@ -37,6 +37,18 @@ public final class UpdateMetadataClient
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public ArtifactMetadata fetchPlexChannelLatest() throws MetadataException
|
||||
{
|
||||
String path = "/api/v1/projects/Plex/channels/" + channel.id() + "/latest.json";
|
||||
ArtifactMetadata metadata = fetch(path);
|
||||
Optional<String> validationError = metadata.validatePlex(channel);
|
||||
if (validationError.isPresent())
|
||||
{
|
||||
throw new MetadataException(validationError.get(), false);
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public ArtifactMetadata fetchModuleLatest(String moduleName, int apiCompatibility) throws MetadataException
|
||||
{
|
||||
return fetchModuleLatest(moduleName, apiCompatibility, List.of());
|
||||
@@ -158,6 +170,11 @@ public final class UpdateMetadataClient
|
||||
{
|
||||
private final boolean notFound;
|
||||
|
||||
public static MetadataException localError(String message)
|
||||
{
|
||||
return new MetadataException(message, false);
|
||||
}
|
||||
|
||||
private MetadataException(String message, boolean notFound)
|
||||
{
|
||||
super(message);
|
||||
|
||||
@@ -18,6 +18,7 @@ import java.nio.file.StandardCopyOption;
|
||||
import java.security.DigestInputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HexFormat;
|
||||
import java.util.List;
|
||||
|
||||
@@ -36,6 +37,18 @@ public class UpdateChecker
|
||||
private ArtifactMetadata latestPlexMetadata;
|
||||
private UpdateMetadataClient.MetadataException latestPlexMetadataFailure;
|
||||
private long latestPlexMetadataFailureAtMillis;
|
||||
private ArtifactMetadata latestPlexChannelLatestMetadata;
|
||||
private UpdateMetadataClient.MetadataException latestPlexChannelLatestMetadataFailure;
|
||||
private long latestPlexChannelLatestMetadataFailureAtMillis;
|
||||
|
||||
public enum UpdateCheckStatus
|
||||
{
|
||||
UP_TO_DATE, UPDATE_AVAILABLE, MINECRAFT_TOO_OLD, MINECRAFT_TOO_NEW, MINECRAFT_UNLISTED, ERROR
|
||||
}
|
||||
|
||||
public record UpdateCheckResult(UpdateCheckStatus status, ArtifactMetadata metadata, UpdateMetadataClient.MetadataException error)
|
||||
{
|
||||
}
|
||||
|
||||
public UpdateChecker(Plex plugin)
|
||||
{
|
||||
@@ -44,56 +57,147 @@ public class UpdateChecker
|
||||
this.metadataClient = new UpdateMetadataClient(channel);
|
||||
}
|
||||
|
||||
public UpdateCheckResult checkForUpdates(boolean useCache)
|
||||
{
|
||||
String runningMinecraftVersion = getRunningMinecraftVersion();
|
||||
if (runningMinecraftVersion == null || runningMinecraftVersion.isBlank() || "unknown".equalsIgnoreCase(runningMinecraftVersion))
|
||||
{
|
||||
return new UpdateCheckResult(UpdateCheckStatus.ERROR, null, UpdateMetadataClient.MetadataException.localError("running Minecraft version could not be determined"));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ArtifactMetadata metadata = fetchLatestPlexMetadata(useCache, runningMinecraftVersion);
|
||||
if (metadata.matchesCurrentBuild(plugin.getPluginMeta().getVersion(), BuildInfo.getNumber(), BuildInfo.getCommit()))
|
||||
{
|
||||
return new UpdateCheckResult(UpdateCheckStatus.UP_TO_DATE, metadata, null);
|
||||
}
|
||||
return new UpdateCheckResult(UpdateCheckStatus.UPDATE_AVAILABLE, metadata, null);
|
||||
}
|
||||
catch (UpdateMetadataClient.MetadataException e)
|
||||
{
|
||||
if (!e.notFound())
|
||||
{
|
||||
return new UpdateCheckResult(UpdateCheckStatus.ERROR, null, e);
|
||||
}
|
||||
}
|
||||
|
||||
ArtifactMetadata channelLatest;
|
||||
try
|
||||
{
|
||||
channelLatest = fetchPlexChannelLatestMetadata(useCache);
|
||||
}
|
||||
catch (UpdateMetadataClient.MetadataException e)
|
||||
{
|
||||
return new UpdateCheckResult(UpdateCheckStatus.ERROR, null, e);
|
||||
}
|
||||
|
||||
if (channelLatest.matchesCurrentBuild(plugin.getPluginMeta().getVersion(), BuildInfo.getNumber(), BuildInfo.getCommit()))
|
||||
{
|
||||
return new UpdateCheckResult(UpdateCheckStatus.UP_TO_DATE, channelLatest, null);
|
||||
}
|
||||
|
||||
List<String> supportedVersions = sortedSupportedVersions(channelLatest);
|
||||
if (!supportedVersions.isEmpty())
|
||||
{
|
||||
String minimumVersion = supportedVersions.get(0);
|
||||
String maximumVersion = supportedVersions.get(supportedVersions.size() - 1);
|
||||
if (compareMinecraftVersions(runningMinecraftVersion, minimumVersion) < 0)
|
||||
{
|
||||
return new UpdateCheckResult(UpdateCheckStatus.MINECRAFT_TOO_OLD, channelLatest, null);
|
||||
}
|
||||
if (compareMinecraftVersions(runningMinecraftVersion, maximumVersion) > 0)
|
||||
{
|
||||
return new UpdateCheckResult(UpdateCheckStatus.MINECRAFT_TOO_NEW, channelLatest, null);
|
||||
}
|
||||
}
|
||||
return new UpdateCheckResult(UpdateCheckStatus.MINECRAFT_UNLISTED, channelLatest, null);
|
||||
}
|
||||
|
||||
public void sendResultMessage(CommandSender sender, UpdateCheckResult result, int verbosity)
|
||||
{
|
||||
switch (result.status())
|
||||
{
|
||||
case UP_TO_DATE:
|
||||
if (verbosity == 2)
|
||||
{
|
||||
sendMessage(sender, PlexUtils.messageComponent("updateUpToDate", channel.id()));
|
||||
}
|
||||
break;
|
||||
case UPDATE_AVAILABLE:
|
||||
if (verbosity >= 1)
|
||||
{
|
||||
sendMessage(sender, PlexUtils.messageComponent("updateAvailable", result.metadata().version(), channel.id()));
|
||||
sendMessage(sender, PlexUtils.messageComponent("updateRunCommand"));
|
||||
}
|
||||
break;
|
||||
case MINECRAFT_TOO_OLD:
|
||||
if (verbosity >= 1)
|
||||
{
|
||||
List<String> supportedVersions = sortedSupportedVersions(result.metadata());
|
||||
sendMessage(sender, PlexUtils.messageComponent("updateRequiresNewerMinecraft",
|
||||
result.metadata().version(), channel.id(), firstSupportedVersion(supportedVersions), getRunningMinecraftVersion(), String.join(", ", supportedVersions)));
|
||||
}
|
||||
break;
|
||||
case MINECRAFT_TOO_NEW:
|
||||
if (verbosity >= 1)
|
||||
{
|
||||
List<String> supportedVersions = sortedSupportedVersions(result.metadata());
|
||||
sendMessage(sender, PlexUtils.messageComponent("updateUnsupportedNewerMinecraft",
|
||||
result.metadata().version(), channel.id(), lastSupportedVersion(supportedVersions), getRunningMinecraftVersion(), String.join(", ", supportedVersions)));
|
||||
}
|
||||
break;
|
||||
case MINECRAFT_UNLISTED:
|
||||
if (verbosity >= 1)
|
||||
{
|
||||
List<String> supportedVersions = sortedSupportedVersions(result.metadata());
|
||||
sendMessage(sender, PlexUtils.messageComponent("updateRequiresMinecraftVersion",
|
||||
result.metadata().version(), channel.id(), String.join(", ", supportedVersions), getRunningMinecraftVersion()));
|
||||
}
|
||||
break;
|
||||
case ERROR:
|
||||
UpdateMetadataClient.MetadataException error = result.error();
|
||||
if (error.notFound())
|
||||
{
|
||||
if (verbosity == 2)
|
||||
{
|
||||
sendMessage(sender, PlexUtils.messageComponent("updateMetadataNotFound", channel.id()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (verbosity >= 1)
|
||||
{
|
||||
sendMessage(sender, updateMetadataErrorComponent(error));
|
||||
PlexLog.error("Unable to check for updates: {0}", error.getMessage());
|
||||
if (error.getCause() != null)
|
||||
{
|
||||
error.getCause().printStackTrace();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If verbose is 0, it will display nothing
|
||||
// If verbose is 1, it will only display a message if there is an update available
|
||||
// If verbose is 2, it will display all messages
|
||||
public boolean getUpdateStatusMessage(CommandSender sender, boolean cached, int verbosity)
|
||||
{
|
||||
try
|
||||
{
|
||||
ArtifactMetadata metadata = fetchLatestPlexMetadata(cached);
|
||||
if (metadata.matchesCurrentBuild(plugin.getPluginMeta().getVersion(), BuildInfo.getNumber(), BuildInfo.getCommit()))
|
||||
{
|
||||
if (verbosity == 2)
|
||||
{
|
||||
sendMessage(sender, PlexUtils.messageComponent("updateUpToDate", channel.id()));
|
||||
}
|
||||
return false;
|
||||
UpdateCheckResult result = checkForUpdates(cached);
|
||||
sendResultMessage(sender, result, verbosity);
|
||||
return result.status() == UpdateCheckStatus.UPDATE_AVAILABLE;
|
||||
}
|
||||
|
||||
if (verbosity >= 1)
|
||||
public void updateJar(CommandSender sender, ArtifactMetadata metadata, Runnable onSuccess)
|
||||
{
|
||||
sendMessage(sender, PlexUtils.messageComponent("updateAvailable", metadata.version(), channel.id()));
|
||||
sendMessage(sender, PlexUtils.messageComponent("updateRunCommand"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (UpdateMetadataClient.MetadataException e)
|
||||
{
|
||||
if (verbosity == 2 || (verbosity >= 1 && !e.notFound()))
|
||||
{
|
||||
sendMessage(sender, updateMetadataErrorComponent(e));
|
||||
}
|
||||
if (!e.notFound())
|
||||
{
|
||||
PlexLog.error("Unable to check for updates: {0}", e.getMessage());
|
||||
if (e.getCause() != null)
|
||||
{
|
||||
e.getCause().printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void updateJar(CommandSender sender, String name, boolean module)
|
||||
{
|
||||
updateJar(sender, name, module, List.of());
|
||||
File copyTo = new File(Bukkit.getUpdateFolderFile(), metadata.fileName());
|
||||
sendMessage(sender, PlexUtils.messageComponent("updateDownloading", metadata.fileName()));
|
||||
plugin.getApi().scheduler().runAsync(() -> downloadAndInstall(sender, metadata, copyTo, onSuccess));
|
||||
}
|
||||
|
||||
public void installModuleJar(CommandSender sender, String name)
|
||||
{
|
||||
updateJar(sender, name, true, List.of(), () -> plugin.getApi().scheduler().runGlobal(() ->
|
||||
updateJar(sender, name, List.of(), () -> plugin.getApi().scheduler().runGlobal(() ->
|
||||
{
|
||||
plugin.getModuleManager().reloadModules();
|
||||
sendMessage(sender, PlexUtils.messageComponent("moduleRestartRequired"));
|
||||
@@ -108,31 +212,20 @@ public class UpdateChecker
|
||||
sendMessage(sender, PlexUtils.messageComponent("moduleUpdateDisabled", moduleFile.getName()));
|
||||
return;
|
||||
}
|
||||
updateJar(sender, moduleFile.getName(), true, moduleFile.getUpdateUrls());
|
||||
updateJar(sender, moduleFile.getName(), moduleFile.getUpdateUrls());
|
||||
}
|
||||
|
||||
private void updateJar(CommandSender sender, String name, boolean module, List<String> moduleUpdateUrls)
|
||||
private void updateJar(CommandSender sender, String name, List<String> moduleUpdateUrls)
|
||||
{
|
||||
updateJar(sender, name, module, moduleUpdateUrls, null);
|
||||
updateJar(sender, name, moduleUpdateUrls, null);
|
||||
}
|
||||
|
||||
private void updateJar(CommandSender sender, String name, boolean module, List<String> moduleUpdateUrls, Runnable onSuccess)
|
||||
private void updateJar(CommandSender sender, String name, List<String> moduleUpdateUrls, Runnable onSuccess)
|
||||
{
|
||||
try
|
||||
{
|
||||
ArtifactMetadata metadata = module
|
||||
? metadataClient.fetchModuleLatest(name, plugin.getApi().compatibility().version(), moduleUpdateUrls)
|
||||
: fetchLatestPlexMetadata(false);
|
||||
|
||||
if (!module && metadata.matchesCurrentBuild(plugin.getPluginMeta().getVersion(), BuildInfo.getNumber(), BuildInfo.getCommit()))
|
||||
{
|
||||
sendMessage(sender, PlexUtils.messageComponent("updateAlreadyUpToDate", channel.id()));
|
||||
return;
|
||||
}
|
||||
|
||||
File copyTo = module
|
||||
? new File(plugin.getModulesFolder(), metadata.fileName())
|
||||
: new File(Bukkit.getUpdateFolderFile(), metadata.fileName());
|
||||
ArtifactMetadata metadata = metadataClient.fetchModuleLatest(name, plugin.getApi().compatibility().version(), moduleUpdateUrls);
|
||||
File copyTo = new File(plugin.getModulesFolder(), metadata.fileName());
|
||||
|
||||
sendMessage(sender, PlexUtils.messageComponent("updateDownloading", metadata.fileName()));
|
||||
plugin.getApi().scheduler().runAsync(() -> downloadAndInstall(sender, metadata, copyTo, onSuccess));
|
||||
@@ -151,15 +244,15 @@ public class UpdateChecker
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized ArtifactMetadata fetchLatestPlexMetadata(boolean cached) throws UpdateMetadataClient.MetadataException
|
||||
private synchronized ArtifactMetadata fetchLatestPlexMetadata(boolean useCache, String runningMinecraftVersion) throws UpdateMetadataClient.MetadataException
|
||||
{
|
||||
if (cached)
|
||||
if (useCache)
|
||||
{
|
||||
if (latestPlexMetadata != null)
|
||||
{
|
||||
return latestPlexMetadata;
|
||||
}
|
||||
if (latestPlexMetadataFailure != null && isPlexMetadataFailureCacheFresh())
|
||||
if (latestPlexMetadataFailure != null && isPlexMetadataFailureCacheFresh(latestPlexMetadataFailureAtMillis))
|
||||
{
|
||||
throw latestPlexMetadataFailure;
|
||||
}
|
||||
@@ -167,7 +260,7 @@ public class UpdateChecker
|
||||
|
||||
try
|
||||
{
|
||||
latestPlexMetadata = metadataClient.fetchPlexLatest(BuildInfo.getMinecraftVersion());
|
||||
latestPlexMetadata = metadataClient.fetchPlexLatest(runningMinecraftVersion);
|
||||
latestPlexMetadataFailure = null;
|
||||
latestPlexMetadataFailureAtMillis = 0L;
|
||||
return latestPlexMetadata;
|
||||
@@ -183,9 +276,116 @@ public class UpdateChecker
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPlexMetadataFailureCacheFresh()
|
||||
private synchronized ArtifactMetadata fetchPlexChannelLatestMetadata(boolean useCache) throws UpdateMetadataClient.MetadataException
|
||||
{
|
||||
return System.currentTimeMillis() - latestPlexMetadataFailureAtMillis < PLEX_METADATA_FAILURE_CACHE_MILLIS;
|
||||
if (useCache)
|
||||
{
|
||||
if (latestPlexChannelLatestMetadata != null)
|
||||
{
|
||||
return latestPlexChannelLatestMetadata;
|
||||
}
|
||||
if (latestPlexChannelLatestMetadataFailure != null && isPlexMetadataFailureCacheFresh(latestPlexChannelLatestMetadataFailureAtMillis))
|
||||
{
|
||||
throw latestPlexChannelLatestMetadataFailure;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
latestPlexChannelLatestMetadata = metadataClient.fetchPlexChannelLatest();
|
||||
latestPlexChannelLatestMetadataFailure = null;
|
||||
latestPlexChannelLatestMetadataFailureAtMillis = 0L;
|
||||
return latestPlexChannelLatestMetadata;
|
||||
}
|
||||
catch (UpdateMetadataClient.MetadataException e)
|
||||
{
|
||||
if (latestPlexChannelLatestMetadata == null)
|
||||
{
|
||||
latestPlexChannelLatestMetadataFailure = e;
|
||||
latestPlexChannelLatestMetadataFailureAtMillis = System.currentTimeMillis();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> sortedSupportedVersions(ArtifactMetadata metadata)
|
||||
{
|
||||
List<String> supportedVersions = new ArrayList<>(metadata.minecraftVersions());
|
||||
supportedVersions.sort(UpdateChecker::compareMinecraftVersions);
|
||||
return supportedVersions;
|
||||
}
|
||||
|
||||
private String firstSupportedVersion(List<String> supportedVersions)
|
||||
{
|
||||
return supportedVersions.isEmpty() ? "unknown" : supportedVersions.get(0);
|
||||
}
|
||||
|
||||
private String lastSupportedVersion(List<String> supportedVersions)
|
||||
{
|
||||
return supportedVersions.isEmpty() ? "unknown" : supportedVersions.get(supportedVersions.size() - 1);
|
||||
}
|
||||
|
||||
private static int compareMinecraftVersions(String left, String right)
|
||||
{
|
||||
String[] leftParts = left.split("\\.");
|
||||
String[] rightParts = right.split("\\.");
|
||||
int length = Math.max(leftParts.length, rightParts.length);
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
int leftPart = i < leftParts.length ? parseVersionPart(leftParts[i]) : 0;
|
||||
int rightPart = i < rightParts.length ? parseVersionPart(rightParts[i]) : 0;
|
||||
if (leftPart != rightPart)
|
||||
{
|
||||
return Integer.compare(leftPart, rightPart);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int parseVersionPart(String part)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Integer.parseInt(part);
|
||||
}
|
||||
catch (NumberFormatException ignored)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPlexMetadataFailureCacheFresh(long failureAtMillis)
|
||||
{
|
||||
return System.currentTimeMillis() - failureAtMillis < PLEX_METADATA_FAILURE_CACHE_MILLIS;
|
||||
}
|
||||
|
||||
private String getRunningMinecraftVersion()
|
||||
{
|
||||
String version = Bukkit.getBukkitVersion();
|
||||
int buildIndex = version.indexOf(".build");
|
||||
if (buildIndex >= 0)
|
||||
{
|
||||
return version.substring(0, buildIndex);
|
||||
}
|
||||
|
||||
int separatorIndex = version.indexOf('-');
|
||||
if (separatorIndex >= 0)
|
||||
{
|
||||
return version.substring(0, separatorIndex);
|
||||
}
|
||||
|
||||
String buildMinecraftVersion = BuildInfo.getMinecraftVersion();
|
||||
int rangeIndex = buildMinecraftVersion.indexOf(" - ");
|
||||
if (rangeIndex >= 0)
|
||||
{
|
||||
return buildMinecraftVersion.substring(0, rangeIndex);
|
||||
}
|
||||
int listIndex = buildMinecraftVersion.indexOf(',');
|
||||
if (listIndex >= 0)
|
||||
{
|
||||
return buildMinecraftVersion.substring(0, listIndex);
|
||||
}
|
||||
return buildMinecraftVersion;
|
||||
}
|
||||
|
||||
private void downloadAndInstall(CommandSender sender, ArtifactMetadata metadata, File copyTo, Runnable onSuccess)
|
||||
|
||||
@@ -220,24 +220,6 @@ togglePvp: "PVP"
|
||||
togglePvpLower: "PVP"
|
||||
toggleChat: "Chat"
|
||||
toggleChatLower: "chat"
|
||||
toggleMenuExplosionsName: "<!italic><light_purple>Toggle explosions"
|
||||
# 0 - The toggle status
|
||||
toggleMenuExplosionsLore: "<!italic><yellow>Explosions are {0}"
|
||||
toggleMenuFluidSpreadName: "<!italic><light_purple>Toggle fluid spread"
|
||||
# 0 - The toggle status
|
||||
toggleMenuFluidSpreadLore: "<!italic><yellow>Fluid spread is {0}"
|
||||
toggleMenuDropsName: "<!italic><light_purple>Toggle drops"
|
||||
# 0 - The toggle status
|
||||
toggleMenuDropsLore: "<!italic><yellow>Drops are {0}"
|
||||
toggleMenuRedstoneName: "<!italic><light_purple>Redstone"
|
||||
# 0 - The toggle status
|
||||
toggleMenuRedstoneLore: "<!italic><yellow>Redstone is {0}"
|
||||
toggleMenuPvpName: "<!italic><light_purple>PVP"
|
||||
# 0 - The toggle status
|
||||
toggleMenuPvpLore: "<!italic><yellow>PVP is {0}"
|
||||
toggleMenuChatName: "<!italic><light_purple>Toggle chat"
|
||||
# 0 - The toggle status
|
||||
toggleMenuChatLore: "<!italic><yellow>Chat is currently {0}"
|
||||
specifyLoginMessage: "<red>Please specify a login message."
|
||||
# 0 - The login message
|
||||
setOwnLoginMessage: "<gray>Your login message is now:<newline><gray>> <reset>{0}"
|
||||
@@ -312,27 +294,10 @@ prismRollbackMessage: "<gray>Rolled back {0} activities"
|
||||
# 0 - Error message returned from Prism
|
||||
prismRollbackError: "<red>Rollback failed: {0}"
|
||||
prismNoResult: "<gray>No activities have been rolled back"
|
||||
pageNext: "<light_purple>Next Page"
|
||||
pagePrevious: "<light_purple>Previous Page"
|
||||
pageClose: "<red>Close"
|
||||
pageableNotInitialized: "<red>Looks like this inventory was not initialized! Please contact a developer to report this."
|
||||
pageNotFound: "<red>Could not find a page to open"
|
||||
punishmentMenuTitle: "<aqua><bold>Punishments"
|
||||
# 0 - The player
|
||||
punishmentPlayerItem: "<!italic><yellow>{0}"
|
||||
# 0 - The player
|
||||
punishedPlayerMenuTitle: "<red><bold>Punishments - {0}"
|
||||
punishmentPlayerNotFound: '<red>This player does not exist. Try doing /punishments \<player> instead.'
|
||||
# 0 - The punishment type
|
||||
punishmentItemTitle: "<!italic><red>{0}"
|
||||
# 0 - The punisher
|
||||
punishmentItemPunisher: "<!italic><red>By: <gold>{0}"
|
||||
# 0 - The issue date
|
||||
punishmentItemIssued: "<!italic><red>Issued: <gold>{0}"
|
||||
# 0 - The expiration date
|
||||
punishmentItemExpires: "<!italic><red>Expire(d/s): <gold>{0}"
|
||||
# 0 - The reason
|
||||
punishmentItemReason: "<!italic><red>Reason: <gold>{0}"
|
||||
# 0 - The amount of active bans
|
||||
# 1 - The active ban list
|
||||
activeBansList: "<gold>Active Bans ({0}): <yellow>{1}"
|
||||
@@ -343,8 +308,6 @@ updateUpToDate: "<green>Plex is up to date on the {0} channel."
|
||||
# 1 - The channel
|
||||
updateAvailable: "<red>Plex {0} is available on the {1} channel."
|
||||
updateRunCommand: "<red>Run: /plex update"
|
||||
# 0 - The channel
|
||||
updateAlreadyUpToDate: "<red>Plex is already up to date on the {0} channel."
|
||||
# 0 - The file name
|
||||
updateDownloading: "<green>Downloading latest JAR file: {0}"
|
||||
updateDownloaded: "<green>New JAR file downloaded and verified successfully."
|
||||
@@ -354,6 +317,23 @@ updateDirectoryFailed: "<red>Unable to create update directory: {0}"
|
||||
updateDownloadFailed: "<red>Something went wrong while downloading {0}. Please check the log for more information."
|
||||
# 0 - The channel
|
||||
updateMetadataNotFound: "<red>No compatible update is available on the {0} channel."
|
||||
# 0 - The Plex version
|
||||
# 1 - The channel
|
||||
# 2 - The supported Minecraft versions
|
||||
# 3 - The running Minecraft version
|
||||
updateRequiresMinecraftVersion: "<yellow>No Plex build exists for Minecraft {3}. Plex {0} on the {1} channel supports Minecraft: {2}."
|
||||
# 0 - The Plex version
|
||||
# 1 - The channel
|
||||
# 2 - The oldest supported Minecraft version
|
||||
# 3 - The running Minecraft version
|
||||
# 4 - The supported Minecraft versions
|
||||
updateRequiresNewerMinecraft: "<yellow>Your server is running Minecraft {3}, which is older than any version supported by Plex {0} on the {1} channel (oldest supported: {2}). Supported versions: {4}."
|
||||
# 0 - The Plex version
|
||||
# 1 - The channel
|
||||
# 2 - The newest supported Minecraft version
|
||||
# 3 - The running Minecraft version
|
||||
# 4 - The supported Minecraft versions
|
||||
updateUnsupportedNewerMinecraft: "<yellow>No Plex build exists yet for Minecraft {3}. Plex {0} on the {1} channel supports up to Minecraft {2}. Supported versions: {4}."
|
||||
# 0 - The error message
|
||||
updateMetadataError: "<red>There was an error checking update metadata: {0}"
|
||||
moduleUpdateDisabled: "<yellow>Skipping {0}; module updates are disabled."
|
||||
|
||||
Reference in New Issue
Block a user