Merge remote-tracking branch 'upstream/main'

This commit is contained in:
2025-06-26 22:39:23 +02:00
67 changed files with 1021 additions and 521 deletions

View File

@@ -1,3 +1,4 @@
import io.papermc.fill.model.BuildChannel
import io.papermc.paperweight.attribute.DevBundleOutput
import io.papermc.paperweight.util.*
import io.papermc.paperweight.util.data.FileEntry
@@ -10,6 +11,7 @@ plugins {
`maven-publish`
idea
id("io.papermc.paperweight.core")
id("io.papermc.fill.gradle") version "1.0.3"
}
val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/"
@@ -132,7 +134,7 @@ dependencies {
implementation("org.jline:jline-terminal-ffm:3.27.1") // use ffm on java 22+
implementation("org.jline:jline-terminal-jni:3.27.1") // fall back to jni on java 21
implementation("net.minecrell:terminalconsoleappender:1.3.0")
implementation("net.kyori:adventure-text-serializer-ansi:4.21.0") // Keep in sync with adventureVersion from Paper-API build file
implementation("net.kyori:adventure-text-serializer-ansi:4.23.0") // Keep in sync with adventureVersion from Paper-API build file
runtimeConfiguration(sourceSets.main.map { it.runtimeClasspath })
/*
@@ -372,3 +374,20 @@ tasks.registerRunTask("runReobfPaperclip") {
classpath(tasks.createReobfPaperclipJar.flatMap { it.outputZip })
mainClass.set(null as String?)
}
fill {
project("paper")
versionFamily(paperweight.minecraftVersion.map { it.split(".", "-").takeWhile { part -> part.toIntOrNull() != null }.take(2).joinToString(".") })
version(paperweight.minecraftVersion)
build {
channel = BuildChannel.STABLE
downloads {
register("server:default") {
file = tasks.createMojmapPaperclipJar.flatMap { it.outputZip }
nameResolver.set { project, _, version, build -> "$project-$version-$build.jar" }
}
}
}
}

View File

@@ -354,7 +354,7 @@ index 0000000000000000000000000000000000000000..ae2bb9a73106febfe5f0d090abd4252b
+ }
+}
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
index 7b5ed00c9b2f22af5cbc44171192d674936dc7d7..5fe3c9a159908785e08fa874982bc1a82283bb1d 100644
index d51645b115780dac9ff6010806e8bd62dedc8e9f..3faf1b5556c55f3468182f75b2dbff4aaa3aae3a 100644
--- a/net/minecraft/server/level/ChunkMap.java
+++ b/net/minecraft/server/level/ChunkMap.java
@@ -4,7 +4,6 @@ import com.google.common.collect.ImmutableList;
@@ -484,7 +484,7 @@ index c70a58f5f633fa8e255f74c42f5e87c96b7b013a..ec20a5a6d7c8f65abda528fec36bec7b
public void tick() {
super.tick();
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index f961540a00bfb5e1c8eb0e739f8ae535e9eee8f3..7453ddb09f349b7836f966573e4933646a75cba6 100644
index 75f81a6bc156a6455a616b8de0d7701fd2255a2d..b3d951670b3a097d04cfe347d7df496b1d0a0e09 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -409,6 +409,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -661,10 +661,10 @@ index 3f780276be6766ef253c50212e06fd93a96b0caa..7e70c7bee633c54497d1cd2854dd60f4
}
}
diff --git a/net/minecraft/world/entity/item/ItemEntity.java b/net/minecraft/world/entity/item/ItemEntity.java
index 548d7c8dc517da6c4db86b11f579ae63e6db56cf..a29860af4c37b2b45df49f9ba18f7e38921dfb02 100644
index fca31bbab8e7830933ceffcf992ff56ccc84414c..51804b611f469f2ab53e455e8c633b867b00cc88 100644
--- a/net/minecraft/world/entity/item/ItemEntity.java
+++ b/net/minecraft/world/entity/item/ItemEntity.java
@@ -121,6 +121,29 @@ public class ItemEntity extends Entity implements TraceableEntity {
@@ -129,6 +129,29 @@ public class ItemEntity extends Entity implements TraceableEntity {
return 0.04;
}
@@ -695,7 +695,7 @@ index 548d7c8dc517da6c4db86b11f579ae63e6db56cf..a29860af4c37b2b45df49f9ba18f7e38
public void tick() {
if (this.getItem().isEmpty()) {
diff --git a/net/minecraft/world/entity/npc/Villager.java b/net/minecraft/world/entity/npc/Villager.java
index b0607f4a9b35570b319423c7876bb904d5154e8e..98c8653647dc52059d8becfe38a74d4e62edf08f 100644
index ef8347329b440833b45a54be2b6e4204ac0a425e..43f16df230f87a43e249a58fc10ef2da517f22ee 100644
--- a/net/minecraft/world/entity/npc/Villager.java
+++ b/net/minecraft/world/entity/npc/Villager.java
@@ -269,11 +269,35 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
@@ -838,7 +838,7 @@ index 52acc72841f0c6980f5f3f8ef21d0b29dd472ce3..41a6ec508a10a49a37539d2f10171d15
+
}
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index d26e4d85d8fd8bd4f0c7de30b50a2ce370b37bf5..bab28e7afb7b1249d40631aabff16fc18cf95ea0 100644
index 06069d3ac598f5f12feab038de4f1199794298f6..980eaba27ce2616c1573a4760cf4acc2dd251190 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -143,6 +143,12 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl

View File

@@ -5,10 +5,10 @@ Subject: [PATCH] Anti-Xray
diff --git a/io/papermc/paper/FeatureHooks.java b/io/papermc/paper/FeatureHooks.java
index 55cc0dec4a88baea17f160e95d5d8316e0bb7a50..338dc0fb07cdba5f7350cca332fa3e942c622bfb 100644
index 811a8e5141f2061a185b53b63d951646141c0c7d..33d3eb510c5844e72bbc382bd24641aae080962d 100644
--- a/io/papermc/paper/FeatureHooks.java
+++ b/io/papermc/paper/FeatureHooks.java
@@ -40,20 +40,25 @@ public final class FeatureHooks {
@@ -45,20 +45,25 @@ public final class FeatureHooks {
}
public static LevelChunkSection createSection(final Registry<Biome> biomeRegistry, final Level level, final ChunkPos chunkPos, final int chunkSection) {

View File

@@ -14,17 +14,17 @@ movement will load only the chunk the player enters anyways and avoids loading
massive amounts of surrounding chunks due to large AABB lookups.
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index 7453ddb09f349b7836f966573e4933646a75cba6..58eda0d6426f30cda604f4120f1ddb012316c108 100644
index 23dfc87db1d5e90099270627197abc0f787a4393..27a01fd28ea565221768f31df02f0a2ddf242fce 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -229,6 +229,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
// Paper end - Share random for entities to make them more random
@@ -230,6 +230,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
public @Nullable org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; // Paper - Entity#getEntitySpawnReason
private volatile @Nullable org.bukkit.craftbukkit.entity.CraftEntity bukkitEntity; // Paper - Folia schedulers - volatile
+ public boolean collisionLoadChunks = false; // Paper
private @Nullable org.bukkit.craftbukkit.entity.CraftEntity bukkitEntity;
public org.bukkit.craftbukkit.entity.CraftEntity getBukkitEntity() {
if (this.bukkitEntity == null) {
diff --git a/net/minecraft/world/level/BlockCollisions.java b/net/minecraft/world/level/BlockCollisions.java
index ed6e4f9fd0c7ad1219e66bc1cb4038191dd6edd8..45a20dbb935b12d429153463dba5d6fd3385dd7a 100644
--- a/net/minecraft/world/level/BlockCollisions.java

View File

@@ -32481,7 +32481,7 @@ index 0000000000000000000000000000000000000000..b028017b9c44821a8a313a04e0b10f5d
+ }
+}
diff --git a/ca/spottedleaf/moonrise/paper/PaperHooks.java b/ca/spottedleaf/moonrise/paper/PaperHooks.java
index 0c611598a6912b692a7639301811ee557e2304f1..6f65564f6a6e99d6549de9a23a031b1f4a8a9798 100644
index e4f0653c575c33b1ef8160b6c88e29ee9fb44508..b6a34796d33f1593301c3a67a013fa7e812cb329 100644
--- a/ca/spottedleaf/moonrise/paper/PaperHooks.java
+++ b/ca/spottedleaf/moonrise/paper/PaperHooks.java
@@ -211,6 +211,43 @@ public final class PaperHooks extends BaseChunkSystemHooks implements PlatformHo
@@ -32542,7 +32542,7 @@ index 6536dc08c80170f5679acedd65cd2b9f6ad3fb3a..294cd15a796ad25823c8ccf98fbfae46
return structureTemplate.save(new CompoundTag());
}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 794a01ee70a2a30d91550f5265f774ba73828cf9..c716521fb1497dc8a22d827ddb50fc1cc21a05f4 100644
index 2d597e50dcd957bd566c4da384fac5f36b5362f7..75aba65cbe1a943f21c7464ff9465e64f63e8e5b 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -305,6 +305,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -32585,10 +32585,10 @@ index 8c1417c659ea0e079e99b9bfa79e1cf6ba9b712b..a8a32edea080f32fd25c9e009d4efa41
if (stopBelowZero) {
chunkData.putString("Status", net.minecraft.core.registries.BuiltInRegistries.CHUNK_STATUS.getKey(net.minecraft.world.level.chunk.status.ChunkStatus.SPAWN).toString());
diff --git a/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java b/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java
index 6be673172548c1382c7402ec4e1ec6ef51f702d3..18750f1ea3101b6c0ab0b8e33c304eb7fa1ed04d 100644
index 6be673172548c1382c7402ec4e1ec6ef51f702d3..49be43ac896d60587511a97445c53c10c587a341 100644
--- a/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java
+++ b/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java
@@ -32,13 +32,30 @@ public class SimpleRegionStorage implements AutoCloseable {
@@ -32,13 +32,32 @@ public class SimpleRegionStorage implements AutoCloseable {
return this.worker.store(chunkPos, data);
}
@@ -32609,7 +32609,9 @@ index 6be673172548c1382c7402ec4e1ec6ef51f702d3..18750f1ea3101b6c0ab0b8e33c304eb7
- return this.dataFixType.updateToCurrentVersion(this.fixerUpper, tag, dataVersion);
+ // Paper start - rewrite data conversion system
+ final int dataVer = NbtUtils.getDataVersion(tag, version);
+ return ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(this.getDataConverterType(), tag, dataVer, ca.spottedleaf.dataconverter.minecraft.util.Version.getCurrentVersion());
+ final CompoundTag ret = ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(this.getDataConverterType(), tag, dataVer, ca.spottedleaf.dataconverter.minecraft.util.Version.getCurrentVersion());
+ NbtUtils.addCurrentDataVersion(ret); // Fix MC-299110
+ return ret;
+ // Paper end - rewrite data conversion system
}

View File

@@ -23061,7 +23061,7 @@ index 0000000000000000000000000000000000000000..f1f72a051083b61273202cb4e67ecb11
+ private SaveUtil() {}
+}
diff --git a/io/papermc/paper/FeatureHooks.java b/io/papermc/paper/FeatureHooks.java
index 338dc0fb07cdba5f7350cca332fa3e942c622bfb..e1fe49e4bf014e2405708270efd81bab4e1512da 100644
index b1a7af2dd3a3e166b1e58125f13ce08b9ec6d9ff..df6fbb35e5023b42de0b97434712e04a6b3e66a3 100644
--- a/io/papermc/paper/FeatureHooks.java
+++ b/io/papermc/paper/FeatureHooks.java
@@ -1,6 +1,9 @@
@@ -23074,8 +23074,13 @@ index 338dc0fb07cdba5f7350cca332fa3e942c622bfb..e1fe49e4bf014e2405708270efd81bab
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import it.unimi.dsi.fastutil.longs.LongSet;
import it.unimi.dsi.fastutil.longs.LongSets;
@@ -31,12 +34,16 @@ import org.bukkit.World;
public final class FeatureHooks {
@@ -32,16 +35,20 @@ public final class FeatureHooks {
// this includes non-accessible entities
public static Iterable<Entity> getAllEntities(final net.minecraft.server.level.ServerLevel world) {
- return ((net.minecraft.world.level.entity.LevelEntityGetterAdapter<Entity>)world.getEntities()).sectionStorage.getAllEntities();
+ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup)world.getEntities()).getAllMapped(); // Paper - rewrite chunk system
}
public static void setPlayerChunkUnloadDelay(final long ticks) {
+ ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.setUnloadDelay(ticks); // Paper - rewrite chunk system
@@ -23091,7 +23096,7 @@ index 338dc0fb07cdba5f7350cca332fa3e942c622bfb..e1fe49e4bf014e2405708270efd81bab
}
public static LevelChunkSection createSection(final Registry<Biome> biomeRegistry, final Level level, final ChunkPos chunkPos, final int chunkSection) {
@@ -62,111 +69,58 @@ public final class FeatureHooks {
@@ -67,111 +74,58 @@ public final class FeatureHooks {
}
public static Set<Long> getSentChunkKeys(final ServerPlayer player) {
@@ -23224,7 +23229,7 @@ index 338dc0fb07cdba5f7350cca332fa3e942c622bfb..e1fe49e4bf014e2405708270efd81bab
org.bukkit.Chunk chunk = null;
for (net.minecraft.server.level.Ticket ticket : tickets) {
@@ -186,15 +140,15 @@ public final class FeatureHooks {
@@ -191,15 +145,15 @@ public final class FeatureHooks {
}
public static int getViewDistance(net.minecraft.server.level.ServerLevel world) {
@@ -23243,7 +23248,7 @@ index 338dc0fb07cdba5f7350cca332fa3e942c622bfb..e1fe49e4bf014e2405708270efd81bab
}
public static void setViewDistance(net.minecraft.server.level.ServerLevel world, int distance) {
@@ -212,35 +166,31 @@ public final class FeatureHooks {
@@ -217,35 +171,31 @@ public final class FeatureHooks {
}
public static void setSendViewDistance(net.minecraft.server.level.ServerLevel world, int distance) {
@@ -23286,6 +23291,7 @@ index 338dc0fb07cdba5f7350cca332fa3e942c622bfb..e1fe49e4bf014e2405708270efd81bab
}
}
\ No newline at end of file
diff --git a/io/papermc/paper/command/subcommands/ChunkDebugCommand.java b/io/papermc/paper/command/subcommands/ChunkDebugCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..2dca7afbd93cfbb8686f336fcd3b45dd01fba0fc
@@ -23861,7 +23867,7 @@ index 46de98a6bbbae48c4837e1e588ba198a363d2dde..fd3553bdc1c3cdbf6aa3dc00e0a4987f
thread1 -> {
DedicatedServer dedicatedServer1 = new DedicatedServer(
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index c716521fb1497dc8a22d827ddb50fc1cc21a05f4..80442494db670fec34df310390ea787fb963eef4 100644
index 75aba65cbe1a943f21c7464ff9465e64f63e8e5b..32475c0958fd7e0f1f9b494b0cc78a4a718d12b8 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -173,7 +173,7 @@ import net.minecraft.world.phys.Vec2;
@@ -23960,7 +23966,7 @@ index c716521fb1497dc8a22d827ddb50fc1cc21a05f4..80442494db670fec34df310390ea787f
this.server.getPluginManager().callEvent(new org.bukkit.event.world.WorldLoadEvent(serverLevel.getWorld()));
}
@@ -844,6 +915,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -845,6 +916,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
public abstract boolean shouldRconBroadcast();
public boolean saveAllChunks(boolean suppressLog, boolean flush, boolean forced) {
@@ -23972,7 +23978,7 @@ index c716521fb1497dc8a22d827ddb50fc1cc21a05f4..80442494db670fec34df310390ea787f
boolean flag = false;
for (ServerLevel serverLevel : this.getAllLevels()) {
@@ -851,7 +927,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -852,7 +928,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
LOGGER.info("Saving chunks for level '{}'/{}", serverLevel, serverLevel.dimension().location());
}
@@ -23981,7 +23987,7 @@ index c716521fb1497dc8a22d827ddb50fc1cc21a05f4..80442494db670fec34df310390ea787f
flag = true;
}
@@ -944,7 +1020,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -945,7 +1021,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
}
@@ -23990,7 +23996,7 @@ index c716521fb1497dc8a22d827ddb50fc1cc21a05f4..80442494db670fec34df310390ea787f
this.nextTickTimeNanos = Util.getNanos() + TimeUtil.NANOSECONDS_PER_MILLISECOND;
for (ServerLevel serverLevelx : this.getAllLevels()) {
@@ -954,18 +1030,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -955,18 +1031,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.waitUntilNextTick();
}
@@ -24016,7 +24022,7 @@ index c716521fb1497dc8a22d827ddb50fc1cc21a05f4..80442494db670fec34df310390ea787f
this.isSaving = false;
this.resources.close();
@@ -985,6 +1057,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -986,6 +1058,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.getProfileCache().save(false); // Paper - Perf: Async GameProfileCache saving
}
// Spigot end
@@ -24031,7 +24037,7 @@ index c716521fb1497dc8a22d827ddb50fc1cc21a05f4..80442494db670fec34df310390ea787f
// Paper start - Improved watchdog support - move final shutdown items here
Util.shutdownExecutors();
try {
@@ -1169,6 +1249,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1170,6 +1250,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
profilerFiller.push("tick");
this.tickFrame.start();
this.tickServer(flag ? () -> false : this::haveTime);
@@ -24045,7 +24051,7 @@ index c716521fb1497dc8a22d827ddb50fc1cc21a05f4..80442494db670fec34df310390ea787f
this.tickFrame.end();
profilerFiller.popPush("nextTickWait");
this.mayHaveDelayedTasks = true;
@@ -1339,6 +1426,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1340,6 +1427,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
private boolean pollTaskInternal() {
if (super.pollTask()) {
@@ -24053,7 +24059,7 @@ index c716521fb1497dc8a22d827ddb50fc1cc21a05f4..80442494db670fec34df310390ea787f
return true;
} else {
boolean ret = false; // Paper - force execution of all worlds, do not just bias the first
@@ -2468,6 +2556,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2478,6 +2566,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
}
@@ -24067,7 +24073,7 @@ index c716521fb1497dc8a22d827ddb50fc1cc21a05f4..80442494db670fec34df310390ea787f
// CraftBukkit start
public boolean isDebugging() {
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
index 5db176be3bd31eb886a541eeaee922ee30ee9908..5fea5e2e9fc10d348fa3e65cd354ef6a4a717a4d 100644
index 4488d0a2f05ef07afab0f9a1483f54b21757b29e..98927d4a5fba2a0dcdb147ac10b82c3286ccdc6b 100644
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -391,7 +391,33 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
@@ -27685,7 +27691,7 @@ index 49008b4cbaead8a66a93d2b0d4b50b335a6c3eed..f9c96bbdc54e68b9216b7f8662bfae03
}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 69dbff3f62e3a9ba7090156380f842bb44deebf8..c0b74d408340101bc3aac4cb4b7232c5cc78b08a 100644
index 6f7f92cc43c56a7453b289f205502d089474ef6d..b390ba657b8b880e431c84e9dd948ac9c84af2fd 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -193,7 +193,7 @@ import net.minecraft.world.scores.Team;
@@ -28722,7 +28728,7 @@ index 8cc5c0716392ba06501542ff5cbe71ee43979e5d..09fd99c9cbd23b5f3c899bfb00c9b896
+ // Paper end - block counting
}
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index fa2ffc44336c3ddfe576b202154f14ef91a301b9..7546ff4c5ffc62d93a3f874519db8fef1e3bfbcb 100644
index 06d07f93e42edcfdd7d69df0b52efe2a58e7dfc1..da880f52920b1101f23ef94f3fd0dbdea218c373 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -147,7 +147,7 @@ import net.minecraft.world.waypoints.WaypointTransmitter;
@@ -29430,7 +29436,7 @@ index fa2ffc44336c3ddfe576b202154f14ef91a301b9..7546ff4c5ffc62d93a3f874519db8fef
if (!checkPosition(this, x, y, z)) {
return;
}
@@ -4828,6 +5135,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4818,6 +5125,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@Override
public final void setRemoved(Entity.RemovalReason removalReason, @Nullable org.bukkit.event.entity.EntityRemoveEvent.Cause cause) { // CraftBukkit - add Bukkit remove cause
@@ -29443,7 +29449,7 @@ index fa2ffc44336c3ddfe576b202154f14ef91a301b9..7546ff4c5ffc62d93a3f874519db8fef
org.bukkit.craftbukkit.event.CraftEventFactory.callEntityRemoveEvent(this, cause); // CraftBukkit
final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers
if (this.removalReason == null) {
@@ -4838,7 +5151,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4828,7 +5141,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
this.stopRiding();
}
@@ -29452,7 +29458,7 @@ index fa2ffc44336c3ddfe576b202154f14ef91a301b9..7546ff4c5ffc62d93a3f874519db8fef
this.levelCallback.onRemove(removalReason);
this.onRemoval(removalReason);
// Paper start - Folia schedulers
@@ -4872,7 +5185,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4862,7 +5175,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
public boolean shouldBeSaved() {
return (this.removalReason == null || this.removalReason.shouldSave())
&& !this.isPassenger()
@@ -34311,7 +34317,7 @@ index 15417fab103feec3c1f7d5bd5b332e89d3ace3f5..2e6263d8b466e0f61bc72eb818044734
}
}
diff --git a/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java b/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java
index 18750f1ea3101b6c0ab0b8e33c304eb7fa1ed04d..bf708ff89ea1f2c7279e48c41c4f44abc77ceebb 100644
index 49be43ac896d60587511a97445c53c10c587a341..1b070cf7e3612dbcb170cf5d954eba5f5b3c777c 100644
--- a/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java
+++ b/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java
@@ -14,7 +14,7 @@ import net.minecraft.util.datafix.DataFixTypes;
@@ -36675,10 +36681,10 @@ index c634d795644be86ad85395ffa39fbac33bf7418b..66d0a6390febe929ef774b0a78133290
for (SavedTick<T> savedTick : this.pendingTicks) {
diff --git a/net/minecraft/world/waypoints/WaypointTransmitter.java b/net/minecraft/world/waypoints/WaypointTransmitter.java
index b579839c03b371d408e3750ec09af7da1d7bc9a0..9b41c62afc861847571ad739d1dd848b8276230c 100644
index 47382efcd50f29601a6623876be50c4d047336c5..5d1c933dfa862d0733777d305563a89ea7827f07 100644
--- a/net/minecraft/world/waypoints/WaypointTransmitter.java
+++ b/net/minecraft/world/waypoints/WaypointTransmitter.java
@@ -31,7 +31,10 @@ public interface WaypointTransmitter extends Waypoint {
@@ -32,7 +32,10 @@ public interface WaypointTransmitter extends Waypoint {
}
static boolean isChunkVisible(ChunkPos pos, ServerPlayer player) {

View File

@@ -5,10 +5,10 @@ Subject: [PATCH] Incremental chunk and player saving
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 80442494db670fec34df310390ea787fb963eef4..2dd512565ab901bf853f34b384155902b0fe8120 100644
index 338ef549efe82c250c74365c1c1071986920c8c9..39581095ccc69d113d954ed835bdfa32d25b5489 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -954,7 +954,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -955,7 +955,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
boolean var4;
try {
this.isSaving = true;
@@ -17,7 +17,7 @@ index 80442494db670fec34df310390ea787fb963eef4..2dd512565ab901bf853f34b384155902
var4 = this.saveAllChunks(suppressLog, flush, forced);
} finally {
this.isSaving = false;
@@ -1533,9 +1533,29 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1534,9 +1534,29 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
this.ticksUntilAutosave--;

View File

@@ -48,10 +48,10 @@ index 0000000000000000000000000000000000000000..24a2090e068ad3c0d08705050944abdf
+ }
+}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 2dd512565ab901bf853f34b384155902b0fe8120..d6dcb6d146d89a8fb96e7c669e5deb802223abd6 100644
index cff9d761dfee8a90b19fb2f3e678f99a39fc000c..0a260fdf6b198a8ab52e60bf6db2fb5eab719c48 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1708,6 +1708,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1718,6 +1718,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
serverLevel.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent
serverLevel.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent
serverLevel.updateLagCompensationTick(); // Paper - lag compensation

View File

@@ -0,0 +1,204 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Tue, 24 Jun 2025 03:41:38 -0700
Subject: [PATCH] Improve keepalive ping system
Send more keepalives, record all transactions within the last minute.
We send more keepalives so that the latency calculation is more
accurate. Since we send more keepalives, we track all pending
keepalives in case multiple end up in flight.
Additionally, replace the latency calculation with a true
average over the last 5 seconds of keepalive transactions.
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 53f038e1b5e7a13a08a0c925c8bd3f8a40868195..f3eca351021c37b64315872d075bd0a84aeee267 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -461,6 +461,70 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
return this.viewDistanceHolder;
}
// Paper end - rewrite chunk system
+ // Paper start - improve keepalives
+ public long lastKeepAliveTx = System.nanoTime();
+ public static final record KeepAliveResponse(long txTimeNS, long rxTimeNS) {
+ public long latencyNS() {
+ return this.rxTimeNS - this.txTimeNS;
+ }
+ }
+ public static final record PendingKeepAlive(long txTimeNS, long challengeId) {}
+
+ public final ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue<PendingKeepAlive> pendingKeepAlives = new ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue<>();
+
+ public final PingCalculator pingCalculator1m = new PingCalculator(java.util.concurrent.TimeUnit.MINUTES.toNanos(1L));
+ public final PingCalculator pingCalculator5s = new PingCalculator(java.util.concurrent.TimeUnit.SECONDS.toNanos(5L));
+
+ public static final class PingCalculator {
+
+ private final long intervalNS;
+ private final ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue<KeepAliveResponse> responses = new ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue<>();
+
+ private long timeSumNS;
+ private int timeSumCount;
+ private volatile long lastAverageNS;
+
+ public PingCalculator(long intervalNS) {
+ this.intervalNS = intervalNS;
+ }
+
+ public void update(KeepAliveResponse response) {
+ long currTime = response.txTimeNS;
+
+ this.responses.add(response);
+
+ ++this.timeSumCount;
+ this.timeSumNS += response.latencyNS();
+
+ // remove out-of-window times
+ KeepAliveResponse removed;
+ while ((removed = this.responses.pollIf((ka) -> (currTime - ka.txTimeNS) > this.intervalNS)) != null) {
+ --this.timeSumCount;
+ this.timeSumNS -= removed.latencyNS();
+ }
+
+ this.lastAverageNS = this.timeSumNS / (long)this.timeSumCount;
+ }
+
+ public int getAvgLatencyMS() {
+ return (int)java.util.concurrent.TimeUnit.NANOSECONDS.toMillis(this.getAvgLatencyNS());
+ }
+
+ public long getAvgLatencyNS() {
+ return this.lastAverageNS;
+ }
+
+ public it.unimi.dsi.fastutil.longs.LongArrayList getAllNS() {
+ it.unimi.dsi.fastutil.longs.LongArrayList ret = new it.unimi.dsi.fastutil.longs.LongArrayList();
+
+ for (KeepAliveResponse response : this.responses) {
+ ret.add(response.latencyNS());
+ }
+
+ return ret;
+ }
+ }
+ // Paper end - improve keepalives
public ServerPlayer(MinecraftServer server, ServerLevel level, GameProfile gameProfile, ClientInformation clientInformation) {
super(level, gameProfile);
diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
index 85e01c3a1536b41a0301a5a6506e058ff9633a4a..43f70a5561d6cc62aaeba6d1e39598ecb382e369 100644
--- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
@@ -38,12 +38,12 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
protected final MinecraftServer server;
public final Connection connection; // Paper
private final boolean transferred;
- private long keepAliveTime;
- private boolean keepAlivePending;
- private long keepAliveChallenge;
+ //private long keepAliveTime; // Paper - improve keepalives
+ //private boolean keepAlivePending; // Paper - improve keepalives
+ //private long keepAliveChallenge; // Paper - improve keepalives
private long closedListenerTime;
private boolean closed = false;
- private int latency;
+ private volatile int latency; // Paper - improve keepalives - make volatile
private volatile boolean suspendFlushingOnServerThread = false;
// CraftBukkit start
protected final net.minecraft.server.level.ServerPlayer player;
@@ -57,7 +57,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
public ServerCommonPacketListenerImpl(MinecraftServer server, Connection connection, CommonListenerCookie cookie, net.minecraft.server.level.ServerPlayer player) { // CraftBukkit
this.server = server;
this.connection = connection;
- this.keepAliveTime = Util.getMillis();
+ //this.keepAliveTime = Util.getMillis(); // Paper - improve keepalives
this.latency = cookie.latency();
this.transferred = cookie.transferred();
// CraftBukkit start - add fields and methods
@@ -120,13 +120,41 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
@Override
public void handleKeepAlive(ServerboundKeepAlivePacket packet) {
- if (this.keepAlivePending && packet.getId() == this.keepAliveChallenge) {
- int i = (int)(Util.getMillis() - this.keepAliveTime);
- this.latency = (this.latency * 3 + i) / 4;
- this.keepAlivePending = false;
- } else if (!this.isSingleplayerOwner()) {
- this.disconnectAsync(TIMEOUT_DISCONNECTION_MESSAGE, org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT); // Paper - add proper async disconnect
+ // Paper start - improve keepalives
+ long now = System.nanoTime();
+ net.minecraft.server.level.ServerPlayer.PendingKeepAlive pending = this.player.pendingKeepAlives.peek();
+ if (pending != null && pending.challengeId() == packet.getId()) {
+ this.player.pendingKeepAlives.remove(pending);
+
+ net.minecraft.server.level.ServerPlayer.KeepAliveResponse response = new net.minecraft.server.level.ServerPlayer.KeepAliveResponse(pending.txTimeNS(), now);
+
+ this.player.pingCalculator1m.update(response);
+ this.player.pingCalculator5s.update(response);
+
+ this.latency = this.player.pingCalculator5s.getAvgLatencyMS();
+ return;
+ }
+
+ for (java.util.Iterator<net.minecraft.server.level.ServerPlayer.PendingKeepAlive> itr = this.player.pendingKeepAlives.iterator(); itr.hasNext();) {
+ net.minecraft.server.level.ServerPlayer.PendingKeepAlive ka = itr.next();
+ if (ka.challengeId() == packet.getId()) {
+ itr.remove();
+
+ if (!this.processedDisconnect) {
+ LOGGER.info("Disconnecting " + this.player.getScoreboardName() + " for sending keepalive response (" + packet.getId() + ") out-of-order!");
+ this.disconnectAsync(TIMEOUT_DISCONNECTION_MESSAGE, org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT);
+ return;
+ }
+ break;
+ }
}
+
+ if (!this.processedDisconnect) {
+ LOGGER.info("Disconnecting " + this.player.getScoreboardName() + " for sending keepalive response (" + packet.getId() + ") without matching challenge!");
+ this.disconnectAsync(TIMEOUT_DISCONNECTION_MESSAGE, org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT);
+ return;
+ }
+ // Paper end - improve keepalives
}
@Override
@@ -247,20 +275,23 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
protected void keepConnectionAlive() {
Profiler.get().push("keepAlive");
long millis = Util.getMillis();
- // Paper start - give clients a longer time to respond to pings as per pre 1.12.2 timings
- // This should effectively place the keepalive handling back to "as it was" before 1.12.2
- final long elapsedTime = millis - this.keepAliveTime;
- if (!this.isSingleplayerOwner() && elapsedTime >= 15000L) { // use vanilla's 15000L between keep alive packets
- if (this.keepAlivePending) {
- if (!this.processedDisconnect && elapsedTime >= KEEPALIVE_LIMIT) { // check keepalive limit, don't fire if already disconnected
- this.disconnect(TIMEOUT_DISCONNECTION_MESSAGE, org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause
- }
- // Paper end - give clients a longer time to respond to pings as per pre 1.12.2 timings
- } else if (this.checkIfClosed(millis)) {
- this.keepAlivePending = true;
- this.keepAliveTime = millis;
- this.keepAliveChallenge = millis;
- this.send(new ClientboundKeepAlivePacket(this.keepAliveChallenge));
+ // Paper start - improve keepalives
+ if (this.checkIfClosed(millis) && !this.processedDisconnect) {
+ long currTime = System.nanoTime();
+
+ if ((currTime - this.player.lastKeepAliveTx) >= java.util.concurrent.TimeUnit.SECONDS.toNanos(1L)) {
+ this.player.lastKeepAliveTx = currTime;
+
+ net.minecraft.server.level.ServerPlayer.PendingKeepAlive pka = new net.minecraft.server.level.ServerPlayer.PendingKeepAlive(currTime, millis);
+ this.player.pendingKeepAlives.add(pka);
+ this.send(new ClientboundKeepAlivePacket(pka.challengeId()));
+ }
+
+ net.minecraft.server.level.ServerPlayer.PendingKeepAlive oldest = this.player.pendingKeepAlives.peek();
+ if (oldest != null && (currTime - oldest.txTimeNS()) > java.util.concurrent.TimeUnit.MILLISECONDS.toNanos(KEEPALIVE_LIMIT)) {
+ LOGGER.warn(this.player.getScoreboardName() + " was kicked due to keepalive timeout!");
+ this.disconnect(TIMEOUT_DISCONNECTION_MESSAGE, org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT);
+ // Paper end - improve keepalives
}
}

View File

@@ -0,0 +1,84 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Tue, 24 Jun 2025 07:05:51 -0700
Subject: [PATCH] Optimise EntityScheduler ticking
The vast majority of the time, there are no tasks scheduled to
the EntityScheduler. We can avoid iterating the entire entity list
by tracking which schedulers have any tasks scheduled.
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java
index 5f2deeb5cc01d8bbeb7449bd4e59c466b3dfdf57..82824ae7ffbced513a8bcace684af94916135e84 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java
@@ -96,6 +96,7 @@ public final class ServerEntityLookup extends EntityLookup {
if (entity instanceof ThrownEnderpearl enderpearl) {
this.addEnderPearl(CoordinateUtils.getChunkKey(enderpearl.chunkPosition()));
}
+ entity.registerScheduler(); // Paper - optimise Folia entity scheduler
}
@Override
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 0a260fdf6b198a8ab52e60bf6db2fb5eab719c48..52fa5112cd90ba766c94512a02401dd3aee82cc9 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1654,33 +1654,22 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
}
+ public final io.papermc.paper.threadedregions.EntityScheduler.EntitySchedulerTickList entitySchedulerTickList = new io.papermc.paper.threadedregions.EntityScheduler.EntitySchedulerTickList(); // Paper - optimise Folia entity scheduler
+
protected void tickChildren(BooleanSupplier hasTimeLeft) {
ProfilerFiller profilerFiller = Profiler.get();
this.getPlayerList().getPlayers().forEach(serverPlayer1 -> serverPlayer1.connection.suspendFlushing());
this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit
- // Paper start - Folia scheduler API
- ((io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler) org.bukkit.Bukkit.getGlobalRegionScheduler()).tick();
- for (ServerPlayer player : this.playerList.players) {
- if (!this.playerList.players.contains(player)) {
+ // Paper start - optimise Folia entity scheduler
+ ((io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler)org.bukkit.Bukkit.getGlobalRegionScheduler()).tick();
+ for (io.papermc.paper.threadedregions.EntityScheduler scheduler : this.entitySchedulerTickList.getAllSchedulers()) {
+ if (scheduler.isRetired()) {
continue;
}
- final org.bukkit.craftbukkit.entity.CraftEntity bukkit = player.getBukkitEntityRaw();
- if (bukkit != null) {
- bukkit.taskScheduler.executeTick();
- }
+
+ scheduler.executeTick();
}
- getAllLevels().forEach(level -> {
- for (final net.minecraft.world.entity.Entity entity : io.papermc.paper.FeatureHooks.getAllEntities(level)) {
- if (entity.isRemoved() || entity instanceof ServerPlayer) {
- continue;
- }
- final org.bukkit.craftbukkit.entity.CraftEntity bukkit = entity.getBukkitEntityRaw();
- if (bukkit != null) {
- bukkit.taskScheduler.executeTick();
- }
- }
- });
- // Paper end - Folia scheduler API
+ // Paper end - optimise Folia entity scheduler
io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CALLBACK_MANAGER.handleQueue(this.tickCount); // Paper
profilerFiller.push("commandFunctions");
this.getFunctions().tick();
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index da880f52920b1101f23ef94f3fd0dbdea218c373..3d2c0a4d3a1f9d3e5cc6cd0cdb988ae1205de821 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -5165,6 +5165,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
this.getBukkitEntity().taskScheduler.retire();
}
// Paper end - Folia schedulers
+ // Paper start - optimise Folia entity scheduler
+ public final void registerScheduler() {
+ this.getBukkitEntity().taskScheduler.registerTo(net.minecraft.server.MinecraftServer.getServer().entitySchedulerTickList);
+ }
+ // Paper end - optimise Folia entity scheduler
@Override
public void setLevelCallback(EntityInLevelCallback levelCallback) {

View File

@@ -1,6 +1,6 @@
--- /dev/null
+++ b/io/papermc/paper/FeatureHooks.java
@@ -1,0 +_,241 @@
@@ -1,0 +_,246 @@
+package io.papermc.paper;
+
+import io.papermc.paper.command.PaperSubcommand;
@@ -33,6 +33,11 @@
+
+public final class FeatureHooks {
+
+ // this includes non-accessible entities
+ public static Iterable<Entity> getAllEntities(final net.minecraft.server.level.ServerLevel world) {
+ return ((net.minecraft.world.level.entity.LevelEntityGetterAdapter<Entity>)world.getEntities()).sectionStorage.getAllEntities();
+ }
+
+ public static void setPlayerChunkUnloadDelay(final long ticks) {
+ }
+

View File

@@ -1,6 +1,13 @@
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -176,6 +_,11 @@
@@ -170,12 +_,18 @@
@Override
public boolean isRestricted(CommandNode<CommandSourceStack> node) {
+ if (node.getRequirement() instanceof PermissionSource.RestrictedMarker) return true; // Paper - restricted api
return node.getRequirement() instanceof PermissionCheck<?> permissionCheck && permissionCheck.requiredLevel() > 0;
}
};
private final CommandDispatcher<CommandSourceStack> dispatcher = new CommandDispatcher<>();
public Commands(Commands.CommandSelection selection, CommandBuildContext context) {
@@ -55,76 +62,29 @@
this.dispatcher.setConsumer(ExecutionCommandSource.resultConsumer());
}
@@ -289,9 +_,41 @@
return new ParseResults<>(commandContextBuilder, parseResults.getReader(), parseResults.getExceptions());
}
+ // CraftBukkit start
+ public void dispatchServerCommand(CommandSourceStack sender, String command) {
+ com.google.common.base.Joiner joiner = com.google.common.base.Joiner.on(" ");
+ if (command.startsWith("/")) {
+ command = command.substring(1);
+ }
+
+ org.bukkit.event.server.ServerCommandEvent event = new org.bukkit.event.server.ServerCommandEvent(sender.getBukkitSender(), command);
+ org.bukkit.Bukkit.getPluginManager().callEvent(event);
+ if (event.isCancelled()) {
+ return;
+ }
+ command = event.getCommand();
+
+ String[] args = command.split(" ");
+ if (args.length == 0) return; // Paper - empty commands shall not be dispatched
+
+ // Paper - Fix permission levels for command blocks
+
+ // Handle vanilla commands; // Paper - handled in CommandNode/CommandDispatcher
+
+ String newCommand = joiner.join(args);
+ this.performPrefixedCommand(sender, newCommand, newCommand);
+ }
+ // CraftBukkit end
+
public void performPrefixedCommand(CommandSourceStack source, String command) {
+ // CraftBukkit start
+ this.performPrefixedCommand(source, command, command);
+ }
+
+ public void performPrefixedCommand(CommandSourceStack source, String command, String label) {
command = trimOptionalPrefix(command);
- this.performCommand(this.dispatcher.parse(command, source), command);
+ this.performCommand(this.dispatcher.parse(command, source), command, label);
+ // CraftBukkit end
}
public static String trimOptionalPrefix(String command) {
@@ -299,9 +_,20 @@
@@ -299,6 +_,13 @@
}
public void performCommand(ParseResults<CommandSourceStack> parseResults, String command) {
+ // CraftBukkit start
+ this.performCommand(parseResults, command, command);
+ // Paper start
+ this.performCommand(parseResults, command, false);
+ }
+
+ public void performCommand(ParseResults<CommandSourceStack> parseResults, String command, String label) {
+ // CraftBukkit end
+ // Paper start
+ this.performCommand(parseResults, command, label, false);
+ }
+ public void performCommand(ParseResults<CommandSourceStack> parseResults, String command, String label, boolean throwCommandError) {
+ public void performCommand(ParseResults<CommandSourceStack> parseResults, String command, boolean throwCommandError) {
+ org.spigotmc.AsyncCatcher.catchOp("Cannot perform command async");
+ // Paper end
CommandSourceStack commandSourceStack = parseResults.getContext().getSource();
Profiler.get().push(() -> "/" + command);
- ContextChain<CommandSourceStack> contextChain = finishParsing(parseResults, command, commandSourceStack);
+ ContextChain contextChain = this.finishParsing(parseResults, command, commandSourceStack, label); // CraftBukkit // Paper - Add UnknownCommandEvent
try {
if (contextChain != null) {
@@ -313,9 +_,10 @@
ContextChain<CommandSourceStack> contextChain = finishParsing(parseResults, command, commandSourceStack);
@@ -312,10 +_,13 @@
)
);
}
} catch (Exception var12) {
+ if (throwCommandError) throw var12; // Paper
- } catch (Exception var12) {
+ // Paper start
+ } catch (Throwable var12) { // always gracefully handle it, no matter how bad:tm:
+ if (throwCommandError) throw var12; // rethrow directly if requested
+ // Paper end
MutableComponent mutableComponent = Component.literal(var12.getMessage() == null ? var12.getClass().getName() : var12.getMessage());
- if (LOGGER.isDebugEnabled()) {
- LOGGER.error("Command exception: /{}", command, var12);
@@ -133,12 +93,12 @@
StackTraceElement[] stackTrace = var12.getStackTrace();
for (int i = 0; i < Math.min(stackTrace.length, 3); i++) {
@@ -341,18 +_,22 @@
@@ -341,13 +_,17 @@
}
@Nullable
- private static ContextChain<CommandSourceStack> finishParsing(ParseResults<CommandSourceStack> parseResults, String command, CommandSourceStack source) {
+ private ContextChain<CommandSourceStack> finishParsing(ParseResults<CommandSourceStack> parseResults, String command, CommandSourceStack source, String label) { // CraftBukkit // Paper - Add UnknownCommandEvent
+ private ContextChain<CommandSourceStack> finishParsing(ParseResults<CommandSourceStack> parseResults, String command, CommandSourceStack source) {
try {
validateParseResults(parseResults);
return ContextChain.tryFlatten(parseResults.getContext().build(command))
@@ -153,12 +113,6 @@
if (var7.getInput() != null && var7.getCursor() >= 0) {
int min = Math.min(var7.getInput().length(), var7.getCursor());
MutableComponent mutableComponent = Component.empty()
.withStyle(ChatFormatting.GRAY)
- .withStyle(style -> style.withClickEvent(new ClickEvent.SuggestCommand("/" + command)));
+ .withStyle(style -> style.withClickEvent(new ClickEvent.SuggestCommand("/" + label))); // CraftBukkit // Paper
if (min > 10) {
mutableComponent.append(CommonComponents.ELLIPSIS);
}
@@ -364,7 +_,17 @@
}

View File

@@ -1,16 +1,18 @@
--- a/net/minecraft/commands/PermissionSource.java
+++ b/net/minecraft/commands/PermissionSource.java
@@ -9,9 +_,20 @@
@@ -9,9 +_,22 @@
return this.hasPermission(2);
}
- public record Check<T extends PermissionSource>(@Override int requiredLevel) implements PermissionCheck<T> {
+ public record Check<T extends PermissionSource>(@Override int requiredLevel, java.util.concurrent.atomic.AtomicReference<com.mojang.brigadier.tree.CommandNode<CommandSourceStack>> vanillaNode) implements PermissionCheck<T> { // Paper
+ // Paper start - Vanilla Command permission checking
+ // Paper start - Vanilla Command permission checking & expose restricted API
+ interface RestrictedMarker { }
+
+ public record Check<T extends PermissionSource>(@Override int requiredLevel, java.util.concurrent.atomic.AtomicReference<com.mojang.brigadier.tree.CommandNode<CommandSourceStack>> vanillaNode) implements PermissionCheck<T> {
+ public Check(int requiredLevel) {
+ this(requiredLevel, new java.util.concurrent.atomic.AtomicReference<>());
+ }
+ // Paper end - Vanilla Command permission checking
+ // Paper end - Vanilla Command permission checking & expose restricted API
@Override
public boolean test(T source) {
+ // Paper start - Vanilla Command permission checking

View File

@@ -1,6 +1,6 @@
--- a/net/minecraft/network/protocol/game/VecDeltaCodec.java
+++ b/net/minecraft/network/protocol/game/VecDeltaCodec.java
@@ -5,16 +_,16 @@
@@ -5,7 +_,7 @@
public class VecDeltaCodec {
private static final double TRUNCATION_STEPS = 4096.0;
@@ -9,14 +9,3 @@
@VisibleForTesting
static long encode(double value) {
- return Math.round(value * 4096.0);
+ return Math.round(value * 4096.0); // Paper - Fix MC-4; diff on change
}
@VisibleForTesting
static double decode(long value) {
- return value / 4096.0;
+ return value / 4096.0; // Paper - Fix MC-4; diff on change
}
public Vec3 decode(long x, long y, long z) {

View File

@@ -172,7 +172,7 @@
if (profiledDuration != null) {
profiledDuration.finish(true);
}
@@ -364,25 +_,265 @@
@@ -364,25 +_,266 @@
protected void forceDifficulty() {
}
@@ -439,6 +439,7 @@
+ if (io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper != null) io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper.pluginsEnabled(); // Paper - Remap plugins
+ io.papermc.paper.command.brigadier.PaperCommands.INSTANCE.setValid(); // Paper - reset invalid state for event fire below
+ io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner.INSTANCE.callReloadableRegistrarEvent(io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents.COMMANDS, io.papermc.paper.command.brigadier.PaperCommands.INSTANCE, org.bukkit.plugin.Plugin.class, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL); // Paper - call commands event for regular plugins
+ this.server.getCommandMap().registerServerAliases(); // Paper - relocate initial CommandMap#registerServerAliases() call
+ ((org.bukkit.craftbukkit.help.SimpleHelpMap) this.server.getHelpMap()).initializeCommands();
+ this.server.getPluginManager().callEvent(new org.bukkit.event.server.ServerLoadEvent(org.bukkit.event.server.ServerLoadEvent.LoadType.STARTUP));
+ this.connection.acceptConnections();
@@ -983,16 +984,25 @@
ObjectArrayList<GameProfile> list = new ObjectArrayList<>(min);
int randomInt = Mth.nextInt(this.random, 0, players.size() - min);
@@ -1040,17 +_,66 @@
@@ -1040,17 +_,75 @@
protected void tickChildren(BooleanSupplier hasTimeLeft) {
ProfilerFiller profilerFiller = Profiler.get();
this.getPlayerList().getPlayers().forEach(serverPlayer1 -> serverPlayer1.connection.suspendFlushing());
+ this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit
+ // Paper start - Folia scheduler API
+ ((io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler) org.bukkit.Bukkit.getGlobalRegionScheduler()).tick();
+ for (ServerPlayer player : this.playerList.players) {
+ if (!this.playerList.players.contains(player)) {
+ continue;
+ }
+ final org.bukkit.craftbukkit.entity.CraftEntity bukkit = player.getBukkitEntityRaw();
+ if (bukkit != null) {
+ bukkit.taskScheduler.executeTick();
+ }
+ }
+ getAllLevels().forEach(level -> {
+ for (final net.minecraft.world.entity.Entity entity : level.getEntities().getAll()) {
+ if (entity.isRemoved()) {
+ for (final net.minecraft.world.entity.Entity entity : io.papermc.paper.FeatureHooks.getAllEntities(level)) {
+ if (entity.isRemoved() || entity instanceof ServerPlayer) {
+ continue;
+ }
+ final org.bukkit.craftbukkit.entity.CraftEntity bukkit = entity.getBukkitEntityRaw();

View File

@@ -273,7 +273,7 @@
}
@Override
@@ -291,13 +_,23 @@
@@ -291,12 +_,20 @@
}
public void handleConsoleInput(String msg, CommandSourceStack source) {
@@ -284,23 +284,19 @@
public void handleConsoleInputs() {
- while (!this.consoleInput.isEmpty()) {
- ConsoleInput consoleInput = this.consoleInput.remove(0);
- this.getCommands().performPrefixedCommand(consoleInput.source, consoleInput.msg);
+ // Paper start - Perf: use proper queue
+ ConsoleInput servercommand;
+ while ((servercommand = this.serverCommandQueue.poll()) != null) {
+ ConsoleInput consoleInput;
+ while ((consoleInput = this.serverCommandQueue.poll()) != null) {
+ // Paper end - Perf: use proper queue
+ // CraftBukkit start - ServerCommand for preprocessing
+ org.bukkit.event.server.ServerCommandEvent event = new org.bukkit.event.server.ServerCommandEvent(this.console, servercommand.msg);
+ org.bukkit.event.server.ServerCommandEvent event = new org.bukkit.event.server.ServerCommandEvent(this.console, consoleInput.msg);
+ this.server.getPluginManager().callEvent(event);
+ if (event.isCancelled()) continue;
+ servercommand = new ConsoleInput(event.getCommand(), servercommand.source);
+
+ // this.getCommands().performPrefixedCommand(servercommand.source, servercommand.msg); // Called in dispatchServerCommand
+ this.server.dispatchServerCommand(this.console, servercommand);
+ consoleInput = new ConsoleInput(event.getCommand(), consoleInput.source);
+ // CraftBukkit end
this.getCommands().performPrefixedCommand(consoleInput.source, consoleInput.msg);
}
}
@@ -430,7 +_,11 @@
@Override
public boolean enforceSecureProfile() {
@@ -314,7 +310,7 @@
}
@Override
@@ -515,14 +_,54 @@
@@ -515,14 +_,53 @@
@Override
public String getPluginNames() {
@@ -365,8 +361,7 @@
+ if (event.isCancelled()) {
+ return;
+ }
+ ConsoleInput serverCommand = new ConsoleInput(event.getCommand(), wrapper);
+ this.server.dispatchServerCommand(event.getSender(), serverCommand);
+ this.getCommands().performPrefixedCommand(wrapper, event.getCommand());
+ });
+ return rconConsoleSource.getCommandResponse();
+ // CraftBukkit end

View File

@@ -1334,7 +1334,8 @@
if (traceItem) {
- ItemStack itemStack = itemEntity != null ? itemEntity.getItem() : ItemStack.EMPTY;
if (!itemStack.isEmpty()) {
this.awardStat(Stats.ITEM_DROPPED.get(itemStack.getItem()), droppedItem.getCount());
- this.awardStat(Stats.ITEM_DROPPED.get(itemStack.getItem()), droppedItem.getCount());
+ this.awardStat(Stats.ITEM_DROPPED.get(itemStack.getItem()), itemStack.getCount()); // Paper - use size from dropped item
this.awardStat(Stats.DROP);
}
}

View File

@@ -1,6 +1,6 @@
--- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
@@ -29,30 +_,67 @@
@@ -29,14 +_,14 @@
import net.minecraft.util.profiling.Profiler;
import org.slf4j.Logger;
@@ -15,11 +15,9 @@
- protected final Connection connection;
+ public final Connection connection; // Paper
private final boolean transferred;
- private long keepAliveTime;
+ private long keepAliveTime = Util.getMillis(); // Paper
private long keepAliveTime;
private boolean keepAlivePending;
private long keepAliveChallenge;
private long closedListenerTime;
@@ -45,14 +_,51 @@
private boolean closed = false;
private int latency;
private volatile boolean suspendFlushingOnServerThread = false;

View File

@@ -295,7 +295,7 @@
rootVehicle.absSnapTo(d, d1, d2, f, f1);
+ // CraftBukkit start - fire PlayerMoveEvent TODO: this should be removed.
+ this.player.absSnapTo(x, y, z, this.player.getYRot(), this.player.getXRot()); // Paper - TODO: This breaks alot of stuff
+ this.player.absSnapTo(d, d1, d2, this.player.getYRot(), this.player.getXRot()); // Paper - TODO: This breaks alot of stuff
+ org.bukkit.entity.Player player = this.getCraftPlayer();
+ if (!this.hasMoved) {
+ this.lastPosX = prevX;
@@ -1146,8 +1146,7 @@
return;
case RELEASE_USE_ITEM:
- this.player.releaseUsingItem();
+ if (this.player.getUseItem() == this.player.getItemInHand(this.player.getUsedItemHand())) this.player.releaseUsingItem(); // Paper - validate use item before processing release
this.player.releaseUsingItem();
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdates(); // Paper - Force update attributes.
return;
case START_DESTROY_BLOCK:
@@ -2610,7 +2609,7 @@
if (!this.receivedMovementThisTick) {
this.player.setKnownMovement(Vec3.ZERO);
}
@@ -2078,4 +_,17 @@
@@ -2078,4 +_,29 @@
interface EntityInteraction {
InteractionResult run(ServerPlayer player, Entity entity, InteractionHand hand);
}
@@ -2627,4 +2626,16 @@
+ return event;
+ }
+ // Paper end - Add fail move event
+
+ // Paper start - Implement click callbacks with custom click action
+ @Override
+ public void handleCustomClickAction(final net.minecraft.network.protocol.common.ServerboundCustomClickActionPacket packet) {
+ super.handleCustomClickAction(packet);
+ if (packet.id().equals(io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CLICK_CALLBACK_RESOURCE_LOCATION)) {
+ packet.payload().ifPresent(tag ->
+ io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CALLBACK_MANAGER.tryRunCallback(this.player.getBukkitEntity(), tag)
+ );
+ }
+ }
+ // Paper end - Implement click callbacks with custom click action
}

View File

@@ -85,7 +85,7 @@
+ // Paper end - Share random for entities to make them more random
+ public @Nullable org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; // Paper - Entity#getEntitySpawnReason
+
+ private @Nullable org.bukkit.craftbukkit.entity.CraftEntity bukkitEntity;
+ private volatile @Nullable org.bukkit.craftbukkit.entity.CraftEntity bukkitEntity; // Paper - Folia schedulers - volatile
+
+ public org.bukkit.craftbukkit.entity.CraftEntity getBukkitEntity() {
+ if (this.bukkitEntity == null) {
@@ -1786,7 +1786,7 @@
}
public void addDeltaMovement(Vec3 addend) {
@@ -3661,9 +_,45 @@
@@ -3661,9 +_,35 @@
return this.getZ((2.0 * this.random.nextDouble() - 1.0) * scale);
}
@@ -1815,16 +1815,6 @@
+ return;
+ }
+ // Paper end - Block invalid positions and bounding box
+ // Paper start - Fix MC-4
+ if (this instanceof ItemEntity) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.fixEntityPositionDesync) {
+ // encode/decode from VecDeltaCodec todo computation changed?
+ x = Mth.lfloor(x * 4096.0) * (1 / 4096.0);
+ y = Mth.lfloor(y * 4096.0) * (1 / 4096.0);
+ z = Mth.lfloor(z * 4096.0) * (1 / 4096.0);
+ }
+ }
+ // Paper end - Fix MC-4
if (this.position.x != x || this.position.y != y || this.position.z != z) {
+ synchronized (this.posLock) { // Paper - detailed watchdog information
this.position = new Vec3(x, y, z);

View File

@@ -27,3 +27,25 @@
}
}
@@ -120,7 +_,12 @@
return this.level().getBlockState(this.pos).is(BlockTags.FENCES);
}
+ // Paper start - Track if a knot was created
public static LeashFenceKnotEntity getOrCreateKnot(Level level, BlockPos pos) {
+ return getOrCreateKnot(level, pos, null);
+ }
+ public static LeashFenceKnotEntity getOrCreateKnot(Level level, BlockPos pos, @Nullable org.apache.commons.lang3.mutable.MutableBoolean created) {
+ // Paper end - Track if a knot was created
int x = pos.getX();
int y = pos.getY();
int z = pos.getZ();
@@ -134,7 +_,7 @@
}
LeashFenceKnotEntity leashFenceKnotEntity1 = new LeashFenceKnotEntity(level, pos);
- level.addFreshEntity(leashFenceKnotEntity1);
+ if (level.addFreshEntity(leashFenceKnotEntity1) && created != null) { created.setTrue(); } // Paper - Track if a knot was created
return leashFenceKnotEntity1;
}

View File

@@ -24,6 +24,21 @@
}
public ItemEntity(Level level, double posX, double posY, double posZ, ItemStack itemStack, double deltaX, double deltaY, double deltaZ) {
@@ -79,6 +_,14 @@
this.bobOffs = other.bobOffs;
}
+ // Paper start - Require item entities to send their location precisely (Fixes MC-4)
+ {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.sendFullPosForItemEntities) {
+ this.setRequiresPrecisePosition(true);
+ }
+ }
+ // Paper end - Require item entities to send their location precisely (Fixes MC-4)
+
@Override
public boolean dampensVibrations() {
return this.getItem().is(ItemTags.DAMPENS_VIBRATIONS);
@@ -116,7 +_,7 @@
@Override
public void tick() {

View File

@@ -43,23 +43,36 @@
if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) {
LocalDate localDate = LocalDate.now();
int i = localDate.get(ChronoField.DAY_OF_MONTH);
@@ -196,9 +_,19 @@
@@ -188,7 +_,8 @@
@Override
public void performRangedAttack(LivingEntity target, float distanceFactor) {
- ItemStack itemInHand = this.getItemInHand(ProjectileUtil.getWeaponHoldingHand(this, Items.BOW));
+ net.minecraft.world.InteractionHand hand = ProjectileUtil.getWeaponHoldingHand(this, Items.BOW); // Paper - call EntityShootBowEvent
+ ItemStack itemInHand = this.getItemInHand(hand); // Paper - call EntityShootBowEvent
ItemStack projectile = this.getProjectile(itemInHand);
AbstractArrow arrow = this.getArrow(projectile, distanceFactor, itemInHand);
double d = target.getX() - this.getX();
@@ -196,9 +_,21 @@
double d2 = target.getZ() - this.getZ();
double squareRoot = Math.sqrt(d * d + d2 * d2);
if (this.level() instanceof ServerLevel serverLevel) {
+ // CraftBukkit start
+ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, this.getMainHandItem(), arrow.getPickupItem(), arrow, net.minecraft.world.InteractionHand.MAIN_HAND, distanceFactor, true); // Paper - improve entity shoot bow event, add arrow stack to event
- Projectile.spawnProjectileUsingShoot(
+ Projectile.Delayed<AbstractArrow> delayedEntity = Projectile.spawnProjectileUsingShootDelayed( // Paper - delayed
arrow, serverLevel, projectile, d, d1 + squareRoot * 0.2F, d2, 1.6F, 14 - serverLevel.getDifficulty().getId() * 4
);
+
+ // Paper start - call EntityShootBowEvent
+ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, itemInHand, arrow.getPickupItem(), arrow, hand, distanceFactor, true);
+ if (event.isCancelled()) {
+ event.getProjectile().remove();
+ return;
+ }
+
+ if (event.getProjectile() == arrow.getBukkitEntity()) {
+ // CraftBukkit end
Projectile.spawnProjectileUsingShoot(
arrow, serverLevel, projectile, d, d1 + squareRoot * 0.2F, d2, 1.6F, 14 - serverLevel.getDifficulty().getId() * 4
);
+ } // CraftBukkit
+ delayedEntity.spawn();
+ }
+ // Paper end - call EntityShootBowEvent
}
this.playSound(SoundEvents.SKELETON_SHOOT, 1.0F, 1.0F / (this.getRandom().nextFloat() * 0.4F + 0.8F));

View File

@@ -1,22 +1,35 @@
--- a/net/minecraft/world/entity/monster/Illusioner.java
+++ b/net/minecraft/world/entity/monster/Illusioner.java
@@ -180,9 +_,19 @@
@@ -172,7 +_,8 @@
@Override
public void performRangedAttack(LivingEntity target, float distanceFactor) {
- ItemStack itemInHand = this.getItemInHand(ProjectileUtil.getWeaponHoldingHand(this, Items.BOW));
+ net.minecraft.world.InteractionHand hand = ProjectileUtil.getWeaponHoldingHand(this, Items.BOW); // Paper - call EntityShootBowEvent
+ ItemStack itemInHand = this.getItemInHand(hand); // Paper - call EntityShootBowEvent
ItemStack projectile = this.getProjectile(itemInHand);
AbstractArrow mobArrow = ProjectileUtil.getMobArrow(this, projectile, distanceFactor, itemInHand);
double d = target.getX() - this.getX();
@@ -180,9 +_,21 @@
double d2 = target.getZ() - this.getZ();
double squareRoot = Math.sqrt(d * d + d2 * d2);
if (this.level() instanceof ServerLevel serverLevel) {
+ // Paper start - EntityShootBowEvent
+ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, this.getMainHandItem(), mobArrow.getPickupItem(), mobArrow, target.getUsedItemHand(), distanceFactor, true);
- Projectile.spawnProjectileUsingShoot(
+ Projectile.Delayed<AbstractArrow> delayedEntity = Projectile.spawnProjectileUsingShootDelayed( // Paper - delayed
mobArrow, serverLevel, projectile, d, d1 + squareRoot * 0.2F, d2, 1.6F, 14 - serverLevel.getDifficulty().getId() * 4
);
+
+ // Paper start - call EntityShootBowEvent
+ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, itemInHand, mobArrow.getPickupItem(), mobArrow, hand, distanceFactor, true);
+ if (event.isCancelled()) {
+ event.getProjectile().remove();
+ return;
+ }
+
+ if (event.getProjectile() == mobArrow.getBukkitEntity()) {
Projectile.spawnProjectileUsingShoot(
mobArrow, serverLevel, projectile, d, d1 + squareRoot * 0.2F, d2, 1.6F, 14 - serverLevel.getDifficulty().getId() * 4
);
+ delayedEntity.spawn();
+ }
+ // Paper end - EntityShootBowEvent
+ // Paper end - call EntityShootBowEvent
}
this.playSound(SoundEvents.SKELETON_SHOOT, 1.0F, 1.0F / (this.getRandom().nextFloat() * 0.4F + 0.8F));

View File

@@ -1,6 +1,6 @@
--- a/net/minecraft/world/item/LeadItem.java
+++ b/net/minecraft/world/item/LeadItem.java
@@ -26,24 +_,43 @@
@@ -26,24 +_,46 @@
if (blockState.is(BlockTags.FENCES)) {
Player player = context.getPlayer();
if (!level.isClientSide && player != null) {
@@ -22,15 +22,19 @@
+ for (java.util.Iterator<Leashable> iterator = list.iterator(); iterator.hasNext();) { // Paper - use iterator to remove
+ Leashable leashable = iterator.next(); // Paper - use iterator to remove
if (leashFenceKnotEntity == null) {
leashFenceKnotEntity = LeashFenceKnotEntity.getOrCreateKnot(level, pos);
- leashFenceKnotEntity = LeashFenceKnotEntity.getOrCreateKnot(level, pos);
+ // CraftBukkit start - fire HangingPlaceEvent
+ org.bukkit.inventory.EquipmentSlot hand = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(interactionHand);
+ org.bukkit.event.hanging.HangingPlaceEvent event = new org.bukkit.event.hanging.HangingPlaceEvent((org.bukkit.entity.Hanging) leashFenceKnotEntity.getBukkitEntity(), player != null ? (org.bukkit.entity.Player) player.getBukkitEntity() : null, org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), org.bukkit.block.BlockFace.SELF, hand);
+ level.getCraftServer().getPluginManager().callEvent(event);
+ org.apache.commons.lang3.mutable.MutableBoolean created = new org.apache.commons.lang3.mutable.MutableBoolean(false);
+ leashFenceKnotEntity = LeashFenceKnotEntity.getOrCreateKnot(level, pos, created);
+ if (created.booleanValue()) {
+ org.bukkit.inventory.EquipmentSlot hand = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(interactionHand);
+ org.bukkit.event.hanging.HangingPlaceEvent event = new org.bukkit.event.hanging.HangingPlaceEvent((org.bukkit.entity.Hanging) leashFenceKnotEntity.getBukkitEntity(), player != null ? (org.bukkit.entity.Player) player.getBukkitEntity() : null, org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), org.bukkit.block.BlockFace.SELF, hand);
+ level.getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ leashFenceKnotEntity.discard(null); // CraftBukkit - add Bukkit remove cause
+ return InteractionResult.PASS;
+ if (event.isCancelled()) {
+ leashFenceKnotEntity.discard(null); // CraftBukkit - add Bukkit remove cause
+ return InteractionResult.PASS;
+ }
+ }
+ // CraftBukkit end
leashFenceKnotEntity.playPlacementSound();

View File

@@ -12,12 +12,18 @@
public int getSuccessCount() {
return this.successCount;
@@ -108,7 +_,7 @@
@@ -108,7 +_,13 @@
this.successCount++;
}
});
- server.getCommands().performPrefixedCommand(commandSourceStack, this.command);
+ server.getCommands().dispatchServerCommand(commandSourceStack, this.command); // CraftBukkit
+ // Paper start - ServerCommandEvent
+ org.bukkit.event.server.ServerCommandEvent event = new org.bukkit.event.server.ServerCommandEvent(commandSourceStack.getBukkitSender(), net.minecraft.commands.Commands.trimOptionalPrefix(this.command));
+ if (!event.callEvent()) {
+ return true;
+ }
+ server.getCommands().performPrefixedCommand(commandSourceStack, event.getCommand());
+ // Paper end - ServerCommandEvent
} catch (Throwable var6) {
CrashReport crashReport = CrashReport.forThrowable(var6, "Executing command block");
CrashReportCategory crashReportCategory = crashReport.addCategory("Command to be executed");

View File

@@ -30,7 +30,7 @@
- builder.withParameter(LootContextParams.EXPLOSION_RADIUS, explosion.radius());
+ // CraftBukkit start - add yield
+ if (explosion instanceof net.minecraft.world.level.ServerExplosion serverExplosion && serverExplosion.yield < 1.0F) {
+ builder.withParameter(LootContextParams.EXPLOSION_RADIUS, serverExplosion.yield == 0 ? 0 : 1.0F / serverExplosion.yield);
+ builder.withParameter(LootContextParams.EXPLOSION_RADIUS, 1.0F / serverExplosion.yield);
+ // CraftBukkit end
}

View File

@@ -0,0 +1,15 @@
--- a/net/minecraft/world/level/entity/EntitySection.java
+++ b/net/minecraft/world/level/entity/EntitySection.java
@@ -19,6 +_,12 @@
this.storage = new ClassInstanceMultiMap<>(entityClazz);
}
+ // Paper start - support retrieving all entities, regardless of whether they are accessible
+ public void getEntities(java.util.List<T> into) {
+ into.addAll(this.storage);
+ }
+ // Paper end - support retrieving all entities, regardless of whether they are accessible
+
public void add(T entity) {
this.storage.add(entity);
}

View File

@@ -0,0 +1,19 @@
--- a/net/minecraft/world/level/entity/EntitySectionStorage.java
+++ b/net/minecraft/world/level/entity/EntitySectionStorage.java
@@ -34,6 +_,16 @@
this.intialSectionVisibility = initialSectionVisibility;
}
+ // Paper start - support retrieving all entities, regardless of whether they are accessible
+ public Iterable<T> getAllEntities() {
+ java.util.List<T> ret = new java.util.ArrayList<>();
+ for (EntitySection<T> section : this.sections.values()) {
+ section.getEntities(ret);
+ }
+ return ret;
+ }
+ // Paper end - support retrieving all entities, regardless of whether they are accessible
+
public void forEachAccessibleNonEmptySection(AABB boundingBox, AbortableIterationConsumer<EntitySection<T>> consumer) {
int sectionPosCoord = SectionPos.posToSectionCoord(boundingBox.minX - 2.0);
int sectionPosCoord1 = SectionPos.posToSectionCoord(boundingBox.minY - 4.0);

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java
+++ b/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java
@@ -8,7 +_,7 @@
public class LevelEntityGetterAdapter<T extends EntityAccess> implements LevelEntityGetter<T> {
private final EntityLookup<T> visibleEntities;
- private final EntitySectionStorage<T> sectionStorage;
+ public final EntitySectionStorage<T> sectionStorage; // Paper - public
public LevelEntityGetterAdapter(EntityLookup<T> visibleEntities, EntitySectionStorage<T> sectionStorage) {
this.visibleEntities = visibleEntities;

View File

@@ -0,0 +1,10 @@
--- a/net/minecraft/world/waypoints/WaypointTransmitter.java
+++ b/net/minecraft/world/waypoints/WaypointTransmitter.java
@@ -20,6 +_,7 @@
Waypoint.Icon waypointIcon();
static boolean doesSourceIgnoreReceiver(LivingEntity entity, ServerPlayer player) {
+ if (!player.getBukkitEntity().canSee(entity.getBukkitEntity())) return true; // Paper - ignore if entity is hidden from player
if (player.isSpectator()) {
return false;
} else if (!entity.isSpectator() && !entity.hasIndirectPassenger(player)) {

View File

@@ -1,10 +1,12 @@
package io.papermc.paper;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.world.damagesource.CombatEntry;
import io.papermc.paper.world.damagesource.FallLocationType;
import io.papermc.paper.world.damagesource.PaperCombatEntryWrapper;
import io.papermc.paper.world.damagesource.PaperCombatTrackerWrapper;
import net.minecraft.Optionull;
import net.minecraft.commands.PermissionSource;
import net.minecraft.world.damagesource.FallLocation;
import org.bukkit.block.Biome;
import org.bukkit.craftbukkit.block.CraftBiome;
@@ -16,6 +18,7 @@ import org.bukkit.damage.DamageSource;
import org.bukkit.entity.LivingEntity;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.function.Predicate;
@NullMarked
public class PaperServerInternalAPIBridge implements InternalAPIBridge {
@@ -71,4 +74,16 @@ public class PaperServerInternalAPIBridge implements InternalAPIBridge {
damageSource, damage, fallLocation, fallDistance
));
}
@Override
public Predicate<CommandSourceStack> restricted(final Predicate<CommandSourceStack> predicate) {
record RestrictedPredicate(Predicate<CommandSourceStack> predicate) implements Predicate<CommandSourceStack>, PermissionSource.RestrictedMarker {
@Override
public boolean test(final CommandSourceStack commandSourceStack) {
return this.predicate.test(commandSourceStack);
}
}
return new RestrictedPredicate(predicate);
}
}

View File

@@ -1,5 +1,6 @@
package io.papermc.paper.adventure;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
@@ -14,6 +15,7 @@ import java.util.function.Function;
import java.util.function.Predicate;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.nbt.api.BinaryTagHolder;
import net.kyori.adventure.text.BlockNBTComponent;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.EntityNBTComponent;
@@ -37,6 +39,9 @@ import net.kyori.adventure.text.format.TextDecoration;
import net.minecraft.commands.arguments.selector.SelectorPattern;
import net.minecraft.core.UUIDUtil;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.nbt.TagParser;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.chat.ComponentSerialization;
import net.minecraft.network.chat.contents.KeybindContents;
@@ -44,6 +49,7 @@ import net.minecraft.network.chat.contents.ScoreContents;
import net.minecraft.network.chat.contents.TranslatableContents;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.item.Item;
@@ -63,7 +69,14 @@ import static net.kyori.adventure.text.TranslationArgument.numeric;
@DefaultQualifier(NonNull.class)
public final class AdventureCodecs {
public static final Codec<BinaryTagHolder> BINARY_TAG_HOLDER_CODEC = ExtraCodecs.NBT.flatComapMap(tag -> BinaryTagHolder.encode(tag, PaperAdventure.NBT_CODEC), api -> {
try {
final Tag tag = api.get(PaperAdventure.NBT_CODEC);
return DataResult.success(tag);
} catch (CommandSyntaxException e) {
return DataResult.error(e::getMessage);
}
});
public static final Codec<Component> COMPONENT_CODEC = recursive("adventure Component", AdventureCodecs::createCodec);
public static final StreamCodec<RegistryFriendlyByteBuf, Component> STREAM_COMPONENT_CODEC = ByteBufCodecs.fromCodecWithRegistriesTrusted(COMPONENT_CODEC);
@@ -89,27 +102,37 @@ public final class AdventureCodecs {
return Key.parseable(s) ? DataResult.success(Key.key(s)) : DataResult.error(() -> "Cannot convert " + s + " to adventure Key");
}, Key::asString);
static final Function<ClickEvent, String> TEXT_PAYLOAD_EXTRACTOR = a -> ((ClickEvent.Payload.Text) a.payload()).value();
/*
* Click
*/
static final MapCodec<ClickEvent> OPEN_URL_CODEC = mapCodec((instance) -> instance.group(
ExtraCodecs.UNTRUSTED_URI.fieldOf("url").forGetter(a -> URI.create(!a.value().contains("://") ? "https://" + a.value() : a.value()))
ExtraCodecs.UNTRUSTED_URI.fieldOf("url").forGetter(a -> {
final String url = ((ClickEvent.Payload.Text) a.payload()).value();
return URI.create(!url.contains("://") ? "https://" + url : url);
}
)
).apply(instance, (url) -> ClickEvent.openUrl(url.toString())));
static final MapCodec<ClickEvent> OPEN_FILE_CODEC = mapCodec((instance) -> instance.group(
Codec.STRING.fieldOf("path").forGetter(ClickEvent::value)
Codec.STRING.fieldOf("path").forGetter(TEXT_PAYLOAD_EXTRACTOR)
).apply(instance, ClickEvent::openFile));
static final MapCodec<ClickEvent> RUN_COMMAND_CODEC = mapCodec((instance) -> instance.group(
ExtraCodecs.CHAT_STRING.fieldOf("command").forGetter(ClickEvent::value)
ExtraCodecs.CHAT_STRING.fieldOf("command").forGetter(TEXT_PAYLOAD_EXTRACTOR)
).apply(instance, ClickEvent::runCommand));
static final MapCodec<ClickEvent> SUGGEST_COMMAND_CODEC = mapCodec((instance) -> instance.group(
ExtraCodecs.CHAT_STRING.fieldOf("command").forGetter(ClickEvent::value)
ExtraCodecs.CHAT_STRING.fieldOf("command").forGetter(TEXT_PAYLOAD_EXTRACTOR)
).apply(instance, ClickEvent::suggestCommand));
static final MapCodec<ClickEvent> CHANGE_PAGE_CODEC = mapCodec((instance) -> instance.group(
ExtraCodecs.POSITIVE_INT.fieldOf("page").forGetter(a -> Integer.parseInt(a.value()))
ExtraCodecs.POSITIVE_INT.fieldOf("page").forGetter(a -> ((ClickEvent.Payload.Int) a.payload()).integer())
).apply(instance, ClickEvent::changePage));
static final MapCodec<ClickEvent> COPY_TO_CLIPBOARD_CODEC = mapCodec((instance) -> instance.group(
Codec.STRING.fieldOf("value").forGetter(ClickEvent::value)
Codec.STRING.fieldOf("value").forGetter(TEXT_PAYLOAD_EXTRACTOR)
).apply(instance, ClickEvent::copyToClipboard));
static final MapCodec<ClickEvent> CUSTOM_CODEC = mapCodec((instance) -> instance.group(
KEY_CODEC.fieldOf("id").forGetter(a -> ((ClickEvent.Payload.Custom) a.payload()).key()),
BINARY_TAG_HOLDER_CODEC.fieldOf("payload").forGetter(a -> ((ClickEvent.Payload.Custom) a.payload()).nbt())
).apply(instance, ClickEvent::custom));
static final ClickEventType OPEN_URL_CLICK_EVENT_TYPE = new ClickEventType(OPEN_URL_CODEC, "open_url");
static final ClickEventType OPEN_FILE_CLICK_EVENT_TYPE = new ClickEventType(OPEN_FILE_CODEC, "open_file");
@@ -117,7 +140,8 @@ public final class AdventureCodecs {
static final ClickEventType SUGGEST_COMMAND_CLICK_EVENT_TYPE = new ClickEventType(SUGGEST_COMMAND_CODEC, "suggest_command");
static final ClickEventType CHANGE_PAGE_CLICK_EVENT_TYPE = new ClickEventType(CHANGE_PAGE_CODEC, "change_page");
static final ClickEventType COPY_TO_CLIPBOARD_CLICK_EVENT_TYPE = new ClickEventType(COPY_TO_CLIPBOARD_CODEC, "copy_to_clipboard");
static final Codec<ClickEventType> CLICK_EVENT_TYPE_CODEC = StringRepresentable.fromValues(() -> new ClickEventType[]{OPEN_URL_CLICK_EVENT_TYPE, OPEN_FILE_CLICK_EVENT_TYPE, RUN_COMMAND_CLICK_EVENT_TYPE, SUGGEST_COMMAND_CLICK_EVENT_TYPE, CHANGE_PAGE_CLICK_EVENT_TYPE, COPY_TO_CLIPBOARD_CLICK_EVENT_TYPE});
static final ClickEventType CUSTOM_CLICK_EVENT_TYPE = new ClickEventType(CUSTOM_CODEC, "custom");
static final Codec<ClickEventType> CLICK_EVENT_TYPE_CODEC = StringRepresentable.fromValues(() -> new ClickEventType[]{OPEN_URL_CLICK_EVENT_TYPE, OPEN_FILE_CLICK_EVENT_TYPE, RUN_COMMAND_CLICK_EVENT_TYPE, SUGGEST_COMMAND_CLICK_EVENT_TYPE, CHANGE_PAGE_CLICK_EVENT_TYPE, COPY_TO_CLIPBOARD_CLICK_EVENT_TYPE, CUSTOM_CLICK_EVENT_TYPE});
record ClickEventType(MapCodec<ClickEvent> codec, String id) implements StringRepresentable {
@Override
@@ -126,23 +150,17 @@ public final class AdventureCodecs {
}
}
private static final Function<ClickEvent, ClickEventType> GET_CLICK_EVENT_TYPE = he -> {
if (he.action() == ClickEvent.Action.OPEN_URL) {
return OPEN_URL_CLICK_EVENT_TYPE;
} else if (he.action() == ClickEvent.Action.OPEN_FILE) {
return OPEN_FILE_CLICK_EVENT_TYPE;
} else if (he.action() == ClickEvent.Action.RUN_COMMAND) {
return RUN_COMMAND_CLICK_EVENT_TYPE;
} else if (he.action() == ClickEvent.Action.SUGGEST_COMMAND) {
return SUGGEST_COMMAND_CLICK_EVENT_TYPE;
} else if (he.action() == ClickEvent.Action.CHANGE_PAGE) {
return CHANGE_PAGE_CLICK_EVENT_TYPE;
} else if (he.action() == ClickEvent.Action.COPY_TO_CLIPBOARD) {
return COPY_TO_CLIPBOARD_CLICK_EVENT_TYPE;
} else {
throw new IllegalStateException();
}
};
private static final Function<ClickEvent, ClickEventType> GET_CLICK_EVENT_TYPE =
he -> switch (he.action()) {
case OPEN_URL -> OPEN_URL_CLICK_EVENT_TYPE;
case OPEN_FILE -> OPEN_FILE_CLICK_EVENT_TYPE;
case RUN_COMMAND -> RUN_COMMAND_CLICK_EVENT_TYPE;
case SUGGEST_COMMAND -> SUGGEST_COMMAND_CLICK_EVENT_TYPE;
case CHANGE_PAGE -> CHANGE_PAGE_CLICK_EVENT_TYPE;
case COPY_TO_CLIPBOARD -> COPY_TO_CLIPBOARD_CLICK_EVENT_TYPE;
case SHOW_DIALOG -> throw new UnsupportedOperationException(); // todo: dialog codec with dialog "api"
case CUSTOM -> CUSTOM_CLICK_EVENT_TYPE;
};
static final Codec<ClickEvent> CLICK_EVENT_CODEC = CLICK_EVENT_TYPE_CODEC.dispatch("action", GET_CLICK_EVENT_TYPE, ClickEventType::codec);

View File

@@ -35,8 +35,6 @@ import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import net.kyori.adventure.translation.GlobalTranslator;
import net.kyori.adventure.translation.TranslationRegistry;
import net.kyori.adventure.translation.Translator;
import net.kyori.adventure.util.Codec;
import net.minecraft.ChatFormatting;
import net.minecraft.commands.CommandSourceStack;
@@ -78,16 +76,16 @@ import static java.util.Objects.requireNonNull;
public final class PaperAdventure {
private static final Pattern LOCALIZATION_PATTERN = Pattern.compile("%(?:(\\d+)\\$)?s");
public static final ComponentFlattener FLATTENER = ComponentFlattener.basic().toBuilder()
.nestingLimit(30) // todo: should this be configurable? a system property or config value?
.complexMapper(TranslatableComponent.class, (translatable, consumer) -> {
if (!Language.getInstance().has(translatable.key())) {
for (final Translator source : GlobalTranslator.translator().sources()) {
if (source instanceof TranslationRegistry registry && registry.contains(translatable.key())) {
consumer.accept(GlobalTranslator.render(translatable, Locale.US));
return;
}
final Language language = Language.getInstance();
final @Nullable String fallback = translatable.fallback();
if (!language.has(translatable.key()) && (fallback == null || !language.has(fallback))) {
if (GlobalTranslator.translator().canTranslate(translatable.key(), Locale.US)) {
consumer.accept(GlobalTranslator.render(translatable, Locale.US));
return;
}
}
final @Nullable String fallback = translatable.fallback();
final @NotNull String translated = Language.getInstance().getOrDefault(translatable.key(), fallback != null ? fallback : translatable.key());
final Matcher matcher = LOCALIZATION_PATTERN.matcher(translated);
@@ -379,6 +377,7 @@ public final class PaperAdventure {
case PLAYER -> SoundSource.PLAYERS;
case AMBIENT -> SoundSource.AMBIENT;
case VOICE -> SoundSource.VOICE;
case UI -> SoundSource.UI;
};
}

View File

@@ -1,24 +1,33 @@
package io.papermc.paper.adventure.providers;
import io.papermc.paper.adventure.PaperAdventure;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedQueue;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.event.ClickCallback;
import net.kyori.adventure.text.event.ClickEvent;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.NotNull;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
@SuppressWarnings("UnstableApiUsage") // permitted provider
public class ClickCallbackProviderImpl implements ClickCallback.Provider {
private static final Key CLICK_CALLBACK_KEY = Key.key("paper", "click_callback");
private static final String ID_KEY = "id";
public static final ResourceLocation CLICK_CALLBACK_RESOURCE_LOCATION = PaperAdventure.asVanilla(CLICK_CALLBACK_KEY);
public static final CallbackManager CALLBACK_MANAGER = new CallbackManager();
@Override
public @NotNull ClickEvent create(final @NotNull ClickCallback<Audience> callback, final ClickCallback.@NotNull Options options) {
return ClickEvent.runCommand("/paper:callback " + CALLBACK_MANAGER.addCallback(callback, options));
final CompoundTag tag = new CompoundTag();
tag.putString(ID_KEY, CALLBACK_MANAGER.addCallback(callback, options).toString());
return ClickEvent.custom(CLICK_CALLBACK_KEY, PaperAdventure.asBinaryTagHolder(tag));
}
public static final class CallbackManager {
@@ -48,12 +57,21 @@ public class ClickCallbackProviderImpl implements ClickCallback.Provider {
}
}
public void runCallback(final @NotNull Audience audience, final UUID id) {
final StoredCallback callback = this.callbacks.get(id);
if (callback != null && callback.valid()) { //TODO Message if expired/invalid?
callback.takeUse();
callback.callback.accept(audience);
}
public void tryRunCallback(final @NotNull Audience audience, final Tag tag) {
tag.asCompound().flatMap(t -> t.getString(ID_KEY)).ifPresent(s -> {
final UUID id;
try {
id = UUID.fromString(s);
} catch (final IllegalArgumentException ignored) {
return;
}
final StoredCallback callback = this.callbacks.get(id);
if (callback != null && callback.valid()) {
callback.takeUse();
callback.callback.accept(audience);
}
});
}
}

View File

@@ -1,35 +0,0 @@
package io.papermc.paper.command;
import io.papermc.paper.adventure.providers.ClickCallbackProviderImpl;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.framework.qual.DefaultQualifier;
import java.util.UUID;
@DefaultQualifier(NonNull.class)
public class CallbackCommand extends Command {
protected CallbackCommand(final String name) {
super(name);
this.description = "ClickEvent callback";
this.usageMessage = "/callback <uuid>";
}
@Override
public boolean execute(final CommandSender sender, final String commandLabel, final String[] args) {
if (args.length != 1) {
return false;
}
final UUID id;
try {
id = UUID.fromString(args[0]);
} catch (final IllegalArgumentException ignored) {
return false;
}
ClickCallbackProviderImpl.CALLBACK_MANAGER.runCallback(sender, id);
return true;
}
}

View File

@@ -23,7 +23,6 @@ public final class PaperCommands {
public static void registerCommands(final MinecraftServer server) {
COMMANDS.put("paper", new PaperCommand("paper"));
COMMANDS.put("callback", new CallbackCommand("callback"));
COMMANDS.put("mspt", new MSPTCommand("mspt"));
COMMANDS.forEach((s, command) -> {

View File

@@ -20,6 +20,7 @@ import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.stream.Stream;
import org.bukkit.command.Command;
import org.bukkit.craftbukkit.command.VanillaCommandWrapper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -96,7 +97,7 @@ public class BukkitBrigForwardingMap extends HashMap<String, Command> {
public Command put(String key, Command value) {
Command old = this.get(key);
this.getDispatcher().getRoot().removeCommand(key); // Override previous command
if (value instanceof PluginVanillaCommandWrapper wrapper && wrapper.getName().equals(key)) {
if (value instanceof VanillaCommandWrapper wrapper && wrapper.getName().equals(key)) {
// Don't break when some plugin tries to remove and add back a plugin command registered with modern API...
this.getDispatcher().getRoot().addChild((CommandNode) wrapper.vanillaCommand);
} else {

View File

@@ -1,6 +1,7 @@
package io.papermc.paper.command.subcommands;
import com.google.common.collect.Maps;
import io.papermc.paper.FeatureHooks;
import io.papermc.paper.command.CommandUtil;
import io.papermc.paper.command.PaperSubcommand;
import java.util.Collections;
@@ -9,7 +10,6 @@ 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;
@@ -102,7 +102,7 @@ public final class EntityCommand implements PaperSubcommand {
ServerLevel world = ((CraftWorld) bukkitWorld).getHandle();
Map<ResourceLocation, Integer> nonEntityTicking = Maps.newHashMap();
ServerChunkCache chunkProviderServer = world.getChunkSource();
world.getAllEntities().forEach(e -> {
FeatureHooks.getAllEntities(world).forEach(e -> {
ResourceLocation key = EntityType.getKey(e.getType());
MutablePair<Integer, Map<ChunkPos, Integer>> info = list.computeIfAbsent(key, k -> MutablePair.of(0, Maps.newHashMap()));

View File

@@ -343,7 +343,7 @@ public class GlobalConfiguration extends ConfigurationPart {
}
}
public int maxJoinsPerTick = 5;
public boolean fixEntityPositionDesync = true;
public boolean sendFullPosForItemEntities = false;
public boolean loadPermissionsYmlBeforePlugins = true;
@Constraints.Min(4)
public int regionFileCacheSize = 256;

View File

@@ -82,6 +82,7 @@ interface RemovedConfigurations {
path("unsupported-settings", "allow-grindstone-overstacking"),
path("unsupported-settings", "allow-tripwire-disarming-exploits"),
path("commands", "fix-target-selector-tag-completion"),
path("misc", "fix-entity-position-desync")
};
}

View File

@@ -1,6 +1,7 @@
package io.papermc.paper.threadedregions;
import ca.spottedleaf.concurrentutil.util.Validate;
import ca.spottedleaf.moonrise.common.list.ReferenceList;
import ca.spottedleaf.moonrise.common.util.TickThread;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minecraft.world.entity.Entity;
@@ -9,6 +10,8 @@ import org.bukkit.craftbukkit.entity.CraftEntity;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.StampedLock;
import java.util.function.Consumer;
/**
@@ -43,6 +46,8 @@ public final class EntityScheduler {
private static final long RETIRED_TICK_COUNT = -1L;
private final Object stateLock = new Object();
private final Long2ObjectOpenHashMap<List<ScheduledTask>> oneTimeDelayed = new Long2ObjectOpenHashMap<>();
private EntitySchedulerTickList scheduledList;
private boolean insideScheduledList;
private final ArrayDeque<ScheduledTask> currentlyExecuting = new ArrayDeque<>();
@@ -50,6 +55,51 @@ public final class EntityScheduler {
this.entity = Validate.notNull(entity);
}
// must own state lock
private boolean hasTasks() {
return !this.currentlyExecuting.isEmpty() || !this.oneTimeDelayed.isEmpty();
}
public void registerTo(final EntitySchedulerTickList newTickList) {
synchronized (this.stateLock) {
final EntitySchedulerTickList prevList = this.scheduledList;
if (prevList == newTickList) {
return;
}
this.scheduledList = newTickList;
// make sure tasks scheduled before registration can be ticked
if (prevList == null && this.hasTasks()) {
this.insideScheduledList = true;
}
// transfer to new list
if (this.insideScheduledList) {
if (prevList != null) {
prevList.remove(this);
}
if (newTickList != null) {
newTickList.add(this);
} else {
// retired
this.insideScheduledList = false;
}
}
}
}
/**
* Returns whether this scheduler is retired.
*
* <p>
* Note: This should only be invoked on the owning thread for the entity.
* </p>
* @return whether this scheduler is retired.
*/
public boolean isRetired() {
return this.tickCount == RETIRED_TICK_COUNT;
}
/**
* Retires the scheduler, preventing new tasks from being scheduled and invoking the retired callback
* on all currently scheduled tasks.
@@ -66,6 +116,7 @@ public final class EntityScheduler {
throw new IllegalStateException("Already retired");
}
this.tickCount = RETIRED_TICK_COUNT;
this.registerTo(null);
}
final Entity thisEntity = this.entity.getHandleRaw();
@@ -127,6 +178,11 @@ public final class EntityScheduler {
this.oneTimeDelayed.computeIfAbsent(this.tickCount + Math.max(1L, delay), (final long keyInMap) -> {
return new ArrayList<>();
}).add(task);
if (!this.insideScheduledList && this.scheduledList != null) {
this.scheduledList.add(this);
this.insideScheduledList = true;
}
}
return true;
@@ -147,6 +203,12 @@ public final class EntityScheduler {
throw new IllegalStateException("Ticking retired scheduler");
}
++this.tickCount;
if (this.scheduledList != null && !this.hasTasks()) {
this.scheduledList.remove(this);
this.insideScheduledList = false;
}
if (this.oneTimeDelayed.isEmpty()) {
toRun = null;
} else {
@@ -178,4 +240,34 @@ public final class EntityScheduler {
}
}
}
public static final class EntitySchedulerTickList {
private static final EntityScheduler[] ENTITY_SCHEDULER_ARRAY = new EntityScheduler[0];
private final ReferenceList<EntityScheduler> entitySchedulers = new ReferenceList<>(ENTITY_SCHEDULER_ARRAY);
public boolean add(final EntityScheduler scheduler) {
synchronized (this) {
return this.entitySchedulers.add(scheduler);
}
}
public void remove(final EntityScheduler scheduler) {
synchronized (this) {
this.entitySchedulers.remove(scheduler);
}
}
public EntityScheduler[] getAllSchedulers() {
EntityScheduler[] ret = new EntityScheduler[this.entitySchedulers.size()];
synchronized (this) {
if (ret.length != this.entitySchedulers.size()) {
ret = new EntityScheduler[this.entitySchedulers.size()];
}
System.arraycopy(this.entitySchedulers.getRawDataUnchecked(), 0, ret, 0, this.entitySchedulers.size());
return ret;
}
}
}
}

View File

@@ -302,7 +302,6 @@ public final class CraftServer implements Server {
public CraftDataPackManager dataPackManager;
private final CraftServerTickManager serverTickManager;
private final CraftServerLinks serverLinks;
public boolean playerCommandState;
private boolean printSaveWarning;
private CraftIconCache icon;
private boolean overrideAllCommandBlockCommands = false;
@@ -613,7 +612,6 @@ public final class CraftServer implements Server {
// Spigot start - Allow vanilla commands to be forced to be the main command
this.commandMap.setFallbackCommands();
// Spigot end
this.commandMap.registerServerAliases();
DefaultPermissions.registerCorePermissions();
CraftDefaultPermissions.registerCorePermissions();
if (!io.papermc.paper.configuration.GlobalConfiguration.get().misc.loadPermissionsYmlBeforePlugins) this.loadCustomPermissions(); // Paper
@@ -974,41 +972,13 @@ public final class CraftServer implements Server {
return this.playerList;
}
// NOTE: Should only be called from DedicatedServer.ah()
public boolean dispatchServerCommand(CommandSender sender, ConsoleInput serverCommand) {
if (sender instanceof Conversable) {
Conversable conversable = (Conversable) sender;
if (conversable.isConversing()) {
conversable.acceptConversationInput(serverCommand.msg);
return true;
}
}
try {
this.playerCommandState = true;
return this.dispatchCommand(sender, serverCommand.msg);
} catch (Exception ex) {
this.getLogger().log(Level.WARNING, "Unexpected exception while parsing console command \"" + serverCommand.msg + '"', ex);
return false;
} finally {
this.playerCommandState = false;
}
}
@Override
public boolean dispatchCommand(CommandSender sender, String commandLine) {
Preconditions.checkArgument(sender != null, "sender cannot be null");
public boolean dispatchCommand(CommandSender rawSender, String commandLine) {
Preconditions.checkArgument(rawSender != null, "sender cannot be null");
Preconditions.checkArgument(commandLine != null, "commandLine cannot be null");
org.spigotmc.AsyncCatcher.catchOp("Command Dispatched Async: " + commandLine); // Spigot // Paper - Include command in error message
CommandSourceStack sourceStack = VanillaCommandWrapper.getListener(rawSender);
if (this.commandMap.dispatch(sender, commandLine)) {
return true;
}
return this.dispatchCommand(VanillaCommandWrapper.getListener(sender), commandLine);
}
public boolean dispatchCommand(CommandSourceStack sourceStack, String commandLine) {
net.minecraft.commands.Commands commands = this.getHandle().getServer().getCommands();
com.mojang.brigadier.CommandDispatcher<CommandSourceStack> dispatcher = commands.getDispatcher();
com.mojang.brigadier.ParseResults<CommandSourceStack> results = dispatcher.parse(commandLine, sourceStack);
@@ -1018,7 +988,12 @@ public final class CraftServer implements Server {
Command target = this.commandMap.getCommand(args[0].toLowerCase(java.util.Locale.ENGLISH));
try {
commands.performCommand(results, commandLine, commandLine, true);
if (results.getContext().getNodes().isEmpty()) {
return false;
}
Commands.validateParseResults(results);
commands.performCommand(results, commandLine, true);
return true;
} catch (CommandException ex) {
new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerCommandException(ex, target, sender, args)).callEvent(); // Paper
throw ex;
@@ -1027,9 +1002,6 @@ public final class CraftServer implements Server {
new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerCommandException(ex, target, sender, args)).callEvent(); // Paper
throw new CommandException(msg, ex);
}
// Paper end
return false;
}
@Override
@@ -2609,7 +2581,7 @@ public final class CraftServer implements Server {
}
public void checkSaveState() {
if (this.playerCommandState || this.printSaveWarning || this.console.autosavePeriod <= 0) {
if (this.printSaveWarning || this.console.autosavePeriod <= 0) {
return;
}
this.printSaveWarning = true;

View File

@@ -29,6 +29,7 @@ import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import net.kyori.adventure.pointer.PointersSupplier;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
@@ -157,6 +158,10 @@ import org.jetbrains.annotations.Nullable;
public class CraftWorld extends CraftRegionAccessor implements World {
public static final int CUSTOM_DIMENSION_OFFSET = 10;
private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
private static final PointersSupplier<World> POINTERS_SUPPLIER = PointersSupplier.<World>builder()
.resolving(net.kyori.adventure.identity.Identity.NAME, World::getName)
.resolving(net.kyori.adventure.identity.Identity.UUID, World::getUID)
.build();
private final ServerLevel world;
private WorldBorder worldBorder;
@@ -168,7 +173,6 @@ public class CraftWorld extends CraftRegionAccessor implements World {
private final BlockMetadataStore blockMetadata = new BlockMetadataStore(this);
private final Object2IntOpenHashMap<SpawnCategory> spawnCategoryLimit = new Object2IntOpenHashMap<>();
private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftWorld.DATA_TYPE_REGISTRY);
private net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers
// Paper start - void damage configuration
private boolean voidDamageEnabled;
private float voidDamageAmount;
@@ -2481,14 +2485,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
// Paper start - implement pointers
@Override
public net.kyori.adventure.pointer.Pointers pointers() {
if (this.adventure$pointers == null) {
this.adventure$pointers = net.kyori.adventure.pointer.Pointers.builder()
.withDynamic(net.kyori.adventure.identity.Identity.NAME, this::getName)
.withDynamic(net.kyori.adventure.identity.Identity.UUID, this::getUID)
.build();
}
return this.adventure$pointers;
return POINTERS_SUPPLIER.view(this);
}
// Paper end
}

View File

@@ -74,7 +74,7 @@ public abstract class CraftBlockEntityState<T extends BlockEntity> extends Craft
this.loadData(state.getSnapshotNBT());
}
private RegistryAccess getRegistryAccess() {
public RegistryAccess getRegistryAccess() {
LevelAccessor worldHandle = this.getWorldHandle();
return (worldHandle != null) ? worldHandle.registryAccess() : CraftRegistry.getMinecraftRegistry();
}

View File

@@ -8,7 +8,6 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.InclusiveRange;
import net.minecraft.util.ProblemReporter;
@@ -51,7 +50,7 @@ public class CraftCreatureSpawner extends CraftBlockEntityState<SpawnerBlockEnti
}
try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(() -> "spawner@" + getLocation(), LOGGER)) {
ValueInput valueInput = TagValueInput.create(scopedCollector, this.getInternalWorld().registryAccess(), spawnData.entityToSpawn());
ValueInput valueInput = TagValueInput.create(scopedCollector, this.getRegistryAccess(), spawnData.entityToSpawn());
Optional<net.minecraft.world.entity.EntityType<?>> type = net.minecraft.world.entity.EntityType.by(valueInput);
return type.map(CraftEntityType::minecraftToBukkit).orElse(null);
}
@@ -183,7 +182,7 @@ public class CraftCreatureSpawner extends CraftBlockEntityState<SpawnerBlockEnti
return null;
}
try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(() -> "spawner@" + getLocation(), LOGGER)) {
ValueInput valueInput = TagValueInput.create(scopedCollector, this.getInternalWorld().registryAccess(), spawnData.getEntityToSpawn());
ValueInput valueInput = TagValueInput.create(scopedCollector, this.getRegistryAccess(), spawnData.getEntityToSpawn());
Optional<net.minecraft.world.entity.EntityType<?>> type = net.minecraft.world.entity.EntityType.by(valueInput);
return type.map(CraftEntityType::minecraftToBukkit).map(CraftEntityType::bukkitToString).orElse(null);

View File

@@ -2,6 +2,7 @@ package org.bukkit.craftbukkit.command;
import java.util.Set;
import java.util.UUID;
import net.kyori.adventure.pointer.PointersSupplier;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
@@ -12,8 +13,12 @@ import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin;
public abstract class ServerCommandSender implements CommandSender {
private static final PointersSupplier<ServerCommandSender> POINTERS_SUPPLIER = PointersSupplier.<ServerCommandSender>builder()
.resolving(net.kyori.adventure.identity.Identity.DISPLAY_NAME, ServerCommandSender::name)
.resolving(net.kyori.adventure.permission.PermissionChecker.POINTER, serverCommandSender -> serverCommandSender::permissionValue)
.build();
public final PermissibleBase perm;
private net.kyori.adventure.pointer.Pointers adventure$pointers;
protected ServerCommandSender() {
this.perm = new PermissibleBase(this);
@@ -126,13 +131,6 @@ public abstract class ServerCommandSender implements CommandSender {
@Override
public net.kyori.adventure.pointer.Pointers pointers() {
if (this.adventure$pointers == null) {
this.adventure$pointers = net.kyori.adventure.pointer.Pointers.builder()
.withDynamic(net.kyori.adventure.identity.Identity.DISPLAY_NAME, this::name)
.withStatic(net.kyori.adventure.permission.PermissionChecker.POINTER, this::permissionValue)
.build();
}
return this.adventure$pointers;
return POINTERS_SUPPLIER.view(this);
}
}

View File

@@ -50,7 +50,7 @@ public class VanillaCommandWrapper extends BukkitCommand { // Paper
if (!this.testPermission(sender)) return true;
CommandSourceStack source = VanillaCommandWrapper.getListener(sender);
this.commands().performPrefixedCommand(source, this.toDispatcher(args, this.getName()), this.toDispatcher(args, commandLabel)); // Paper
this.commands().performPrefixedCommand(source, this.toDispatcher(args, this.getName()));
return true;
}

View File

@@ -14,6 +14,7 @@ import java.util.Set;
import java.util.UUID;
import io.papermc.paper.entity.LookAnchor;
import java.util.concurrent.CompletableFuture;
import net.kyori.adventure.pointer.PointersSupplier;
import net.kyori.adventure.util.TriState;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
@@ -85,13 +86,17 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
private static PermissibleBase perm;
private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
static final PointersSupplier<org.bukkit.entity.Entity> POINTERS_SUPPLIER = PointersSupplier.<org.bukkit.entity.Entity>builder()
.resolving(net.kyori.adventure.identity.Identity.DISPLAY_NAME, org.bukkit.entity.Entity::name)
.resolving(net.kyori.adventure.identity.Identity.UUID, org.bukkit.entity.Entity::getUniqueId)
.resolving(net.kyori.adventure.permission.PermissionChecker.POINTER, entity1 -> entity1::permissionValue)
.build();
protected final CraftServer server;
protected Entity entity;
private final EntityType entityType;
private EntityDamageEvent lastDamageEvent;
private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftEntity.DATA_TYPE_REGISTRY);
protected net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers
// Paper start - Folia shedulers
public final io.papermc.paper.threadedregions.EntityScheduler taskScheduler = new io.papermc.paper.threadedregions.EntityScheduler(this);
private final io.papermc.paper.threadedregions.scheduler.FoliaEntityScheduler apiScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaEntityScheduler(this);
@@ -670,15 +675,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
@Override
public net.kyori.adventure.pointer.Pointers pointers() {
if (this.adventure$pointers == null) {
this.adventure$pointers = net.kyori.adventure.pointer.Pointers.builder()
.withDynamic(net.kyori.adventure.identity.Identity.DISPLAY_NAME, this::name)
.withDynamic(net.kyori.adventure.identity.Identity.UUID, this::getUniqueId)
.withStatic(net.kyori.adventure.permission.PermissionChecker.POINTER, this::permissionValue)
.build();
}
return this.adventure$pointers;
return POINTERS_SUPPLIER.view(this);
}
@Override

View File

@@ -4,6 +4,7 @@ import com.google.common.base.Preconditions;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import net.minecraft.core.RegistryAccess;
import net.minecraft.util.ProblemReporter;
import net.minecraft.util.RandomSource;
import net.minecraft.util.random.WeightedList;
@@ -186,6 +187,11 @@ public class CraftMinecartMobSpawner extends CraftMinecart implements SpawnerMin
return this.getHandle().level();
}
@Override
public RegistryAccess getRegistryAccess() {
return this.getHandle().registryAccess();
}
@Override
public net.minecraft.core.BlockPos getInternalPosition() {
return this.getHandle().blockPosition();

View File

@@ -44,6 +44,8 @@ import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.pointer.PointersSupplier;
import net.kyori.adventure.util.TriState;
import net.md_5.bungee.api.chat.BaseComponent;
import net.minecraft.advancements.AdvancementProgress;
@@ -213,6 +215,12 @@ import org.jspecify.annotations.Nullable;
@DelegateDeserialization(CraftOfflinePlayer.class)
public class CraftPlayer extends CraftHumanEntity implements Player {
private static final PointersSupplier<Player> POINTERS_SUPPLIER = PointersSupplier.<Player>builder()
.parent(CraftEntity.POINTERS_SUPPLIER)
.resolving(Identity.NAME, Player::getName)
.resolving(Identity.DISPLAY_NAME, Player::displayName)
.resolving(Identity.LOCALE, Player::locale)
.build();
private long firstPlayed = 0;
private long lastPlayed = 0;
@@ -3283,17 +3291,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
@Override
public net.kyori.adventure.pointer.Pointers pointers() {
if (this.adventure$pointers == null) {
this.adventure$pointers = net.kyori.adventure.pointer.Pointers.builder()
.withDynamic(net.kyori.adventure.identity.Identity.DISPLAY_NAME, this::displayName)
.withDynamic(net.kyori.adventure.identity.Identity.NAME, this::getName)
.withDynamic(net.kyori.adventure.identity.Identity.UUID, this::getUniqueId)
.withStatic(net.kyori.adventure.permission.PermissionChecker.POINTER, this::permissionValue)
.withDynamic(net.kyori.adventure.identity.Identity.LOCALE, this::locale)
.build();
}
return this.adventure$pointers;
return POINTERS_SUPPLIER.view(this);
}
@Override

View File

@@ -185,11 +185,6 @@ public class CraftItemType<M extends ItemMeta> extends HolderableBase<Item> impl
return expectedItem.isEmpty() ? null : CraftItemType.minecraftToBukkitNew(expectedItem.getItem());
}
// @Override
// public EquipmentSlot getEquipmentSlot() {
// return CraftEquipmentSlot.getSlot(EntityInsentient.getEquipmentSlotForItem(CraftItemStack.asNMSCopy(ItemStack.of(this))));
// }
@Override
public Multimap<Attribute, AttributeModifier> getDefaultAttributeModifiers() {
return this.getDefaultAttributeModifiers(sg -> true);

View File

@@ -34,6 +34,8 @@ public interface PaperSharedSpawnerLogic extends Spawner {
Level getInternalWorld();
RegistryAccess getRegistryAccess();
BlockPos getInternalPosition();
default boolean isActivated() {
return this.getSpawner().isNearPlayer(this.getInternalWorld(), this.getInternalPosition());

View File

@@ -11,11 +11,14 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.net.URI;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Stream;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.nbt.api.BinaryTagHolder;
import net.kyori.adventure.text.BlockNBTComponent;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
@@ -106,23 +109,35 @@ class AdventureCodecsTest {
}
@ParameterizedTest(name = PARAMETERIZED_NAME)
@EnumSource(value = ClickEvent.Action.class, mode = EnumSource.Mode.EXCLUDE, names = {"OPEN_FILE"})
@EnumSource(value = ClickEvent.Action.class, mode = EnumSource.Mode.EXCLUDE, names = {"OPEN_FILE", "SHOW_DIALOG", "CUSTOM"})
void testClickEvent(final ClickEvent.Action action) {
final ClickEvent event = ClickEvent.clickEvent(action, action.name().equals("OPEN_URL") ? "https://google.com" : "1337");
final Tag result = CLICK_EVENT_CODEC.encodeStart(NbtOps.INSTANCE, event).result().orElseThrow();
final ClickEvent event = switch (action) {
case OPEN_URL -> openUrl("https://google.com");
case RUN_COMMAND -> ClickEvent.runCommand("/say hello");
case SUGGEST_COMMAND -> suggestCommand("/suggest hello");
case CHANGE_PAGE -> ClickEvent.changePage(2);
case COPY_TO_CLIPBOARD -> ClickEvent.copyToClipboard("clipboard content");
case CUSTOM -> ClickEvent.custom(key("test"), BinaryTagHolder.binaryTagHolder("3"));
case SHOW_DIALOG, OPEN_FILE -> throw new IllegalArgumentException();
};
final Tag result = CLICK_EVENT_CODEC.encodeStart(NbtOps.INSTANCE, event).result().orElseThrow(() -> new RuntimeException("Failed to encode ClickEvent: " + event));
final net.minecraft.network.chat.ClickEvent nms = net.minecraft.network.chat.ClickEvent.CODEC.decode(NbtOps.INSTANCE, result).result().orElseThrow().getFirst();
assertEquals(event.action().toString(), nms.action().getSerializedName());
switch (nms) {
case net.minecraft.network.chat.ClickEvent.OpenUrl(java.net.URI uri) ->
assertEquals(event.value(), uri.toString());
case net.minecraft.network.chat.ClickEvent.OpenUrl(URI uri) ->
assertEquals(((ClickEvent.Payload.Text) event.payload()).value(), uri.toString());
case net.minecraft.network.chat.ClickEvent.SuggestCommand(String command) ->
assertEquals(event.value(), command);
assertEquals(((ClickEvent.Payload.Text) event.payload()).value(), command);
case net.minecraft.network.chat.ClickEvent.RunCommand(String command) ->
assertEquals(event.value(), command);
assertEquals(((ClickEvent.Payload.Text) event.payload()).value(), command);
case net.minecraft.network.chat.ClickEvent.CopyToClipboard(String value) ->
assertEquals(event.value(), value);
assertEquals(((ClickEvent.Payload.Text) event.payload()).value(), value);
case net.minecraft.network.chat.ClickEvent.ChangePage(int page) ->
assertEquals(event.value(), String.valueOf(page));
assertEquals(((ClickEvent.Payload.Int) event.payload()).integer(), page);
case net.minecraft.network.chat.ClickEvent.Custom(ResourceLocation id, Optional<Tag> payload) -> {
assertEquals(((ClickEvent.Payload.Custom) event.payload()).key().toString(), id.toString());
assertEquals(((ClickEvent.Payload.Custom) event.payload()).nbt(), payload.orElseThrow().asString());
}
default -> throw new AssertionError("Unexpected ClickEvent type: " + nms.getClass());
}
}
@@ -294,10 +309,10 @@ class AdventureCodecsTest {
.clickEvent(openUrl("https://github.com"))
.build(),
style()
.hoverEvent(HoverEvent.showEntity(HoverEvent.ShowEntity.showEntity(
Key.key(Key.MINECRAFT_NAMESPACE, "pig"),
.hoverEvent(showEntity(HoverEvent.ShowEntity.showEntity(
key(Key.MINECRAFT_NAMESPACE, "pig"),
UUID.randomUUID(),
Component.text("Dolores", TextColor.color(0x0a1ab9))
text("Dolores", color(0x0a1ab9))
)))
.build()
);