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
394 changes: 171 additions & 223 deletions paper-server/patches/features/0001-Moonrise-optimisation-patches.patch

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions paper-server/patches/features/0029-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 485413cb6b20c4bd20fbc29a0db43c051993fe79..22f37a0779996c9e3a9416a2a1ba2bee74e3f568 100644
index aabeb29a7f3d593ad78d47cb6baa932f0dffa5aa..5464eb75e1bbf2962491fcc13bcfe3d771644f79 100644
--- a/io/papermc/paper/FeatureHooks.java
+++ b/io/papermc/paper/FeatureHooks.java
@@ -48,20 +48,25 @@ public final class FeatureHooks {
@@ -53,20 +53,25 @@ public final class FeatureHooks {
}

public static LevelChunkSection createSection(final PalettedContainerFactory palettedContainerFactory, final Level level, final ChunkPos chunkPos, final int chunkSection) {
Expand Down Expand Up @@ -184,7 +184,7 @@ index c65b274b965b95eae33690e63c5da2d5a9f2981a..644948d64791d0ffa4166375d0f4419f
if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) {
new io.papermc.paper.event.packet.PlayerChunkLoadEvent(new org.bukkit.craftbukkit.CraftChunk(chunk), packetListener.getPlayer().getBukkitEntity()).callEvent();
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index a17d021269c65d98a2ba847c0059a421ea051863..9f86d1fc4ea4c6987fa207644573565aea7edead 100644
index dec9dd8e42f90ccf7e5e3ad945e459d07159250d..989ac565c47a70c7947cb7315d0f5c2cfecd0363 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -329,7 +329,7 @@ public abstract class PlayerList {
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 +_,243 @@
@@ -1,0 +_,244 @@
+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 @@ -41,7 +42,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 @@ -112,7 +112,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
+ thread.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 legacy 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