mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-02-16 02:20:44 +00:00
CMD
This commit is contained in:
@@ -34,7 +34,7 @@ plugins {
|
||||
}
|
||||
|
||||
group = "art.arcane"
|
||||
version = "3.9.1-1.20.1-1.21.11"
|
||||
version = "4.0.0-1.20.1-1.21.11-Dev1"
|
||||
|
||||
apply<ApiGenerator>()
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ import art.arcane.volmlib.util.collection.KMap;
|
||||
import art.arcane.volmlib.util.exceptions.IrisException;
|
||||
import art.arcane.iris.util.format.C;
|
||||
import art.arcane.volmlib.util.function.NastyRunnable;
|
||||
import art.arcane.volmlib.util.io.FileWatcher;
|
||||
import art.arcane.volmlib.util.hotload.ConfigHotloadEngine;
|
||||
import art.arcane.volmlib.util.io.IO;
|
||||
import art.arcane.volmlib.util.io.InstanceState;
|
||||
import art.arcane.volmlib.util.io.JarScanner;
|
||||
@@ -89,10 +89,11 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
public static Bindings.Adventure audiences;
|
||||
public static MultiverseCoreLink linkMultiverseCore;
|
||||
public static IrisCompat compat;
|
||||
public static FileWatcher configWatcher;
|
||||
public static ConfigHotloadEngine configHotloadEngine;
|
||||
public static ChunkTickets tickets;
|
||||
private static VolmitSender sender;
|
||||
private static Thread shutdownHook;
|
||||
private static File settingsFile;
|
||||
|
||||
static {
|
||||
try {
|
||||
@@ -446,7 +447,14 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
IrisSafeguard.splash();
|
||||
tickets = new ChunkTickets();
|
||||
linkMultiverseCore = new MultiverseCoreLink();
|
||||
configWatcher = new FileWatcher(getDataFile("settings.json"));
|
||||
settingsFile = getDataFile("settings.json");
|
||||
configHotloadEngine = new ConfigHotloadEngine(
|
||||
Iris::isSettingsFile,
|
||||
Iris::knownSettingsFiles,
|
||||
Iris::readSettingsContent,
|
||||
Iris::normalizeSettingsContent
|
||||
);
|
||||
configHotloadEngine.configure(3_000L, List.of(settingsFile), List.of());
|
||||
services.values().forEach(IrisService::onEnable);
|
||||
services.values().forEach(this::registerListener);
|
||||
addShutdownHook();
|
||||
@@ -556,6 +564,10 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
public void onDisable() {
|
||||
if (IrisSafeguard.isForceShutdown()) return;
|
||||
services.values().forEach(IrisService::onDisable);
|
||||
if (configHotloadEngine != null) {
|
||||
configHotloadEngine.clear();
|
||||
configHotloadEngine = null;
|
||||
}
|
||||
Bukkit.getScheduler().cancelTasks(this);
|
||||
HandlerList.unregisterAll((Plugin) this);
|
||||
postShutdown.forEach(Runnable::run);
|
||||
@@ -586,12 +598,51 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
}
|
||||
|
||||
private void checkConfigHotload() {
|
||||
if (configWatcher.checkModified()) {
|
||||
IrisSettings.invalidate();
|
||||
IrisSettings.get();
|
||||
configWatcher.checkModified();
|
||||
Iris.info("Hotloaded settings.json ");
|
||||
if (configHotloadEngine == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (File file : configHotloadEngine.pollTouchedFiles()) {
|
||||
configHotloadEngine.processFileChange(file, ignored -> {
|
||||
IrisSettings.invalidate();
|
||||
IrisSettings.get();
|
||||
return true;
|
||||
}, ignored -> Iris.info("Hotloaded settings.json "));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isSettingsFile(File file) {
|
||||
if (file == null || settingsFile == null) {
|
||||
return false;
|
||||
}
|
||||
return settingsFile.getAbsoluteFile().equals(file.getAbsoluteFile());
|
||||
}
|
||||
|
||||
private static List<File> knownSettingsFiles() {
|
||||
if (settingsFile == null) {
|
||||
return List.of();
|
||||
}
|
||||
return List.of(settingsFile);
|
||||
}
|
||||
|
||||
private static String readSettingsContent(File file) {
|
||||
if (file == null || !file.exists() || !file.isFile()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return IO.readAll(file);
|
||||
} catch (Throwable ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String normalizeSettingsContent(String text) {
|
||||
if (text == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return text.replace("\r\n", "\n").trim();
|
||||
}
|
||||
|
||||
private void tickQueue() {
|
||||
|
||||
@@ -19,40 +19,63 @@
|
||||
package art.arcane.iris.core.service;
|
||||
|
||||
import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.core.IrisSettings;
|
||||
import art.arcane.iris.core.commands.CommandIris;
|
||||
import art.arcane.iris.core.tools.IrisToolbelt;
|
||||
import art.arcane.iris.engine.data.cache.AtomicCache;
|
||||
import art.arcane.volmlib.util.collection.KMap;
|
||||
import art.arcane.iris.util.decree.DecreeContext;
|
||||
import art.arcane.iris.util.decree.DecreeContextHandler;
|
||||
import art.arcane.iris.util.decree.DecreeSystem;
|
||||
import art.arcane.iris.util.decree.virtual.VirtualDecreeCommand;
|
||||
import art.arcane.iris.util.format.C;
|
||||
import art.arcane.iris.util.plugin.IrisService;
|
||||
import art.arcane.iris.util.plugin.VolmitSender;
|
||||
import art.arcane.iris.util.scheduling.J;
|
||||
import art.arcane.volmlib.util.director.compat.DirectorDecreeEngineFactory;
|
||||
import art.arcane.volmlib.util.director.context.DirectorContextRegistry;
|
||||
import art.arcane.volmlib.util.director.runtime.DirectorExecutionMode;
|
||||
import art.arcane.volmlib.util.director.runtime.DirectorExecutionResult;
|
||||
import art.arcane.volmlib.util.director.runtime.DirectorInvocation;
|
||||
import art.arcane.volmlib.util.director.runtime.DirectorInvocationHook;
|
||||
import art.arcane.volmlib.util.director.runtime.DirectorRuntimeEngine;
|
||||
import art.arcane.volmlib.util.director.runtime.DirectorRuntimeNode;
|
||||
import art.arcane.volmlib.util.director.runtime.DirectorSender;
|
||||
import art.arcane.volmlib.util.director.visual.DirectorVisualCommand;
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.server.ServerCommandEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class CommandSVC implements IrisService, DecreeSystem {
|
||||
private final KMap<String, CompletableFuture<String>> futures = new KMap<>();
|
||||
private final transient AtomicCache<VirtualDecreeCommand> commandCache = new AtomicCache<>();
|
||||
private CompletableFuture<String> consoleFuture = null;
|
||||
public class CommandSVC implements IrisService, CommandExecutor, TabCompleter, DirectorInvocationHook {
|
||||
private static final String ROOT_COMMAND = "iris";
|
||||
private static final String ROOT_PERMISSION = "iris.all";
|
||||
|
||||
private final transient AtomicCache<DirectorRuntimeEngine> directorCache = new AtomicCache<>();
|
||||
private final transient AtomicCache<DirectorVisualCommand> helpCache = new AtomicCache<>();
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
Iris.instance.getCommand("iris").setExecutor(this);
|
||||
J.a(() -> {
|
||||
DecreeContext.touch(Iris.getSender());
|
||||
try {
|
||||
getRoot().cacheAll();
|
||||
} finally {
|
||||
DecreeContext.remove();
|
||||
}
|
||||
});
|
||||
PluginCommand command = Iris.instance.getCommand(ROOT_COMMAND);
|
||||
if (command == null) {
|
||||
Iris.warn("Failed to find command '" + ROOT_COMMAND + "'");
|
||||
return;
|
||||
}
|
||||
|
||||
command.setExecutor(this);
|
||||
command.setTabCompleter(this);
|
||||
J.a(this::getDirector);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -64,44 +87,184 @@ public class CommandSVC implements IrisService, DecreeSystem {
|
||||
public void on(PlayerCommandPreprocessEvent e) {
|
||||
String msg = e.getMessage().startsWith("/") ? e.getMessage().substring(1) : e.getMessage();
|
||||
|
||||
if (msg.startsWith("irisdecree ")) {
|
||||
String[] args = msg.split("\\Q \\E");
|
||||
CompletableFuture<String> future = futures.get(args[1]);
|
||||
|
||||
if (future != null) {
|
||||
future.complete(args[2]);
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((msg.startsWith("locate ") || msg.startsWith("locatebiome ")) && IrisToolbelt.isIrisWorld(e.getPlayer().getWorld())) {
|
||||
new VolmitSender(e.getPlayer()).sendMessage(C.RED + "Locating biomes & objects is disabled in Iris Worlds. Use /iris studio goto <biome>");
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void on(ServerCommandEvent e) {
|
||||
if (consoleFuture != null && !consoleFuture.isCancelled() && !consoleFuture.isDone()) {
|
||||
if (!e.getCommand().contains(" ")) {
|
||||
String pick = e.getCommand().trim().toLowerCase(Locale.ROOT);
|
||||
consoleFuture.complete(pick);
|
||||
e.setCancelled(true);
|
||||
public DirectorRuntimeEngine getDirector() {
|
||||
return directorCache.aquireNastyPrint(() -> DirectorDecreeEngineFactory.create(
|
||||
new CommandIris(),
|
||||
null,
|
||||
buildDirectorContexts(),
|
||||
this::dispatchDirector,
|
||||
this,
|
||||
DecreeSystem.handlers
|
||||
));
|
||||
}
|
||||
|
||||
private DirectorContextRegistry buildDirectorContexts() {
|
||||
DirectorContextRegistry contexts = new DirectorContextRegistry();
|
||||
|
||||
for (Map.Entry<Class<?>, DecreeContextHandler<?>> entry : DecreeContextHandler.contextHandlers.entrySet()) {
|
||||
registerContextHandler(contexts, entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
return contexts;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private void registerContextHandler(DirectorContextRegistry contexts, Class<?> type, DecreeContextHandler<?> handler) {
|
||||
contexts.register((Class) type, (invocation, map) -> {
|
||||
if (invocation.getSender() instanceof BukkitDirectorSender sender) {
|
||||
return ((DecreeContextHandler) handler).handle(new VolmitSender(sender.sender()));
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private void dispatchDirector(DirectorExecutionMode mode, Runnable runnable) {
|
||||
if (mode == DirectorExecutionMode.SYNC) {
|
||||
J.s(runnable);
|
||||
} else {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VirtualDecreeCommand getRoot() {
|
||||
return commandCache.aquireNastyPrint(() -> VirtualDecreeCommand.createRoot(new CommandIris()));
|
||||
public void beforeInvoke(DirectorInvocation invocation, DirectorRuntimeNode node) {
|
||||
if (invocation.getSender() instanceof BukkitDirectorSender sender) {
|
||||
DecreeContext.touch(new VolmitSender(sender.sender()));
|
||||
}
|
||||
}
|
||||
|
||||
public void post(String password, CompletableFuture<String> future) {
|
||||
futures.put(password, future);
|
||||
@Override
|
||||
public void afterInvoke(DirectorInvocation invocation, DirectorRuntimeNode node) {
|
||||
DecreeContext.remove();
|
||||
}
|
||||
|
||||
public void postConsole(CompletableFuture<String> future) {
|
||||
consoleFuture = future;
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
|
||||
if (!command.getName().equalsIgnoreCase(ROOT_COMMAND)) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
List<String> v = runDirectorTab(sender, alias, args);
|
||||
if (sender instanceof Player player && IrisSettings.get().getGeneral().isCommandSounds()) {
|
||||
player.playSound(player.getLocation(), Sound.BLOCK_AMETHYST_BLOCK_CHIME, 0.25f, RNG.r.f(0.125f, 1.95f));
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||
if (!command.getName().equalsIgnoreCase(ROOT_COMMAND)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sender.hasPermission(ROOT_PERMISSION)) {
|
||||
sender.sendMessage("You lack the Permission '" + ROOT_PERMISSION + "'");
|
||||
return true;
|
||||
}
|
||||
|
||||
J.aBukkit(() -> executeCommand(sender, label, args));
|
||||
return true;
|
||||
}
|
||||
|
||||
private void executeCommand(CommandSender sender, String label, String[] args) {
|
||||
if (sendHelpIfRequested(sender, args)) {
|
||||
playSuccessSound(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
DirectorExecutionResult result = runDirector(sender, label, args);
|
||||
|
||||
if (result.isSuccess()) {
|
||||
playSuccessSound(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
playFailureSound(sender);
|
||||
if (result.getMessage() == null || result.getMessage().trim().isEmpty()) {
|
||||
new VolmitSender(sender).sendMessage(C.RED + "Unknown Iris Command");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean sendHelpIfRequested(CommandSender sender, String[] args) {
|
||||
Optional<DirectorVisualCommand.HelpRequest> request = DirectorVisualCommand.resolveHelp(getHelpRoot(), Arrays.asList(args));
|
||||
if (request.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
VolmitSender volmitSender = new VolmitSender(sender);
|
||||
volmitSender.sendDecreeHelp(request.get().command(), request.get().page());
|
||||
return true;
|
||||
}
|
||||
|
||||
private DirectorVisualCommand getHelpRoot() {
|
||||
return helpCache.aquireNastyPrint(() -> DirectorVisualCommand.createRoot(getDirector()));
|
||||
}
|
||||
|
||||
private DirectorExecutionResult runDirector(CommandSender sender, String label, String[] args) {
|
||||
try {
|
||||
return getDirector().execute(new DirectorInvocation(new BukkitDirectorSender(sender), label, Arrays.asList(args)));
|
||||
} catch (Throwable e) {
|
||||
Iris.warn("Director command execution failed: " + e.getClass().getSimpleName() + " " + e.getMessage());
|
||||
return DirectorExecutionResult.notHandled();
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> runDirectorTab(CommandSender sender, String alias, String[] args) {
|
||||
try {
|
||||
return getDirector().tabComplete(new DirectorInvocation(new BukkitDirectorSender(sender), alias, Arrays.asList(args)));
|
||||
} catch (Throwable e) {
|
||||
Iris.warn("Director tab completion failed: " + e.getClass().getSimpleName() + " " + e.getMessage());
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
||||
private void playFailureSound(CommandSender sender) {
|
||||
if (!IrisSettings.get().getGeneral().isCommandSounds()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sender instanceof Player player) {
|
||||
player.playSound(player.getLocation(), Sound.BLOCK_AMETHYST_CLUSTER_BREAK, 0.77f, 0.25f);
|
||||
player.playSound(player.getLocation(), Sound.BLOCK_BEACON_DEACTIVATE, 0.2f, 0.45f);
|
||||
}
|
||||
}
|
||||
|
||||
private void playSuccessSound(CommandSender sender) {
|
||||
if (!IrisSettings.get().getGeneral().isCommandSounds()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sender instanceof Player player) {
|
||||
player.playSound(player.getLocation(), Sound.BLOCK_AMETHYST_CLUSTER_BREAK, 0.77f, 1.65f);
|
||||
player.playSound(player.getLocation(), Sound.BLOCK_RESPAWN_ANCHOR_CHARGE, 0.125f, 2.99f);
|
||||
}
|
||||
}
|
||||
|
||||
private record BukkitDirectorSender(CommandSender sender) implements DirectorSender {
|
||||
@Override
|
||||
public String getName() {
|
||||
return sender.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlayer() {
|
||||
return sender instanceof Player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(String message) {
|
||||
if (message != null && !message.trim().isEmpty()) {
|
||||
sender.sendMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
package art.arcane.iris.util.decree;
|
||||
|
||||
import art.arcane.volmlib.util.decree.DecreeNodeBase;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
|
||||
public class DecreeNode extends DecreeNodeBase<DecreeParameter> {
|
||||
public DecreeNode(Object instance, Method method) {
|
||||
super(instance, method);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DecreeParameter createParameter(Parameter parameter) {
|
||||
return new DecreeParameter(parameter);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package art.arcane.iris.util.decree;
|
||||
|
||||
import art.arcane.volmlib.util.decree.DecreeParameterBase;
|
||||
import art.arcane.volmlib.util.decree.specialhandlers.NoParameterHandler;
|
||||
import art.arcane.iris.util.decree.specialhandlers.DummyHandler;
|
||||
|
||||
import java.lang.reflect.Parameter;
|
||||
|
||||
public class DecreeParameter extends DecreeParameterBase {
|
||||
public DecreeParameter(Parameter parameter) {
|
||||
super(parameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean useSystemHandler(Class<?> customHandler) {
|
||||
return customHandler.equals(NoParameterHandler.class) || customHandler.equals(DummyHandler.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected art.arcane.volmlib.util.decree.DecreeParameterHandler<?> getSystemHandler(Class<?> type) {
|
||||
return DecreeSystem.getHandler(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DecreeParameterHandler<?> getHandler() {
|
||||
return (DecreeParameterHandler<?>) super.getHandler();
|
||||
}
|
||||
}
|
||||
@@ -20,33 +20,11 @@ package art.arcane.iris.util.decree;
|
||||
|
||||
import art.arcane.volmlib.util.decree.DecreeSystemSupport;
|
||||
import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.core.IrisSettings;
|
||||
import art.arcane.volmlib.util.collection.KList;
|
||||
import art.arcane.iris.util.decree.virtual.VirtualDecreeCommand;
|
||||
import art.arcane.iris.util.format.C;
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
import art.arcane.iris.util.plugin.VolmitSender;
|
||||
import art.arcane.iris.util.scheduling.J;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
public final class DecreeSystem {
|
||||
public static final KList<DecreeParameterHandler<?>> handlers = Iris.initialize("art.arcane.iris.util.decree.handlers", null).convert((i) -> (DecreeParameterHandler<?>) i);
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface DecreeSystem extends CommandExecutor, TabCompleter {
|
||||
KList<DecreeParameterHandler<?>> handlers = Iris.initialize("art.arcane.iris.util.decree.handlers", null).convert((i) -> (DecreeParameterHandler<?>) i);
|
||||
|
||||
static KList<String> enhanceArgs(String[] args) {
|
||||
return new KList<>(DecreeSystemSupport.enhanceArgs(args));
|
||||
}
|
||||
|
||||
static KList<String> enhanceArgs(String[] args, boolean trim) {
|
||||
return new KList<>(DecreeSystemSupport.enhanceArgs(args, trim));
|
||||
private DecreeSystem() {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,7 +33,7 @@ public interface DecreeSystem extends CommandExecutor, TabCompleter {
|
||||
* @param type The type to handle
|
||||
* @return The corresponding {@link DecreeParameterHandler}, or null
|
||||
*/
|
||||
static DecreeParameterHandler<?> getHandler(Class<?> type) {
|
||||
public static DecreeParameterHandler<?> getHandler(Class<?> type) {
|
||||
DecreeParameterHandler<?> handler = DecreeSystemSupport.getHandler(handlers, type, (h, t) -> h.supports(t));
|
||||
if (handler != null) {
|
||||
return handler;
|
||||
@@ -64,70 +42,4 @@ public interface DecreeSystem extends CommandExecutor, TabCompleter {
|
||||
Iris.error("Unhandled type in Decree Parameter: " + type.getName() + ". This is bad!");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The root class to start command searching from
|
||||
*/
|
||||
VirtualDecreeCommand getRoot();
|
||||
|
||||
default boolean call(VolmitSender sender, String[] args) {
|
||||
DecreeContext.touch(sender);
|
||||
try {
|
||||
return getRoot().invoke(sender, enhanceArgs(args));
|
||||
} finally {
|
||||
DecreeContext.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
default List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
|
||||
DecreeContext.touch(new VolmitSender(sender));
|
||||
try {
|
||||
KList<String> enhanced = new KList<>(args);
|
||||
KList<String> v = getRoot().tabComplete(enhanced, enhanced.toString(" "));
|
||||
v.removeDuplicates();
|
||||
|
||||
if (sender instanceof Player) {
|
||||
if (IrisSettings.get().getGeneral().isCommandSounds()) {
|
||||
((Player) sender).playSound(((Player) sender).getLocation(), Sound.BLOCK_AMETHYST_BLOCK_CHIME, 0.25f, RNG.r.f(0.125f, 1.95f));
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
} finally {
|
||||
DecreeContext.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||
if (!sender.hasPermission("iris.all")) {
|
||||
sender.sendMessage("You lack the Permission 'iris.all'");
|
||||
return true;
|
||||
}
|
||||
|
||||
J.aBukkit(() -> {
|
||||
var volmit = new VolmitSender(sender);
|
||||
if (!call(volmit, args)) {
|
||||
|
||||
if (IrisSettings.get().getGeneral().isCommandSounds()) {
|
||||
if (sender instanceof Player) {
|
||||
((Player) sender).playSound(((Player) sender).getLocation(), Sound.BLOCK_AMETHYST_CLUSTER_BREAK, 0.77f, 0.25f);
|
||||
((Player) sender).playSound(((Player) sender).getLocation(), Sound.BLOCK_BEACON_DEACTIVATE, 0.2f, 0.45f);
|
||||
}
|
||||
}
|
||||
|
||||
volmit.sendMessage(C.RED + "Unknown Iris Command");
|
||||
} else {
|
||||
if (IrisSettings.get().getGeneral().isCommandSounds()) {
|
||||
if (sender instanceof Player) {
|
||||
((Player) sender).playSound(((Player) sender).getLocation(), Sound.BLOCK_AMETHYST_CLUSTER_BREAK, 0.77f, 1.65f);
|
||||
((Player) sender).playSound(((Player) sender).getLocation(), Sound.BLOCK_RESPAWN_ANCHOR_CHARGE, 0.125f, 2.99f);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,596 +0,0 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2022 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.util.decree.virtual;
|
||||
|
||||
import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.core.IrisSettings;
|
||||
import art.arcane.volmlib.util.collection.KList;
|
||||
import art.arcane.volmlib.util.collection.KMap;
|
||||
import art.arcane.volmlib.util.collection.KSet;
|
||||
import art.arcane.iris.util.decree.*;
|
||||
import art.arcane.volmlib.util.decree.DecreeOrigin;
|
||||
import art.arcane.volmlib.util.decree.annotations.Decree;
|
||||
import art.arcane.volmlib.util.decree.exceptions.DecreeParsingException;
|
||||
import art.arcane.iris.util.format.C;
|
||||
import art.arcane.volmlib.util.format.Form;
|
||||
import art.arcane.iris.util.plugin.CommandDummy;
|
||||
import art.arcane.iris.util.plugin.VolmitSender;
|
||||
import art.arcane.volmlib.util.scheduling.ChronoLatch;
|
||||
import art.arcane.iris.util.scheduling.J;
|
||||
import lombok.Data;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Data
|
||||
public class VirtualDecreeCommand {
|
||||
private final Class<?> type;
|
||||
private final VirtualDecreeCommand parent;
|
||||
private final KList<VirtualDecreeCommand> nodes;
|
||||
private final DecreeNode node;
|
||||
String[] gradients = new String[]{
|
||||
"<gradient:#f5bc42:#45b32d>",
|
||||
"<gradient:#1ed43f:#1ecbd4>",
|
||||
"<gradient:#1e2ad4:#821ed4>",
|
||||
"<gradient:#d41ea7:#611ed4>",
|
||||
"<gradient:#1ed473:#1e55d4>",
|
||||
"<gradient:#6ad41e:#9a1ed4>"
|
||||
};
|
||||
private ChronoLatch cl = new ChronoLatch(1000);
|
||||
|
||||
private VirtualDecreeCommand(Class<?> type, VirtualDecreeCommand parent, KList<VirtualDecreeCommand> nodes, DecreeNode node) {
|
||||
this.parent = parent;
|
||||
this.type = type;
|
||||
this.nodes = nodes;
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public static VirtualDecreeCommand createRoot(Object v) throws Throwable {
|
||||
return createRoot(null, v);
|
||||
}
|
||||
|
||||
public static VirtualDecreeCommand createRoot(VirtualDecreeCommand parent, Object v) throws Throwable {
|
||||
VirtualDecreeCommand c = new VirtualDecreeCommand(v.getClass(), parent, new KList<>(), null);
|
||||
|
||||
for (Field i : v.getClass().getDeclaredFields()) {
|
||||
if (Modifier.isStatic(i.getModifiers()) || Modifier.isFinal(i.getModifiers()) || Modifier.isTransient(i.getModifiers()) || Modifier.isVolatile(i.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!i.getType().isAnnotationPresent(Decree.class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
i.setAccessible(true);
|
||||
Object childRoot = i.get(v);
|
||||
|
||||
if (childRoot == null) {
|
||||
childRoot = i.getType().getConstructor().newInstance();
|
||||
i.set(v, childRoot);
|
||||
}
|
||||
|
||||
c.getNodes().add(createRoot(c, childRoot));
|
||||
}
|
||||
|
||||
for (Method i : v.getClass().getDeclaredMethods()) {
|
||||
if (Modifier.isStatic(i.getModifiers()) || Modifier.isFinal(i.getModifiers()) || Modifier.isPrivate(i.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!i.isAnnotationPresent(Decree.class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
c.getNodes().add(new VirtualDecreeCommand(v.getClass(), c, new KList<>(), new DecreeNode(v, i)));
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
public void cacheAll() {
|
||||
VolmitSender sender = new VolmitSender(new CommandDummy());
|
||||
|
||||
if (isNode()) {
|
||||
sender.sendDecreeHelpNode(this);
|
||||
}
|
||||
|
||||
for (VirtualDecreeCommand j : nodes) {
|
||||
j.cacheAll();
|
||||
}
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
KList<String> n = new KList<>();
|
||||
VirtualDecreeCommand cursor = this;
|
||||
|
||||
while (cursor.getParent() != null) {
|
||||
cursor = cursor.getParent();
|
||||
n.add(cursor.getName());
|
||||
}
|
||||
|
||||
return "/" + n.reverse().qadd(getName()).toString(" ");
|
||||
}
|
||||
|
||||
public String getParentPath() {
|
||||
return getParent().getPath();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return isNode() ? getNode().getName() : getType().getDeclaredAnnotation(Decree.class).name();
|
||||
}
|
||||
|
||||
private boolean isStudio() {
|
||||
return isNode() ? getNode().getDecree().studio() : getType().getDeclaredAnnotation(Decree.class).studio();
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return isNode() ? getNode().getDescription() : getType().getDeclaredAnnotation(Decree.class).description();
|
||||
}
|
||||
|
||||
public KList<String> getNames() {
|
||||
if (isNode()) {
|
||||
return getNode().getNames();
|
||||
}
|
||||
|
||||
Decree dc = getType().getDeclaredAnnotation(Decree.class);
|
||||
KList<String> d = new KList<>();
|
||||
d.add(dc.name());
|
||||
for (String i : dc.aliases()) {
|
||||
if (i.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
d.add(i);
|
||||
}
|
||||
|
||||
d.removeDuplicates();
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
public boolean isNode() {
|
||||
return node != null;
|
||||
}
|
||||
|
||||
public KList<String> tabComplete(KList<String> args, String raw) {
|
||||
KList<Integer> skip = new KList<>();
|
||||
KList<String> tabs = new KList<>();
|
||||
invokeTabComplete(args, skip, tabs, raw);
|
||||
return tabs;
|
||||
}
|
||||
|
||||
private boolean invokeTabComplete(KList<String> args, KList<Integer> skip, KList<String> tabs, String raw) {
|
||||
if (isStudio() && !IrisSettings.get().getStudio().isStudio()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isNode()) {
|
||||
tab(args, tabs);
|
||||
skip.add(hashCode());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (args.isEmpty()) {
|
||||
tab(args, tabs);
|
||||
return true;
|
||||
}
|
||||
|
||||
String head = args.get(0);
|
||||
|
||||
if (args.size() > 1 || head.endsWith(" ")) {
|
||||
VirtualDecreeCommand match = matchNode(head, skip);
|
||||
|
||||
if (match != null) {
|
||||
args.pop();
|
||||
return match.invokeTabComplete(args, skip, tabs, raw);
|
||||
}
|
||||
|
||||
skip.add(hashCode());
|
||||
} else {
|
||||
tab(args, tabs);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void tab(KList<String> args, KList<String> tabs) {
|
||||
String last = null;
|
||||
KList<DecreeParameter> ignore = new KList<>();
|
||||
Runnable la = () -> {
|
||||
|
||||
};
|
||||
for (String a : args) {
|
||||
la.run();
|
||||
last = a;
|
||||
la = () -> {
|
||||
if (isNode()) {
|
||||
String sea = a.contains("=") ? a.split("\\Q=\\E")[0] : a;
|
||||
sea = sea.trim();
|
||||
|
||||
searching:
|
||||
for (DecreeParameter i : getNode().getParameters()) {
|
||||
for (String m : i.getNames()) {
|
||||
if (m.equalsIgnoreCase(sea) || m.toLowerCase().contains(sea.toLowerCase()) || sea.toLowerCase().contains(m.toLowerCase())) {
|
||||
ignore.add(i);
|
||||
continue searching;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (last != null) {
|
||||
if (isNode()) {
|
||||
for (DecreeParameter i : getNode().getParameters()) {
|
||||
if (ignore.contains(i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int g = 0;
|
||||
|
||||
if (last.contains("=")) {
|
||||
String[] vv = last.trim().split("\\Q=\\E");
|
||||
String vx = vv.length == 2 ? vv[1] : "";
|
||||
for (String f : i.getHandler().getPossibilities(vx).convert((v) -> i.getHandler().toStringForce(v))) {
|
||||
g++;
|
||||
tabs.add(i.getName() + "=" + f);
|
||||
}
|
||||
} else {
|
||||
for (String f : i.getHandler().getPossibilities("").convert((v) -> i.getHandler().toStringForce(v))) {
|
||||
g++;
|
||||
tabs.add(i.getName() + "=" + f);
|
||||
}
|
||||
}
|
||||
|
||||
if (g == 0) {
|
||||
tabs.add(i.getName() + "=");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (VirtualDecreeCommand i : getNodes()) {
|
||||
String m = i.getName();
|
||||
if (m.equalsIgnoreCase(last) || m.toLowerCase().contains(last.toLowerCase()) || last.toLowerCase().contains(m.toLowerCase())) {
|
||||
tabs.addAll(i.getNames());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the input a player typed to the parameters of this command
|
||||
*
|
||||
* @param sender The sender
|
||||
* @param in The input
|
||||
* @return A map of all the parameter names and their values
|
||||
*/
|
||||
private KMap<String, Object> map(VolmitSender sender, KList<String> in) {
|
||||
KMap<String, Object> data = new KMap<>();
|
||||
KSet<Integer> nowhich = new KSet<>();
|
||||
|
||||
KList<String> unknownInputs = new KList<>(in.stream().filter(s -> !s.contains("=")).collect(Collectors.toList()));
|
||||
KList<String> knownInputs = new KList<>(in.stream().filter(s -> s.contains("=")).collect(Collectors.toList()));
|
||||
|
||||
//Loop known inputs
|
||||
for (int x = 0; x < knownInputs.size(); x++) {
|
||||
String stringParam = knownInputs.get(x);
|
||||
int original = in.indexOf(stringParam);
|
||||
|
||||
String[] v = stringParam.split("\\Q=\\E");
|
||||
String key = v[0];
|
||||
String value = v[1];
|
||||
DecreeParameter param = null;
|
||||
|
||||
//Find decree parameter from string param
|
||||
for (DecreeParameter j : getNode().getParameters()) {
|
||||
for (String k : j.getNames()) {
|
||||
if (k.equalsIgnoreCase(key)) {
|
||||
param = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//If it failed, see if we can find it by checking if the names contain the param
|
||||
if (param == null) {
|
||||
for (DecreeParameter j : getNode().getParameters()) {
|
||||
for (String k : j.getNames()) {
|
||||
if (k.toLowerCase().contains(key.toLowerCase()) || key.toLowerCase().contains(k.toLowerCase())) {
|
||||
param = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Still failed to find, error them
|
||||
if (param == null) {
|
||||
Iris.debug("Can't find parameter key for " + key + "=" + value + " in " + getPath());
|
||||
sender.sendMessage(C.YELLOW + "Unknown Parameter: " + key);
|
||||
unknownInputs.add(value); //Add the value to the unknowns and see if we can assume it later
|
||||
continue;
|
||||
}
|
||||
|
||||
key = param.getName();
|
||||
|
||||
try {
|
||||
data.put(key, param.getHandler().parse(value, nowhich.contains(original))); //Parse and put
|
||||
} catch (DecreeParsingException e) {
|
||||
Iris.debug("Can't parse parameter value for " + key + "=" + value + " in " + getPath() + " using handler " + param.getHandler().getClass().getSimpleName());
|
||||
sender.sendMessage(C.RED + "Cannot convert \"" + value + "\" into a " + param.getType().getSimpleName());
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//Make a list of decree params that haven't been identified
|
||||
KList<DecreeParameter> decreeParameters = new KList<>(getNode().getParameters().stream().filter(param -> !data.contains(param.getName())).collect(Collectors.toList()));
|
||||
|
||||
//Loop Unknown inputs
|
||||
for (int x = 0; x < unknownInputs.size(); x++) {
|
||||
String stringParam = unknownInputs.get(x);
|
||||
int original = in.indexOf(stringParam);
|
||||
try {
|
||||
DecreeParameter par = decreeParameters.get(x);
|
||||
|
||||
try {
|
||||
data.put(par.getName(), par.getHandler().parse(stringParam, nowhich.contains(original)));
|
||||
} catch (DecreeParsingException e) {
|
||||
Iris.debug("Can't parse parameter value for " + par.getName() + "=" + stringParam + " in " + getPath() + " using handler " + par.getHandler().getClass().getSimpleName());
|
||||
sender.sendMessage(C.RED + "Cannot convert \"" + stringParam + "\" into a " + par.getType().getSimpleName());
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
sender.sendMessage(C.YELLOW + "Unknown Parameter: " + stringParam + " (" + Form.getNumberSuffixThStRd(x + 1) + " argument)");
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public boolean invoke(VolmitSender sender, KList<String> realArgs) {
|
||||
return invoke(sender, realArgs, new KList<>());
|
||||
}
|
||||
|
||||
public boolean invoke(VolmitSender sender, KList<String> args, KList<Integer> skip) {
|
||||
if (isStudio() && !IrisSettings.get().getStudio().isStudio()) {
|
||||
sender.sendMessage(C.RED + "To use Iris Studio Commands, please enable studio in Iris/settings.json (settings auto-reload)");
|
||||
return false;
|
||||
}
|
||||
|
||||
DecreeOrigin origin = type.getDeclaredAnnotation(Decree.class).origin();
|
||||
if (!origin.validFor(sender.isPlayer())) {
|
||||
sender.sendMessage(C.RED + "This command has to be sent from another origin: " + C.GOLD + origin);
|
||||
return false;
|
||||
}
|
||||
|
||||
Iris.debug("@ " + getPath() + " with " + args.toString(", "));
|
||||
if (isNode()) {
|
||||
Iris.debug("Invoke " + getPath() + "(" + args.toString(",") + ") at ");
|
||||
if (invokeNode(sender, map(sender, args))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
skip.add(hashCode());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (args.isEmpty()) {
|
||||
sender.sendDecreeHelp(this);
|
||||
|
||||
return true;
|
||||
} else if (args.size() == 1) {
|
||||
for (String i : args) {
|
||||
if (i.startsWith("help=")) {
|
||||
sender.sendDecreeHelp(this, Integer.parseInt(i.split("\\Q=\\E")[1]) - 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String head = args.get(0);
|
||||
VirtualDecreeCommand match = matchNode(head, skip);
|
||||
|
||||
if (match != null) {
|
||||
args.pop();
|
||||
return match.invoke(sender, args, skip);
|
||||
}
|
||||
|
||||
skip.add(hashCode());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean invokeNode(VolmitSender sender, KMap<String, Object> map) {
|
||||
if (map == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Object[] params = new Object[getNode().getMethod().getParameterCount()];
|
||||
int vm = 0;
|
||||
for (DecreeParameter i : getNode().getParameters()) {
|
||||
Object value = map.get(i.getName());
|
||||
|
||||
try {
|
||||
if (value == null && i.hasDefault()) {
|
||||
value = i.getDefaultValue();
|
||||
}
|
||||
} catch (DecreeParsingException e) {
|
||||
Iris.debug("Can't parse parameter value for " + i.getName() + "=" + i.getParam().defaultValue() + " in " + getPath() + " using handler " + i.getHandler().getClass().getSimpleName());
|
||||
sender.sendMessage(C.RED + "Cannot convert \"" + i.getParam().defaultValue() + "\" into a " + i.getType().getSimpleName());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sender.isPlayer() && i.isContextual() && value == null) {
|
||||
Iris.debug("Contextual!");
|
||||
DecreeContextHandler<?> ch = DecreeContextHandler.contextHandlers.get(i.getType());
|
||||
|
||||
if (ch != null) {
|
||||
value = ch.handle(sender);
|
||||
|
||||
if (value != null) {
|
||||
Iris.debug("Parameter \"" + i.getName() + "\" derived a value of \"" + i.getHandler().toStringForce(value) + "\" from " + ch.getClass().getSimpleName());
|
||||
} else {
|
||||
Iris.debug("Parameter \"" + i.getName() + "\" could not derive a value from \"" + ch.getClass().getSimpleName());
|
||||
}
|
||||
} else {
|
||||
Iris.debug("Parameter \"" + i.getName() + "\" is contextual but has no context handler for \"" + i.getType().getCanonicalName() + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
if (i.hasDefault() && value == null) {
|
||||
try {
|
||||
Iris.debug("Parameter \"" + i.getName() + "\" is using default value \"" + i.getParam().defaultValue() + "\"");
|
||||
value = i.getDefaultValue();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (i.isRequired() && value == null) {
|
||||
sender.sendMessage(C.RED + "Missing argument \"" + i.getName() + "\" (" + i.getType().getSimpleName() + ") as the " + Form.getNumberSuffixThStRd(vm + 1) + " argument.");
|
||||
sender.sendDecreeHelpNode(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
params[vm] = value;
|
||||
vm++;
|
||||
}
|
||||
|
||||
DecreeContext.touch(sender);
|
||||
try {
|
||||
Runnable rx = () -> {
|
||||
DecreeContext.touch(sender);
|
||||
try {
|
||||
getNode().getMethod().setAccessible(true);
|
||||
getNode().getMethod().invoke(getNode().getInstance(), params);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("Failed to execute <INSERT REAL NODE HERE>"); // TODO:
|
||||
} finally {
|
||||
DecreeContext.remove();
|
||||
}
|
||||
};
|
||||
|
||||
if (getNode().isSync()) {
|
||||
J.s(rx);
|
||||
} else {
|
||||
rx.run();
|
||||
}
|
||||
} finally {
|
||||
DecreeContext.remove();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public KList<VirtualDecreeCommand> matchAllNodes(String in) {
|
||||
KList<VirtualDecreeCommand> g = new KList<>();
|
||||
|
||||
if (in.trim().isEmpty()) {
|
||||
g.addAll(nodes);
|
||||
return g;
|
||||
}
|
||||
|
||||
for (VirtualDecreeCommand i : nodes) {
|
||||
if (i.matches(in)) {
|
||||
g.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
for (VirtualDecreeCommand i : nodes) {
|
||||
if (i.deepMatches(in)) {
|
||||
g.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
g.removeDuplicates();
|
||||
return g;
|
||||
}
|
||||
|
||||
public VirtualDecreeCommand matchNode(String in, KList<Integer> skip) {
|
||||
if (in.trim().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (VirtualDecreeCommand i : nodes) {
|
||||
if (skip.contains(i.hashCode())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i.matches(in)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
for (VirtualDecreeCommand i : nodes) {
|
||||
if (skip.contains(i.hashCode())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i.deepMatches(in)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean deepMatches(String in) {
|
||||
KList<String> a = getNames();
|
||||
|
||||
for (String i : a) {
|
||||
if (i.toLowerCase().contains(in.toLowerCase()) || in.toLowerCase().contains(i.toLowerCase())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getName(), getDescription(), getType(), getPath());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof VirtualDecreeCommand)) {
|
||||
return false;
|
||||
}
|
||||
return this.hashCode() == obj.hashCode();
|
||||
}
|
||||
|
||||
public boolean matches(String in) {
|
||||
KList<String> a = getNames();
|
||||
|
||||
for (String i : a) {
|
||||
if (i.equalsIgnoreCase(in)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -22,8 +22,8 @@ import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.core.IrisSettings;
|
||||
import art.arcane.volmlib.util.collection.KList;
|
||||
import art.arcane.volmlib.util.collection.KMap;
|
||||
import art.arcane.iris.util.decree.DecreeParameter;
|
||||
import art.arcane.iris.util.decree.virtual.VirtualDecreeCommand;
|
||||
import art.arcane.volmlib.util.director.visual.DirectorVisualCommand;
|
||||
import art.arcane.volmlib.util.director.visual.DirectorVisualCommand.DirectorVisualParameter;
|
||||
import art.arcane.iris.util.format.C;
|
||||
import art.arcane.volmlib.util.format.Form;
|
||||
import art.arcane.volmlib.util.math.M;
|
||||
@@ -409,19 +409,19 @@ public class VolmitSender implements CommandSender {
|
||||
return s.spigot();
|
||||
}
|
||||
|
||||
private String pickRandoms(int max, VirtualDecreeCommand i) {
|
||||
private String pickRandoms(int max, DirectorVisualCommand i) {
|
||||
KList<String> m = new KList<>();
|
||||
for (int ix = 0; ix < max; ix++) {
|
||||
m.add((i.isNode()
|
||||
? (i.getNode().getParameters().isNotEmpty())
|
||||
? "<#aebef2>✦ <#5ef288>"
|
||||
? "<#c2f7d2>✦ <#5ef288>"
|
||||
+ i.getParentPath()
|
||||
+ " <#42ecf5>"
|
||||
+ " <#32bfad>"
|
||||
+ i.getName() + " "
|
||||
+ i.getNode().getParameters().shuffleCopy(RNG.r).convert((f)
|
||||
-> (f.isRequired() || RNG.r.b(0.5)
|
||||
? "<#f2e15e>" + f.getNames().getRandom() + "="
|
||||
+ "<#d665f0>" + f.example()
|
||||
+ "<#5ef288>" + f.example()
|
||||
: ""))
|
||||
.toString(" ")
|
||||
: ""
|
||||
@@ -443,7 +443,7 @@ public class VolmitSender implements CommandSender {
|
||||
if (name.trim().isEmpty()) {
|
||||
sendMessageRaw("<font:minecraft:uniform><strikethrough><gradient:#34eb6b:#32bfad>" + sf + s + "<reset><font:minecraft:uniform><strikethrough><gradient:#32bfad:#34eb6b>" + s + se);
|
||||
} else {
|
||||
sendMessageRaw("<font:minecraft:uniform><strikethrough><gradient:#34eb6b:#32bfad>" + sf + s + si + "<reset> <gradient:#3299bf:#323bbf>" + name + "<reset> <font:minecraft:uniform><strikethrough><gradient:#32bfad:#34eb6b>" + so + s + se);
|
||||
sendMessageRaw("<font:minecraft:uniform><strikethrough><gradient:#34eb6b:#32bfad>" + sf + s + si + "<reset> <gradient:#32bfad:#34eb6b>" + name + "<reset> <font:minecraft:uniform><strikethrough><gradient:#32bfad:#34eb6b>" + so + s + se);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,31 +451,29 @@ public class VolmitSender implements CommandSender {
|
||||
sendHeader(name, 44);
|
||||
}
|
||||
|
||||
public void sendDecreeHelp(VirtualDecreeCommand v) {
|
||||
public void sendDecreeHelp(DirectorVisualCommand v) {
|
||||
sendDecreeHelp(v, 0);
|
||||
}
|
||||
|
||||
public void sendDecreeHelp(VirtualDecreeCommand v, int page) {
|
||||
public void sendDecreeHelp(DirectorVisualCommand v, int page) {
|
||||
if (!isPlayer()) {
|
||||
for (VirtualDecreeCommand i : v.getNodes()) {
|
||||
for (DirectorVisualCommand i : v.getNodes()) {
|
||||
sendDecreeHelpNode(i);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int m = v.getNodes().size();
|
||||
|
||||
sendMessageRaw("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
|
||||
|
||||
if (v.getNodes().isNotEmpty()) {
|
||||
sendHeader(v.getPath() + (page > 0 ? (" {" + (page + 1) + "}") : ""));
|
||||
if (isPlayer() && v.getParent() != null) {
|
||||
sendMessageRaw("<hover:show_text:'" + "<#b54b38>Click to go back to <#3299bf>" + Form.capitalize(v.getParent().getName()) + " Help" + "'><click:run_command:" + v.getParent().getPath() + "><font:minecraft:uniform><#f58571>〈 Back</click></hover>");
|
||||
sendMessageRaw("<hover:show_text:'" + "<#2b7a3f>Click to go back to <#32bfad>" + Form.capitalize(v.getParent().getName()) + " Help" + "'><click:run_command:" + v.getParent().getPath() + "><font:minecraft:uniform><#6fe98f>〈 Back</click></hover>");
|
||||
}
|
||||
|
||||
AtomicBoolean next = new AtomicBoolean(false);
|
||||
for (VirtualDecreeCommand i : paginate(v.getNodes(), 17, page, next)) {
|
||||
for (DirectorVisualCommand i : paginate(v.getNodes(), 17, page, next)) {
|
||||
sendDecreeHelpNode(i);
|
||||
}
|
||||
|
||||
@@ -483,13 +481,13 @@ public class VolmitSender implements CommandSender {
|
||||
int l = 75 - (page > 0 ? 10 : 0) - (next.get() ? 10 : 0);
|
||||
|
||||
if (page > 0) {
|
||||
s += "<hover:show_text:'<green>Click to go back to page " + page + "'><click:run_command:" + v.getPath() + " help=" + page + "><gradient:#27b84d:#2770b8>〈 Page " + page + "</click></hover><reset> ";
|
||||
s += "<hover:show_text:'<green>Click to go back to page " + page + "'><click:run_command:" + v.getPath() + " help=" + page + "><gradient:#34eb6b:#1f8f4d>〈 Page " + page + "</click></hover><reset> ";
|
||||
}
|
||||
|
||||
s += "<reset><font:minecraft:uniform><strikethrough><gradient:#32bfad:#34eb6b>" + Form.repeat(" ", l) + "<reset>";
|
||||
|
||||
if (next.get()) {
|
||||
s += " <hover:show_text:'<green>Click to go to back to page " + (page + 2) + "'><click:run_command:" + v.getPath() + " help=" + (page + 2) + "><gradient:#2770b8:#27b84d>Page " + (page + 2) + " ❭</click></hover>";
|
||||
s += " <hover:show_text:'<green>Click to go to back to page " + (page + 2) + "'><click:run_command:" + v.getPath() + " help=" + (page + 2) + "><gradient:#1f8f4d:#34eb6b>Page " + (page + 2) + " ❭</click></hover>";
|
||||
}
|
||||
|
||||
sendMessageRaw(s);
|
||||
@@ -498,15 +496,13 @@ public class VolmitSender implements CommandSender {
|
||||
}
|
||||
}
|
||||
|
||||
public void sendDecreeHelpNode(VirtualDecreeCommand i) {
|
||||
public void sendDecreeHelpNode(DirectorVisualCommand i) {
|
||||
if (isPlayer() || s instanceof CommandDummy) {
|
||||
sendMessageRaw(helpCache.computeIfAbsent(i.getPath(), (k) -> {
|
||||
String newline = "<reset>\n";
|
||||
|
||||
/// Command
|
||||
// Contains main command & aliases
|
||||
String realText = i.getPath() + " >" + "<#46826a>⇀<gradient:#42ecf5:#428df5> " + i.getName();
|
||||
String hoverTitle = i.getNames().copy().reverse().convert((f) -> "<#42ecf5>" + f).toString(", ");
|
||||
String realText = i.getPath() + " >" + "<#46826a>⇀<gradient:#5ef288:#32bfad> " + i.getName();
|
||||
String hoverTitle = i.getNames().copy().reverse().convert((f) -> "<#5ef288>" + f).toString(", ");
|
||||
String description = "<#3fe05a>✎ <#6ad97d><font:minecraft:uniform>" + i.getDescription();
|
||||
String usage = "<#bbe03f>✒ <#a8e0a2><font:minecraft:uniform>";
|
||||
String onClick;
|
||||
@@ -526,18 +522,16 @@ public class VolmitSender implements CommandSender {
|
||||
String suggestion = "";
|
||||
String suggestions = "";
|
||||
if (i.isNode() && i.getNode().getParameters().isNotEmpty()) {
|
||||
suggestion += newline + "<#aebef2>✦ <#5ef288><font:minecraft:uniform>" + i.getParentPath() + " <#42ecf5>" + i.getName() + " "
|
||||
+ i.getNode().getParameters().convert((f) -> "<#d665f0>" + f.example()).toString(" ");
|
||||
suggestion += newline + "<#c2f7d2>✦ <#5ef288><font:minecraft:uniform>" + i.getParentPath() + " <#32bfad>" + i.getName() + " "
|
||||
+ i.getNode().getParameters().convert((f) -> "<#5ef288>" + f.example()).toString(" ");
|
||||
suggestions += newline + "<font:minecraft:uniform>" + pickRandoms(Math.min(i.getNode().getParameters().size() + 1, 5), i);
|
||||
}
|
||||
|
||||
/// Params
|
||||
StringBuilder nodes = new StringBuilder();
|
||||
if (i.isNode()) {
|
||||
for (DecreeParameter p : i.getNode().getParameters()) {
|
||||
|
||||
String nTitle = "<gradient:#d665f0:#a37feb>" + p.getName();
|
||||
String nHoverTitle = p.getNames().convert((ff) -> "<#d665f0>" + ff).toString(", ");
|
||||
for (DirectorVisualParameter p : i.getNode().getParameters()) {
|
||||
String nTitle = "<gradient:#5ef288:#32bfad>" + p.getName();
|
||||
String nHoverTitle = p.getNames().convert((ff) -> "<#5ef288>" + ff).toString(", ");
|
||||
String nDescription = "<#3fe05a>✎ <#6ad97d><font:minecraft:uniform>" + p.getDescription();
|
||||
String nUsage;
|
||||
String fullTitle;
|
||||
@@ -550,12 +544,12 @@ public class VolmitSender implements CommandSender {
|
||||
nUsage = "<#db4321>⚠ <#faa796><font:minecraft:uniform>This parameter is required.";
|
||||
} else if (p.hasDefault()) {
|
||||
fullTitle = "<#4f4f4f>⊰" + nTitle + "<#4f4f4f>⊱";
|
||||
nUsage = "<#2181db>✔ <#78dcf0><font:minecraft:uniform>Defaults to \"" + p.getParam().defaultValue() + "\" if undefined.";
|
||||
nUsage = "<#3fbe6f>✔ <#9de5b6><font:minecraft:uniform>Defaults to \"" + p.getParam().defaultValue() + "\" if undefined.";
|
||||
} else {
|
||||
fullTitle = "<#4f4f4f>⊰" + nTitle + "<#4f4f4f>⊱";
|
||||
nUsage = "<#a73abd>✔ <#78dcf0><font:minecraft:uniform>This parameter is optional.";
|
||||
nUsage = "<#3fbe6f>✔ <#9de5b6><font:minecraft:uniform>This parameter is optional.";
|
||||
}
|
||||
String type = "<#cc00ff>✢ <#ff33cc><font:minecraft:uniform>This parameter is of type " + p.getType().getSimpleName() + ".";
|
||||
String type = "<#4fbf7f>✢ <#8ad9af><font:minecraft:uniform>This parameter is of type " + p.getType().getSimpleName() + ".";
|
||||
|
||||
nodes
|
||||
.append("<hover:show_text:'")
|
||||
@@ -568,28 +562,24 @@ public class VolmitSender implements CommandSender {
|
||||
.append("</hover>");
|
||||
}
|
||||
} else {
|
||||
nodes = new StringBuilder("<gradient:#afe3d3:#a2dae0> - Category of Commands");
|
||||
nodes = new StringBuilder("<gradient:#b7eecb:#9de5b6> - Category of Commands");
|
||||
}
|
||||
|
||||
/// Wrapper
|
||||
String wrapper =
|
||||
"<hover:show_text:'" +
|
||||
hoverTitle + newline +
|
||||
description + newline +
|
||||
usage +
|
||||
suggestion + //Newlines for suggestions are added when they're built, to prevent blanklines.
|
||||
suggestions + // ^
|
||||
"'>" +
|
||||
"<click:" +
|
||||
onClick +
|
||||
":" +
|
||||
realText +
|
||||
"</click>" +
|
||||
"</hover>" +
|
||||
" " +
|
||||
nodes;
|
||||
|
||||
return wrapper;
|
||||
return "<hover:show_text:'" +
|
||||
hoverTitle + newline +
|
||||
description + newline +
|
||||
usage +
|
||||
suggestion +
|
||||
suggestions +
|
||||
"'>" +
|
||||
"<click:" +
|
||||
onClick +
|
||||
":" +
|
||||
realText +
|
||||
"</click>" +
|
||||
"</hover>" +
|
||||
" " +
|
||||
nodes;
|
||||
}));
|
||||
} else {
|
||||
sendMessage(i.getPath());
|
||||
|
||||
Reference in New Issue
Block a user