diff options
author | Nassim Jahnke <[email protected]> | 2023-03-14 18:11:24 +0100 |
---|---|---|
committer | Nassim Jahnke <[email protected]> | 2023-03-14 18:11:24 +0100 |
commit | 2ed604cf725820344878b0d49117bd5ef31463bc (patch) | |
tree | 701daae297f65de2ae3b2cc233047e7903adcb51 /patches/server/0011-Paper-command.patch | |
parent | 155aa36d89b260ef5841615899299756b5983c0a (diff) | |
download | Paper-2ed604cf725820344878b0d49117bd5ef31463bc.tar.gz Paper-2ed604cf725820344878b0d49117bd5ef31463bc.zip |
Start working on 1.19.4
Diffstat (limited to 'patches/server/0011-Paper-command.patch')
-rw-r--r-- | patches/server/0011-Paper-command.patch | 620 |
1 files changed, 0 insertions, 620 deletions
diff --git a/patches/server/0011-Paper-command.patch b/patches/server/0011-Paper-command.patch deleted file mode 100644 index 20e2de5bee..0000000000 --- a/patches/server/0011-Paper-command.patch +++ /dev/null @@ -1,620 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Zach Brown <[email protected]> -Date: Mon, 29 Feb 2016 21:02:09 -0600 -Subject: [PATCH] Paper command - - -diff --git a/src/main/java/io/papermc/paper/command/CommandUtil.java b/src/main/java/io/papermc/paper/command/CommandUtil.java -new file mode 100644 -index 0000000000000000000000000000000000000000..953c30500892e5f0c55b8597bc708ea85bf56d6e ---- /dev/null -+++ b/src/main/java/io/papermc/paper/command/CommandUtil.java -@@ -0,0 +1,69 @@ -+package io.papermc.paper.command; -+ -+import com.google.common.base.Functions; -+import com.google.common.collect.Iterables; -+import com.google.common.collect.Lists; -+import java.util.ArrayList; -+import java.util.Arrays; -+import java.util.Collection; -+import java.util.Iterator; -+import java.util.List; -+import net.minecraft.resources.ResourceLocation; -+import org.bukkit.command.CommandSender; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+@DefaultQualifier(NonNull.class) -+public final class CommandUtil { -+ private CommandUtil() { -+ } -+ -+ // Code from Mojang - copyright them -+ public static List<String> getListMatchingLast( -+ final CommandSender sender, -+ final String[] args, -+ final String... matches -+ ) { -+ return getListMatchingLast(sender, args, Arrays.asList(matches)); -+ } -+ -+ public static boolean matches(final String s, final String s1) { -+ return s1.regionMatches(true, 0, s, 0, s.length()); -+ } -+ -+ public static List<String> getListMatchingLast( -+ final CommandSender sender, -+ final String[] strings, -+ final 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(PaperCommand.BASE_PERM + s1) || sender.hasPermission("bukkit.command.paper"))) { -+ 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; -+ } -+ // end copy stuff -+} -diff --git a/src/main/java/io/papermc/paper/command/PaperCommand.java b/src/main/java/io/papermc/paper/command/PaperCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b3a58bf4b654e336826dc04da9e2f80ff8b9a9a7 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/command/PaperCommand.java -@@ -0,0 +1,145 @@ -+package io.papermc.paper.command; -+ -+import io.papermc.paper.command.subcommands.EntityCommand; -+import io.papermc.paper.command.subcommands.HeapDumpCommand; -+import io.papermc.paper.command.subcommands.ReloadCommand; -+import io.papermc.paper.command.subcommands.VersionCommand; -+import it.unimi.dsi.fastutil.Pair; -+import java.util.ArrayList; -+import java.util.Arrays; -+import java.util.Collections; -+import java.util.HashMap; -+import java.util.List; -+import java.util.Locale; -+import java.util.Map; -+import java.util.Set; -+import java.util.stream.Collectors; -+import net.minecraft.Util; -+import org.bukkit.Bukkit; -+import org.bukkit.Location; -+import org.bukkit.command.Command; -+import org.bukkit.command.CommandSender; -+import org.bukkit.permissions.Permission; -+import org.bukkit.permissions.PermissionDefault; -+import org.bukkit.plugin.PluginManager; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.checker.nullness.qual.Nullable; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+import static net.kyori.adventure.text.Component.text; -+import static net.kyori.adventure.text.format.NamedTextColor.RED; -+ -+@DefaultQualifier(NonNull.class) -+public final class PaperCommand extends Command { -+ static final String BASE_PERM = "bukkit.command.paper."; -+ // subcommand label -> subcommand -+ private static final Map<String, PaperSubcommand> SUBCOMMANDS = Util.make(() -> { -+ final Map<Set<String>, PaperSubcommand> commands = new HashMap<>(); -+ -+ commands.put(Set.of("heap"), new HeapDumpCommand()); -+ commands.put(Set.of("entity"), new EntityCommand()); -+ commands.put(Set.of("reload"), new ReloadCommand()); -+ commands.put(Set.of("version"), new VersionCommand()); -+ -+ return commands.entrySet().stream() -+ .flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue()))) -+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); -+ }); -+ // alias -> subcommand label -+ private static final Map<String, String> ALIASES = Util.make(() -> { -+ final Map<String, Set<String>> aliases = new HashMap<>(); -+ -+ aliases.put("version", Set.of("ver")); -+ -+ return aliases.entrySet().stream() -+ .flatMap(entry -> entry.getValue().stream().map(s -> Map.entry(s, entry.getKey()))) -+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); -+ }); -+ -+ public PaperCommand(final String name) { -+ super(name); -+ this.description = "Paper related commands"; -+ this.usageMessage = "/paper [" + String.join(" | ", SUBCOMMANDS.keySet()) + "]"; -+ final List<String> permissions = new ArrayList<>(); -+ permissions.add("bukkit.command.paper"); -+ permissions.addAll(SUBCOMMANDS.keySet().stream().map(s -> BASE_PERM + s).toList()); -+ this.setPermission(String.join(";", permissions)); -+ final PluginManager pluginManager = Bukkit.getServer().getPluginManager(); -+ for (final String perm : permissions) { -+ pluginManager.addPermission(new Permission(perm, PermissionDefault.OP)); -+ } -+ } -+ -+ private static boolean testPermission(final CommandSender sender, final String permission) { -+ if (sender.hasPermission(BASE_PERM + permission) || sender.hasPermission("bukkit.command.paper")) { -+ return true; -+ } -+ sender.sendMessage(text("I'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is in error.", RED)); -+ return false; -+ } -+ -+ @Override -+ public List<String> tabComplete( -+ final CommandSender sender, -+ final String alias, -+ final String[] args, -+ final @Nullable Location location -+ ) throws IllegalArgumentException { -+ if (args.length <= 1) { -+ return CommandUtil.getListMatchingLast(sender, args, SUBCOMMANDS.keySet()); -+ } -+ -+ final @Nullable Pair<String, PaperSubcommand> subCommand = resolveCommand(args[0]); -+ if (subCommand != null) { -+ return subCommand.second().tabComplete(sender, subCommand.first(), Arrays.copyOfRange(args, 1, args.length)); -+ } -+ -+ return Collections.emptyList(); -+ } -+ -+ @Override -+ public boolean execute( -+ final CommandSender sender, -+ final String commandLabel, -+ final String[] args -+ ) { -+ if (!testPermission(sender)) { -+ return true; -+ } -+ -+ if (args.length == 0) { -+ sender.sendMessage(text("Usage: " + this.usageMessage, RED)); -+ return false; -+ } -+ final @Nullable Pair<String, PaperSubcommand> subCommand = resolveCommand(args[0]); -+ -+ if (subCommand == null) { -+ sender.sendMessage(text("Usage: " + this.usageMessage, RED)); -+ return false; -+ } -+ -+ if (!testPermission(sender, subCommand.first())) { -+ return true; -+ } -+ final String[] choppedArgs = Arrays.copyOfRange(args, 1, args.length); -+ return subCommand.second().execute(sender, subCommand.first(), choppedArgs); -+ } -+ -+ private static @Nullable Pair<String, PaperSubcommand> resolveCommand(String label) { -+ label = label.toLowerCase(Locale.ENGLISH); -+ @Nullable PaperSubcommand subCommand = SUBCOMMANDS.get(label); -+ if (subCommand == null) { -+ final @Nullable String command = ALIASES.get(label); -+ if (command != null) { -+ label = command; -+ subCommand = SUBCOMMANDS.get(command); -+ } -+ } -+ -+ if (subCommand != null) { -+ return Pair.of(label, subCommand); -+ } -+ -+ return null; -+ } -+} -diff --git a/src/main/java/io/papermc/paper/command/PaperCommands.java b/src/main/java/io/papermc/paper/command/PaperCommands.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6a00f3d38da8107825ab1d405f337fd077b09f72 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/command/PaperCommands.java -@@ -0,0 +1,27 @@ -+package io.papermc.paper.command; -+ -+import net.minecraft.server.MinecraftServer; -+import org.bukkit.command.Command; -+ -+import java.util.HashMap; -+import java.util.Map; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+@DefaultQualifier(NonNull.class) -+public final class PaperCommands { -+ -+ private PaperCommands() { -+ } -+ -+ private static final Map<String, Command> COMMANDS = new HashMap<>(); -+ static { -+ COMMANDS.put("paper", new PaperCommand("paper")); -+ } -+ -+ public static void registerCommands(final MinecraftServer server) { -+ COMMANDS.forEach((s, command) -> { -+ server.server.getCommandMap().register(s, "Paper", command); -+ }); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/command/PaperSubcommand.java b/src/main/java/io/papermc/paper/command/PaperSubcommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6ff5d42a866d2752c73a766815aa190b2b0dc36f ---- /dev/null -+++ b/src/main/java/io/papermc/paper/command/PaperSubcommand.java -@@ -0,0 +1,16 @@ -+package io.papermc.paper.command; -+ -+import java.util.Collections; -+import java.util.List; -+import org.bukkit.command.CommandSender; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+@DefaultQualifier(NonNull.class) -+public interface PaperSubcommand { -+ boolean execute(CommandSender sender, String subCommand, String[] args); -+ -+ default List<String> tabComplete(final CommandSender sender, final String subCommand, final String[] args) { -+ return Collections.emptyList(); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java b/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ff99336e0b8131ae161cfa5c4fc83c6905e3dbc8 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java -@@ -0,0 +1,158 @@ -+package io.papermc.paper.command.subcommands; -+ -+import com.google.common.collect.Maps; -+import io.papermc.paper.command.CommandUtil; -+import io.papermc.paper.command.PaperSubcommand; -+import java.util.Collections; -+import java.util.List; -+import java.util.Locale; -+import java.util.Map; -+import java.util.Set; -+import java.util.stream.Collectors; -+ -+import net.kyori.adventure.text.Component; -+import net.kyori.adventure.text.event.ClickEvent; -+import net.kyori.adventure.text.event.HoverEvent; -+import net.minecraft.core.registries.BuiltInRegistries; -+import net.minecraft.resources.ResourceLocation; -+import net.minecraft.server.level.ServerChunkCache; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.world.entity.EntityType; -+import net.minecraft.world.level.ChunkPos; -+import org.apache.commons.lang3.tuple.MutablePair; -+import org.apache.commons.lang3.tuple.Pair; -+import org.bukkit.Bukkit; -+import org.bukkit.HeightMap; -+import org.bukkit.World; -+import org.bukkit.command.CommandSender; -+import org.bukkit.craftbukkit.CraftWorld; -+import org.bukkit.entity.Player; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.checker.nullness.qual.Nullable; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+import static net.kyori.adventure.text.Component.text; -+import static net.kyori.adventure.text.format.NamedTextColor.GREEN; -+import static net.kyori.adventure.text.format.NamedTextColor.RED; -+ -+@DefaultQualifier(NonNull.class) -+public final class EntityCommand implements PaperSubcommand { -+ @Override -+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) { -+ this.listEntities(sender, args); -+ return true; -+ } -+ -+ @Override -+ public List<String> tabComplete(final CommandSender sender, final String subCommand, final String[] args) { -+ if (args.length == 1) { -+ return CommandUtil.getListMatchingLast(sender, args, "help", "list"); -+ } else if (args.length == 2) { -+ return CommandUtil.getListMatchingLast(sender, args, BuiltInRegistries.ENTITY_TYPE.keySet().stream().map(ResourceLocation::toString).sorted().toArray(String[]::new)); -+ } -+ return Collections.emptyList(); -+ } -+ -+ /* -+ * Ported from MinecraftForge - author: LexManos <[email protected]> - License: LGPLv2.1 -+ */ -+ private void listEntities(final CommandSender sender, final String[] args) { -+ // help -+ if (args.length < 1 || !args[0].toLowerCase(Locale.ENGLISH).equals("list")) { -+ sender.sendMessage(text("Use /paper entity [list] help for more information on a specific command", RED)); -+ return; -+ } -+ -+ if ("list".equals(args[0].toLowerCase(Locale.ENGLISH))) { -+ String filter = "*"; -+ if (args.length > 1) { -+ if (args[1].toLowerCase(Locale.ENGLISH).equals("help")) { -+ sender.sendMessage(text("Use /paper entity list [filter] [worldName] to get entity info that matches the optional filter.", RED)); -+ return; -+ } -+ filter = args[1]; -+ } -+ final String cleanfilter = filter.replace("?", ".?").replace("*", ".*?"); -+ Set<ResourceLocation> names = BuiltInRegistries.ENTITY_TYPE.keySet().stream() -+ .filter(n -> n.toString().matches(cleanfilter)) -+ .collect(Collectors.toSet()); -+ if (names.isEmpty()) { -+ sender.sendMessage(text("Invalid filter, does not match any entities. Use /paper entity list for a proper list", RED)); -+ sender.sendMessage(text("Usage: /paper entity list [filter] [worldName]", RED)); -+ return; -+ } -+ String worldName; -+ if (args.length > 2) { -+ worldName = args[2]; -+ } else if (sender instanceof Player) { -+ worldName = ((Player) sender).getWorld().getName(); -+ } else { -+ sender.sendMessage(text("Please specify the name of a world", RED)); -+ sender.sendMessage(text("To do so without a filter, specify '*' as the filter", RED)); -+ sender.sendMessage(text("Usage: /paper entity list [filter] [worldName]", RED)); -+ return; -+ } -+ Map<ResourceLocation, MutablePair<Integer, Map<ChunkPos, Integer>>> list = Maps.newHashMap(); -+ @Nullable World bukkitWorld = Bukkit.getWorld(worldName); -+ if (bukkitWorld == null) { -+ sender.sendMessage(text("Could not load world for " + worldName + ". Please select a valid world.", RED)); -+ sender.sendMessage(text("Usage: /paper entity list [filter] [worldName]", RED)); -+ return; -+ } -+ ServerLevel world = ((CraftWorld) bukkitWorld).getHandle(); -+ Map<ResourceLocation, Integer> nonEntityTicking = Maps.newHashMap(); -+ ServerChunkCache chunkProviderServer = world.getChunkSource(); -+ world.getAllEntities().forEach(e -> { -+ ResourceLocation key = EntityType.getKey(e.getType()); -+ -+ MutablePair<Integer, Map<ChunkPos, Integer>> info = list.computeIfAbsent(key, k -> MutablePair.of(0, Maps.newHashMap())); -+ ChunkPos chunk = e.chunkPosition(); -+ info.left++; -+ info.right.put(chunk, info.right.getOrDefault(chunk, 0) + 1); -+ if (!chunkProviderServer.isPositionTicking(e)) { -+ nonEntityTicking.merge(key, 1, Integer::sum); -+ } -+ }); -+ if (names.size() == 1) { -+ ResourceLocation name = names.iterator().next(); -+ Pair<Integer, Map<ChunkPos, Integer>> info = list.get(name); -+ int nonTicking = nonEntityTicking.getOrDefault(name, 0); -+ if (info == null) { -+ sender.sendMessage(text("No entities found.", RED)); -+ return; -+ } -+ sender.sendMessage("Entity: " + name + " Total Ticking: " + (info.getLeft() - nonTicking) + ", Total Non-Ticking: " + nonTicking); -+ info.getRight().entrySet().stream() -+ .sorted((a, b) -> !a.getValue().equals(b.getValue()) ? b.getValue() - a.getValue() : a.getKey().toString().compareTo(b.getKey().toString())) -+ .limit(10).forEach(e -> { -+ final int x = (e.getKey().x << 4) + 8; -+ final int z = (e.getKey().z << 4) + 8; -+ final Component message = text(" " + e.getValue() + ": " + e.getKey().x + ", " + e.getKey().z + (chunkProviderServer.isPositionTicking(e.getKey().toLong()) ? " (Ticking)" : " (Non-Ticking)")) -+ .hoverEvent(HoverEvent.showText(text("Click to teleport to chunk", GREEN))) -+ .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, "/minecraft:execute as @s in " + world.getWorld().getKey() + " run tp " + x + " " + (world.getWorld().getHighestBlockYAt(x, z, HeightMap.MOTION_BLOCKING) + 1) + " " + z)); -+ sender.sendMessage(message); -+ }); -+ } else { -+ List<Pair<ResourceLocation, Integer>> info = list.entrySet().stream() -+ .filter(e -> names.contains(e.getKey())) -+ .map(e -> Pair.of(e.getKey(), e.getValue().left)) -+ .sorted((a, b) -> !a.getRight().equals(b.getRight()) ? b.getRight() - a.getRight() : a.getKey().toString().compareTo(b.getKey().toString())) -+ .toList(); -+ -+ if (info.isEmpty()) { -+ sender.sendMessage(text("No entities found.", RED)); -+ return; -+ } -+ -+ int count = info.stream().mapToInt(Pair::getRight).sum(); -+ int nonTickingCount = nonEntityTicking.values().stream().mapToInt(Integer::intValue).sum(); -+ sender.sendMessage("Total Ticking: " + (count - nonTickingCount) + ", Total Non-Ticking: " + nonTickingCount); -+ info.forEach(e -> { -+ int nonTicking = nonEntityTicking.getOrDefault(e.getKey(), 0); -+ sender.sendMessage(" " + (e.getValue() - nonTicking) + " (" + nonTicking + ") " + ": " + e.getKey()); -+ }); -+ sender.sendMessage("* First number is ticking entities, second number is non-ticking entities"); -+ } -+ } -+ } -+} -diff --git a/src/main/java/io/papermc/paper/command/subcommands/HeapDumpCommand.java b/src/main/java/io/papermc/paper/command/subcommands/HeapDumpCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cd2e4d792e972b8bf1e07b8961594a670ae949cf ---- /dev/null -+++ b/src/main/java/io/papermc/paper/command/subcommands/HeapDumpCommand.java -@@ -0,0 +1,38 @@ -+package io.papermc.paper.command.subcommands; -+ -+import io.papermc.paper.command.PaperSubcommand; -+import java.time.LocalDateTime; -+import java.time.format.DateTimeFormatter; -+import org.bukkit.command.Command; -+import org.bukkit.command.CommandSender; -+import org.bukkit.craftbukkit.CraftServer; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+import static net.kyori.adventure.text.Component.text; -+import static net.kyori.adventure.text.format.NamedTextColor.GREEN; -+import static net.kyori.adventure.text.format.NamedTextColor.RED; -+import static net.kyori.adventure.text.format.NamedTextColor.YELLOW; -+ -+@DefaultQualifier(NonNull.class) -+public final class HeapDumpCommand implements PaperSubcommand { -+ @Override -+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) { -+ this.dumpHeap(sender); -+ return true; -+ } -+ -+ private void dumpHeap(final CommandSender sender) { -+ java.nio.file.Path dir = java.nio.file.Paths.get("./dumps"); -+ String name = "heap-dump-" + DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss").format(LocalDateTime.now()); -+ -+ Command.broadcastCommandMessage(sender, text("Writing JVM heap data...", YELLOW)); -+ -+ java.nio.file.Path file = CraftServer.dumpHeap(dir, name); -+ if (file != null) { -+ Command.broadcastCommandMessage(sender, text("Heap dump saved to " + file, GREEN)); -+ } else { -+ Command.broadcastCommandMessage(sender, text("Failed to write heap dump, see server log for details", RED)); -+ } -+ } -+} -diff --git a/src/main/java/io/papermc/paper/command/subcommands/ReloadCommand.java b/src/main/java/io/papermc/paper/command/subcommands/ReloadCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..bd68139ae635f2ad7ec8e7a21e0056a139c4c62e ---- /dev/null -+++ b/src/main/java/io/papermc/paper/command/subcommands/ReloadCommand.java -@@ -0,0 +1,33 @@ -+package io.papermc.paper.command.subcommands; -+ -+import io.papermc.paper.command.PaperSubcommand; -+import net.minecraft.server.MinecraftServer; -+import org.bukkit.command.Command; -+import org.bukkit.command.CommandSender; -+import org.bukkit.craftbukkit.CraftServer; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+import static net.kyori.adventure.text.Component.text; -+import static net.kyori.adventure.text.format.NamedTextColor.GREEN; -+import static net.kyori.adventure.text.format.NamedTextColor.RED; -+ -+@DefaultQualifier(NonNull.class) -+public final class ReloadCommand implements PaperSubcommand { -+ @Override -+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) { -+ this.doReload(sender); -+ return true; -+ } -+ -+ private void doReload(final CommandSender sender) { -+ Command.broadcastCommandMessage(sender, text("Please note that this command is not supported and may cause issues.", RED)); -+ Command.broadcastCommandMessage(sender, text("If you encounter any issues please use the /stop command to restart your server.", RED)); -+ -+ MinecraftServer server = ((CraftServer) sender.getServer()).getServer(); -+ server.paperConfigurations.reloadConfigs(server); -+ server.server.reloadCount++; -+ -+ Command.broadcastCommandMessage(sender, text("Paper config reload complete.", GREEN)); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/command/subcommands/VersionCommand.java b/src/main/java/io/papermc/paper/command/subcommands/VersionCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ae60bd96b5284d54676d8e7e4dd5d170b526ec1e ---- /dev/null -+++ b/src/main/java/io/papermc/paper/command/subcommands/VersionCommand.java -@@ -0,0 +1,21 @@ -+package io.papermc.paper.command.subcommands; -+ -+import io.papermc.paper.command.PaperSubcommand; -+import net.minecraft.server.MinecraftServer; -+import org.bukkit.command.Command; -+import org.bukkit.command.CommandSender; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.checker.nullness.qual.Nullable; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+@DefaultQualifier(NonNull.class) -+public final class VersionCommand implements PaperSubcommand { -+ @Override -+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) { -+ final @Nullable Command ver = MinecraftServer.getServer().server.getCommandMap().getCommand("version"); -+ if (ver != null) { -+ ver.execute(sender, "paper", new String[0]); -+ } -+ return true; -+ } -+} -diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index 1fe07773cf9664164b29164caba22800e5a6bdae..cb6f192c11cda6230ec365e6cefb44a37416236d 100644 ---- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -186,6 +186,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - // Paper start - paperConfigurations.initializeGlobalConfiguration(); - paperConfigurations.initializeWorldDefaultsConfiguration(); -+ io.papermc.paper.command.PaperCommands.registerCommands(this); - // Paper end - - this.setPvpAllowed(dedicatedserverproperties.pvp); -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 877a104e3899debd387544b740896ffbe86bb581..26ca07b5e302cc4cc02e06f5d07f6d9eb541275e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -909,6 +909,7 @@ public final class CraftServer implements Server { - this.commandMap.clearCommands(); - this.reloadData(); - org.spigotmc.SpigotConfig.registerCommands(); // Spigot -+ io.papermc.paper.command.PaperCommands.registerCommands(this.console); // Paper - this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*"); - this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions"); - -@@ -2438,6 +2439,34 @@ public final class CraftServer implements Server { - // Spigot end - - // Paper start -+ @SuppressWarnings({"rawtypes", "unchecked"}) -+ public static java.nio.file.Path dumpHeap(java.nio.file.Path dir, String name) { -+ try { -+ java.nio.file.Files.createDirectories(dir); -+ -+ javax.management.MBeanServer server = java.lang.management.ManagementFactory.getPlatformMBeanServer(); -+ java.nio.file.Path file; -+ -+ try { -+ Class clazz = Class.forName("openj9.lang.management.OpenJ9DiagnosticsMXBean"); -+ Object openj9Mbean = java.lang.management.ManagementFactory.newPlatformMXBeanProxy(server, "openj9.lang.management:type=OpenJ9Diagnostics", clazz); -+ java.lang.reflect.Method m = clazz.getMethod("triggerDumpToFile", String.class, String.class); -+ file = dir.resolve(name + ".phd"); -+ m.invoke(openj9Mbean, "heap", file.toString()); -+ } catch (ClassNotFoundException e) { -+ Class clazz = Class.forName("com.sun.management.HotSpotDiagnosticMXBean"); -+ Object hotspotMBean = java.lang.management.ManagementFactory.newPlatformMXBeanProxy(server, "com.sun.management:type=HotSpotDiagnostic", clazz); -+ java.lang.reflect.Method m = clazz.getMethod("dumpHeap", String.class, boolean.class); -+ file = dir.resolve(name + ".hprof"); -+ m.invoke(hotspotMBean, file.toString(), true); -+ } -+ -+ return file; -+ } catch (Throwable t) { -+ Bukkit.getLogger().log(Level.SEVERE, "Could not write heap", t); -+ return null; -+ } -+ } - private Iterable<? extends net.kyori.adventure.audience.Audience> adventure$audiences; - @Override - public Iterable<? extends net.kyori.adventure.audience.Audience> audiences() { |