Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ ij_java_method_parameters_right_paren_on_new_line = true
ij_java_use_fq_class_names = false
ij_java_class_names_in_javadoc = 1

[paper-server/src/minecraft/java/**/*.java]
[paper-server/src/minecraft/java/{net/minecraft,com/mojang}/**/*.java]
ij_java_use_fq_class_names = true

[paper-server/src/minecraft/resources/data/**/*.json]
Expand Down
7 changes: 5 additions & 2 deletions paper-api/src/main/java/org/bukkit/event/HandlerList.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import java.util.EnumMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredListener;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -36,7 +38,8 @@ public class HandlerList {
/**
* Event types which have instantiated a {@link HandlerList}.
*/
private static final java.util.Set<String> EVENT_TYPES = java.util.concurrent.ConcurrentHashMap.newKeySet();
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private static final Map<String, HandlerList> EVENT_TYPES = new ConcurrentHashMap<>();

/**
* Bake all handler lists. Best used just after all normal event
Expand Down Expand Up @@ -102,7 +105,7 @@ public HandlerList() {
java.lang.StackWalker.getInstance(java.util.EnumSet.of(java.lang.StackWalker.Option.RETAIN_CLASS_REFERENCE), 4)
.walk(s -> s.filter(f -> Event.class.isAssignableFrom(f.getDeclaringClass())).findFirst())
.map(f -> f.getDeclaringClass().getName())
.ifPresent(EVENT_TYPES::add);
.ifPresent(name -> EVENT_TYPES.put(name, this));

handlerslots = new EnumMap<>(EventPriority.class);
for (EventPriority o : EventPriority.values()) {
Expand Down
358 changes: 172 additions & 186 deletions paper-server/patches/features/0001-Moonrise-optimisation-patches.patch

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions paper-server/patches/features/0030-Anti-Xray.patch
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ Subject: [PATCH] Anti-Xray


diff --git a/io/papermc/paper/FeatureHooks.java b/io/papermc/paper/FeatureHooks.java
index fadce1c051e6c7bc0c3d041c0cc8ecd7e1ae43e0..4dd1baf17597d8801a286346a2b74345f4d23dfa 100644
index 4da3c7b78e8c52823cb2bec18c4e55bbcd9164ed..944698477273c94ce1a2ca27ec1a245be4cf2f8e 100644
--- a/io/papermc/paper/FeatureHooks.java
+++ b/io/papermc/paper/FeatureHooks.java
@@ -47,20 +47,25 @@ public final class FeatureHooks {
@@ -51,20 +51,25 @@ public final class FeatureHooks {
}

public static LevelChunkSection createSection(final PalettedContainerFactory palettedContainerFactory, final Level level, final ChunkPos chunkPos, final int chunkSection) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
--- /dev/null
+++ b/io/papermc/paper/FeatureHooks.java
@@ -1,0 +_,248 @@
@@ -1,0 +_,249 @@
+package io.papermc.paper;
+
+import io.papermc.paper.command.PaperSubcommand;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import io.papermc.paper.command.brigadier.CommandSourceStack;
+import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
+import it.unimi.dsi.fastutil.longs.LongSet;
+import it.unimi.dsi.fastutil.longs.LongSets;
Expand Down Expand Up @@ -40,7 +41,7 @@
+ public static void setPlayerChunkUnloadDelay(final long ticks) {
+ }
+
+ public static void registerPaperCommands(final Map<Set<String>, PaperSubcommand> commands) {
+ public static void registerPaperCommands(final List<LiteralArgumentBuilder<CommandSourceStack>> commands) {
+ }
+
+ public static LevelChunkSection createSection(final PalettedContainerFactory palettedContainerFactory, final Level level, final ChunkPos chunkPos, final int chunkSection) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@
+ // Paper end - fix converting txt to json file
+ org.spigotmc.WatchdogThread.doStart(org.spigotmc.SpigotConfig.timeoutTime, org.spigotmc.SpigotConfig.restartOnCrash); // Paper - start watchdog thread
+ consoleThread.start(); // Paper - Enhance console tab completions for brigadier commands; start console thread after MinecraftServer.console & PaperConfig are initialized
+ io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command
+ io.papermc.paper.command.PaperCommands.registerLegacyCommands(this); // Paper - setup /paper command
+ this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark
+ com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics
+ com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
Expand Down

This file was deleted.

177 changes: 57 additions & 120 deletions paper-server/src/main/java/io/papermc/paper/command/PaperCommand.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package io.papermc.paper.command;

import com.mojang.brigadier.Command;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.tree.LiteralCommandNode;
import io.papermc.paper.FeatureHooks;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.command.brigadier.Commands;
import io.papermc.paper.command.subcommands.DumpItemCommand;
import io.papermc.paper.command.subcommands.DumpListenersCommand;
import io.papermc.paper.command.subcommands.DumpPluginsCommand;
Expand All @@ -10,149 +15,81 @@
import io.papermc.paper.command.subcommands.ReloadCommand;
import io.papermc.paper.command.subcommands.SyncLoadInfoCommand;
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 it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.nio.file.Path;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import net.minecraft.util.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 org.jspecify.annotations.NullMarked;

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<>();
@NullMarked
public final class PaperCommand {

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());
commands.put(Set.of("dumpplugins"), new DumpPluginsCommand());
commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand());
commands.put(Set.of("dumpitem"), new DumpItemCommand());
commands.put(Set.of("mobcaps", "playermobcaps"), new MobcapsCommand());
commands.put(Set.of("dumplisteners"), new DumpListenersCommand());
FeatureHooks.registerPaperCommands(commands);
public static final DateTimeFormatter FILENAME_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss", Locale.ROOT); // could use the formatter in Util too

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));
});
private static final Set<String> COMPLETABLE_SUBCOMMANDS = SUBCOMMANDS.entrySet().stream().filter(entry -> entry.getValue().tabCompletes()).map(Map.Entry::getKey).collect(Collectors.toSet());
// 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));
}
public static Component asFriendlyPath(final Path path) {
return text(path.toString())
.hoverEvent(text("Click to copy the full path of the file"))
.clickEvent(ClickEvent.copyToClipboard(path.toAbsolutePath().toString()));
}

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(Bukkit.permissionMessage());
return false;
}
public static final String BASE_PERM = "bukkit.command.paper";
static final String DESCRIPTION = "Paper related commands";

@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, COMPLETABLE_SUBCOMMANDS);
}
public static LiteralCommandNode<CommandSourceStack> create() {
final LiteralArgumentBuilder<CommandSourceStack> rootNode = Commands.literal("paper")
.requires(source -> source.getSender().hasPermission(BASE_PERM) || SUBPERMISSIONS.stream().anyMatch(name -> source.getSender().hasPermission(name)))
.executes(context -> {
context.getSource().getSender().sendPlainMessage("/paper [" + SUBCOMMANDS.keySet().stream().filter(
name -> hasPermission(name).test(context.getSource())
).collect(Collectors.joining(" | ")) + "]");
return Command.SINGLE_SUCCESS;
});

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));
}
SUBCOMMANDS.values().forEach(rootNode::then);
rootNode.then(VersionCommand.create("ver"));

return Collections.emptyList();
return rootNode.build();
}

@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);
public static Predicate<CommandSourceStack> hasPermission(String name) {
return source -> source.getSender().hasPermission(BASE_PERM) || source.getSender().hasPermission(BASE_PERM + '.' + name);
}

private static @Nullable Pair<String, PaperSubcommand> resolveCommand(String label) {
label = label.toLowerCase(Locale.ROOT);
@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);
public static void registerPermissions() {
final PluginManager pluginManager = Bukkit.getServer().getPluginManager();
pluginManager.addPermission(new Permission(BASE_PERM, PermissionDefault.OP));
for (final String permission : SUBPERMISSIONS) {
pluginManager.addPermission(new Permission(permission, PermissionDefault.OP));
}

return null;
}

private static final Map<String, LiteralArgumentBuilder<CommandSourceStack>> SUBCOMMANDS = Util.make(new ObjectArrayList<LiteralArgumentBuilder<CommandSourceStack>>(), list -> {
list.add(HeapDumpCommand.create());
list.add(EntityCommand.create());
list.add(ReloadCommand.create());
list.add(VersionCommand.create("version"));
list.add(DumpPluginsCommand.create());
list.add(SyncLoadInfoCommand.create());
list.add(DumpItemCommand.create());
list.add(MobcapsCommand.createGlobal());
list.add(MobcapsCommand.createPlayer());
list.add(DumpListenersCommand.create());
FeatureHooks.registerPaperCommands(list);
}).stream().collect(Collectors.toMap(LiteralArgumentBuilder::getLiteral, Function.identity()));

private static final List<String> SUBPERMISSIONS = SUBCOMMANDS.keySet().stream().map(name -> BASE_PERM + '.' + name).toList();
}
Loading
Loading