Add scissors config, command & disable command books (1.17.1) (#39)

* Add Scissors configuration file & command

* Disable running commands in books by default
This commit is contained in:
Allink 2022-07-10 16:46:47 +01:00 committed by GitHub
parent 3b8ad1a45d
commit 611e77e503
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 551 additions and 0 deletions

View file

@ -0,0 +1,24 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Allink <arclicious@vivaldi.net>
Date: Sun, 10 Jul 2022 07:27:37 +0100
Subject: [PATCH] Add Scissors configuration file
diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java
index c34cfba8f9ed7e9dbd0b6b8ffef9fba46abff046..416bdfccc6cae51a584f29949a32172fb10f78a6 100644
--- a/src/main/java/org/bukkit/Server.java
+++ b/src/main/java/org/bukkit/Server.java
@@ -1715,6 +1715,13 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
}
// Paper end
+ // Scissors start
+ @NotNull
+ public org.bukkit.configuration.file.YamlConfiguration getScissorsConfig() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ // Scissors end
+
/**
* Sends the component to the player
*

View file

@ -0,0 +1,424 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Allink <arclicious@vivaldi.net>
Date: Sun, 10 Jul 2022 07:53:59 +0100
Subject: [PATCH] Add Scissors config & command
diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java
index e29b0a90019b12bd6586ad0f7b5314f307e527ba..02caf0f7d5357e9117397eda1e23cf00c667df57 100644
--- a/src/main/java/co/aikar/timings/TimingsExport.java
+++ b/src/main/java/co/aikar/timings/TimingsExport.java
@@ -228,7 +228,8 @@ public class TimingsExport extends Thread {
parent.put("config", createObject(
pair("spigot", mapAsJSON(Bukkit.spigot().getSpigotConfig(), null)),
pair("bukkit", mapAsJSON(Bukkit.spigot().getBukkitConfig(), null)),
- pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null))
+ pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)),
+ pair("scissors", mapAsJSON(Bukkit.spigot().getScissorsConfig(), null)) // Scissors
));
new TimingsExport(listeners, parent, history).start();
diff --git a/src/main/java/com/github/atlasmediagroup/scissors/ScissorsCommand.java b/src/main/java/com/github/atlasmediagroup/scissors/ScissorsCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..f5202deac5b3a715a22d0d482f1302b6074b26ac
--- /dev/null
+++ b/src/main/java/com/github/atlasmediagroup/scissors/ScissorsCommand.java
@@ -0,0 +1,150 @@
+package com.github.atlasmediagroup.scissors;
+
+import com.google.common.base.Functions;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.MinecraftServer;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+
+import java.io.File;
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class ScissorsCommand extends Command
+{
+
+ private static final String BASE_PERM = "bukkit.command.scissors.";
+ private static final ImmutableSet<String> SUBCOMMANDS = ImmutableSet.<String>builder().add("reload", "version").build();
+
+ public ScissorsCommand(String name)
+ {
+ super(name);
+ this.description = "Scissors related commands";
+ this.usageMessage = "/scissors [" + Joiner.on(" | ").join(SUBCOMMANDS) + "]";
+ this.setPermission("bukkit.command.scissors;" + Joiner.on(';').join(SUBCOMMANDS.stream().map(s -> BASE_PERM + s).collect(Collectors.toSet())));
+ }
+
+ private static boolean testPermission(CommandSender commandSender, String permission)
+ {
+ if (commandSender.hasPermission(BASE_PERM + permission) || commandSender.hasPermission("bukkit.command.scissors"))
+ return true;
+ commandSender.sendMessage(Bukkit.getPermissionMessage()); // Sorry, kashike
+ return false;
+ }
+
+ // Code from Mojang - copyright them
+ public static List<String> getListMatchingLast(CommandSender sender, String[] args, String... matches)
+ {
+ return getListMatchingLast(sender, args, Arrays.asList(matches));
+ }
+
+ public static boolean matches(String s, String s1)
+ {
+ return s1.regionMatches(true, 0, s, 0, s.length());
+ }
+
+ public static List<String> getListMatchingLast(CommandSender sender, String[] strings, Collection<?> collection)
+ {
+ String last = strings[strings.length - 1];
+ ArrayList<String> results = Lists.newArrayList();
+
+ if (!collection.isEmpty())
+ {
+ Iterator iterator = Iterables.transform(collection, Functions.toStringFunction()).iterator();
+
+ while (iterator.hasNext())
+ {
+ String s1 = (String) iterator.next();
+
+ if (matches(last, s1) && (sender.hasPermission(BASE_PERM + s1) || sender.hasPermission("bukkit.command.scissors")))
+ {
+ results.add(s1);
+ }
+ }
+
+ if (results.isEmpty())
+ {
+ iterator = collection.iterator();
+
+ while (iterator.hasNext())
+ {
+ Object object = iterator.next();
+
+ if (object instanceof ResourceLocation && matches(last, ((ResourceLocation) object).getPath()))
+ {
+ results.add(String.valueOf(object));
+ }
+ }
+ }
+ }
+
+ return results;
+ }
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException
+ {
+ if (args.length <= 1)
+ return getListMatchingLast(sender, args, SUBCOMMANDS);
+
+ return Collections.emptyList();
+ }
+ // end copy stuff
+
+ @Override
+ public boolean execute(CommandSender sender, String commandLabel, String[] args)
+ {
+ if (!testPermission(sender)) return true;
+
+ if (args.length == 0)
+ {
+ sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
+ return false;
+ }
+ if (SUBCOMMANDS.contains(args[0].toLowerCase(Locale.ENGLISH)))
+ {
+ if (!testPermission(sender, args[0].toLowerCase(Locale.ENGLISH))) return true;
+ }
+ switch (args[0].toLowerCase(Locale.ENGLISH))
+ {
+ case "reload":
+ doReload(sender);
+ break;
+ case "ver":
+ if (!testPermission(sender, "version"))
+ break; // "ver" needs a special check because it's an alias. All other commands are checked up before the switch statement (because they are present in the SUBCOMMANDS set)
+ case "version":
+ Command ver = MinecraftServer.getServer().server.getCommandMap().getCommand("version");
+ if (ver != null)
+ {
+ ver.execute(sender, commandLabel, new String[0]);
+ break;
+ }
+ // else - fall through to default
+ default:
+ sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
+ return false;
+ }
+
+ return true;
+ }
+
+ private void doReload(CommandSender sender)
+ {
+ Command.broadcastCommandMessage(sender, ChatColor.RED + "Please note that this command is not supported and may cause issues.");
+ Command.broadcastCommandMessage(sender, ChatColor.RED + "If you encounter any issues please use the /stop command to restart your server.");
+
+ MinecraftServer console = MinecraftServer.getServer();
+ ScissorsConfig.init((File) console.options.valueOf("scissors-settings"));
+ console.server.reloadCount++;
+
+ Command.broadcastCommandMessage(sender, ChatColor.GREEN + "Scissors config reload complete.");
+ }
+}
diff --git a/src/main/java/com/github/atlasmediagroup/scissors/ScissorsConfig.java b/src/main/java/com/github/atlasmediagroup/scissors/ScissorsConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..d0e2bcf4671d723d5893e0a9bc8c6e30a9b83be6
--- /dev/null
+++ b/src/main/java/com/github/atlasmediagroup/scissors/ScissorsConfig.java
@@ -0,0 +1,170 @@
+package com.github.atlasmediagroup.scissors;
+
+import com.google.common.base.Throwables;
+import net.minecraft.server.MinecraftServer;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.configuration.InvalidConfigurationException;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.regex.Pattern;
+
+public class ScissorsConfig
+{
+
+ private static final String HEADER = """
+ This is the main configuration file for Scissors.
+ As you can see, there's tons to configure. Some options may impact gameplay, so use
+ with caution, and make sure you know what each option does before configuring.
+
+ If you need help with the configuration or have any questions related to Scissors,
+ join us in our Discord.
+
+ Discord: https://discord.com/invite/mtVQcHn58h
+ Website: https://scissors.gg/\s
+ Docs: https://scissors.gg/javadoc/1.17.1/\s
+ """;
+ private static final Pattern SPACE = Pattern.compile(" ");
+ private static final Pattern NOT_NUMERIC = Pattern.compile("[^-\\d.]");
+ /*========================================================================*/
+ public static YamlConfiguration config;
+ static int version;
+ /*========================================================================*/
+ static Map<String, Command> commands;
+ private static File CONFIG_FILE;
+
+ public static void init(File configFile)
+ {
+ CONFIG_FILE = configFile;
+ config = new YamlConfiguration();
+ try
+ {
+ config.load(CONFIG_FILE);
+ }
+ catch (IOException ex)
+ {
+ }
+ catch (InvalidConfigurationException ex)
+ {
+ Bukkit.getLogger().log(Level.SEVERE, "Could not load scissors.yml, please correct your syntax errors", ex);
+ throw Throwables.propagate(ex);
+ }
+
+ commands = new HashMap<>();
+ commands.put("scissors", new ScissorsCommand("scissors"));
+
+ config.options().header(HEADER);
+ config.options().copyDefaults(true);
+
+ version = getInt("config-version", 1);
+ set("config-version", 1);
+ readConfig(ScissorsConfig.class, null);
+ }
+
+ protected static void logError(String s)
+ {
+ Bukkit.getLogger().severe(s);
+ }
+
+ protected static void fatal(String s)
+ {
+ throw new RuntimeException("Fatal scissors.yml config error: " + s);
+ }
+
+ public static void registerCommands()
+ {
+ for (Map.Entry<String, Command> entry : commands.entrySet())
+ {
+ MinecraftServer.getServer().server.getCommandMap().register(entry.getKey(), "Scissors", entry.getValue());
+ }
+ }
+
+ static void readConfig(Class<?> clazz, Object instance)
+ {
+ for (Method method : clazz.getDeclaredMethods())
+ {
+ if (Modifier.isPrivate(method.getModifiers()))
+ {
+ if (method.getParameterTypes().length == 0 && method.getReturnType() == Void.TYPE)
+ {
+ try
+ {
+ method.setAccessible(true);
+ method.invoke(instance);
+ }
+ catch (InvocationTargetException ex)
+ {
+ throw Throwables.propagate(ex.getCause());
+ }
+ catch (Exception ex)
+ {
+ Bukkit.getLogger().log(Level.SEVERE, "Error invoking " + method, ex);
+ }
+ }
+ }
+ }
+ saveConfig();
+ }
+
+ static void saveConfig()
+ {
+ try
+ {
+ config.save(CONFIG_FILE);
+ }
+ catch (IOException ex)
+ {
+ Bukkit.getLogger().log(Level.SEVERE, "Could not save " + CONFIG_FILE, ex);
+ }
+ }
+
+ private static void set(String path, Object val)
+ {
+ config.set(path, val);
+ }
+
+ private static boolean getBoolean(String path, boolean def)
+ {
+ config.addDefault(path, def);
+ return config.getBoolean(path, config.getBoolean(path));
+ }
+
+ private static double getDouble(String path, double def)
+ {
+ config.addDefault(path, def);
+ return config.getDouble(path, config.getDouble(path));
+ }
+
+ private static float getFloat(String path, float def)
+ {
+ // TODO: Figure out why getFloat() always returns the default value.
+ return (float) getDouble(path, def);
+ }
+
+ private static int getInt(String path, int def)
+ {
+ config.addDefault(path, def);
+ return config.getInt(path, config.getInt(path));
+ }
+
+ private static <T> List getList(String path, T def)
+ {
+ config.addDefault(path, def);
+ return config.getList(path, config.getList(path));
+ }
+
+ private static String getString(String path, String def)
+ {
+ config.addDefault(path, def);
+ return config.getString(path, config.getString(path));
+ }
+}
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
index 6a00ee7f69bf44c5a9a329df26ac5640b368283b..3fed82a0b271234065767ec37c9ddd0a9f39da27 100644
--- a/src/main/java/net/minecraft/server/Main.java
+++ b/src/main/java/net/minecraft/server/Main.java
@@ -106,6 +106,7 @@ public class Main {
org.bukkit.configuration.file.YamlConfiguration bukkitConfiguration = loadConfigFile((File) optionset.valueOf("bukkit-settings"));
org.bukkit.configuration.file.YamlConfiguration spigotConfiguration = loadConfigFile((File) optionset.valueOf("spigot-settings"));
org.bukkit.configuration.file.YamlConfiguration paperConfiguration = loadConfigFile((File) optionset.valueOf("paper-settings"));
+ org.bukkit.configuration.file.YamlConfiguration scissorsConfiguration = loadConfigFile((File) optionset.valueOf("scissors-settings")); // Scissors
// Paper end
Path path1 = Paths.get("eula.txt");
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index b6ee0e709b0f0529b99567bc9b8fb6bfd99bcd8e..4cd18a681dedea26b98002902a3c3b1f47966887 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -234,7 +234,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // load mappings for stacktrace deobf and etc.
io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // init PaperBrigadierProvider
// Paper end
-
+ // Scissors start
+ try {
+ com.github.atlasmediagroup.scissors.ScissorsConfig.init((java.io.File) options.valueOf("scissors-settings"));
+ } catch (Exception e) {
+ DedicatedServer.LOGGER.error("Unable to load server configuration", e);
+ return false;
+ }
+ com.github.atlasmediagroup.scissors.ScissorsConfig.registerCommands();
+ // Scissors end
this.setPvpAllowed(dedicatedserverproperties.pvp);
this.setFlightAllowed(dedicatedserverproperties.allowFlight);
this.setResourcePack(dedicatedserverproperties.resourcePack, this.getPackHash());
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index cc797b45674163b5913e20031d110796d78b928b..e8d2cf26596281aafc5d261e46273f1bbef399ea 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -924,6 +924,7 @@ public final class CraftServer implements Server {
org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); // Spigot
com.destroystokyo.paper.PaperConfig.init((File) console.options.valueOf("paper-settings")); // Paper
+ com.github.atlasmediagroup.scissors.ScissorsConfig.init(((File) console.options.valueOf("scissors-settings"))); // Scissors
for (ServerLevel world : this.console.getAllLevels()) {
// world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty
world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters, config.spawnAnimals); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean))
@@ -979,6 +980,7 @@ public final class CraftServer implements Server {
this.reloadData();
org.spigotmc.SpigotConfig.registerCommands(); // Spigot
com.destroystokyo.paper.PaperConfig.registerCommands(); // Paper
+ com.github.atlasmediagroup.scissors.ScissorsConfig.registerCommands(); // Scissors
this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*");
this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions");
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
index d033caf5dabbd2a240286c5623b3d287ae5cbdd9..facfcc3f478a21240fa2938c94de7dc599eeafd3 100644
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
@@ -160,6 +160,14 @@ public class Main {
.defaultsTo(new File[] {})
.describedAs("Jar file");
// Paper end
+
+ // Scissors start
+ acceptsAll(asList("scissors", "scissors-settings"), "File for scissors settings")
+ .withRequiredArg()
+ .ofType(File.class)
+ .defaultsTo(new File("scissors.yml"))
+ .describedAs("Yml file");
+ // Scissors end
}
};

View file

@ -0,0 +1,103 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Allink <arclicious@vivaldi.net>
Date: Sun, 10 Jul 2022 09:46:20 +0100
Subject: [PATCH] Disable running commands in books by default
diff --git a/src/main/java/com/github/atlasmediagroup/scissors/ScissorsConfig.java b/src/main/java/com/github/atlasmediagroup/scissors/ScissorsConfig.java
index d0e2bcf4671d723d5893e0a9bc8c6e30a9b83be6..6fcbd02c02d70617e4533b450747c918ec3339d5 100644
--- a/src/main/java/com/github/atlasmediagroup/scissors/ScissorsConfig.java
+++ b/src/main/java/com/github/atlasmediagroup/scissors/ScissorsConfig.java
@@ -127,6 +127,12 @@ public class ScissorsConfig
}
}
+ public static boolean runCommandsInBooks = false;
+
+ private static void runCommandsInBooks() {
+ runCommandsInBooks = getBoolean("runCommandsInBooks", false);
+ }
+
private static void set(String path, Object val)
{
config.set(path, val);
diff --git a/src/main/java/net/minecraft/world/item/WrittenBookItem.java b/src/main/java/net/minecraft/world/item/WrittenBookItem.java
index de11f8b4a783e7aa6029693f6812c950649fe88c..526206f11bdfc2aa7cb88649c47d707678753007 100644
--- a/src/main/java/net/minecraft/world/item/WrittenBookItem.java
+++ b/src/main/java/net/minecraft/world/item/WrittenBookItem.java
@@ -1,7 +1,10 @@
package net.minecraft.world.item;
import java.util.List;
+import java.util.stream.Collectors;
import javax.annotation.Nullable;
+
+import com.github.atlasmediagroup.scissors.ScissorsConfig;
import net.minecraft.ChatFormatting;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.BlockPos;
@@ -9,10 +12,7 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
-import net.minecraft.network.chat.Component;
-import net.minecraft.network.chat.ComponentUtils;
-import net.minecraft.network.chat.TextComponent;
-import net.minecraft.network.chat.TranslatableComponent;
+import net.minecraft.network.chat.*;
import net.minecraft.stats.Stats;
import net.minecraft.util.StringUtil;
import net.minecraft.world.InteractionHand;
@@ -113,8 +113,7 @@ public class WrittenBookItem extends Item {
public static boolean resolveBookComponents(ItemStack book, @Nullable CommandSourceStack commandSource, @Nullable Player player) {
CompoundTag compoundTag = book.getTag();
- if (compoundTag != null && !compoundTag.getBoolean("resolved")) {
- compoundTag.putBoolean("resolved", true);
+ if (compoundTag != null) {
if (!makeSureTagIsValid(compoundTag)) {
return false;
} else {
@@ -148,8 +147,41 @@ public class WrittenBookItem extends Item {
component2 = new TextComponent(string);
}
- return Component.Serializer.toJson(component2);
+ return Component.Serializer.toJson(!ScissorsConfig.runCommandsInBooks ? sanitize(component2, 0) : component2); // Scissors - Allow server owners to disable run command in books
+ }
+
+ // Scissors start - Allow server owners to disable run command in books
+ public static Component sanitize(Component component, int depth) {
+ if (depth > 128) {
+ return Component.nullToEmpty("Sanitization function depth limit exceeded");
+ }
+
+ MutableComponent component2 = component.copy();
+
+ final Style style = component2.getStyle();
+ final ClickEvent clickEvent = style.getClickEvent();
+
+ if(clickEvent != null && clickEvent.getAction().equals(ClickEvent.Action.RUN_COMMAND))
+ {
+ final String clickEventValue = clickEvent.getValue();
+
+ component2 = component2.copy().setStyle(style
+ .withClickEvent(null)
+ .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.nullToEmpty("Would've " + (clickEventValue.startsWith("/") ? "ran": "said") + ": " + clickEvent.getValue())))
+ );
+ }
+
+ final List<Component> processedExtra = component2.getSiblings()
+ .stream()
+ .map(comp -> sanitize(comp, depth + 1))
+ .toList();
+
+ component2.getSiblings().clear();
+ component2.getSiblings().addAll(processedExtra);
+
+ return component2;
}
+ // Scissors end
@Override
public boolean isFoil(ItemStack stack) {