From 978882db88d9e893a07164963a0d48e083cc4bcc Mon Sep 17 00:00:00 2001 From: Eren KARA Date: Tue, 8 Jul 2025 19:59:16 +0300 Subject: [PATCH 1/4] new structure test --- ...riptCommand.java => OldSkriptCommand.java} | 2 +- ...java => OldSkriptCommandTabCompleter.java} | 2 +- src/main/java/ch/njol/skript/Skript.java | 9 +- .../skript/conditions/CondScriptLoaded.java | 1 - .../ch/njol/skript/effects/EffScriptFile.java | 11 -- .../ch/njol/skript/skcommand/HelpCommand.java | 25 ++++ .../njol/skript/skcommand/SkriptCommand.java | 107 ++++++++++++++++++ .../ch/njol/skript/skcommand/TestCommand.java | 25 ++++ 8 files changed, 164 insertions(+), 18 deletions(-) rename src/main/java/ch/njol/skript/{SkriptCommand.java => OldSkriptCommand.java} (99%) rename src/main/java/ch/njol/skript/{SkriptCommandTabCompleter.java => OldSkriptCommandTabCompleter.java} (98%) create mode 100644 src/main/java/ch/njol/skript/skcommand/HelpCommand.java create mode 100644 src/main/java/ch/njol/skript/skcommand/SkriptCommand.java create mode 100644 src/main/java/ch/njol/skript/skcommand/TestCommand.java diff --git a/src/main/java/ch/njol/skript/SkriptCommand.java b/src/main/java/ch/njol/skript/OldSkriptCommand.java similarity index 99% rename from src/main/java/ch/njol/skript/SkriptCommand.java rename to src/main/java/ch/njol/skript/OldSkriptCommand.java index d27ec05ed45..5436f78c422 100644 --- a/src/main/java/ch/njol/skript/SkriptCommand.java +++ b/src/main/java/ch/njol/skript/OldSkriptCommand.java @@ -41,7 +41,7 @@ import java.util.stream.Collectors; -public class SkriptCommand implements CommandExecutor { +public class OldSkriptCommand implements CommandExecutor { private static final String CONFIG_NODE = "skript command"; private static final ArgsMessage m_reloading = new ArgsMessage(CONFIG_NODE + ".reload.reloading"); diff --git a/src/main/java/ch/njol/skript/SkriptCommandTabCompleter.java b/src/main/java/ch/njol/skript/OldSkriptCommandTabCompleter.java similarity index 98% rename from src/main/java/ch/njol/skript/SkriptCommandTabCompleter.java rename to src/main/java/ch/njol/skript/OldSkriptCommandTabCompleter.java index c73da8e9f02..72cbafa0073 100644 --- a/src/main/java/ch/njol/skript/SkriptCommandTabCompleter.java +++ b/src/main/java/ch/njol/skript/OldSkriptCommandTabCompleter.java @@ -15,7 +15,7 @@ import java.util.List; import java.util.stream.Stream; -public class SkriptCommandTabCompleter implements TabCompleter { +public class OldSkriptCommandTabCompleter implements TabCompleter { @Override @Nullable diff --git a/src/main/java/ch/njol/skript/Skript.java b/src/main/java/ch/njol/skript/Skript.java index 00358e9ee60..2621b3a31ff 100644 --- a/src/main/java/ch/njol/skript/Skript.java +++ b/src/main/java/ch/njol/skript/Skript.java @@ -33,6 +33,7 @@ import ch.njol.skript.registrations.Classes; import ch.njol.skript.registrations.EventValues; import ch.njol.skript.registrations.Feature; +import ch.njol.skript.skcommand.SkriptCommand; import ch.njol.skript.test.runner.EffObjectives; import ch.njol.skript.test.runner.SkriptAsyncJUnitTest; import ch.njol.skript.test.runner.SkriptJUnitTest; @@ -546,7 +547,6 @@ public void onEnable() { // Use the updater, now that it has been configured to (not) do stuff if (updater != null) { CommandSender console = Bukkit.getConsoleSender(); - assert console != null; assert updater != null; updater.updateCheck(console); } @@ -559,9 +559,10 @@ public void onEnable() { } PluginCommand skriptCommand = getCommand("skript"); - assert skriptCommand != null; // It is defined, unless build is corrupted or something like that - skriptCommand.setExecutor(new SkriptCommand()); - skriptCommand.setTabCompleter(new SkriptCommandTabCompleter()); + assert skriptCommand != null; // It is defined, unless the build is corrupted or something like that + SkriptCommand commandHandler = new SkriptCommand(); + skriptCommand.setExecutor(commandHandler); + skriptCommand.setTabCompleter(commandHandler); // Load Bukkit stuff. It is done after platform check, because something might be missing! new BukkitEventValues(); diff --git a/src/main/java/ch/njol/skript/conditions/CondScriptLoaded.java b/src/main/java/ch/njol/skript/conditions/CondScriptLoaded.java index 67bdb250e10..85c1c931f63 100644 --- a/src/main/java/ch/njol/skript/conditions/CondScriptLoaded.java +++ b/src/main/java/ch/njol/skript/conditions/CondScriptLoaded.java @@ -2,7 +2,6 @@ import ch.njol.skript.ScriptLoader; import ch.njol.skript.Skript; -import ch.njol.skript.SkriptCommand; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Name; diff --git a/src/main/java/ch/njol/skript/effects/EffScriptFile.java b/src/main/java/ch/njol/skript/effects/EffScriptFile.java index 5a90098798b..7f52ae251e6 100644 --- a/src/main/java/ch/njol/skript/effects/EffScriptFile.java +++ b/src/main/java/ch/njol/skript/effects/EffScriptFile.java @@ -2,24 +2,14 @@ import ch.njol.skript.ScriptLoader; import ch.njol.skript.Skript; -import ch.njol.skript.SkriptCommand; -import ch.njol.skript.command.ScriptCommand; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Name; import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Effect; import ch.njol.skript.lang.Expression; -import ch.njol.skript.localization.Language; -import ch.njol.skript.localization.PluralizingArgsMessage; -import ch.njol.skript.log.LogEntry; -import ch.njol.skript.log.LogHandler; import ch.njol.skript.log.RedirectingLogHandler; -import ch.njol.skript.log.RetainingLogHandler; -import ch.njol.skript.log.TimingLogHandler; import ch.njol.skript.registrations.Feature; -import ch.njol.skript.util.Utils; -import ch.njol.util.StringUtils; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.Nullable; @@ -36,7 +26,6 @@ import java.io.IOException; import java.util.HashSet; import java.util.Set; -import java.util.logging.Level; import java.util.stream.Collectors; @Name("Enable/Disable/Unload/Reload Script") diff --git a/src/main/java/ch/njol/skript/skcommand/HelpCommand.java b/src/main/java/ch/njol/skript/skcommand/HelpCommand.java new file mode 100644 index 00000000000..627b936201c --- /dev/null +++ b/src/main/java/ch/njol/skript/skcommand/HelpCommand.java @@ -0,0 +1,25 @@ +package ch.njol.skript.skcommand; + +import ch.njol.skript.skcommand.SkriptCommand.SubCommand; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class HelpCommand extends SubCommand { + + public HelpCommand() { + super("help"); + } + + @Override + public void execute(@NotNull CommandSender sender, @NotNull String @NotNull [] args) { + sender.sendMessage("help"); + } + + @Override + public List getTabCompletions(@NotNull CommandSender sender, @NotNull String @NotNull [] args) { + return List.of("help"); + } + +} diff --git a/src/main/java/ch/njol/skript/skcommand/SkriptCommand.java b/src/main/java/ch/njol/skript/skcommand/SkriptCommand.java new file mode 100644 index 00000000000..fe5311c38d0 --- /dev/null +++ b/src/main/java/ch/njol/skript/skcommand/SkriptCommand.java @@ -0,0 +1,107 @@ +package ch.njol.skript.skcommand; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +public class SkriptCommand implements TabExecutor { + + private static final Set SUB_COMMANDS = Set.of( + new HelpCommand(), + new TestCommand() + ); + + /** + * Gets a SubCommand by its alias + * @param alias The alias + * @return The SubCommand or null if no such alias exists + */ + private SubCommand findSubCommand(String alias) { + for (SubCommand subCommand : SUB_COMMANDS) { + for (String subCommandAlias : subCommand.getAliases()) { + if (subCommandAlias.equalsIgnoreCase(alias)) { + return subCommand; + } + } + } + return null; + } + + public static List getAllAliases() { + Set aliases = new HashSet<>(); + + for (SubCommand subCommand : SUB_COMMANDS) { + aliases.addAll(Arrays.asList(subCommand.getAliases())); + } + + return new ArrayList<>(aliases); + } + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, + @NotNull String @NotNull [] args) { + SubCommand subCommand = null; + + if (args.length > 0) { + subCommand = findSubCommand(args[0]); + } + + if (subCommand == null) { + // TODO - send unknown command text + sender.sendMessage(""); + return true; + } + + subCommand.execute(sender, args); + return true; + } + + @Override + public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, + @NotNull String @NotNull [] args) { + if (args.length == 0 || args[0].isEmpty()) { + return getAllAliases(); + } + + SubCommand subCommand = findSubCommand(args[0]); + if (subCommand == null) { + return List.of(); + } + + return subCommand.getTabCompletions(sender, args); + } + + public static abstract class SubCommand { + + public final String[] aliases; + + public SubCommand(String... aliases) { + this.aliases = aliases; + } + + public String[] getAliases() { + return aliases; + } + + /** + * Executes this SubCommand + * @param sender Source of the command + * @param args The arguments + */ + public abstract void execute(@NotNull CommandSender sender, @NotNull String @NotNull [] args); + + /** + * Returns the tab completions for this SubCommand + * @param sender Source of the command + * @param args The arguments + * @return The tab completions + */ + public abstract List getTabCompletions(@NotNull CommandSender sender, @NotNull String @NotNull [] args); + + } + +} diff --git a/src/main/java/ch/njol/skript/skcommand/TestCommand.java b/src/main/java/ch/njol/skript/skcommand/TestCommand.java new file mode 100644 index 00000000000..2051276a6bf --- /dev/null +++ b/src/main/java/ch/njol/skript/skcommand/TestCommand.java @@ -0,0 +1,25 @@ +package ch.njol.skript.skcommand; + +import ch.njol.skript.skcommand.SkriptCommand.SubCommand; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class TestCommand extends SubCommand { + + public TestCommand() { + super("test"); + } + + @Override + public void execute(@NotNull CommandSender sender, @NotNull String @NotNull [] args) { + sender.sendMessage("test"); + } + + @Override + public List getTabCompletions(@NotNull CommandSender sender, @NotNull String @NotNull [] args) { + return List.of("test"); + } + +} From 287c3cde08162b1216c4dfffd5843b080ed216cd Mon Sep 17 00:00:00 2001 From: Eren KARA Date: Fri, 11 Jul 2025 16:56:31 +0300 Subject: [PATCH 2/4] enable/disable commands --- .../java/ch/njol/skript/OldSkriptCommand.java | 47 +---- .../skript/OldSkriptCommandTabCompleter.java | 1 + .../java/ch/njol/skript/SkriptConfig.java | 2 +- .../njol/skript/skcommand/DisableCommand.java | 101 ++++++++++ .../njol/skript/skcommand/EnableCommand.java | 118 +++++++++++ .../njol/skript/skcommand/ReloadCommand.java | 184 ++++++++++++++++++ .../njol/skript/skcommand/ScriptCommand.java | 159 +++++++++++++++ .../njol/skript/skcommand/SkriptCommand.java | 54 ++++- 8 files changed, 615 insertions(+), 51 deletions(-) create mode 100644 src/main/java/ch/njol/skript/skcommand/DisableCommand.java create mode 100644 src/main/java/ch/njol/skript/skcommand/EnableCommand.java create mode 100644 src/main/java/ch/njol/skript/skcommand/ReloadCommand.java create mode 100644 src/main/java/ch/njol/skript/skcommand/ScriptCommand.java diff --git a/src/main/java/ch/njol/skript/OldSkriptCommand.java b/src/main/java/ch/njol/skript/OldSkriptCommand.java index 5436f78c422..2e46f7f09f5 100644 --- a/src/main/java/ch/njol/skript/OldSkriptCommand.java +++ b/src/main/java/ch/njol/skript/OldSkriptCommand.java @@ -12,6 +12,7 @@ import ch.njol.skript.log.RedirectingLogHandler; import ch.njol.skript.log.TestingLogHandler; import ch.njol.skript.log.TimingLogHandler; +import ch.njol.skript.skcommand.ScriptCommand; import ch.njol.skript.test.runner.SkriptTestEvent; import ch.njol.skript.test.runner.TestMode; import ch.njol.skript.test.runner.TestTracker; @@ -212,7 +213,7 @@ public boolean onCommand(CommandSender sender, Command command, String label, St if (args[1].equalsIgnoreCase("all")) { try { info(sender, "enable.all.enabling"); - ScriptLoader.loadScripts(toggleFiles(Skript.getInstance().getScriptsFolder(), true), logHandler) + ScriptLoader.loadScripts(ScriptCommand.toggleFiles(Skript.getInstance().getScriptsFolder(), true), logHandler) .thenAccept(scriptInfo -> { if (logHandler.numErrors() == 0) { info(sender, "enable.all.enabled"); @@ -235,7 +236,7 @@ public boolean onCommand(CommandSender sender, Command command, String label, St } try { - scriptFile = toggleFile(scriptFile, true); + scriptFile = ScriptCommand.toggleFile(scriptFile, true); } catch (IOException e) { error(sender, "enable.single.io error", scriptFile.getName().substring(ScriptLoader.DISABLED_SCRIPT_PREFIX_LENGTH), ExceptionUtils.toString(e)); return true; @@ -254,7 +255,7 @@ public boolean onCommand(CommandSender sender, Command command, String label, St } else { Set scriptFiles; try { - scriptFiles = toggleFiles(scriptFile, true); + scriptFiles = ScriptCommand.toggleFiles(scriptFile, true); } catch (IOException e) { error(sender, "enable.folder.io error", scriptFile.getName(), ExceptionUtils.toString(e)); return true; @@ -283,7 +284,7 @@ public boolean onCommand(CommandSender sender, Command command, String label, St if (args[1].equalsIgnoreCase("all")) { ScriptLoader.unloadScripts(ScriptLoader.getLoadedScripts()); try { - toggleFiles(Skript.getInstance().getScriptsFolder(), false); + ScriptCommand.toggleFiles(Skript.getInstance().getScriptsFolder(), false); info(sender, "disable.all.disabled"); } catch (IOException e) { error(sender, "disable.all.io error", ExceptionUtils.toString(e)); @@ -306,7 +307,7 @@ public boolean onCommand(CommandSender sender, Command command, String label, St String fileName = scriptFile.getName(); try { - toggleFile(scriptFile, false); + ScriptCommand.toggleFile(scriptFile, false); } catch (IOException e) { error(sender, "disable.single.io error", scriptFile.getName(), ExceptionUtils.toString(e)); return true; @@ -317,7 +318,7 @@ public boolean onCommand(CommandSender sender, Command command, String label, St Set scripts; try { - scripts = toggleFiles(scriptFile, false); + scripts = ScriptCommand.toggleFiles(scriptFile, false); } catch (IOException e) { error(sender, "disable.folder.io error", scriptFile.getName(), ExceptionUtils.toString(e)); return true; @@ -522,40 +523,6 @@ public static File getScriptFromName(String script) { return ScriptLoader.getScriptFromName(script); } - private static File toggleFile(File file, boolean enable) throws IOException { - if (enable) - return FileUtils.move( - file, - new File(file.getParentFile(), file.getName().substring(ScriptLoader.DISABLED_SCRIPT_PREFIX_LENGTH)), - false - ); - return FileUtils.move( - file, - new File(file.getParentFile(), ScriptLoader.DISABLED_SCRIPT_PREFIX + file.getName()), - false - ); - } - - private static Set toggleFiles(File folder, boolean enable) throws IOException { - FileFilter filter = enable ? ScriptLoader.getDisabledScriptsFilter() : ScriptLoader.getLoadedScriptsFilter(); - - Set changed = new HashSet<>(); - for (File file : folder.listFiles()) { - if (file.isDirectory()) { - changed.addAll(toggleFiles(file, enable)); - } else { - if (filter.accept(file)) { - String fileName = file.getName(); - changed.add(FileUtils.move( - file, - new File(file.getParentFile(), enable ? fileName.substring(ScriptLoader.DISABLED_SCRIPT_PREFIX_LENGTH) : ScriptLoader.DISABLED_SCRIPT_PREFIX + fileName), - false - )); - } - } - } - return changed; - } } diff --git a/src/main/java/ch/njol/skript/OldSkriptCommandTabCompleter.java b/src/main/java/ch/njol/skript/OldSkriptCommandTabCompleter.java index 72cbafa0073..03202c5f708 100644 --- a/src/main/java/ch/njol/skript/OldSkriptCommandTabCompleter.java +++ b/src/main/java/ch/njol/skript/OldSkriptCommandTabCompleter.java @@ -41,6 +41,7 @@ public List onTabComplete(CommandSender sender, Command command, String // Live update, this will get all old and new (even not loaded) scripts // TODO Find a better way for caching, it isn't exactly ideal to be calling this method constantly + // TODO Make a cache based on last modified date of the 'scripts' folder? try (Stream files = Files.walk(scripts.toPath())) { files.map(Path::toFile) .forEach(file -> { diff --git a/src/main/java/ch/njol/skript/SkriptConfig.java b/src/main/java/ch/njol/skript/SkriptConfig.java index 9c407b5985b..1bfe867d5b1 100644 --- a/src/main/java/ch/njol/skript/SkriptConfig.java +++ b/src/main/java/ch/njol/skript/SkriptConfig.java @@ -387,7 +387,7 @@ private static void userDisableHooks(Class> hookClass, boolean } // also used for reloading - static void load() { + public static void load() { if (mainConfig != null) mainConfig.invalidate(); // todo try { diff --git a/src/main/java/ch/njol/skript/skcommand/DisableCommand.java b/src/main/java/ch/njol/skript/skcommand/DisableCommand.java new file mode 100644 index 00000000000..c0134b13671 --- /dev/null +++ b/src/main/java/ch/njol/skript/skcommand/DisableCommand.java @@ -0,0 +1,101 @@ +package ch.njol.skript.skcommand; + +import ch.njol.skript.ScriptLoader; +import ch.njol.skript.Skript; +import ch.njol.skript.skcommand.SkriptCommand.SubCommand; +import ch.njol.skript.util.ExceptionUtils; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; +import org.skriptlang.skript.lang.script.Script; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +public class DisableCommand extends SubCommand { + + public DisableCommand() { + super("disable"); + } + + @Override + public void execute(@NotNull CommandSender sender, @NotNull String @NotNull [] args) { + if (args[1].equalsIgnoreCase("all")) { + disableEverything(sender); + } else { + File scriptFile = ScriptCommand.getScriptFromArgs(sender, args); + if (scriptFile == null) // TODO allow disabling deleted/renamed scripts + return; + + if (scriptFile.isDirectory()) { + disableFolder(sender, scriptFile); + } else { + disableSpecificScript(sender, scriptFile); + } + + } + + } + + @Override + public List getTabCompletions(@NotNull CommandSender sender, @NotNull String @NotNull [] args) { + return ScriptCommand.getScriptCommandTabCompletions(args); + } + + // sk disable all + private static void disableEverything(CommandSender sender) { + ScriptLoader.unloadScripts(ScriptLoader.getLoadedScripts()); + try { + ScriptCommand.toggleFiles(Skript.getInstance().getScriptsFolder(), false); + SkriptCommand.info(sender, "disable.all.disabled"); + } catch (IOException e) { + SkriptCommand.error(sender, "disable.all.io error", ExceptionUtils.toString(e)); + } + } + + // sk disable script_name + private static void disableSpecificScript(CommandSender sender, File scriptFile) { + if (ScriptLoader.getDisabledScriptsFilter().accept(scriptFile)) { + String scriptName = scriptFile.getName().substring(ScriptLoader.DISABLED_SCRIPT_PREFIX_LENGTH); + SkriptCommand.info(sender, "disable.single.already disabled", scriptName); + return; + } + + Script script = ScriptLoader.getScript(scriptFile); + if (script != null) { + ScriptLoader.unloadScript(script); + } + + String fileName = scriptFile.getName(); + + try { + ScriptCommand.toggleFile(scriptFile, false); + } catch (IOException e) { + SkriptCommand.error(sender, "disable.single.io error", scriptFile.getName(), ExceptionUtils.toString(e)); + return; + } + SkriptCommand.info(sender, "disable.single.disabled", fileName); + } + + // sk disable folder_name + private static void disableFolder(CommandSender sender, File scriptFolder) { + ScriptLoader.unloadScripts(ScriptLoader.getScripts(scriptFolder)); + + Set scripts; + try { + scripts = ScriptCommand.toggleFiles(scriptFolder, false); + } catch (IOException e) { + SkriptCommand.error(sender, "disable.folder.io error", scriptFolder.getName(), ExceptionUtils.toString(e)); + return; + } + + if (scripts.isEmpty()) { + SkriptCommand.info(sender, "disable.folder.empty", scriptFolder.getName()); + return; + } + + SkriptCommand.info(sender, "disable.folder.disabled", scriptFolder.getName(), scripts.size()); + } + +} diff --git a/src/main/java/ch/njol/skript/skcommand/EnableCommand.java b/src/main/java/ch/njol/skript/skcommand/EnableCommand.java new file mode 100644 index 00000000000..53075c549cb --- /dev/null +++ b/src/main/java/ch/njol/skript/skcommand/EnableCommand.java @@ -0,0 +1,118 @@ +package ch.njol.skript.skcommand; + +import ch.njol.skript.ScriptLoader; +import ch.njol.skript.Skript; +import ch.njol.skript.log.RedirectingLogHandler; +import ch.njol.skript.skcommand.SkriptCommand.SubCommand; +import ch.njol.skript.util.ExceptionUtils; +import ch.njol.util.StringUtils; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +public class EnableCommand extends SubCommand { + + public EnableCommand() { + super("enable"); + } + + @Override + public void execute(@NotNull CommandSender sender, @NotNull String @NotNull [] args) { + try (RedirectingLogHandler redirectingLogHandler = new RedirectingLogHandler(sender, "").start()) { + if (args[1].equalsIgnoreCase("all")) { + enableEverything(sender, redirectingLogHandler); + } else { + File scriptFile = ScriptCommand.getScriptFromArgs(sender, args); + if (scriptFile == null) + return; + + if (scriptFile.isDirectory()) { + enableFolder(sender, redirectingLogHandler, scriptFile); + } else { + enableSpecificScript(sender, redirectingLogHandler, scriptFile, args); + } + } + } + } + + @Override + public List getTabCompletions(@NotNull CommandSender sender, @NotNull String @NotNull [] args) { + return ScriptCommand.getScriptCommandTabCompletions(args); + } + + // sk enable all + private static void enableEverything(CommandSender sender, RedirectingLogHandler redirectingLogHandler) { + try { + SkriptCommand.info(sender, "enable.all.enabling"); + ScriptLoader.loadScripts(ScriptCommand.toggleFiles(Skript.getInstance().getScriptsFolder(), true), redirectingLogHandler) + .thenAccept(scriptInfo -> { + if (redirectingLogHandler.numErrors() == 0) { + SkriptCommand.info(sender, "enable.all.enabled"); + } else { + SkriptCommand.error(sender, "enable.all.error", redirectingLogHandler.numErrors()); + } + }); + } catch (IOException e) { + SkriptCommand.error(sender, "enable.all.io error", ExceptionUtils.toString(e)); + } + } + + // sk enable script_name + private static void enableSpecificScript(CommandSender sender, RedirectingLogHandler redirectingLogHandler, File scriptFile, String[] args) { + if (ScriptLoader.getLoadedScriptsFilter().accept(scriptFile)) { + SkriptCommand.info(sender, "enable.single.already enabled", scriptFile.getName(), StringUtils.join(args, " ", 1, args.length)); + return; + } + + try { + scriptFile = ScriptCommand.toggleFile(scriptFile, true); + } catch (IOException e) { + String scriptName = scriptFile.getName().substring(ScriptLoader.DISABLED_SCRIPT_PREFIX_LENGTH); + SkriptCommand.error(sender, "enable.single.io error", scriptName, ExceptionUtils.toString(e)); + return; + } + + String fileName = scriptFile.getName(); + SkriptCommand.info(sender, "enable.single.enabling", fileName); + ScriptLoader.loadScripts(scriptFile, redirectingLogHandler) + .thenAccept(scriptInfo -> { + if (redirectingLogHandler.numErrors() == 0) { + SkriptCommand.info(sender, "enable.single.enabled", fileName); + } else { + SkriptCommand.error(sender, "enable.single.error", fileName, redirectingLogHandler.numErrors()); + } + }); + } + + // sk enable folder_name + private static void enableFolder(CommandSender sender, RedirectingLogHandler redirectingLogHandler, File scriptFolder) { + Set scriptFiles; + try { + scriptFiles = ScriptCommand.toggleFiles(scriptFolder, true); + } catch (IOException e) { + SkriptCommand.error(sender, "enable.folder.io error", scriptFolder.getName(), ExceptionUtils.toString(e)); + return; + } + + if (scriptFiles.isEmpty()) { + SkriptCommand.info(sender, "enable.folder.empty", scriptFolder.getName()); + return; + } + + String fileName = scriptFolder.getName(); + SkriptCommand.info(sender, "enable.folder.enabling", fileName, scriptFiles.size()); + ScriptLoader.loadScripts(scriptFiles, redirectingLogHandler) + .thenAccept(scriptInfo -> { + if (redirectingLogHandler.numErrors() == 0) { + SkriptCommand.info(sender, "enable.folder.enabled", fileName, scriptInfo.files); + } else { + SkriptCommand.error(sender, "enable.folder.error", fileName, redirectingLogHandler.numErrors()); + } + }); + } + +} diff --git a/src/main/java/ch/njol/skript/skcommand/ReloadCommand.java b/src/main/java/ch/njol/skript/skcommand/ReloadCommand.java new file mode 100644 index 00000000000..0544ddf5a86 --- /dev/null +++ b/src/main/java/ch/njol/skript/skcommand/ReloadCommand.java @@ -0,0 +1,184 @@ +package ch.njol.skript.skcommand; + +import ch.njol.skript.ScriptLoader; +import ch.njol.skript.Skript; +import ch.njol.skript.SkriptConfig; +import ch.njol.skript.aliases.Aliases; +import ch.njol.skript.localization.ArgsMessage; +import ch.njol.skript.localization.Language; +import ch.njol.skript.localization.PluralizingArgsMessage; +import ch.njol.skript.log.LogEntry; +import ch.njol.skript.log.RedirectingLogHandler; +import ch.njol.skript.log.TimingLogHandler; +import ch.njol.skript.skcommand.SkriptCommand.SubCommand; +import ch.njol.skript.util.Utils; +import ch.njol.util.OpenCloseable; +import ch.njol.util.StringUtils; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; +import org.skriptlang.skript.lang.script.Script; + +import java.io.File; +import java.util.List; +import java.util.logging.Level; + +public class ReloadCommand extends SubCommand { + + public ReloadCommand() { + super("reload"); + } + + @Override + public void execute(@NotNull CommandSender sender, @NotNull String @NotNull [] args) { + try ( + RedirectingLogHandler redirectingLogHandler = new RedirectingLogHandler(sender, "").start(); + TimingLogHandler timingLogHandler = new TimingLogHandler().start() + ) { + if (args[1].equalsIgnoreCase("all")) { + reloadEverything(sender, redirectingLogHandler, timingLogHandler); + } else if (args[1].equalsIgnoreCase("scripts")) { + reloadScripts(sender, redirectingLogHandler, timingLogHandler); + } else if (args[1].equalsIgnoreCase("config")) { + reloadConfig(sender, redirectingLogHandler, timingLogHandler); + } else if (args[1].equalsIgnoreCase("aliases")) { + reloadAliases(sender, redirectingLogHandler, timingLogHandler); + } else { // Reloading an individual script or folder + reloadSpecific(sender, args, redirectingLogHandler, timingLogHandler); + } + } + } + + @Override + public List getTabCompletions(@NotNull CommandSender sender, @NotNull String @NotNull [] args) { + return ScriptCommand.getScriptCommandTabCompletions(args); + } + + // sk reload all + private static void reloadEverything(CommandSender sender, RedirectingLogHandler redirectingLogHandler, TimingLogHandler timingLogHandler) { + reloading(sender, "config, aliases and scripts", redirectingLogHandler); + SkriptConfig.load(); + Aliases.clear(); + Aliases.loadAsync().thenRun(() -> { + ScriptLoader.unloadScripts(ScriptLoader.getLoadedScripts()); + ScriptLoader.loadScripts(Skript.getInstance().getScriptsFolder(), OpenCloseable.combine(redirectingLogHandler, timingLogHandler)) + .thenAccept(info -> { + if (info.files == 0) + Skript.warning(Skript.m_no_scripts.toString()); + reloaded(sender, redirectingLogHandler, timingLogHandler, "config, aliases and scripts"); + }); + }); + } + + // sk reload scripts + private static void reloadScripts(CommandSender sender, RedirectingLogHandler redirectingLogHandler, TimingLogHandler timingLogHandler) { + reloading(sender, "scripts", redirectingLogHandler); + + ScriptLoader.unloadScripts(ScriptLoader.getLoadedScripts()); + ScriptLoader.loadScripts(Skript.getInstance().getScriptsFolder(), OpenCloseable.combine(redirectingLogHandler, timingLogHandler)) + .thenAccept(info -> { + if (info.files == 0) + Skript.warning(Skript.m_no_scripts.toString()); + reloaded(sender, redirectingLogHandler, timingLogHandler, "scripts"); + }); + } + + // sk reload config + private static void reloadConfig(CommandSender sender, RedirectingLogHandler redirectingLogHandler, TimingLogHandler timingLogHandler) { + reloading(sender, "main config", redirectingLogHandler); + SkriptConfig.load(); + reloaded(sender, redirectingLogHandler, timingLogHandler, "main config"); + } + + // sk reload aliases + private static void reloadAliases(CommandSender sender, RedirectingLogHandler redirectingLogHandler, TimingLogHandler timingLogHandler) { + reloading(sender, "aliases", redirectingLogHandler); + Aliases.clear(); + Aliases.loadAsync().thenRun(() -> reloaded(sender, redirectingLogHandler, timingLogHandler, "aliases")); + } + + // sk reload script_name + // sk reload folder_name + private static void reloadSpecific(CommandSender sender, String[] args, RedirectingLogHandler redirectingLogHandler, TimingLogHandler timingLogHandler) { + File scriptFile = ScriptCommand.getScriptFromArgs(sender, args); + if (scriptFile == null) + return; + + if (!scriptFile.isDirectory()) { + if (ScriptLoader.getDisabledScriptsFilter().accept(scriptFile)) { + info(sender, "reload.script disabled", scriptFile.getName().substring(ScriptLoader.DISABLED_SCRIPT_PREFIX_LENGTH), StringUtils.join(args, " ", 1, args.length)); + return; + } + + reloading(sender, "script", redirectingLogHandler, scriptFile.getName()); + + Script script = ScriptLoader.getScript(scriptFile); + if (script != null) { + ScriptLoader.unloadScript(script); + } + + ScriptLoader.loadScripts(scriptFile, OpenCloseable.combine(redirectingLogHandler, timingLogHandler)) + .thenAccept(scriptInfo -> + reloaded(sender, redirectingLogHandler, timingLogHandler, "script", scriptFile.getName()) + ); + } else { + String fileName = scriptFile.getName(); + reloading(sender, "scripts in folder", redirectingLogHandler, fileName); + ScriptLoader.unloadScripts(ScriptLoader.getScripts(scriptFile)); + ScriptLoader.loadScripts(scriptFile, OpenCloseable.combine(redirectingLogHandler, timingLogHandler)) + .thenAccept(scriptInfo -> { + if (scriptInfo.files == 0) { + info(sender, "reload.empty folder", fileName); + } else { + if (redirectingLogHandler.numErrors() == 0) { + reloaded(sender, redirectingLogHandler, timingLogHandler, "x scripts in folder success", fileName, scriptInfo.files); + } else { + reloaded(sender, redirectingLogHandler, timingLogHandler, "x scripts in folder error", fileName, scriptInfo.files); + } + } + }); + } + } + + // Messages + private static final ArgsMessage RELOADING_MESSAGE = new ArgsMessage(SkriptCommand.CONFIG_NODE + ".reload.reloading"); + private static final ArgsMessage RELOADED_MESSAGE = new ArgsMessage(SkriptCommand.CONFIG_NODE + ".reload.reloaded"); + private static final ArgsMessage RELOAD_ERROR_MESSAGE = new ArgsMessage(SkriptCommand.CONFIG_NODE + ".reload.error"); + + private static void reloading(CommandSender sender, String what, RedirectingLogHandler logHandler, Object... args) { + what = args.length == 0 + ? Language.get(SkriptCommand.CONFIG_NODE + ".reload." + what) + : Language.format(SkriptCommand.CONFIG_NODE + ".reload." + what, args); + + String message = StringUtils.fixCapitalization(RELOADING_MESSAGE.toString(what)); + Skript.info(sender, message); + + // Log reloading message + String text = Language.format(SkriptCommand.CONFIG_NODE + ".reload." + "player reload", sender.getName(), what); + logHandler.log(new LogEntry(Level.INFO, Utils.replaceEnglishChatStyles(text)), sender); + } + + private static void reloaded(CommandSender sender, RedirectingLogHandler logHandler, TimingLogHandler timingLogHandler, String what, Object... args) { + what = args.length == 0 + ? Language.get(SkriptCommand.CONFIG_NODE + ".reload." + what) + : PluralizingArgsMessage.format(Language.format(SkriptCommand.CONFIG_NODE + ".reload." + what, args)); + + String timeTaken = String.valueOf(timingLogHandler.getTimeTaken()); + String message; + + if (logHandler.numErrors() == 0) { + message = StringUtils.fixCapitalization(PluralizingArgsMessage.format(RELOADED_MESSAGE.toString(what, timeTaken))); + logHandler.log(new LogEntry(Level.INFO, Utils.replaceEnglishChatStyles(message))); + } else { + message = StringUtils.fixCapitalization(PluralizingArgsMessage.format(RELOAD_ERROR_MESSAGE.toString(what, logHandler.numErrors(), timeTaken))); + logHandler.log(new LogEntry(Level.SEVERE, Utils.replaceEnglishChatStyles(message))); + } + } + + private static void info(CommandSender sender, String what, Object... args) { + what = args.length == 0 + ? Language.get(SkriptCommand.CONFIG_NODE + "." + what) + : PluralizingArgsMessage.format(Language.format(SkriptCommand.CONFIG_NODE + "." + what, args)); + Skript.info(sender, StringUtils.fixCapitalization(what)); + } + +} diff --git a/src/main/java/ch/njol/skript/skcommand/ScriptCommand.java b/src/main/java/ch/njol/skript/skcommand/ScriptCommand.java new file mode 100644 index 00000000000..aae5122dac7 --- /dev/null +++ b/src/main/java/ch/njol/skript/skcommand/ScriptCommand.java @@ -0,0 +1,159 @@ +package ch.njol.skript.skcommand; + +import ch.njol.skript.ScriptLoader; +import ch.njol.skript.Skript; +import ch.njol.skript.localization.ArgsMessage; +import ch.njol.skript.test.runner.TestMode; +import ch.njol.skript.util.FileUtils; +import ch.njol.util.StringUtils; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; + +/** + * Utilities for {@link ch.njol.skript.skcommand.SkriptCommand.SubCommand}s that involve scripts. + */ +public class ScriptCommand { + + private static final ArgsMessage INVALID_SCRIPT_MESSAGE = new ArgsMessage(SkriptCommand.CONFIG_NODE + ".invalid script"); + private static final ArgsMessage INVALID_FOLDER_MESSAGE = new ArgsMessage(SkriptCommand.CONFIG_NODE + ".invalid folder"); + + public static @Nullable File getScriptFromArgs(CommandSender sender, String[] args) { + return getScriptFromArgs(sender, args, Skript.getInstance().getScriptsFolder()); + } + + public static @Nullable File getScriptFromArgs(CommandSender sender, String[] args, File directoryFile) { + String script = StringUtils.join(args, " ", 1, args.length); + File f = ScriptLoader.getScriptFromName(script, directoryFile); + if (f == null) { + // Always allow '/' and '\' regardless of OS + boolean isDirectory = script.endsWith("/") || script.endsWith("\\") || script.endsWith(File.separator); + Skript.error(sender, (isDirectory ? INVALID_FOLDER_MESSAGE : INVALID_SCRIPT_MESSAGE).toString(script)); + return null; + } + return f; + } + + /** + * Gets tab completions for script commands such as /sk enable|reload|disable + * + * @param args Args of the SubCommand + * @return A list of directories and Skript files. + */ + public static List getScriptCommandTabCompletions(String[] args) { + List options = new ArrayList<>(); + + boolean useTestDirectory = args[0].equalsIgnoreCase("test") && TestMode.DEV_MODE; + File scripts = useTestDirectory ? TestMode.TEST_DIR.toFile() : Skript.getInstance().getScriptsFolder(); + String scriptsPathString = scripts.toPath().toString(); + int scriptsPathLength = scriptsPathString.length(); + + // support for scripts with spaces in them + String scriptArg = StringUtils.join(args, " ", 1, args.length); + String fs = File.separator; + + boolean enable = args[0].equalsIgnoreCase("enable"); + + // Live update, this will get all old and new (even not loaded) scripts + // TODO Find a better way for caching, it isn't exactly ideal to be calling this method constantly + // TODO Make a cache based on last modified date of the 'scripts' folder? + try (Stream files = Files.walk(scripts.toPath())) { + files.map(Path::toFile) + .forEach(file -> { + if (!(enable ? ScriptLoader.getDisabledScriptsFilter() : ScriptLoader.getLoadedScriptsFilter()).accept(file)) + return; + + // Ignore hidden files like .git/ for users that use git source control. + if (file.isHidden()) + return; + + String fileString = file.toString().substring(scriptsPathLength); + if (fileString.isEmpty()) + return; + + if (file.isDirectory()) { + fileString = fileString + fs; // Add file separator at the end of directories + } else if (file.getParentFile().toPath().toString().equals(scriptsPathString)) { + fileString = fileString.substring(1); // Remove file separator from the beginning of files or directories in root only + if (fileString.isEmpty()) + return; + } + + // Make sure the user's argument matches with the file's name or beginning of file path + if (!scriptArg.isEmpty() && !file.getName().startsWith(scriptArg) && !fileString.startsWith(scriptArg)) + return; + + // Trim off previous arguments if needed + if (args.length > 2 && fileString.length() >= scriptArg.length()) + fileString = fileString.substring(scriptArg.lastIndexOf(" ") + 1); + + // Just in case + if (fileString.isEmpty()) + return; + + options.add(fileString); + }); + } catch (Exception e) { + //noinspection ThrowableNotThrown + Skript.exception(e, "An error occurred while trying to update the list of disabled scripts!"); + } + + // These will be added even if there are incomplete script arg + if (args.length == 2) { + options.add("all"); + if (args[0].equalsIgnoreCase("reload")) { + options.add("config"); + options.add("aliases"); + options.add("scripts"); + } + } + return options; + } + + public static File toggleFile(File file, boolean enable) throws IOException { + if (enable) + return FileUtils.move( + file, + new File(file.getParentFile(), file.getName().substring(ScriptLoader.DISABLED_SCRIPT_PREFIX_LENGTH)), + false + ); + return FileUtils.move( + file, + new File(file.getParentFile(), ScriptLoader.DISABLED_SCRIPT_PREFIX + file.getName()), + false + ); + } + + public static Set toggleFiles(File folder, boolean enable) throws IOException { + FileFilter filter = enable ? ScriptLoader.getDisabledScriptsFilter() : ScriptLoader.getLoadedScriptsFilter(); + + Set changed = new HashSet<>(); + for (File file : folder.listFiles()) { + if (file.isDirectory()) { + changed.addAll(toggleFiles(file, enable)); + } else { + if (filter.accept(file)) { + String fileName = file.getName(); + changed.add(FileUtils.move( + file, + new File(file.getParentFile(), enable ? fileName.substring(ScriptLoader.DISABLED_SCRIPT_PREFIX_LENGTH) : ScriptLoader.DISABLED_SCRIPT_PREFIX + fileName), + false + )); + } + } + } + + return changed; + } + +} diff --git a/src/main/java/ch/njol/skript/skcommand/SkriptCommand.java b/src/main/java/ch/njol/skript/skcommand/SkriptCommand.java index fe5311c38d0..e85e2f191ff 100644 --- a/src/main/java/ch/njol/skript/skcommand/SkriptCommand.java +++ b/src/main/java/ch/njol/skript/skcommand/SkriptCommand.java @@ -1,5 +1,9 @@ package ch.njol.skript.skcommand; +import ch.njol.skript.Skript; +import ch.njol.skript.localization.Language; +import ch.njol.skript.localization.PluralizingArgsMessage; +import ch.njol.util.StringUtils; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; @@ -10,10 +14,27 @@ public class SkriptCommand implements TabExecutor { - private static final Set SUB_COMMANDS = Set.of( - new HelpCommand(), - new TestCommand() - ); + public static final String CONFIG_NODE = "skript command"; + + private static final Set SUB_COMMANDS; + private static final List ALIASES; + + static { + SUB_COMMANDS = Set.of( + new HelpCommand(), + new ReloadCommand(), + new EnableCommand(), + new DisableCommand(), + new TestCommand() + ); + + // cache subcommand aliases for tab completions + ALIASES = new ArrayList<>(); + + for (SubCommand subCommand : SUB_COMMANDS) { + ALIASES.addAll(Arrays.asList(subCommand.getAliases())); + } + } /** * Gets a SubCommand by its alias @@ -31,14 +52,25 @@ private SubCommand findSubCommand(String alias) { return null; } + /** + * @return All aliases of all subcommands. + */ public static List getAllAliases() { - Set aliases = new HashSet<>(); + return ALIASES; + } - for (SubCommand subCommand : SUB_COMMANDS) { - aliases.addAll(Arrays.asList(subCommand.getAliases())); - } + public static void info(CommandSender sender, String what, Object... args) { + what = args.length == 0 + ? Language.get(CONFIG_NODE + "." + what) + : PluralizingArgsMessage.format(Language.format(CONFIG_NODE + "." + what, args)); + Skript.info(sender, StringUtils.fixCapitalization(what)); + } - return new ArrayList<>(aliases); + public static void error(CommandSender sender, String what, Object... args) { + what = args.length == 0 + ? Language.get(CONFIG_NODE + "." + what) + : PluralizingArgsMessage.format(Language.format(CONFIG_NODE + "." + what, args)); + Skript.error(sender, StringUtils.fixCapitalization(what)); } @Override @@ -52,7 +84,6 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command if (subCommand == null) { // TODO - send unknown command text - sender.sendMessage(""); return true; } @@ -75,6 +106,9 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command return subCommand.getTabCompletions(sender, args); } + /** + * Represents a subcommand of the /sk command, like /sk reload + */ public static abstract class SubCommand { public final String[] aliases; From 780c5be31d63d14d34325365faac4b1c4821c324 Mon Sep 17 00:00:00 2001 From: Eren KARA Date: Sat, 12 Jul 2025 21:35:43 +0300 Subject: [PATCH 3/4] list command --- .../java/ch/njol/skript/OldSkriptCommand.java | 10 ++-- .../ch/njol/skript/skcommand/ListCommand.java | 59 +++++++++++++++++++ .../njol/skript/skcommand/SkriptCommand.java | 16 ++++- 3 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 src/main/java/ch/njol/skript/skcommand/ListCommand.java diff --git a/src/main/java/ch/njol/skript/OldSkriptCommand.java b/src/main/java/ch/njol/skript/OldSkriptCommand.java index 2e46f7f09f5..c9242d26896 100644 --- a/src/main/java/ch/njol/skript/OldSkriptCommand.java +++ b/src/main/java/ch/njol/skript/OldSkriptCommand.java @@ -49,24 +49,24 @@ public class OldSkriptCommand implements CommandExecutor { // TODO document this command on the website private static final CommandHelp SKRIPT_COMMAND_HELP = new CommandHelp("/skript", SkriptColor.LIGHT_CYAN, CONFIG_NODE + ".help") - .add(new CommandHelp("reload", SkriptColor.DARK_RED) + .add(new CommandHelp("reload", SkriptColor.DARK_RED) // done .add("all") .add("config") .add("aliases") .add("scripts") .add("