geforkt von Mirrors/Paper
Remove ChatColor usages (#7543)
Dieser Commit ist enthalten in:
Ursprung
b63b1a42cf
Commit
f65eead418
@ -58,17 +58,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ if (args.length == 1) {
|
||||
+ if (args[0].equalsIgnoreCase("permissions")) {
|
||||
+ Bukkit.getServer().reloadPermissions();
|
||||
+ Command.broadcastCommandMessage(sender, ChatColor.GREEN + "Permissions successfully reloaded.");
|
||||
+ Command.broadcastCommandMessage(sender, net.kyori.adventure.text.Component.text("Permissions successfully reloaded.", net.kyori.adventure.text.format.NamedTextColor.GREEN));
|
||||
+ return true;
|
||||
+ } else if ("confirm".equalsIgnoreCase(args[0])) {
|
||||
+ confirmed = true;
|
||||
+ } else {
|
||||
+ Command.broadcastCommandMessage(sender, ChatColor.RED + "Usage: " + usageMessage);
|
||||
+ Command.broadcastCommandMessage(sender, net.kyori.adventure.text.Component.text("Usage: " + usageMessage, net.kyori.adventure.text.format.NamedTextColor.RED));
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ if (!confirmed) {
|
||||
+ Command.broadcastCommandMessage(sender, ChatColor.RED + "Are you sure you wish to reload your server? Doing so may cause bugs and memory leaks. It is recommended to restart instead of using /reload. To confirm, please type " + ChatColor.YELLOW + "/reload confirm");
|
||||
+ Command.broadcastCommandMessage(sender, net.kyori.adventure.text.Component.text("Are you sure you wish to reload your server? Doing so may cause bugs and memory leaks. It is recommended to restart instead of using /reload. To confirm, please type ", net.kyori.adventure.text.format.NamedTextColor.RED).append(net.kyori.adventure.text.Component.text("/reload confirm", net.kyori.adventure.text.format.NamedTextColor.YELLOW)));
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
@ -1366,6 +1366,43 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
|
||||
public static void broadcastCommandMessage(@NotNull CommandSender source, @NotNull String message) {
|
||||
broadcastCommandMessage(source, message, true);
|
||||
}
|
||||
|
||||
public static void broadcastCommandMessage(@NotNull CommandSender source, @NotNull String message, boolean sendToSource) {
|
||||
- String result = source.getName() + ": " + message;
|
||||
+ // Paper start
|
||||
+ broadcastCommandMessage(source, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message), sendToSource);
|
||||
+ }
|
||||
+
|
||||
+ public static void broadcastCommandMessage(@NotNull CommandSender source, @NotNull net.kyori.adventure.text.Component message) {
|
||||
+ broadcastCommandMessage(source, message, true);
|
||||
+ }
|
||||
+
|
||||
+ public static void broadcastCommandMessage(@NotNull CommandSender source, @NotNull net.kyori.adventure.text.Component message, boolean sendToSource) {
|
||||
+ net.kyori.adventure.text.TextComponent.Builder result = net.kyori.adventure.text.Component.text()
|
||||
+ .color(net.kyori.adventure.text.format.NamedTextColor.WHITE)
|
||||
+ .decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false)
|
||||
+ .append(source.name())
|
||||
+ .append(net.kyori.adventure.text.Component.text(": "))
|
||||
+ .append(message);
|
||||
+ // Paper end
|
||||
|
||||
if (source instanceof BlockCommandSender) {
|
||||
BlockCommandSender blockCommandSender = (BlockCommandSender) source;
|
||||
@@ -0,0 +0,0 @@ public abstract class Command {
|
||||
}
|
||||
|
||||
Set<Permissible> users = Bukkit.getPluginManager().getPermissionSubscriptions(Server.BROADCAST_CHANNEL_ADMINISTRATIVE);
|
||||
- String colored = ChatColor.GRAY + "" + ChatColor.ITALIC + "[" + result + ChatColor.GRAY + ChatColor.ITALIC + "]";
|
||||
+ // Paper start
|
||||
+ net.kyori.adventure.text.TextComponent.Builder colored = net.kyori.adventure.text.Component.text()
|
||||
+ .color(net.kyori.adventure.text.format.NamedTextColor.GRAY)
|
||||
+ .decorate(net.kyori.adventure.text.format.TextDecoration.ITALIC)
|
||||
+ .append(net.kyori.adventure.text.Component.text("["), result, net.kyori.adventure.text.Component.text("]"));
|
||||
+ // Paper end
|
||||
|
||||
if (sendToSource && !(source instanceof ConsoleCommandSender)) {
|
||||
source.sendMessage(message);
|
||||
diff --git a/src/main/java/org/bukkit/command/CommandSender.java b/src/main/java/org/bukkit/command/CommandSender.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/command/CommandSender.java
|
||||
|
@ -86,13 +86,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class ReloadCommand extends BukkitCommand {
|
||||
Bukkit.getServer().reloadPermissions();
|
||||
Command.broadcastCommandMessage(sender, ChatColor.GREEN + "Permissions successfully reloaded.");
|
||||
Command.broadcastCommandMessage(sender, net.kyori.adventure.text.Component.text("Permissions successfully reloaded.", net.kyori.adventure.text.format.NamedTextColor.GREEN));
|
||||
return true;
|
||||
+ } else if ("commands".equalsIgnoreCase(args[0])) {
|
||||
+ if (Bukkit.getServer().reloadCommandAliases()) {
|
||||
+ Command.broadcastCommandMessage(sender, ChatColor.GREEN + "Command aliases successfully reloaded.");
|
||||
+ Command.broadcastCommandMessage(sender, net.kyori.adventure.text.Component.text("Command aliases successfully reloaded.", net.kyori.adventure.text.format.NamedTextColor.GREEN));
|
||||
+ } else {
|
||||
+ Command.broadcastCommandMessage(sender, ChatColor.RED + "An error occurred while trying to reload command aliases.");
|
||||
+ Command.broadcastCommandMessage(sender, net.kyori.adventure.text.Component.text("An error occurred while trying to reload command aliases.", net.kyori.adventure.text.format.NamedTextColor.RED));
|
||||
+ }
|
||||
+ return true;
|
||||
} else if ("confirm".equalsIgnoreCase(args[0])) {
|
||||
|
@ -1589,8 +1589,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+package co.aikar.timings;
|
||||
+
|
||||
+import com.google.common.collect.ImmutableList;
|
||||
+import net.kyori.adventure.text.format.NamedTextColor;
|
||||
+import org.apache.commons.lang.Validate;
|
||||
+import org.bukkit.ChatColor;
|
||||
+import org.bukkit.command.CommandSender;
|
||||
+import org.bukkit.command.defaults.BukkitCommand;
|
||||
+import org.bukkit.util.StringUtil;
|
||||
@ -1598,7 +1598,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.List;
|
||||
+import org.jetbrains.annotations.NotNull;
|
||||
+import org.jetbrains.annotations.Nullable;
|
||||
+
|
||||
+import static net.kyori.adventure.text.Component.text;
|
||||
+
|
||||
+
|
||||
+public class TimingsCommand extends BukkitCommand {
|
||||
@ -1618,41 +1619,41 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ return true;
|
||||
+ }
|
||||
+ if (args.length < 1) {
|
||||
+ sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
|
||||
+ sender.sendMessage(text("Usage: " + this.usageMessage, NamedTextColor.RED));
|
||||
+ return true;
|
||||
+ }
|
||||
+ final String arg = args[0];
|
||||
+ if ("on".equalsIgnoreCase(arg)) {
|
||||
+ Timings.setTimingsEnabled(true);
|
||||
+ sender.sendMessage("Enabled Timings & Reset");
|
||||
+ sender.sendMessage(text("Enabled Timings & Reset"));
|
||||
+ return true;
|
||||
+ } else if ("off".equalsIgnoreCase(arg)) {
|
||||
+ Timings.setTimingsEnabled(false);
|
||||
+ sender.sendMessage("Disabled Timings");
|
||||
+ sender.sendMessage(text("Disabled Timings"));
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ if (!Timings.isTimingsEnabled()) {
|
||||
+ sender.sendMessage("Please enable timings by typing /timings on");
|
||||
+ sender.sendMessage(text("Please enable timings by typing /timings on"));
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ long now = System.currentTimeMillis();
|
||||
+ if ("verbon".equalsIgnoreCase(arg)) {
|
||||
+ Timings.setVerboseTimingsEnabled(true);
|
||||
+ sender.sendMessage("Enabled Verbose Timings");
|
||||
+ sender.sendMessage(text("Enabled Verbose Timings"));
|
||||
+ return true;
|
||||
+ } else if ("verboff".equalsIgnoreCase(arg)) {
|
||||
+ Timings.setVerboseTimingsEnabled(false);
|
||||
+ sender.sendMessage("Disabled Verbose Timings");
|
||||
+ sender.sendMessage(text("Disabled Verbose Timings"));
|
||||
+ return true;
|
||||
+ } else if ("reset".equalsIgnoreCase(arg)) {
|
||||
+ if (now - lastResetAttempt < 30000) {
|
||||
+ TimingsManager.reset();
|
||||
+ sender.sendMessage(ChatColor.RED + "Timings reset. Please wait 5-10 minutes before using /timings report.");
|
||||
+ sender.sendMessage(text("Timings reset. Please wait 5-10 minutes before using /timings report.", NamedTextColor.RED));
|
||||
+ } else {
|
||||
+ lastResetAttempt = now;
|
||||
+ sender.sendMessage(ChatColor.RED + "WARNING: Timings v2 should not be reset. If you are encountering lag, please wait 3 minutes and then issue a report. The best timings will include 10+ minutes, with data before and after your lag period. If you really want to reset, run this command again within 30 seconds.");
|
||||
+ sender.sendMessage(text("WARNING: Timings v2 should not be reset. If you are experiencing lag, please wait 3 minutes and then issue a report. The best timings will include 10+ minutes, with data before and after your lag period. If you really want to reset, run this command again within 30 seconds.", NamedTextColor.RED));
|
||||
+ }
|
||||
+ } else if (
|
||||
+ "paste".equalsIgnoreCase(arg) ||
|
||||
@ -1663,7 +1664,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ ) {
|
||||
+ Timings.generateReport(sender);
|
||||
+ } else {
|
||||
+ sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
|
||||
+ sender.sendMessage(text("Usage: " + this.usageMessage, NamedTextColor.RED));
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
|
@ -45,6 +45,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayDeque;
|
||||
@@ -0,0 +0,0 @@ import java.util.stream.Collectors;
|
||||
import static net.kyori.adventure.text.Component.text;
|
||||
import static net.kyori.adventure.text.format.NamedTextColor.BLUE;
|
||||
import static net.kyori.adventure.text.format.NamedTextColor.DARK_AQUA;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.GRAY;
|
||||
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;
|
||||
|
||||
public class PaperCommand extends Command {
|
||||
private static final String BASE_PERM = "bukkit.command.paper.";
|
||||
@ -81,20 +88,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
|
||||
+ private void doSyncLoadInfo(CommandSender sender, String[] args) {
|
||||
+ if (!SyncLoadFinder.ENABLED) {
|
||||
+ sender.sendMessage(ChatColor.RED + "This command requires the server startup flag '-Dpaper.debug-sync-loads=true' to be set.");
|
||||
+ sender.sendMessage(text("This command requires the server startup flag '-Dpaper.debug-sync-loads=true' to be set.", RED));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (args.length > 1 && args[1].equals("clear")) {
|
||||
+ SyncLoadFinder.clear();
|
||||
+ sender.sendMessage(ChatColor.GRAY + "Sync load data cleared.");
|
||||
+ sender.sendMessage(text("Sync load data cleared.", GRAY));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ File file = new File(new File(new File("."), "debug"),
|
||||
+ "sync-load-info" + DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss").format(LocalDateTime.now()) + ".txt");
|
||||
+ file.getParentFile().mkdirs();
|
||||
+ sender.sendMessage(ChatColor.GREEN + "Writing sync load info to " + file.toString());
|
||||
+ sender.sendMessage(text("Writing sync load info to " + file, GREEN));
|
||||
+
|
||||
+
|
||||
+ try {
|
||||
@ -113,9 +120,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ ) {
|
||||
+ out.print(fileData);
|
||||
+ }
|
||||
+ sender.sendMessage(ChatColor.GREEN + "Successfully written sync load information!");
|
||||
+ sender.sendMessage(text("Successfully written sync load information!", GREEN));
|
||||
+ } catch (Throwable thr) {
|
||||
+ sender.sendMessage(ChatColor.RED + "Failed to write sync load information");
|
||||
+ sender.sendMessage(text("Failed to write sync load information!", RED));
|
||||
+ thr.printStackTrace();
|
||||
+ }
|
||||
+ }
|
||||
|
@ -55,6 +55,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+import java.util.function.ToIntFunction;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.kyori.adventure.text.Component.text;
|
||||
@@ -0,0 +0,0 @@ import static net.kyori.adventure.text.format.NamedTextColor.YELLOW;
|
||||
|
||||
public class PaperCommand extends Command {
|
||||
private static final String BASE_PERM = "bukkit.command.paper.";
|
||||
- private static final ImmutableSet<String> SUBCOMMANDS = ImmutableSet.<String>builder().add("heap", "entity", "reload", "version", "debug", "chunkinfo", "fixlight", "syncloadinfo", "dumpitem").build();
|
||||
|
@ -12,8 +12,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
@@ -0,0 +0,0 @@
|
||||
+package com.destroystokyo.paper;
|
||||
+
|
||||
+import net.kyori.adventure.text.Component;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+import org.bukkit.ChatColor;
|
||||
+import org.bukkit.Location;
|
||||
+import org.bukkit.command.Command;
|
||||
+import org.bukkit.command.CommandSender;
|
||||
@ -24,8 +24,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+import java.util.Collections;
|
||||
+import java.util.List;
|
||||
+
|
||||
+import static net.kyori.adventure.text.Component.text;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.GOLD;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.GRAY;
|
||||
+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;
|
||||
+
|
||||
+public class MSPTCommand extends Command {
|
||||
+ private static final DecimalFormat DF = new DecimalFormat("########0.0");
|
||||
+ private static final Component SLASH = text("/");
|
||||
+
|
||||
+ public MSPTCommand(String name) {
|
||||
+ super(name);
|
||||
@ -45,17 +53,44 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+
|
||||
+ MinecraftServer server = MinecraftServer.getServer();
|
||||
+
|
||||
+ List<String> times = new ArrayList<>();
|
||||
+ List<Component> times = new ArrayList<>();
|
||||
+ times.addAll(eval(server.tickTimes5s.getTimes()));
|
||||
+ times.addAll(eval(server.tickTimes10s.getTimes()));
|
||||
+ times.addAll(eval(server.tickTimes60s.getTimes()));
|
||||
+
|
||||
+ sender.sendMessage("§6Server tick times §e(§7avg§e/§7min§e/§7max§e)§6 from last 5s§7,§6 10s§7,§6 1m§e:");
|
||||
+ sender.sendMessage(String.format("§6◴ %s§7/%s§7/%s§e, %s§7/%s§7/%s§e, %s§7/%s§7/%s", times.toArray()));
|
||||
+ sender.sendMessage(text().content("Server tick times ").color(GOLD)
|
||||
+ .append(text().color(YELLOW)
|
||||
+ .append(
|
||||
+ text("("),
|
||||
+ text("avg", GRAY),
|
||||
+ text("/"),
|
||||
+ text("min", GRAY),
|
||||
+ text("/"),
|
||||
+ text("max", GRAY),
|
||||
+ text(")")
|
||||
+ )
|
||||
+ ).append(
|
||||
+ text(" from last 5s"),
|
||||
+ text(",", GRAY),
|
||||
+ text(" 10s"),
|
||||
+ text(",", GRAY),
|
||||
+ text(" 1m"),
|
||||
+ text(":", YELLOW)
|
||||
+ )
|
||||
+ );
|
||||
+ sender.sendMessage(text().content("◴ ").color(GOLD)
|
||||
+ .append(text().color(GRAY)
|
||||
+ .append(
|
||||
+ times.get(0), SLASH, times.get(1), SLASH, times.get(2), text(", ", YELLOW),
|
||||
+ times.get(3), SLASH, times.get(4), SLASH, times.get(5), text(", ", YELLOW),
|
||||
+ times.get(6), SLASH, times.get(7), SLASH, times.get(8)
|
||||
+ )
|
||||
+ )
|
||||
+ );
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ private static List<String> eval(long[] times) {
|
||||
+ private static List<Component> eval(long[] times) {
|
||||
+ long min = Integer.MAX_VALUE;
|
||||
+ long max = 0L;
|
||||
+ long total = 0L;
|
||||
@ -70,8 +105,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ return Arrays.asList(getColor(avgD), getColor(minD), getColor(maxD));
|
||||
+ }
|
||||
+
|
||||
+ private static String getColor(double avg) {
|
||||
+ return ChatColor.COLOR_CHAR + (avg >= 50 ? "c" : avg >= 40 ? "e" : "a") + DF.format(avg);
|
||||
+ private static Component getColor(double avg) {
|
||||
+ return text(DF.format(avg), avg >= 50 ? RED : avg >= 40 ? YELLOW : GREEN);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||
|
@ -52,7 +52,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
import org.apache.commons.lang3.tuple.MutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -0,0 +0,0 @@ import java.util.stream.Collectors;
|
||||
@@ -0,0 +0,0 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.kyori.adventure.text.Component.text;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.BLUE;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.DARK_AQUA;
|
||||
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;
|
||||
|
||||
public class PaperCommand extends Command {
|
||||
private static final String BASE_PERM = "bukkit.command.paper.";
|
||||
@ -109,7 +117,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ for (int i = 1; i < args.length; ++i) {
|
||||
+ org.bukkit.World world = Bukkit.getWorld(args[i]);
|
||||
+ if (world == null) {
|
||||
+ sender.sendMessage(ChatColor.RED + "World '" + args[i] + "' is invalid");
|
||||
+ sender.sendMessage(text("World '" + args[i] + "' is invalid", RED));
|
||||
+ return;
|
||||
+ }
|
||||
+ worlds.add(world);
|
||||
@ -162,22 +170,30 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ accumulatedTicking += ticking;
|
||||
+ accumulatedEntityTicking += entityTicking;
|
||||
+
|
||||
+ sender.sendMessage(ChatColor.BLUE + "Chunks in " + ChatColor.GREEN + bukkitWorld.getName() + ChatColor.DARK_AQUA + ":");
|
||||
+ sender.sendMessage(ChatColor.BLUE + "Total: " + ChatColor.DARK_AQUA + total + ChatColor.BLUE + " Inactive: " + ChatColor.DARK_AQUA
|
||||
+ + inactive + ChatColor.BLUE + " Border: " + ChatColor.DARK_AQUA + border + ChatColor.BLUE + " Ticking: "
|
||||
+ + ChatColor.DARK_AQUA + ticking + ChatColor.BLUE + " Entity: " + ChatColor.DARK_AQUA + entityTicking);
|
||||
+ sender.sendMessage(text().append(text("Chunks in ", BLUE), text(bukkitWorld.getName(), GREEN), text(":")));
|
||||
+ sender.sendMessage(text().color(DARK_AQUA).append(
|
||||
+ text("Total: ", BLUE), text(total),
|
||||
+ text(" Inactive: ", BLUE), text(inactive),
|
||||
+ text(" Border: ", BLUE), text(border),
|
||||
+ text(" Ticking: ", BLUE), text(ticking),
|
||||
+ text(" Entity: ", BLUE), text(entityTicking)
|
||||
+ ));
|
||||
+ }
|
||||
+ if (worlds.size() > 1) {
|
||||
+ sender.sendMessage(ChatColor.BLUE + "Chunks in " + ChatColor.GREEN + "all listed worlds" + ChatColor.DARK_AQUA + ":");
|
||||
+ sender.sendMessage(ChatColor.BLUE + "Total: " + ChatColor.DARK_AQUA + accumulatedTotal + ChatColor.BLUE + " Inactive: " + ChatColor.DARK_AQUA
|
||||
+ + accumulatedInactive + ChatColor.BLUE + " Border: " + ChatColor.DARK_AQUA + accumulatedBorder + ChatColor.BLUE + " Ticking: "
|
||||
+ + ChatColor.DARK_AQUA + accumulatedTicking + ChatColor.BLUE + " Entity: " + ChatColor.DARK_AQUA + accumulatedEntityTicking);
|
||||
+ sender.sendMessage(text().append(text("Chunks in ", BLUE), text("all listed worlds", GREEN), text(":", DARK_AQUA)));
|
||||
+ sender.sendMessage(text().color(DARK_AQUA).append(
|
||||
+ text("Total: ", BLUE), text(accumulatedTotal),
|
||||
+ text(" Inactive: ", BLUE), text(accumulatedInactive),
|
||||
+ text(" Border: ", BLUE), text(accumulatedBorder),
|
||||
+ text(" Ticking: ", BLUE), text(accumulatedTicking),
|
||||
+ text(" Entity: ", BLUE), text(accumulatedEntityTicking)
|
||||
+ ));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private void doDebug(CommandSender sender, String[] args) {
|
||||
+ if (args.length < 2) {
|
||||
+ sender.sendMessage(ChatColor.RED + "Use /paper debug [chunks] help for more information on a specific command");
|
||||
+ sender.sendMessage(text("Use /paper debug [chunks] help for more information on a specific command", RED));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
@ -185,25 +201,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ switch (debugType) {
|
||||
+ case "chunks":
|
||||
+ if (args.length >= 3 && args[2].toLowerCase(Locale.ENGLISH).equals("help")) {
|
||||
+ sender.sendMessage(ChatColor.RED + "Use /paper debug chunks to dump loaded chunk information to a file");
|
||||
+ sender.sendMessage(text("Use /paper debug chunks [world] to dump loaded chunk information to a file", RED));
|
||||
+ break;
|
||||
+ }
|
||||
+ File file = new File(new File(new File("."), "debug"),
|
||||
+ "chunks-" + DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss").format(LocalDateTime.now()) + ".txt");
|
||||
+ sender.sendMessage(ChatColor.GREEN + "Writing chunk information dump to " + file.toString());
|
||||
+ sender.sendMessage(text("Writing chunk information dump to " + file, GREEN));
|
||||
+ try {
|
||||
+ MCUtil.dumpChunks(file);
|
||||
+ sender.sendMessage(ChatColor.GREEN + "Successfully written chunk information!");
|
||||
+ sender.sendMessage(text("Successfully written chunk information!", GREEN));
|
||||
+ } catch (Throwable thr) {
|
||||
+ MinecraftServer.LOGGER.warn("Failed to dump chunk information to file " + file.toString(), thr);
|
||||
+ sender.sendMessage(ChatColor.RED + "Failed to dump chunk information, see console");
|
||||
+ sender.sendMessage(text("Failed to dump chunk information, see console", RED));
|
||||
+ }
|
||||
+
|
||||
+ break;
|
||||
+ case "help":
|
||||
+ // fall through to default
|
||||
+ default:
|
||||
+ sender.sendMessage(ChatColor.RED + "Use /paper debug [chunks] help for more information on a specific command");
|
||||
+ sender.sendMessage(text("Use /paper debug [chunks] help for more information on a specific command", RED));
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
|
@ -39,7 +39,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -0,0 +0,0 @@ import java.util.stream.Collectors;
|
||||
@@ -0,0 +0,0 @@ import static net.kyori.adventure.text.format.NamedTextColor.YELLOW;
|
||||
|
||||
public class PaperCommand extends Command {
|
||||
private static final String BASE_PERM = "bukkit.command.paper.";
|
||||
@ -60,7 +60,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
case "version":
|
||||
@@ -0,0 +0,0 @@ public class PaperCommand extends Command {
|
||||
|
||||
Command.broadcastCommandMessage(sender, ChatColor.GREEN + "Paper config reload complete.");
|
||||
Command.broadcastCommandMessage(sender, text("Paper config reload complete.", GREEN));
|
||||
}
|
||||
+ private void doFixLight(CommandSender sender, String[] args) {
|
||||
+ if (!(sender instanceof Player)) {
|
||||
|
@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
|
||||
private static boolean testPermission(CommandSender commandSender, String permission) {
|
||||
if (commandSender.hasPermission(BASE_PERM + permission) || commandSender.hasPermission("bukkit.command.paper")) return true;
|
||||
- commandSender.sendMessage(ChatColor.RED + "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."); // Sorry, kashike
|
||||
- commandSender.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));
|
||||
+ commandSender.sendMessage(Bukkit.getPermissionMessage()); // Sorry, kashike
|
||||
return false;
|
||||
}
|
||||
|
301
patches/server/Paper-command.patch
Normale Datei
301
patches/server/Paper-command.patch
Normale Datei
@ -0,0 +1,301 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <1254957+zachbr@users.noreply.github.com>
|
||||
Date: Mon, 29 Feb 2016 21:02:09 -0600
|
||||
Subject: [PATCH] Paper command
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+package com.destroystokyo.paper;
|
||||
+
|
||||
+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 com.google.common.collect.Maps;
|
||||
+import net.minecraft.resources.ResourceLocation;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+import net.minecraft.server.level.ServerChunkCache;
|
||||
+import net.minecraft.server.level.ServerLevel;
|
||||
+import net.minecraft.world.entity.Entity;
|
||||
+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.Location;
|
||||
+import org.bukkit.World;
|
||||
+import org.bukkit.command.Command;
|
||||
+import org.bukkit.command.CommandSender;
|
||||
+import org.bukkit.craftbukkit.CraftServer;
|
||||
+import org.bukkit.craftbukkit.CraftWorld;
|
||||
+import org.bukkit.entity.Player;
|
||||
+
|
||||
+import java.io.File;
|
||||
+import java.time.LocalDateTime;
|
||||
+import java.time.format.DateTimeFormatter;
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.Arrays;
|
||||
+import java.util.Collection;
|
||||
+import java.util.Collections;
|
||||
+import java.util.Iterator;
|
||||
+import java.util.List;
|
||||
+import java.util.Locale;
|
||||
+import java.util.Map;
|
||||
+import java.util.Set;
|
||||
+import java.util.stream.Collectors;
|
||||
+
|
||||
+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;
|
||||
+
|
||||
+public class PaperCommand extends Command {
|
||||
+ private static final String BASE_PERM = "bukkit.command.paper.";
|
||||
+ private static final ImmutableSet<String> SUBCOMMANDS = ImmutableSet.<String>builder().add("heap", "entity", "reload", "version").build();
|
||||
+
|
||||
+ public PaperCommand(String name) {
|
||||
+ super(name);
|
||||
+ this.description = "Paper related commands";
|
||||
+ this.usageMessage = "/paper [" + Joiner.on(" | ").join(SUBCOMMANDS) + "]";
|
||||
+ this.setPermission("bukkit.command.paper;" + 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.paper")) return true;
|
||||
+ commandSender.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(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException {
|
||||
+ if (args.length <= 1)
|
||||
+ return getListMatchingLast(sender, args, SUBCOMMANDS);
|
||||
+
|
||||
+ switch (args[0].toLowerCase(Locale.ENGLISH))
|
||||
+ {
|
||||
+ case "entity":
|
||||
+ if (args.length == 2)
|
||||
+ return getListMatchingLast(sender, args, "help", "list");
|
||||
+ if (args.length == 3)
|
||||
+ return getListMatchingLast(sender, args, EntityType.getEntityNameList().stream().map(ResourceLocation::toString).sorted().toArray(String[]::new));
|
||||
+ break;
|
||||
+ }
|
||||
+ return Collections.emptyList();
|
||||
+ }
|
||||
+
|
||||
+ // Code from Mojang - copyright them
|
||||
+ public static List<String> getListMatchingLast(CommandSender sender, String[] args, String... matches) {
|
||||
+ return getListMatchingLast(sender, args, (Collection) 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.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
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean execute(CommandSender sender, String commandLabel, String[] args) {
|
||||
+ if (!testPermission(sender)) return true;
|
||||
+
|
||||
+ if (args.length == 0) {
|
||||
+ sender.sendMessage(text("Usage: " + this.usageMessage, RED));
|
||||
+ 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 "heap":
|
||||
+ dumpHeap(sender);
|
||||
+ break;
|
||||
+ case "entity":
|
||||
+ listEntities(sender, args);
|
||||
+ break;
|
||||
+ 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(text("Usage: " + this.usageMessage, RED));
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Ported from MinecraftForge - author: LexManos <LexManos@gmail.com> - License: LGPLv2.1
|
||||
+ */
|
||||
+ private void listEntities(CommandSender sender, String[] args) {
|
||||
+ if (args.length < 2 || args[1].toLowerCase(Locale.ENGLISH).equals("help")) {
|
||||
+ sender.sendMessage(text("Use /paper entity [list] help for more information on a specific command", RED));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ switch (args[1].toLowerCase(Locale.ENGLISH)) {
|
||||
+ case "list":
|
||||
+ String filter = "*";
|
||||
+ if (args.length > 2) {
|
||||
+ if (args[2].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[2];
|
||||
+ }
|
||||
+ final String cleanfilter = filter.replace("?", ".?").replace("*", ".*?");
|
||||
+ Set<ResourceLocation> names = EntityType.getEntityNameList().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 > 3) {
|
||||
+ worldName = args[3];
|
||||
+ } 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();
|
||||
+ 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) Bukkit.getWorld(worldName)).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, Integer.valueOf(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, Integer.valueOf(0)).intValue();
|
||||
+ 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 -> sender.sendMessage(" " + e.getValue() + ": " + e.getKey().x + ", " + e.getKey().z + (chunkProviderServer.isPositionTicking(e.getKey().toLong()) ? " (Ticking)" : " (Non-Ticking)")));
|
||||
+ } 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()))
|
||||
+ .collect(Collectors.toList());
|
||||
+
|
||||
+ if (info == null || info.size() == 0) {
|
||||
+ 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(), Integer.valueOf(0)).intValue();
|
||||
+ sender.sendMessage(" " + (e.getValue() - nonTicking) + " (" + nonTicking + ") " + ": " + e.getKey());
|
||||
+ });
|
||||
+ sender.sendMessage("* First number is ticking entities, second number is non-ticking entities");
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private void dumpHeap(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));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private void doReload(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 console = MinecraftServer.getServer();
|
||||
+ com.destroystokyo.paper.PaperConfig.init((File) console.options.valueOf("paper-settings"));
|
||||
+ for (ServerLevel world : console.getAllLevels()) {
|
||||
+ world.paperConfig.init();
|
||||
+ }
|
||||
+ console.server.reloadCount++;
|
||||
+
|
||||
+ Command.broadcastCommandMessage(sender, text("Paper config reload complete.", GREEN));
|
||||
+ }
|
||||
+}
|
@ -5,297 +5,6 @@ Subject: [PATCH] Paper config files
|
||||
|
||||
Loads each yml file for early init too so it can be used for early options
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+package com.destroystokyo.paper;
|
||||
+
|
||||
+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 com.google.common.collect.Maps;
|
||||
+import net.minecraft.resources.ResourceLocation;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+import net.minecraft.server.level.ServerChunkCache;
|
||||
+import net.minecraft.server.level.ServerLevel;
|
||||
+import net.minecraft.world.entity.Entity;
|
||||
+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.ChatColor;
|
||||
+import org.bukkit.Location;
|
||||
+import org.bukkit.World;
|
||||
+import org.bukkit.command.Command;
|
||||
+import org.bukkit.command.CommandSender;
|
||||
+import org.bukkit.craftbukkit.CraftServer;
|
||||
+import org.bukkit.craftbukkit.CraftWorld;
|
||||
+import org.bukkit.entity.Player;
|
||||
+
|
||||
+import java.io.File;
|
||||
+import java.time.LocalDateTime;
|
||||
+import java.time.format.DateTimeFormatter;
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.Arrays;
|
||||
+import java.util.Collection;
|
||||
+import java.util.Collections;
|
||||
+import java.util.Iterator;
|
||||
+import java.util.List;
|
||||
+import java.util.Locale;
|
||||
+import java.util.Map;
|
||||
+import java.util.Set;
|
||||
+import java.util.stream.Collectors;
|
||||
+
|
||||
+public class PaperCommand extends Command {
|
||||
+ private static final String BASE_PERM = "bukkit.command.paper.";
|
||||
+ private static final ImmutableSet<String> SUBCOMMANDS = ImmutableSet.<String>builder().add("heap", "entity", "reload", "version").build();
|
||||
+
|
||||
+ public PaperCommand(String name) {
|
||||
+ super(name);
|
||||
+ this.description = "Paper related commands";
|
||||
+ this.usageMessage = "/paper [" + Joiner.on(" | ").join(SUBCOMMANDS) + "]";
|
||||
+ this.setPermission("bukkit.command.paper;" + 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.paper")) return true;
|
||||
+ commandSender.sendMessage(ChatColor.RED + "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."); // Sorry, kashike
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException {
|
||||
+ if (args.length <= 1)
|
||||
+ return getListMatchingLast(sender, args, SUBCOMMANDS);
|
||||
+
|
||||
+ switch (args[0].toLowerCase(Locale.ENGLISH))
|
||||
+ {
|
||||
+ case "entity":
|
||||
+ if (args.length == 2)
|
||||
+ return getListMatchingLast(sender, args, "help", "list");
|
||||
+ if (args.length == 3)
|
||||
+ return getListMatchingLast(sender, args, EntityType.getEntityNameList().stream().map(ResourceLocation::toString).sorted().toArray(String[]::new));
|
||||
+ break;
|
||||
+ }
|
||||
+ return Collections.emptyList();
|
||||
+ }
|
||||
+
|
||||
+ // Code from Mojang - copyright them
|
||||
+ public static List<String> getListMatchingLast(CommandSender sender, String[] args, String... matches) {
|
||||
+ return getListMatchingLast(sender, args, (Collection) 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.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
|
||||
+
|
||||
+ @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 "heap":
|
||||
+ dumpHeap(sender);
|
||||
+ break;
|
||||
+ case "entity":
|
||||
+ listEntities(sender, args);
|
||||
+ break;
|
||||
+ 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;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Ported from MinecraftForge - author: LexManos <LexManos@gmail.com> - License: LGPLv2.1
|
||||
+ */
|
||||
+ private void listEntities(CommandSender sender, String[] args) {
|
||||
+ if (args.length < 2 || args[1].toLowerCase(Locale.ENGLISH).equals("help")) {
|
||||
+ sender.sendMessage(ChatColor.RED + "Use /paper entity [list] help for more information on a specific command.");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ switch (args[1].toLowerCase(Locale.ENGLISH)) {
|
||||
+ case "list":
|
||||
+ String filter = "*";
|
||||
+ if (args.length > 2) {
|
||||
+ if (args[2].toLowerCase(Locale.ENGLISH).equals("help")) {
|
||||
+ sender.sendMessage(ChatColor.RED + "Use /paper entity list [filter] [worldName] to get entity info that matches the optional filter.");
|
||||
+ return;
|
||||
+ }
|
||||
+ filter = args[2];
|
||||
+ }
|
||||
+ final String cleanfilter = filter.replace("?", ".?").replace("*", ".*?");
|
||||
+ Set<ResourceLocation> names = EntityType.getEntityNameList().stream()
|
||||
+ .filter(n -> n.toString().matches(cleanfilter))
|
||||
+ .collect(Collectors.toSet());
|
||||
+
|
||||
+ if (names.isEmpty()) {
|
||||
+ sender.sendMessage(ChatColor.RED + "Invalid filter, does not match any entities. Use /paper entity list for a proper list");
|
||||
+ sender.sendMessage(ChatColor.RED + "Usage: /paper entity list [filter] [worldName]");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ String worldName;
|
||||
+ if (args.length > 3) {
|
||||
+ worldName = args[3];
|
||||
+ } else if (sender instanceof Player) {
|
||||
+ worldName = ((Player) sender).getWorld().getName();
|
||||
+ } else {
|
||||
+ sender.sendMessage(ChatColor.RED + "Please specify the name of a world");
|
||||
+ sender.sendMessage(ChatColor.RED + "To do so without a filter, specify '*' as the filter");
|
||||
+ sender.sendMessage(ChatColor.RED + "Usage: /paper entity list [filter] [worldName]");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ Map<ResourceLocation, MutablePair<Integer, Map<ChunkPos, Integer>>> list = Maps.newHashMap();
|
||||
+ World bukkitWorld = Bukkit.getWorld(worldName);
|
||||
+ if (bukkitWorld == null) {
|
||||
+ sender.sendMessage(ChatColor.RED + "Could not load world for " + worldName + ". Please select a valid world.");
|
||||
+ sender.sendMessage(ChatColor.RED + "Usage: /paper entity list [filter] [worldName]");
|
||||
+ return;
|
||||
+ }
|
||||
+ ServerLevel world = ((CraftWorld) Bukkit.getWorld(worldName)).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, Integer.valueOf(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, Integer.valueOf(0)).intValue();
|
||||
+ if (info == null) {
|
||||
+ sender.sendMessage(ChatColor.RED + "No entities found.");
|
||||
+ 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 -> sender.sendMessage(" " + e.getValue() + ": " + e.getKey().x + ", " + e.getKey().z + (chunkProviderServer.isPositionTicking(e.getKey().toLong()) ? " (Ticking)" : " (Non-Ticking)")));
|
||||
+ } 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()))
|
||||
+ .collect(Collectors.toList());
|
||||
+
|
||||
+ if (info == null || info.size() == 0) {
|
||||
+ sender.sendMessage(ChatColor.RED + "No entities found.");
|
||||
+ 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(), Integer.valueOf(0)).intValue();
|
||||
+ sender.sendMessage(" " + (e.getValue() - nonTicking) + " (" + nonTicking + ") " + ": " + e.getKey());
|
||||
+ });
|
||||
+ sender.sendMessage("* First number is ticking entities, second number is non-ticking entities");
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private void dumpHeap(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, ChatColor.YELLOW + "Writing JVM heap data...");
|
||||
+
|
||||
+ java.nio.file.Path file = CraftServer.dumpHeap(dir, name);
|
||||
+ if (file != null) {
|
||||
+ Command.broadcastCommandMessage(sender, ChatColor.GREEN + "Heap dump saved to " + file);
|
||||
+ } else {
|
||||
+ Command.broadcastCommandMessage(sender, ChatColor.RED + "Failed to write heap dump, see sever log for details");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ 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();
|
||||
+ com.destroystokyo.paper.PaperConfig.init((File) console.options.valueOf("paper-settings"));
|
||||
+ for (ServerLevel world : console.getAllLevels()) {
|
||||
+ world.paperConfig.init();
|
||||
+ }
|
||||
+ console.server.reloadCount++;
|
||||
+
|
||||
+ Command.broadcastCommandMessage(sender, ChatColor.GREEN + "Paper config reload complete.");
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
|
@ -27,7 +27,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
@@ -0,0 +0,0 @@ import java.util.stream.Collectors;
|
||||
@@ -0,0 +0,0 @@ import static net.kyori.adventure.text.format.NamedTextColor.YELLOW;
|
||||
|
||||
public class PaperCommand extends Command {
|
||||
private static final String BASE_PERM = "bukkit.command.paper.";
|
||||
@ -48,7 +48,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
break;
|
||||
@@ -0,0 +0,0 @@ public class PaperCommand extends Command {
|
||||
|
||||
Command.broadcastCommandMessage(sender, ChatColor.GREEN + "Paper config reload complete.");
|
||||
Command.broadcastCommandMessage(sender, text("Paper config reload complete.", GREEN));
|
||||
}
|
||||
+ private void doDumpItem(CommandSender sender) {
|
||||
+ if (!(sender instanceof Player)) {
|
||||
|
@ -4375,20 +4375,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ lightengine.relight(chunks,
|
||||
+ (ChunkPos chunkPos) -> {
|
||||
+ ++relitChunks[0];
|
||||
+ sender.getBukkitEntity().sendMessage(
|
||||
+ ChatColor.BLUE + "Relit chunk " + ChatColor.DARK_AQUA + chunkPos + ChatColor.BLUE +
|
||||
+ ", progress: " + ChatColor.DARK_AQUA + (int)(Math.round(100.0 * (double)(relitChunks[0])/(double)pending[0])) + "%"
|
||||
+ );
|
||||
+ sender.getBukkitEntity().sendMessage(text().color(DARK_AQUA).append(
|
||||
+ text("Relit chunk ", BLUE), text(chunkPos.toString()),
|
||||
+ text(", progress: ", BLUE), text((int)(Math.round(100.0 * (double)(relitChunks[0])/(double)pending[0])) + "%")
|
||||
+ ));
|
||||
+ },
|
||||
+ (int totalRelit) -> {
|
||||
+ final long end = System.nanoTime();
|
||||
+ final long diff = Math.round(1.0e-6*(end - start));
|
||||
+ sender.getBukkitEntity().sendMessage(
|
||||
+ ChatColor.BLUE + "Relit " + ChatColor.DARK_AQUA + totalRelit + ChatColor.BLUE + " chunks. Took " +
|
||||
+ ChatColor.DARK_AQUA + diff + "ms"
|
||||
+ );
|
||||
+ sender.getBukkitEntity().sendMessage(text().color(DARK_AQUA).append(
|
||||
+ text("Relit ", BLUE), text(totalRelit),
|
||||
+ text(" chunks. Took ", BLUE), text(diff + "ms")
|
||||
+ ));
|
||||
+ });
|
||||
+ sender.getBukkitEntity().sendMessage(ChatColor.BLUE + "Relighting " + ChatColor.DARK_AQUA + pending[0] + ChatColor.BLUE + " chunks");
|
||||
+ sender.getBukkitEntity().sendMessage(text().color(BLUE).append(text("Relighting "), text(pending[0], DARK_AQUA), text(" chunks")));
|
||||
+ }
|
||||
+ // Paper end - rewrite light engine
|
||||
+
|
||||
|
@ -193,14 +193,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+package co.aikar.timings;
|
||||
+
|
||||
+import com.google.common.collect.Sets;
|
||||
+import io.papermc.paper.adventure.PaperAdventure;
|
||||
+import net.kyori.adventure.text.format.NamedTextColor;
|
||||
+import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+import org.apache.commons.lang.StringUtils;
|
||||
+import org.bukkit.Bukkit;
|
||||
+import org.bukkit.ChatColor;
|
||||
+import org.bukkit.Material;
|
||||
+import org.bukkit.configuration.ConfigurationSection;
|
||||
+import org.bukkit.configuration.MemorySection;
|
||||
+import org.bukkit.craftbukkit.util.CraftChatMessage;
|
||||
+import org.bukkit.entity.EntityType;
|
||||
+import org.json.simple.JSONObject;
|
||||
+import org.json.simple.JSONValue;
|
||||
@ -230,6 +231,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+import static co.aikar.util.JSONUtil.toArray;
|
||||
+import static co.aikar.util.JSONUtil.toArrayMapper;
|
||||
+import static co.aikar.util.JSONUtil.toObjectMapper;
|
||||
+import static net.kyori.adventure.text.Component.text;
|
||||
+
|
||||
+@SuppressWarnings({"rawtypes", "SuppressionAnnotation"})
|
||||
+public class TimingsExport extends Thread {
|
||||
@ -260,17 +262,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ long now = System.currentTimeMillis();
|
||||
+ final long lastReportDiff = now - lastReport;
|
||||
+ if (lastReportDiff < 60000) {
|
||||
+ listeners.sendMessage(ChatColor.RED + "Please wait at least 1 minute in between Timings reports. (" + (int)((60000 - lastReportDiff) / 1000) + " seconds)");
|
||||
+ listeners.sendMessage(text("Please wait at least 1 minute in between Timings reports. (" + (int)((60000 - lastReportDiff) / 1000) + " seconds)", NamedTextColor.RED));
|
||||
+ listeners.done();
|
||||
+ return;
|
||||
+ }
|
||||
+ final long lastStartDiff = now - TimingsManager.timingStart;
|
||||
+ if (lastStartDiff < 180000) {
|
||||
+ listeners.sendMessage(ChatColor.RED + "Please wait at least 3 minutes before generating a Timings report. Unlike Timings v1, v2 benefits from longer timings and is not as useful with short timings. (" + (int)((180000 - lastStartDiff) / 1000) + " seconds)");
|
||||
+ listeners.sendMessage(text("Please wait at least 3 minutes before generating a Timings report. Unlike Timings v1, v2 benefits from longer timings and is not as useful with short timings. (" + (int)((180000 - lastStartDiff) / 1000) + " seconds)", NamedTextColor.RED));
|
||||
+ listeners.done();
|
||||
+ return;
|
||||
+ }
|
||||
+ listeners.sendMessage(ChatColor.GREEN + "Preparing Timings Report...");
|
||||
+ listeners.sendMessage(text("Preparing Timings Report...", NamedTextColor.GREEN));
|
||||
+ lastReport = now;
|
||||
+ Map parent = createObject(
|
||||
+ // Get some basic system details about the server
|
||||
@ -281,7 +283,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ pair("online-mode", Bukkit.getServer().getOnlineMode()),
|
||||
+ pair("sampletime", (System.currentTimeMillis() - TimingsManager.timingStart) / 1000),
|
||||
+ pair("datapacks", toArrayMapper(MinecraftServer.getServer().getPackRepository().getSelectedPacks(), pack -> {
|
||||
+ return ChatColor.stripColor(CraftChatMessage.fromComponent(pack.getChatLink(true)));
|
||||
+ return PlainTextComponentSerializer.plainText().serialize(PaperAdventure.asAdventure(pack.getChatLink(true)));
|
||||
+ }))
|
||||
+ );
|
||||
+ if (!TimingsManager.privacy) {
|
||||
@ -500,9 +502,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ response = getResponse(con);
|
||||
+
|
||||
+ if (con.getResponseCode() != 302) {
|
||||
+ listeners.sendMessage(
|
||||
+ ChatColor.RED + "Upload Error: " + con.getResponseCode() + ": " + con.getResponseMessage());
|
||||
+ listeners.sendMessage(ChatColor.RED + "Check your logs for more information");
|
||||
+ listeners.sendMessage(text( "Upload Error: " + con.getResponseCode() + ": " + con.getResponseMessage(), NamedTextColor.RED));
|
||||
+ listeners.sendMessage(text("Check your logs for more information", NamedTextColor.RED));
|
||||
+ if (response != null) {
|
||||
+ Bukkit.getLogger().log(Level.SEVERE, response);
|
||||
+ }
|
||||
@ -510,13 +511,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ }
|
||||
+
|
||||
+ timingsURL = con.getHeaderField("Location");
|
||||
+ listeners.sendMessage(ChatColor.GREEN + "View Timings Report: " + timingsURL);
|
||||
+ listeners.sendMessage(text("View Timings Report: " + timingsURL, NamedTextColor.GREEN));
|
||||
+
|
||||
+ if (response != null && !response.isEmpty()) {
|
||||
+ Bukkit.getLogger().log(Level.INFO, "Timing Response: " + response);
|
||||
+ }
|
||||
+ } catch (IOException ex) {
|
||||
+ listeners.sendMessage(ChatColor.RED + "Error uploading timings, check your logs for more information");
|
||||
+ listeners.sendMessage(text("Error uploading timings, check your logs for more information", NamedTextColor.RED));
|
||||
+ if (response != null) {
|
||||
+ Bukkit.getLogger().log(Level.SEVERE, response);
|
||||
+ }
|
||||
@ -540,7 +541,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ return bos.toString();
|
||||
+
|
||||
+ } catch (IOException ex) {
|
||||
+ listeners.sendMessage(ChatColor.RED + "Error uploading timings, check your logs for more information");
|
||||
+ listeners.sendMessage(text("Error uploading timings, check your logs for more information", NamedTextColor.RED));
|
||||
+ Bukkit.getLogger().log(Level.WARNING, con.getResponseMessage(), ex);
|
||||
+ return null;
|
||||
+ } finally {
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren