From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Allink Date: Wed, 15 Mar 2023 23:13:56 -0500 Subject: [PATCH] Add Scissors configuration file & command diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java index 06bff37e4c1fddd3be6343049a66787c63fb420c..1c1cb20190e8edb7f55a60fc662c28e204690223 100644 --- a/src/main/java/co/aikar/timings/TimingsExport.java +++ b/src/main/java/co/aikar/timings/TimingsExport.java @@ -25,6 +25,7 @@ package co.aikar.timings; import com.google.common.collect.Sets; import io.papermc.paper.adventure.PaperAdventure; +import me.totalfreedom.scissors.ScissorsConfig; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; @@ -241,7 +242,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(ScissorsConfig.config, null)) // Scissors )); new TimingsExport(listeners, parent, history).start(); diff --git a/src/main/java/me/totalfreedom/scissors/PositionUtility.java b/src/main/java/me/totalfreedom/scissors/PositionUtility.java index 9e33ad84e50c7e2491aa883f905323f3ad2b070c..b085035794c91074205cb6994c73343283d274d5 100644 --- a/src/main/java/me/totalfreedom/scissors/PositionUtility.java +++ b/src/main/java/me/totalfreedom/scissors/PositionUtility.java @@ -8,7 +8,7 @@ import net.minecraft.world.phys.Vec3; public class PositionUtility { - public static Vec3 getValidVec3(double x, double y, double z, Entity entity) + /*public static Vec3 getValidVec3(double x, double y, double z, Entity entity) { final Level level = entity.level; @@ -37,7 +37,7 @@ public class PositionUtility { // If we throw some sort of exception due to the position being crazy, catch it return new Vec3(0, 0, 0); } - } + }*/ public static Vec3 getValidVec3FromBlockPos(BlockPos blockPos, Entity entity) { diff --git a/src/main/java/me/totalfreedom/scissors/ScissorsCommand.java b/src/main/java/me/totalfreedom/scissors/ScissorsCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..797677d892d83cf54d9a60af1e277b67ed3d6e95 --- /dev/null +++ b/src/main/java/me/totalfreedom/scissors/ScissorsCommand.java @@ -0,0 +1,150 @@ +package me.totalfreedom.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 SUBCOMMANDS = ImmutableSet.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 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 getListMatchingLast(CommandSender sender, String[] strings, Collection collection) + { + String last = strings[strings.length - 1]; + ArrayList 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 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/me/totalfreedom/scissors/ScissorsConfig.java b/src/main/java/me/totalfreedom/scissors/ScissorsConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..9f2a51fddb692f5152c32dcbe1f5a6ba150634e4 --- /dev/null +++ b/src/main/java/me/totalfreedom/scissors/ScissorsConfig.java @@ -0,0 +1,213 @@ +package me.totalfreedom.scissors; + + +import com.google.common.base.Throwables; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +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.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.regex.Pattern; + +// TODO - Migrate to new format +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.19.4/\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 commands; + private static File CONFIG_FILE; + + public static void init(File configFile) + { + final File configFolder = (File) DedicatedServer.getServer().options.valueOf("scissors-settings" + "-directory"); + final Path configFolderPath = configFolder.toPath(); + final Path oldConfigFilePath = configFile.toPath(); + final Path newConfigFilePath = configFolderPath.resolve(configFile.toPath()); + + if (configFile.exists()) + { + try + { + Files.move(oldConfigFilePath, newConfigFilePath); + } + catch (IOException e) + { + throw new RuntimeException("Error migrating configuration file to new directory!", e); + } + } + + CONFIG_FILE = newConfigFilePath.toFile(); + 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", 3); + set("config-version", 3); + 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 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); + } + } + + public static boolean runCommandsInBooks = false; + + private static void runCommandsInBooks() + { + runCommandsInBooks = getBoolean("runCommandsInBooks", false); + } + + // people still may want them to bypass permissions for warps + public static boolean commandSignsBypassPermissions = false; + private static void commandSignsBypassPermissions() + { + commandSignsBypassPermissions = getBoolean("commandSignsBypassPermissions", false); + } + + public static boolean chatSignaturesEnabled = true; + private static void chatSignaturesEnabled() + { + chatSignaturesEnabled = getBoolean("chatSignaturesEnabled", true); + } + + 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 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/network/chat/OutgoingChatMessage.java b/src/main/java/net/minecraft/network/chat/OutgoingChatMessage.java index 74cf1c043beef03cfd5adf481414a5ee78bef2a6..182f68359a7a8c0b331acd103ed3952ea3c33b93 100644 --- a/src/main/java/net/minecraft/network/chat/OutgoingChatMessage.java +++ b/src/main/java/net/minecraft/network/chat/OutgoingChatMessage.java @@ -1,5 +1,6 @@ package net.minecraft.network.chat; +import me.totalfreedom.scissors.ScissorsConfig; import net.minecraft.server.level.ServerPlayer; public interface OutgoingChatMessage { @@ -42,12 +43,16 @@ public interface OutgoingChatMessage { } public void sendToPlayer(ServerPlayer sender, boolean filterMaskEnabled, ChatType.Bound params, @javax.annotation.Nullable Component unsigned) { // Paper end + // Scissors start - Add configuration option to disable chat signatures PlayerChatMessage playerChatMessage = this.message.filter(filterMaskEnabled); playerChatMessage = unsigned != null ? playerChatMessage.withUnsignedContent(unsigned) : playerChatMessage; // Paper - if (!playerChatMessage.isFullyFiltered()) { + if (!playerChatMessage.isFullyFiltered() && /* Scissors */ ScissorsConfig.chatSignaturesEnabled) { sender.connection.sendPlayerChatMessage(playerChatMessage, params); + return; } + sender.connection.sendDisguisedChatMessage(playerChatMessage.decoratedContent(), params); + // Scissors end } } } diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java index c6fa6bcd66d61359124a8426b919493c6ec43f06..0b44304fa7f6c2856f9dd18ffc1239058c1de0a8 100644 --- a/src/main/java/net/minecraft/server/Main.java +++ b/src/main/java/net/minecraft/server/Main.java @@ -136,6 +136,7 @@ public class Main { // Paper start - load config files for access below if needed org.bukkit.configuration.file.YamlConfiguration bukkitConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionset.valueOf("bukkit-settings")); org.bukkit.configuration.file.YamlConfiguration spigotConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionset.valueOf("spigot-settings")); + org.bukkit.configuration.file.YamlConfiguration scissorsConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionset.valueOf("scissors-settings")); // Scissors - TODO Change this // Paper end if (optionset.has("initSettings")) { // CraftBukkit diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java index a7e133f3495e9132a5fdae2c24f225e7b026295a..16f0daad2456ce23f8d73389f62aac9f10235100 100644 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java @@ -222,6 +222,16 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // init PaperBrigadierProvider // Paper end + // Scissors start + try { + me.totalfreedom.scissors.ScissorsConfig.init((java.io.File) options.valueOf("scissors-settings")); + } catch (Exception e) { + DedicatedServer.LOGGER.error("Unable to load server configuration", e); + return false; + } + me.totalfreedom.scissors.ScissorsConfig.registerCommands(); + // Scissors end + this.setPvpAllowed(dedicatedserverproperties.pvp); this.setFlightAllowed(dedicatedserverproperties.allowFlight); this.setMotd(dedicatedserverproperties.motd); diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java index c15c5855dca11cd69f316c42783d32b800a93bd7..1ec1cc90c7e698036f6ae446f0dab97f03ebb064 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -1,5 +1,6 @@ package net.minecraft.server.network; +import me.totalfreedom.scissors.ScissorsConfig; import me.totalfreedom.scissors.event.player.SpectatorTeleportEvent; import com.google.common.collect.Lists; import com.google.common.primitives.Floats; @@ -2360,6 +2361,12 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic Optional optional = this.lastSeenMessages.applyUpdate(acknowledgment); if (optional.isEmpty()) { + // Scissors start - Add configuration option to disable chat signatures + if (!ScissorsConfig.chatSignaturesEnabled) + { + return optional; + } + // Scissors end ServerGamePacketListenerImpl.LOGGER.warn("Failed to validate message acknowledgements from {}", this.player.getName().getString()); this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes } @@ -2592,11 +2599,16 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic @Override public void handleChatAck(ServerboundChatAckPacket packet) { LastSeenMessagesValidator lastseenmessagesvalidator = this.lastSeenMessages; - - synchronized (this.lastSeenMessages) { if (!this.lastSeenMessages.applyOffset(packet.offset())) { - ServerGamePacketListenerImpl.LOGGER.warn("Failed to validate message acknowledgements from {}", this.player.getName().getString()); - this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes + synchronized (this.lastSeenMessages) { + // Scissors start - Add configuration option to disable chat signatures + if (!ScissorsConfig.chatSignaturesEnabled) + { + return; + } + // Scissors end + ServerGamePacketListenerImpl.LOGGER.warn("Failed to validate message acknowledgements from {}", this.player.getName().getString()); + this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes } } diff --git a/src/main/java/net/minecraft/world/item/WrittenBookItem.java b/src/main/java/net/minecraft/world/item/WrittenBookItem.java index 31911c09fe15753ae32fa39417bdc9e9de552a88..97ce45c6e44b1400b8d60b52397617038f8fe911 100644 --- a/src/main/java/net/minecraft/world/item/WrittenBookItem.java +++ b/src/main/java/net/minecraft/world/item/WrittenBookItem.java @@ -2,6 +2,8 @@ package net.minecraft.world.item; import java.util.List; import javax.annotation.Nullable; + +import me.totalfreedom.scissors.ScissorsConfig; import net.minecraft.ChatFormatting; import net.minecraft.commands.CommandSourceStack; import net.minecraft.core.BlockPos; @@ -9,8 +11,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.*; import net.minecraft.stats.Stats; import net.minecraft.util.StringUtil; import net.minecraft.world.InteractionHand; @@ -111,8 +112,7 @@ public class WrittenBookItem extends Item { public static boolean resolveBookComponents(ItemStack book, @Nullable CommandSourceStack commandSource, @Nullable Player player) { CompoundTag compoundTag = book.getTag(); - if (io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.resolveSelectorsInBooks && compoundTag != null && !compoundTag.getBoolean("resolved")) { // Paper - compoundTag.putBoolean("resolved", true); + if (compoundTag != null) { // Paper if (!makeSureTagIsValid(compoundTag)) { return false; } else { @@ -161,8 +161,42 @@ public class WrittenBookItem extends Item { component2 = Component.literal(text); } - 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 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) { diff --git a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java index 4da4edae517a0efec6e03a719ec47b700509dab1..837b20be528bc33f62c0c675d90afebd0a781b6f 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java @@ -4,8 +4,11 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import java.util.UUID; import java.util.function.Function; import javax.annotation.Nullable; + +import me.totalfreedom.scissors.ScissorsConfig; import net.minecraft.commands.CommandSource; import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.ClickEvent; @@ -15,6 +18,7 @@ import net.minecraft.network.chat.ComponentUtils; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.Style; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.FormattedCharSequence; @@ -24,6 +28,8 @@ import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.entity.CraftPlayer; public class SignBlockEntity extends BlockEntity implements CommandSource { // CraftBukkit - implements private static final boolean CONVERT_LEGACY_SIGNS = Boolean.getBoolean("convertLegacySigns"); // Paper @@ -272,6 +278,21 @@ public class SignBlockEntity extends BlockEntity implements CommandSource { // C } player.getServer().getCommands().performPrefixedCommand(this.createCommandSourceStack(((org.bukkit.craftbukkit.entity.CraftPlayer) event.getPlayer()).getHandle()), event.getMessage()); // Paper end + // Scissors start - Add optional permissions to command signs + final MinecraftServer vanillaServer = player.getServer(); + final CraftServer craftServer = vanillaServer.server; + final CraftPlayer craftPlayer = player.getBukkitEntity(); + final Commands commands = vanillaServer.getCommands(); + + if (ScissorsConfig.commandSignsBypassPermissions) + { + commands.performPrefixedCommand(this.createCommandSourceStack(((org.bukkit.craftbukkit.entity.CraftPlayer) event.getPlayer()).getHandle()), event.getMessage()); + } + else + { + craftServer.dispatchCommand(craftPlayer, command.substring(1)); + } + // Scissors end } } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index ccc578bf2d7edfe866a5892978ce9e116787c4b4..4cb94d9e1f4ec56e01289b25c952c00df25f71a1 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -955,6 +955,7 @@ public final class CraftServer implements Server { } org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); // Spigot + me.totalfreedom.scissors.ScissorsConfig.init(((File) console.options.valueOf("scissors-settings"))); // Scissors this.console.paperConfigurations.reloadConfigs(this.console); for (ServerLevel world : this.console.getAllLevels()) { // world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty @@ -986,6 +987,7 @@ public final class CraftServer implements Server { this.reloadData(); org.spigotmc.SpigotConfig.registerCommands(); // Spigot io.papermc.paper.command.PaperCommands.registerCommands(this.console); // Paper + me.totalfreedom.scissors.ScissorsConfig.registerCommands(); // Scissors this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*"); this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions"); @@ -2744,6 +2746,12 @@ public final class CraftServer implements Server { return CraftServer.this.console.paperConfigurations.createLegacyObject(CraftServer.this.console); } + @Override + public YamlConfiguration getScissorsConfig() + { + return me.totalfreedom.scissors.ScissorsConfig.config; + } + @Override public void restart() { org.spigotmc.RestartCommand.restart(); diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java index cd87e192ff09e77538521bbde38416c52daa22b8..1bc7a99a457d0dd8befecfcd11da39a6b76291f1 100644 --- a/src/main/java/org/bukkit/craftbukkit/Main.java +++ b/src/main/java/org/bukkit/craftbukkit/Main.java @@ -180,9 +180,27 @@ public class Main { .defaultsTo("Unknown Server") .describedAs("Name"); // Paper end + + // Scissors start + acceptsAll(asList("scissors-dir", "scissors-settings-directory"), "Directory for Scissors settings") + .withRequiredArg() + .ofType(File.class) + .defaultsTo(new File(io.papermc.paper.configuration.PaperConfigurations.CONFIG_DIR)) + .describedAs("Config directory"); + // Scissors end + + // Scissors start + acceptsAll(asList("scissors", "scissors-settings"), "File for Scissors settings") + .withRequiredArg() + .ofType(File.class) + .defaultsTo(new File("scissors.yml")) + .describedAs("YAML file"); + // Scissors end } }; + + OptionSet options = null; // Paper start - preload logger classes to avoid plugins mixing versions