Merge remote-tracking branch 'upstream/main' into update/1.21.4

This commit is contained in:
2025-03-30 11:43:18 +02:00
519 changed files with 7311 additions and 3127 deletions

View File

@@ -21,10 +21,6 @@ paperweight {
// macheOldPath = file("F:\\Projects\\PaperTooling\\mache\\versions\\1.21.4\\src\\main\\java")
// gitFilePatches = true
paper {
reobfMappingsPatch = layout.projectDirectory.file("../build-data/reobf-mappings-patch.tiny")
}
spigot {
buildDataRef = "3edaf46ec1eed4115ce1b18d2846cded42577e42"
packageVersion = "v1_21_R3" // also needs to be updated in MappingEnvironment
@@ -124,7 +120,7 @@ abstract class MockitoAgentProvider : CommandLineArgumentProvider {
dependencies {
implementation(project(":paper-api"))
implementation("ca.spottedleaf:concurrentutil:0.0.2")
implementation("ca.spottedleaf:concurrentutil:0.0.3")
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")
@@ -141,13 +137,14 @@ dependencies {
runtimeOnly(log4jPlugins.output)
alsoShade(log4jPlugins.output)
implementation("com.velocitypowered:velocity-native:3.3.0-SNAPSHOT") {
implementation("com.velocitypowered:velocity-native:3.4.0-SNAPSHOT") {
isTransitive = false
}
implementation("io.netty:netty-codec-haproxy:4.1.97.Final") // Add support for proxy protocol
implementation("io.netty:netty-codec-haproxy:4.1.115.Final") // Add support for proxy protocol
implementation("org.apache.logging.log4j:log4j-iostreams:2.24.1")
implementation("org.ow2.asm:asm-commons:9.7.1")
implementation("org.spongepowered:configurate-yaml:4.2.0-SNAPSHOT")
implementation("org.spongepowered:configurate-yaml:4.2.0-20250225.064233-199")
implementation("org.spongepowered:configurate-core:4.2.0-20250225.064233-204") // Pinned dependency of above pinned yaml snapshot.
implementation("commons-lang:commons-lang:2.6")
runtimeOnly("org.xerial:sqlite-jdbc:3.47.0.0")
runtimeOnly("com.mysql:mysql-connector-j:9.1.0")
@@ -177,7 +174,7 @@ dependencies {
// Spark
implementation("me.lucko:spark-api:0.1-20240720.200737-2")
implementation("me.lucko:spark-paper:1.10.119-SNAPSHOT")
implementation("me.lucko:spark-paper:1.10.119-20241121.092015-1")
}
tasks.jar {

View File

@@ -28,7 +28,7 @@ and then catch exceptions and close if they fire.
Part of this commit was authored by: Spottedleaf, sandtechnology
diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
index 42f44c7cb0bd55ddfacd18acb0e596e7a953870e..ad8f8428b75e37097487cdfbd0db2421ee4cbe37 100644
index 42f44c7cb0bd55ddfacd18acb0e596e7a953870e..2040b9555c430420a8a8697cc131d42eafb96fa1 100644
--- a/net/minecraft/network/Connection.java
+++ b/net/minecraft/network/Connection.java
@@ -85,7 +85,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -232,7 +232,7 @@ index 42f44c7cb0bd55ddfacd18acb0e596e7a953870e..ad8f8428b75e37097487cdfbd0db2421
// Paper start - Add PlayerConnectionCloseEvent
if (packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl commonPacketListener) {
/* Player was logged in, either game listener or configuration listener */
@@ -797,4 +888,93 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -797,4 +888,97 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
public void setBandwidthLogger(LocalSampleLogger bandwithLogger) {
this.bandwidthDebugMonitor = new BandwidthDebugMonitor(bandwithLogger);
}
@@ -280,6 +280,7 @@ index 42f44c7cb0bd55ddfacd18acb0e596e7a953870e..ad8f8428b75e37097487cdfbd0db2421
+ packet instanceof net.minecraft.network.protocol.common.ClientboundKeepAlivePacket ||
+ packet instanceof net.minecraft.network.protocol.game.ClientboundPlayerChatPacket ||
+ packet instanceof net.minecraft.network.protocol.game.ClientboundSystemChatPacket ||
+ packet instanceof net.minecraft.network.protocol.game.ClientboundDisguisedChatPacket ||
+ packet instanceof net.minecraft.network.protocol.game.ClientboundCommandSuggestionsPacket ||
+ packet instanceof net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket ||
+ packet instanceof net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket ||
@@ -290,7 +291,10 @@ index 42f44c7cb0bd55ddfacd18acb0e596e7a953870e..ad8f8428b75e37097487cdfbd0db2421
+ packet instanceof net.minecraft.network.protocol.game.ClientboundSoundEntityPacket ||
+ packet instanceof net.minecraft.network.protocol.game.ClientboundStopSoundPacket ||
+ packet instanceof net.minecraft.network.protocol.game.ClientboundLevelParticlesPacket ||
+ packet instanceof net.minecraft.network.protocol.game.ClientboundBossEventPacket;
+ packet instanceof net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket ||
+ packet instanceof net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket ||
+ packet instanceof net.minecraft.network.protocol.game.ClientboundBossEventPacket ||
+ packet instanceof net.minecraft.network.protocol.ping.ClientboundPongResponsePacket;
+ }
+ }
+

View File

@@ -15,7 +15,7 @@ Adds villagers as separate config
diff --git a/io/papermc/paper/entity/activation/ActivationRange.java b/io/papermc/paper/entity/activation/ActivationRange.java
new file mode 100644
index 0000000000000000000000000000000000000000..bd888ef719b9bfc93bace0b1d0fb771ac659f515
index 0000000000000000000000000000000000000000..ade6110cc6adb1263c0359ff7e96e96b959e61f3
--- /dev/null
+++ b/io/papermc/paper/entity/activation/ActivationRange.java
@@ -0,0 +1,318 @@
@@ -105,10 +105,10 @@ index 0000000000000000000000000000000000000000..bd888ef719b9bfc93bace0b1d0fb771a
+ * @return boolean If it should always tick.
+ */
+ public static boolean initializeEntityActivationState(final Entity entity, final SpigotWorldConfig config) {
+ return (entity.activationType == ActivationType.MISC && config.miscActivationRange == 0)
+ || (entity.activationType == ActivationType.RAIDER && config.raiderActivationRange == 0)
+ || (entity.activationType == ActivationType.ANIMAL && config.animalActivationRange == 0)
+ || (entity.activationType == ActivationType.MONSTER && config.monsterActivationRange == 0)
+ return (entity.activationType == ActivationType.MISC && config.miscActivationRange <= 0)
+ || (entity.activationType == ActivationType.RAIDER && config.raiderActivationRange <= 0)
+ || (entity.activationType == ActivationType.ANIMAL && config.animalActivationRange <= 0)
+ || (entity.activationType == ActivationType.MONSTER && config.monsterActivationRange <= 0)
+ || (entity.activationType == ActivationType.VILLAGER && config.villagerActivationRange <= 0)
+ || (entity.activationType == ActivationType.WATER && config.waterActivationRange <= 0)
+ || (entity.activationType == ActivationType.FLYING_MONSTER && config.flyingMonsterActivationRange <= 0)
@@ -366,7 +366,7 @@ index d95413af04121fe91ca0f3b0c70025b9808acef9..ad665c7535c615d2b03a3e7864be435f
import org.slf4j.Logger;
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 3164f3784131babf9a6663335517a12df7e88a7b..da8848e2a3e3745949eb2356a049451d30f763a7 100644
index f45fb8ddb08d82ce76018b5a5c4fce5b3b319559..12f0dc36c5adcdbd9e1dad5f8512ac184da3960f 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -551,6 +551,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -377,8 +377,8 @@ index 3164f3784131babf9a6663335517a12df7e88a7b..da8848e2a3e3745949eb2356a049451d
this.entityTickList
.forEach(
entity -> {
@@ -979,12 +980,15 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
entity.tickCount++;
@@ -980,12 +981,15 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
entity.totalEntityAge++; // Paper - age-like counter for all entities
profilerFiller.push(() -> BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString());
profilerFiller.incrementCounter("tickNonPassenger");
+ final boolean isActive = io.papermc.paper.entity.activation.ActivationRange.checkIfActive(entity); // Paper - EAR 2
@@ -394,7 +394,7 @@ index 3164f3784131babf9a6663335517a12df7e88a7b..da8848e2a3e3745949eb2356a049451d
}
// Paper start - log detailed entity tick information
} finally {
@@ -995,7 +999,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -996,7 +1000,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// Paper end - log detailed entity tick information
}
@@ -403,7 +403,7 @@ index 3164f3784131babf9a6663335517a12df7e88a7b..da8848e2a3e3745949eb2356a049451d
if (passengerEntity.isRemoved() || passengerEntity.getVehicle() != ridingEntity) {
passengerEntity.stopRiding();
} else if (passengerEntity instanceof Player || this.entityTickList.contains(passengerEntity)) {
@@ -1004,12 +1008,21 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1006,12 +1010,21 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
ProfilerFiller profilerFiller = Profiler.get();
profilerFiller.push(() -> BuiltInRegistries.ENTITY_TYPE.getKey(passengerEntity.getType()).toString());
profilerFiller.incrementCounter("tickPassenger");
@@ -476,12 +476,12 @@ index 24735284fda151414d99faad401d25ba60995f9a..23b342cc31c7e72ade0e1ccad86a9ccf
public void tick() {
super.tick();
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index e7889c9c7b155db46730f5e168bb7fd3d1732a8c..334859c5ff7023c730513301cc11c9837b2c7823 100644
index 2facc7ad69bfe28c2f928a026ba5ab37387ab039..6256d7f8f4ee8bd4e3673b4e069af5cc0069c8f2 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -380,6 +380,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
public boolean fixedPose = false; // Paper - Expand Pose API
@@ -381,6 +381,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
private final int despawnTime; // Paper - entity despawn time limit
public int totalEntityAge; // Paper - age-like counter for all entities
public final io.papermc.paper.entity.activation.ActivationType activationType = io.papermc.paper.entity.activation.ActivationType.activationTypeFor(this); // Paper - EAR 2/tracking ranges
+ // Paper start - EAR 2
+ public final boolean defaultActivationState;
@@ -495,7 +495,7 @@ index e7889c9c7b155db46730f5e168bb7fd3d1732a8c..334859c5ff7023c730513301cc11c983
public void setOrigin(@javax.annotation.Nonnull org.bukkit.Location location) {
this.origin = location.toVector();
@@ -417,6 +426,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -414,6 +423,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
this.position = Vec3.ZERO;
this.blockPosition = BlockPos.ZERO;
this.chunkPosition = ChunkPos.ZERO;
@@ -509,7 +509,7 @@ index e7889c9c7b155db46730f5e168bb7fd3d1732a8c..334859c5ff7023c730513301cc11c983
SynchedEntityData.Builder builder = new SynchedEntityData.Builder(this);
builder.define(DATA_SHARED_FLAGS_ID, (byte)0);
builder.define(DATA_AIR_SUPPLY_ID, this.getMaxAirSupply());
@@ -981,6 +997,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -978,6 +994,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
} else {
this.wasOnFire = this.isOnFire();
if (type == MoverType.PISTON) {
@@ -518,7 +518,7 @@ index e7889c9c7b155db46730f5e168bb7fd3d1732a8c..334859c5ff7023c730513301cc11c983
movement = this.limitPistonMovement(movement);
if (movement.equals(Vec3.ZERO)) {
return;
@@ -994,6 +1012,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -991,6 +1009,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
this.stuckSpeedMultiplier = Vec3.ZERO;
this.setDeltaMovement(Vec3.ZERO);
}
@@ -533,10 +533,10 @@ index e7889c9c7b155db46730f5e168bb7fd3d1732a8c..334859c5ff7023c730513301cc11c983
movement = this.maybeBackOffFromEdge(movement, type);
Vec3 vec3 = this.collide(movement);
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index ff513e8c87bf42be756e46f4dbfec8dda2b8cb60..239c443ddc9bacc08a39a8ef2ab17016a2480549 100644
index e0c310d970a687945b6a771b4ecb94044128c33c..4546aca8e2e144ec207653c713fc49f849908827 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -3096,6 +3096,14 @@ public abstract class LivingEntity extends Entity implements Attackable {
@@ -3103,6 +3103,14 @@ public abstract class LivingEntity extends Entity implements Attackable {
return false;
}
@@ -552,7 +552,7 @@ index ff513e8c87bf42be756e46f4dbfec8dda2b8cb60..239c443ddc9bacc08a39a8ef2ab17016
public void tick() {
super.tick();
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
index f7d69db61d1293510428ae275e8a50571dde5ddf..1ed07fd23985a6bf8cf8300f74c92b7531a79fc6 100644
index e12b47ca5eeb842bae606c0c7a8e3e4cf7d468a9..e330bf990e4874baed1b21cd8c9b44d66ec5b823 100644
--- a/net/minecraft/world/entity/Mob.java
+++ b/net/minecraft/world/entity/Mob.java
@@ -215,6 +215,19 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
@@ -764,7 +764,7 @@ index c1e09e701757a300183b62d343ded03033e63aa7..56574f8ef879159edc0114da09300143
public void tick() {
super.tick();
diff --git a/net/minecraft/world/entity/projectile/FireworkRocketEntity.java b/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
index 7c0862c50b44555fb27ce7dc46f4ec95a3eb0022..774ca9e0b56fd175ae246051de762d0c4256ca58 100644
index a3e4605a81eeaca77cc3a3ab937b75a415d83037..c7ae41b2cbc1eb85a6eb9c16813bd326fb8f49f0 100644
--- a/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
+++ b/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
@@ -102,6 +102,21 @@ public class FireworkRocketEntity extends Projectile implements ItemSupplier {
@@ -776,11 +776,11 @@ index 7c0862c50b44555fb27ce7dc46f4ec95a3eb0022..774ca9e0b56fd175ae246051de762d0c
+ public void inactiveTick() {
+ this.life++;
+ if (this.life > this.lifetime && this.level() instanceof ServerLevel serverLevel) {
+ // CraftBukkit start
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this).isCancelled()) {
+ // Paper start - Call FireworkExplodeEvent
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this)) {
+ this.explode(serverLevel);
+ }
+ // CraftBukkit end
+ // Paper end - Call FireworkExplodeEvent
+ }
+ super.inactiveTick();
+ }
@@ -845,7 +845,7 @@ index 32f184288f6065259c921293922c1b0163df4dc4..0f346faa82b988e86834c38837f6f11b
public final org.spigotmc.SpigotWorldConfig spigotConfig; // Spigot
// Paper start - add paper world config
diff --git a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
index 754cfdcd5a28287aa3545aaffdce1e391cbefc1e..1e6e940fca9d96ef410c7bf05524bd9b24db4a79 100644
index ce880bd45fbda4829d17de8507034b3a39c68cbb..ee2f8e8deb35059824b5730a1442f383dc79f01c 100644
--- a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
+++ b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
@@ -149,6 +149,10 @@ public class PistonMovingBlockEntity extends BlockEntity {

View File

@@ -14,7 +14,7 @@ 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 334859c5ff7023c730513301cc11c9837b2c7823..45f69a914d5a0565196c4105d61541047301470f 100644
index 054ece1d539d69a4b7eec57e681179343c7e75c3..6f35067c64f378e955261e763f2bda9a0a6d0153 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -218,6 +218,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -22,7 +22,7 @@ index 334859c5ff7023c730513301cc11c9837b2c7823..45f69a914d5a0565196c4105d6154104
public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; // Paper - Entity#getEntitySpawnReason
+ public boolean collisionLoadChunks = false; // Paper
private org.bukkit.craftbukkit.entity.CraftEntity bukkitEntity;
private @Nullable org.bukkit.craftbukkit.entity.CraftEntity bukkitEntity;
public org.bukkit.craftbukkit.entity.CraftEntity getBukkitEntity() {
diff --git a/net/minecraft/world/level/BlockCollisions.java b/net/minecraft/world/level/BlockCollisions.java

View File

@@ -1,152 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 22 Aug 2021 15:21:57 -0700
Subject: [PATCH] Fix entity type tags suggestions in selectors
This would really be better as a client fix because just to fix it
all EntityArguments have been told to ask the server for completions
when if this was fixed on the client, that wouldn't be needed.
Mojira Issue: https://bugs.mojang.com/browse/MC-235045
diff --git a/net/minecraft/commands/CommandSourceStack.java b/net/minecraft/commands/CommandSourceStack.java
index 704a63890a06d793f8ac3452838917e7c7335232..75262c8c9eaecb4a88a94f4076d67119c67a97da 100644
--- a/net/minecraft/commands/CommandSourceStack.java
+++ b/net/minecraft/commands/CommandSourceStack.java
@@ -652,4 +652,20 @@ public class CommandSourceStack implements ExecutionCommandSource<CommandSourceS
return this.source.getBukkitSender(this);
}
// CraftBukkit end
+ // Paper start - tell clients to ask server for suggestions for EntityArguments
+ @Override
+ public Collection<String> getSelectedEntities() {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && this.source instanceof ServerPlayer player) {
+ final Entity cameraEntity = player.getCamera();
+ final double pickDistance = player.entityInteractionRange();
+ final Vec3 min = cameraEntity.getEyePosition(1.0F);
+ final Vec3 viewVector = cameraEntity.getViewVector(1.0F);
+ final Vec3 max = min.add(viewVector.x * pickDistance, viewVector.y * pickDistance, viewVector.z * pickDistance);
+ final net.minecraft.world.phys.AABB aabb = cameraEntity.getBoundingBox().expandTowards(viewVector.scale(pickDistance)).inflate(1.0D, 1.0D, 1.0D);
+ final net.minecraft.world.phys.EntityHitResult hitResult = net.minecraft.world.entity.projectile.ProjectileUtil.getEntityHitResult(cameraEntity, min, max, aabb, (e) -> !e.isSpectator() && e.isPickable(), pickDistance * pickDistance);
+ return hitResult != null ? java.util.Collections.singletonList(hitResult.getEntity().getStringUUID()) : SharedSuggestionProvider.super.getSelectedEntities();
+ }
+ return SharedSuggestionProvider.super.getSelectedEntities();
+ }
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
}
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
index fa8c5ba4e0efd0c36613aaa8eaafba0cb70ceb87..19ccf3abf14c67f72a1ca065e4a304f50e645ef4 100644
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -509,6 +509,7 @@ public class Commands {
Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> commandNodeToSuggestionNode
) {
commandNodeToSuggestionNode.keySet().removeIf((node) -> !org.spigotmc.SpigotConfig.sendNamespaced && node.getName().contains(":")); // Paper - Remove namedspaced from result nodes to prevent redirect trimming ~ see comment below
+ boolean registeredAskServerSuggestionsForTree = false; // Paper - tell clients to ask server for suggestions for EntityArguments
for (CommandNode<CommandSourceStack> commandNode : children) { // Paper - Perf: Async command map building; pass copy of children
// Paper start - Brigadier API
if (commandNode.clientNode != null) {
@@ -572,6 +573,12 @@ public class Commands {
RequiredArgumentBuilder<SharedSuggestionProvider, ?> requiredArgumentBuilder = (RequiredArgumentBuilder<SharedSuggestionProvider, ?>)argumentBuilder;
if (requiredArgumentBuilder.getSuggestionsProvider() != null) {
requiredArgumentBuilder.suggests(SuggestionProviders.safelySwap(requiredArgumentBuilder.getSuggestionsProvider()));
+ // Paper start - tell clients to ask server for suggestions for EntityArguments
+ registeredAskServerSuggestionsForTree = requiredArgumentBuilder.getSuggestionsProvider() == net.minecraft.commands.synchronization.SuggestionProviders.ASK_SERVER;
+ } else if (io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && !registeredAskServerSuggestionsForTree && requiredArgumentBuilder.getType() instanceof net.minecraft.commands.arguments.EntityArgument) {
+ requiredArgumentBuilder.suggests(requiredArgumentBuilder.getType()::listSuggestions);
+ registeredAskServerSuggestionsForTree = true; // You can only
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
}
}
diff --git a/net/minecraft/commands/arguments/EntityArgument.java b/net/minecraft/commands/arguments/EntityArgument.java
index 0a01df6ebd14afe79bc76364cb1df5e0c5c08074..7a06ad9940d25e163178370bfa9ccc3bbd3d1189 100644
--- a/net/minecraft/commands/arguments/EntityArgument.java
+++ b/net/minecraft/commands/arguments/EntityArgument.java
@@ -138,7 +138,7 @@ public class EntityArgument implements ArgumentType<EntitySelector> {
final boolean permission = sharedSuggestionProvider instanceof CommandSourceStack stack
? stack.bypassSelectorPermissions || stack.hasPermission(2, "minecraft.command.selector")
: sharedSuggestionProvider.hasPermission(2);
- EntitySelectorParser entitySelectorParser = new EntitySelectorParser(stringReader, permission);
+ EntitySelectorParser entitySelectorParser = new EntitySelectorParser(stringReader, permission, true); // Paper - tell clients to ask server for suggestions for EntityArguments
// Paper end - Fix EntityArgument permissions
try {
@@ -149,7 +149,19 @@ public class EntityArgument implements ArgumentType<EntitySelector> {
return entitySelectorParser.fillSuggestions(
builder,
offsetBuilder -> {
- Collection<String> onlinePlayerNames = sharedSuggestionProvider.getOnlinePlayerNames();
+ // Paper start - tell clients to ask server for suggestions for EntityArguments
+ final Collection<String> onlinePlayerNames;
+ if (sharedSuggestionProvider instanceof CommandSourceStack commandSourceStack && commandSourceStack.getEntity() instanceof ServerPlayer sourcePlayer) {
+ onlinePlayerNames = new java.util.ArrayList<>();
+ for (final ServerPlayer player : commandSourceStack.getServer().getPlayerList().getPlayers()) {
+ if (sourcePlayer.getBukkitEntity().canSee(player.getBukkitEntity())) {
+ onlinePlayerNames.add(player.getGameProfile().getName());
+ }
+ }
+ } else {
+ onlinePlayerNames = sharedSuggestionProvider.getOnlinePlayerNames();
+ }
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
Iterable<String> iterable = (Iterable<String>)(this.playersOnly
? onlinePlayerNames
: Iterables.concat(onlinePlayerNames, sharedSuggestionProvider.getSelectedEntities()));
diff --git a/net/minecraft/commands/arguments/selector/EntitySelectorParser.java b/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
index a6f232747df631f6afe440606bea94c588f1a0dd..fb42630741674c6cbd20b7d45d78dea1dc73a78f 100644
--- a/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
+++ b/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
@@ -115,8 +115,15 @@ public class EntitySelectorParser {
private boolean hasScores;
private boolean hasAdvancements;
private boolean usesSelectors;
+ public boolean parsingEntityArgumentSuggestions; // Paper - tell clients to ask server for suggestions for EntityArguments
public EntitySelectorParser(StringReader reader, boolean allowSelectors) {
+ // Paper start - tell clients to ask server for suggestions for EntityArguments
+ this(reader, allowSelectors, false);
+ }
+ public EntitySelectorParser(StringReader reader, boolean allowSelectors, boolean parsingEntityArgumentSuggestions) {
+ this.parsingEntityArgumentSuggestions = parsingEntityArgumentSuggestions;
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
this.reader = reader;
this.allowSelectors = allowSelectors;
}
diff --git a/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java b/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java
index f6b58139aace70436034f0a16370236d975cb4ae..ee9949c41d38817b21b6f4fd728059a46fddf135 100644
--- a/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java
+++ b/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java
@@ -76,6 +76,19 @@ public class EntitySelectorOptions {
public static final DynamicCommandExceptionType ERROR_ENTITY_TYPE_INVALID = new DynamicCommandExceptionType(
type -> Component.translatableEscape("argument.entity.options.type.invalid", type)
);
+ // Paper start - tell clients to ask server for suggestions for EntityArguments
+ public static final DynamicCommandExceptionType ERROR_ENTITY_TAG_INVALID = new DynamicCommandExceptionType((object) -> {
+ return io.papermc.paper.adventure.PaperAdventure
+ .asVanilla(net.kyori.adventure.text.Component
+ .text("Invalid or unknown entity type tag '" + object + "'")
+ .hoverEvent(net.kyori.adventure.text.event.HoverEvent
+ .showText(net.kyori.adventure.text.Component
+ .text("You can disable this error in 'paper.yml'")
+ )
+ )
+ );
+ });
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
private static void register(String id, EntitySelectorOptions.Modifier handler, Predicate<EntitySelectorParser> predicate, Component tooltip) {
OPTIONS.put(id, new EntitySelectorOptions.Option(handler, predicate, tooltip));
@@ -299,6 +312,12 @@ public class EntitySelectorOptions {
if (parser.isTag()) {
TagKey<EntityType<?>> tagKey = TagKey.create(Registries.ENTITY_TYPE, ResourceLocation.read(parser.getReader()));
+ // Paper start - tell clients to ask server for suggestions for EntityArguments; throw error if invalid entity tag (only on suggestions to keep cmd success behavior)
+ if (parser.parsingEntityArgumentSuggestions && io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && net.minecraft.core.registries.BuiltInRegistries.ENTITY_TYPE.get(tagKey).isEmpty()) {
+ parser.getReader().setCursor(cursor);
+ throw ERROR_ENTITY_TAG_INVALID.createWithContext(parser.getReader(), tagKey);
+ }
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
parser.addPredicate(entity -> entity.getType().is(tagKey) != shouldInvertValue);
} else {
ResourceLocation resourceLocation = ResourceLocation.read(parser.getReader());

View File

@@ -30621,7 +30621,7 @@ index 1110ca4075a1bbaa46b66686435dab91b275c945..c2218630c3074c8b3f82364e37503b12
return structureTemplate.save(new CompoundTag());
}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 0d65bf24f515b80701150fdc430f324a533cb478..b92a3da5c325e69f5601416d4205fb33429742b3 100644
index e54b5a165ad4dc4d2158dab34c5008512e5f7885..841a41485af62470d833aba578069b19a0bd1e8d 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -305,6 +305,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa

View File

@@ -23552,7 +23552,7 @@ index 2b46ca9a2a046063cad422bec00d76107537b091..9aa664537cc37e44db46d5a2a64ae311
thread1 -> {
DedicatedServer dedicatedServer1 = new DedicatedServer(
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index b92a3da5c325e69f5601416d4205fb33429742b3..d967d605c2e4227ae980c30f1c8b86edbc680d6d 100644
index 841a41485af62470d833aba578069b19a0bd1e8d..409c1134327bfcc338c3ac5e658a83cc396645d1 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -173,7 +173,7 @@ import net.minecraft.world.phys.Vec2;
@@ -23737,7 +23737,7 @@ index b92a3da5c325e69f5601416d4205fb33429742b3..d967d605c2e4227ae980c30f1c8b86ed
return true;
} else {
boolean ret = false; // Paper - force execution of all worlds, do not just bias the first
@@ -2472,6 +2554,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2473,6 +2555,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
}
@@ -23751,7 +23751,7 @@ index b92a3da5c325e69f5601416d4205fb33429742b3..d967d605c2e4227ae980c30f1c8b86ed
// CraftBukkit start
public boolean isDebugging() {
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
index f8c81d795b19e73d56d6e0196c75e441ab4c2bef..97a294d2f5c1ddf0af7ffec3e1425eb329c5751b 100644
index ac7bc193f7ea63cbbba73df49f54a17ef7cdec40..d2db6e3a4af13984b0a790fb38e83c253914a973 100644
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -433,7 +433,33 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
@@ -26735,7 +26735,7 @@ index da793ad12565c36fffb26eb771ff68c76632caf7..db06f966077928419bfe469260f04d7d
if (!passengers.equals(this.lastPassengers)) {
this.broadcastAndSend(new ClientboundSetPassengersPacket(this.entity)); // CraftBukkit
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 192977dd661ee795ada13db895db770293e9b402..95a4e37a3c93f9b3c56c7a7376ed521cd46fbb6f 100644
index d1f235ebd835f58cf0c703c3a64d29825d98e183..080091efc19bc768bb9a660f366c42e831225505 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -170,7 +170,7 @@ import net.minecraft.world.phys.shapes.VoxelShape;
@@ -27305,7 +27305,7 @@ index 192977dd661ee795ada13db895db770293e9b402..95a4e37a3c93f9b3c56c7a7376ed521c
}
// Paper start - log detailed entity tick information
@@ -1033,6 +1316,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1035,6 +1318,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
public void save(@Nullable ProgressListener progress, boolean flush, boolean skipSave) {
@@ -27317,7 +27317,7 @@ index 192977dd661ee795ada13db895db770293e9b402..95a4e37a3c93f9b3c56c7a7376ed521c
ServerChunkCache chunkSource = this.getChunkSource();
if (!skipSave) {
org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(this.getWorld())); // CraftBukkit
@@ -1045,13 +1333,18 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1047,13 +1335,18 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
progress.progressStage(Component.translatable("menu.savingChunks"));
}
@@ -27341,7 +27341,7 @@ index 192977dd661ee795ada13db895db770293e9b402..95a4e37a3c93f9b3c56c7a7376ed521c
// CraftBukkit start - moved from MinecraftServer.saveChunks
ServerLevel worldserver1 = this;
@@ -1182,7 +1475,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1184,7 +1477,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
this.removePlayerImmediately((ServerPlayer)entity, Entity.RemovalReason.DISCARDED);
}
@@ -27350,7 +27350,7 @@ index 192977dd661ee795ada13db895db770293e9b402..95a4e37a3c93f9b3c56c7a7376ed521c
}
// CraftBukkit start
@@ -1213,7 +1506,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1215,7 +1508,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
// CraftBukkit end
@@ -27359,7 +27359,7 @@ index 192977dd661ee795ada13db895db770293e9b402..95a4e37a3c93f9b3c56c7a7376ed521c
}
}
@@ -1224,7 +1517,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1226,7 +1519,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
public boolean tryAddFreshEntityWithPassengers(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) {
// CraftBukkit end
@@ -27368,7 +27368,7 @@ index 192977dd661ee795ada13db895db770293e9b402..95a4e37a3c93f9b3c56c7a7376ed521c
return false;
} else {
this.addFreshEntityWithPassengers(entity, reason); // CraftBukkit
@@ -1959,7 +2252,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1961,7 +2254,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
}
@@ -27377,7 +27377,7 @@ index 192977dd661ee795ada13db895db770293e9b402..95a4e37a3c93f9b3c56c7a7376ed521c
bufferedWriter.write(String.format(Locale.ROOT, "block_entity_tickers: %d\n", this.blockEntityTickers.size()));
bufferedWriter.write(String.format(Locale.ROOT, "block_ticks: %d\n", this.getBlockTicks().count()));
bufferedWriter.write(String.format(Locale.ROOT, "fluid_ticks: %d\n", this.getFluidTicks().count()));
@@ -1977,13 +2270,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1979,13 +2272,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
Path path1 = path.resolve("chunks.csv");
try (Writer bufferedWriter2 = Files.newBufferedWriter(path1)) {
@@ -27393,7 +27393,7 @@ index 192977dd661ee795ada13db895db770293e9b402..95a4e37a3c93f9b3c56c7a7376ed521c
}
Path path3 = path.resolve("entities.csv");
@@ -2092,8 +2385,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -2094,8 +2387,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
Locale.ROOT,
"players: %s, entities: %s [%s], block_entities: %d [%s], block_ticks: %d, fluid_ticks: %d, chunk_source: %s",
this.players.size(),
@@ -27404,7 +27404,7 @@ index 192977dd661ee795ada13db895db770293e9b402..95a4e37a3c93f9b3c56c7a7376ed521c
this.blockEntityTickers.size(),
getTypeCount(this.blockEntityTickers, TickingBlockEntity::getType),
this.getBlockTicks().count(),
@@ -2125,15 +2418,25 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -2127,15 +2420,25 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@Override
public LevelEntityGetter<Entity> getEntities() {
org.spigotmc.AsyncCatcher.catchOp("Chunk getEntities call"); // Spigot
@@ -27433,7 +27433,7 @@ index 192977dd661ee795ada13db895db770293e9b402..95a4e37a3c93f9b3c56c7a7376ed521c
}
public void startTickingChunk(LevelChunk chunk) {
@@ -2151,32 +2454,45 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -2153,32 +2456,45 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@Override
public void close() throws IOException {
super.close();
@@ -27486,7 +27486,7 @@ index 192977dd661ee795ada13db895db770293e9b402..95a4e37a3c93f9b3c56c7a7376ed521c
}
@Override
@@ -2230,7 +2546,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -2232,7 +2548,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@Override
public CrashReportCategory fillReportDetails(CrashReport report) {
CrashReportCategory crashReportCategory = super.fillReportDetails(report);
@@ -27496,7 +27496,7 @@ index 192977dd661ee795ada13db895db770293e9b402..95a4e37a3c93f9b3c56c7a7376ed521c
}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 097ec55166b9e9269142be58992c29687122fe28..aeabb79512aabd7a9e8af1be72e1745f0e7eefe4 100644
index 0bb610f12e3ddda649ecb5ad62ffdc7bfd243223..19428343b37c9b739b3d28984d52e257f85f253f 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -178,7 +178,7 @@ import net.minecraft.world.scores.Team;
@@ -27508,7 +27508,7 @@ index 097ec55166b9e9269142be58992c29687122fe28..aeabb79512aabd7a9e8af1be72e1745f
private static final Logger LOGGER = LogUtils.getLogger();
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32;
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10;
@@ -388,6 +388,36 @@ public class ServerPlayer extends Player {
@@ -395,6 +395,36 @@ public class ServerPlayer extends Player {
public @Nullable String clientBrandName = null; // Paper - Brand support
public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - Add API for quit reason; there are a lot of changes to do if we change all methods leading to the event
@@ -27976,10 +27976,10 @@ index 4eb040006f5d41b47e5ac9df5d9f19c4315d6343..7fa41dea184b01891f45d8e404bc1cba
this.generatingStep = generatingStep;
this.cache = cache;
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index ff0315cffdb282fdc0a1ffd15e2954caa76835c9..5e94dd9e26aa4fd6545dbaae2ae0cb51cb6f13e0 100644
index 7eebb494e38b57e81b4f92f0a96d3a4c610d86df..065f4c810439dde464529b54ae300ecfcb1c2c31 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -1312,7 +1312,7 @@ public abstract class PlayerList {
@@ -1317,7 +1317,7 @@ public abstract class PlayerList {
public void setViewDistance(int viewDistance) {
this.viewDistance = viewDistance;
@@ -27988,7 +27988,7 @@ index ff0315cffdb282fdc0a1ffd15e2954caa76835c9..5e94dd9e26aa4fd6545dbaae2ae0cb51
for (ServerLevel serverLevel : this.server.getAllLevels()) {
if (serverLevel != null) {
@@ -1323,7 +1323,7 @@ public abstract class PlayerList {
@@ -1328,7 +1328,7 @@ public abstract class PlayerList {
public void setSimulationDistance(int simulationDistance) {
this.simulationDistance = simulationDistance;
@@ -28372,7 +28372,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 189385600b9094291152035b17df869eaccc0428..25a1089a7376f0cbd96bb43b5c203640c88fc282 100644
index 9b3b770f6986dd132da78fdc3626d334166ec52a..b2b61203438bb1fad1ee807729781718d2467155 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -135,7 +135,7 @@ import net.minecraft.world.scores.ScoreHolder;
@@ -28466,7 +28466,7 @@ index 189385600b9094291152035b17df869eaccc0428..25a1089a7376f0cbd96bb43b5c203640
}
// Paper end - Share random for entities to make them more random
public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; // Paper - Entity#getEntitySpawnReason
@@ -419,6 +375,156 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -416,6 +372,156 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
return this.dimensions.makeBoundingBox(x, y, z);
}
// Paper end
@@ -28623,7 +28623,7 @@ index 189385600b9094291152035b17df869eaccc0428..25a1089a7376f0cbd96bb43b5c203640
public Entity(EntityType<?> entityType, Level level) {
this.type = entityType;
@@ -1327,35 +1433,77 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -1324,35 +1430,77 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
return distance;
}
@@ -28725,7 +28725,7 @@ index 189385600b9094291152035b17df869eaccc0428..25a1089a7376f0cbd96bb43b5c203640
}
private static float[] collectCandidateStepUpHeights(AABB box, List<VoxelShape> colliders, float deltaY, float maxUpStep) {
@@ -2662,23 +2810,110 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -2659,23 +2807,110 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
public boolean isInWall() {
@@ -28849,7 +28849,7 @@ index 189385600b9094291152035b17df869eaccc0428..25a1089a7376f0cbd96bb43b5c203640
}
public InteractionResult interact(Player player, InteractionHand hand) {
@@ -4102,15 +4337,17 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4099,15 +4334,17 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
public Iterable<Entity> getIndirectPassengers() {
@@ -28875,7 +28875,7 @@ index 189385600b9094291152035b17df869eaccc0428..25a1089a7376f0cbd96bb43b5c203640
}
public int countPlayerPassengers() {
@@ -4248,77 +4485,136 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4245,77 +4482,136 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
return Mth.lerp(partialTick, this.yRotO, this.yRot);
}
@@ -29066,7 +29066,7 @@ index 189385600b9094291152035b17df869eaccc0428..25a1089a7376f0cbd96bb43b5c203640
public boolean touchingUnloadedChunk() {
AABB aabb = this.getBoundingBox().inflate(1.0);
@@ -4471,6 +4767,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4468,6 +4764,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
this.setPosRaw(x, y, z, false);
}
public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) {
@@ -29082,7 +29082,7 @@ index 189385600b9094291152035b17df869eaccc0428..25a1089a7376f0cbd96bb43b5c203640
if (!checkPosition(this, x, y, z)) {
return;
}
@@ -4601,6 +4906,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4598,6 +4903,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@Override
public final void setRemoved(Entity.RemovalReason removalReason, org.bukkit.event.entity.EntityRemoveEvent.Cause cause) {
@@ -29095,7 +29095,7 @@ index 189385600b9094291152035b17df869eaccc0428..25a1089a7376f0cbd96bb43b5c203640
org.bukkit.craftbukkit.event.CraftEventFactory.callEntityRemoveEvent(this, cause);
// CraftBukkit end
final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers
@@ -4612,7 +4923,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4609,7 +4920,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
this.stopRiding();
}
@@ -29104,7 +29104,7 @@ index 189385600b9094291152035b17df869eaccc0428..25a1089a7376f0cbd96bb43b5c203640
this.levelCallback.onRemove(removalReason);
this.onRemoval(removalReason);
// Paper start - Folia schedulers
@@ -4646,7 +4957,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4643,7 +4954,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
public boolean shouldBeSaved() {
return (this.removalReason == null || this.removalReason.shouldSave())
&& !this.isPassenger()
@@ -29379,7 +29379,7 @@ index 9f34fc4278860dd7bcfa1fd79b15e588b0cc3973..a7ebd624652cb6f0edc735bf6b9760e7
public ClipContext(Vec3 from, Vec3 to, ClipContext.Block block, ClipContext.Fluid fluid, Entity entity) {
diff --git a/net/minecraft/world/level/EntityGetter.java b/net/minecraft/world/level/EntityGetter.java
index 300f3ed58109219d97846082941b860585f66fed..e81195df621159da67136f020fa7a6d39d1ee5ed 100644
index 300f3ed58109219d97846082941b860585f66fed..892a7c1eb1b321ca6d5ca709142e7feae1220815 100644
--- a/net/minecraft/world/level/EntityGetter.java
+++ b/net/minecraft/world/level/EntityGetter.java
@@ -15,7 +15,7 @@ import net.minecraft.world.phys.shapes.BooleanOp;
@@ -29397,14 +29397,6 @@ index 300f3ed58109219d97846082941b860585f66fed..e81195df621159da67136f020fa7a6d3
- default boolean isUnobstructed(@Nullable Entity entity, VoxelShape shape) {
- if (shape.isEmpty()) {
- return true;
- } else {
- for (Entity entity1 : this.getEntities(entity, shape.bounds())) {
- if (!entity1.isRemoved()
- && entity1.blocksBuilding
- && (entity == null || !entity1.isPassengerOfSameVehicle(entity))
- && Shapes.joinIsNotEmpty(shape, Shapes.create(entity1.getBoundingBox()), BooleanOp.AND)) {
- return false;
+ // Paper start - rewrite chunk system
+ @Override
+ default List<Entity> moonrise$getHardCollidingEntities(final Entity entity, final AABB box, final Predicate<? super Entity> predicate) {
@@ -29415,7 +29407,14 @@ index 300f3ed58109219d97846082941b860585f66fed..e81195df621159da67136f020fa7a6d3
+ // Paper start - optimise collisions
+ default boolean isUnobstructed(@Nullable Entity entity, VoxelShape voxel) {
+ if (voxel.isEmpty()) {
+ return false;
return true;
- } else {
- for (Entity entity1 : this.getEntities(entity, shape.bounds())) {
- if (!entity1.isRemoved()
- && entity1.blocksBuilding
- && (entity == null || !entity1.isPassengerOfSameVehicle(entity))
- && Shapes.joinIsNotEmpty(shape, Shapes.create(entity1.getBoundingBox()), BooleanOp.AND)) {
- return false;
+ }
+
+ final AABB singleAABB = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)voxel).moonrise$getSingleAABBRepresentation();
@@ -29503,7 +29502,7 @@ index 300f3ed58109219d97846082941b860585f66fed..e81195df621159da67136f020fa7a6d3
// Paper start - Affects Spawning API
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index 771d6ed6a7c889c09efd4ff6e20298c851eaa79f..8331b49185500ab3b4307e9ae05126b4f83a318a 100644
index 771d6ed6a7c889c09efd4ff6e20298c851eaa79f..a768f041fd16d253ec4ab5eb75288b1771d5cb00 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -79,6 +79,7 @@ import net.minecraft.world.level.storage.LevelData;
@@ -29673,7 +29672,7 @@ index 771d6ed6a7c889c09efd4ff6e20298c851eaa79f..8331b49185500ab3b4307e9ae05126b4
+ public boolean isUnobstructed(final Entity entity) {
+ final AABB boundingBox = entity.getBoundingBox();
+ if (ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isEmpty(boundingBox)) {
+ return false;
+ return true;
+ }
+
+ final List<Entity> entities = this.getEntities(
@@ -30419,7 +30418,7 @@ index 2709803b9266ff4a2034d83321cd0ba4e30fc0aa..26c8c1e5598daf3550aef05b12218c47
ChunkAccess getChunk(int x, int z, ChunkStatus chunkStatus, boolean requireChunk);
diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java
index 3619509d51ebd2e5e36fe4b67e76c94a8d272d1b..7b132c55caf9d3c3df3b0a123f4b5bfc7ae35984 100644
index 155bf7ccff5c1332fceda2598342bb03624608ff..c4485f28def66264846a436cfba7bddccb66b82e 100644
--- a/net/minecraft/world/level/ServerExplosion.java
+++ b/net/minecraft/world/level/ServerExplosion.java
@@ -63,6 +63,249 @@ public class ServerExplosion implements Explosion {
@@ -30867,7 +30866,7 @@ index 3619509d51ebd2e5e36fe4b67e76c94a8d272d1b..7b132c55caf9d3c3df3b0a123f4b5bfc
}
diff --git a/net/minecraft/world/level/biome/Biome.java b/net/minecraft/world/level/biome/Biome.java
index ea521e1d636b8ffdeb22882dfc8875b2ddbd8da1..7b666bbeefe296e7fdbadcc72dbf9e602f73e925 100644
index 21b9021df95d3611ad17c9fd5f429f97e824ed2f..f44461f92a10cbfdb8fcdbc3a2442e526b9d3d33 100644
--- a/net/minecraft/world/level/biome/Biome.java
+++ b/net/minecraft/world/level/biome/Biome.java
@@ -117,20 +117,7 @@ public final class Biome {
@@ -33699,6 +33698,25 @@ index 342c83309b19c64d86e0dd97c1756c96be52772b..423779a2b690f387a4f0bd07b97b50e0
+ // Paper end - rewrite chunk system
}
}
diff --git a/net/minecraft/world/level/gameevent/DynamicGameEventListener.java b/net/minecraft/world/level/gameevent/DynamicGameEventListener.java
index 2b98932e69271571e6e9350c55c82edc858d76f6..c8980c50713e1526c526ed181fb2ad9486bab353 100644
--- a/net/minecraft/world/level/gameevent/DynamicGameEventListener.java
+++ b/net/minecraft/world/level/gameevent/DynamicGameEventListener.java
@@ -27,6 +27,14 @@ public class DynamicGameEventListener<T extends GameEventListener> {
public void remove(ServerLevel level) {
ifChunkExists(level, this.lastSection, listenerRegistry -> listenerRegistry.unregister(this.listener));
+ // Paper start - rewrite chunk system
+ // We need to unset the last section when removed, otherwise if the same instance is re-added at the same position it
+ // will assume there was no change and fail to re-register.
+ // In vanilla, chunks rarely unload and re-load quickly enough to trigger this issue. However, our chunk system has a
+ // quirk where fast chunk reload cycles will often occur on player login (see PR #22).
+ // So we fix this vanilla oversight as our changes cause it to manifest in bugs much more often (see issue #87).
+ this.lastSection = null;
+ // Paper end - rewrite chunk system
}
public void move(ServerLevel level) {
diff --git a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java b/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java
index 6d61739574155f89511b9adcaf1174841bdc7da7..65728ef17e63d71833677fdcbd5bb90794b4822b 100644
--- a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java

View File

@@ -22,7 +22,7 @@ Alternate Current's wire handler.
diff --git a/alternate/current/wire/LevelHelper.java b/alternate/current/wire/LevelHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..eda108e2df9bf7d1ddd89287b8d2c2d7f1637c96
index 0000000000000000000000000000000000000000..ff663d3089627e75221aa128aff4bf5cc459addb
--- /dev/null
+++ b/alternate/current/wire/LevelHelper.java
@@ -0,0 +1,66 @@
@@ -57,7 +57,7 @@ index 0000000000000000000000000000000000000000..eda108e2df9bf7d1ddd89287b8d2c2d7
+ static boolean setWireState(ServerLevel level, BlockPos pos, BlockState state, boolean updateNeighborShapes) {
+ int y = pos.getY();
+
+ if (y < level.getMinY() || y >= level.getMaxY()) {
+ if (y < level.getMinY() || y > level.getMaxY()) {
+ return false;
+ }
+
@@ -2326,7 +2326,7 @@ index 0000000000000000000000000000000000000000..298076a0db4e6ee6e4775ac43bf749d9
+ }
+}
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 95a4e37a3c93f9b3c56c7a7376ed521cd46fbb6f..46dfaed12c998c219a20c711a06531aed2c68012 100644
index a293d1481b5f4a1d18addc3e518486c639223f09..5bf38ab129451e867b638cfbd2d7be59cbf7f38d 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -214,6 +214,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -2337,7 +2337,7 @@ index 95a4e37a3c93f9b3c56c7a7376ed521cd46fbb6f..46dfaed12c998c219a20c711a06531ae
public LevelChunk getChunkIfLoaded(int x, int z) {
return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately
@@ -2555,6 +2556,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -2557,6 +2558,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
return this.chunkSource.getGenerator().getSeaLevel();
}
@@ -2352,7 +2352,7 @@ index 95a4e37a3c93f9b3c56c7a7376ed521cd46fbb6f..46dfaed12c998c219a20c711a06531ae
@Override
public void onCreated(Entity entity) {
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index 8331b49185500ab3b4307e9ae05126b4f83a318a..2bbebb4335d927f240abcac67a5b423e38dc33d7 100644
index a768f041fd16d253ec4ab5eb75288b1771d5cb00..1dbe7c7c1051c3972105534a07ce50d4cf98fc85 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -2099,6 +2099,17 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl

View File

@@ -8,7 +8,7 @@ This ensures at least a valid version of the chunk exists
on disk, even if outdated
diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java
index 7da388ffab162c282cad0f297bb7304f3c2abbaf..ff4fc280409f680f3879a495e37cf1925b1a38f1 100644
index 984db72272d552c7210bd6f437ea88694ddd2828..dea2823a9d1d69dcb0a4759d8ea9b3015ede20dc 100644
--- a/net/minecraft/world/level/chunk/storage/RegionFile.java
+++ b/net/minecraft/world/level/chunk/storage/RegionFile.java
@@ -24,6 +24,7 @@ import org.slf4j.Logger;

View File

@@ -42,7 +42,7 @@ index 64a718c98f799c62a5bb28e1e8e5f66cc96c915d..666f2e967c99f78422c83fb20e1a3bf3
this.used.set(sectorOffset, sectorOffset + sectorCount);
}
diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java
index ff4fc280409f680f3879a495e37cf1925b1a38f1..a4621c96fd456c5cdd1b6847931806e677b26b30 100644
index dea2823a9d1d69dcb0a4759d8ea9b3015ede20dc..0c41177462cca5c4bbab6490e323b9535fd6300f 100644
--- a/net/minecraft/world/level/chunk/storage/RegionFile.java
+++ b/net/minecraft/world/level/chunk/storage/RegionFile.java
@@ -46,6 +46,355 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
@@ -699,7 +699,7 @@ index 0c739ca5b01ac0ec35a11fd01c5fc65de97c2852..de7deee4b79c969a7797bd57b657a164
public static final RegionFileVersion VERSION_GZIP = register(
new RegionFileVersion(
diff --git a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
index 70a9972252576e039ac126f6057a6ed66b80cdfc..d783c3580ea274a0a9cb07449eb8037bc5a04d76 100644
index 879d411775a2fece1d8a970300cb3a550baa6305..6b6aaeca14178b5b709e20ae13552d42217f15c0 100644
--- a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
+++ b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
@@ -120,6 +120,18 @@ public record SerializableChunkData(

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] Incremental chunk and player saving
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index d967d605c2e4227ae980c30f1c8b86edbc680d6d..6dbae12bbfd47cd4e75bc3089561e8e226e9e604 100644
index 409c1134327bfcc338c3ac5e658a83cc396645d1..cc2d442682496197d29ace79b22e6cf6fb7edf5e 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -960,7 +960,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -50,10 +50,10 @@ index d967d605c2e4227ae980c30f1c8b86edbc680d6d..6dbae12bbfd47cd4e75bc3089561e8e2
ProfilerFiller profilerFiller = Profiler.get();
this.runAllTasks(); // Paper - move runAllTasks() into full server tick (previously for timings)
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 46dfaed12c998c219a20c711a06531aed2c68012..ebeeb63c3dca505a3ce8b88feaa5d2ca20ec24a2 100644
index 42995dac38248032b6abecc27124adfe12ec4cab..28a67294c3e678e01d5dfd68b950234213d8e55c 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -1316,6 +1316,28 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1318,6 +1318,28 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
return !this.server.isUnderSpawnProtection(this, pos, player) && this.getWorldBorder().isWithinBounds(pos);
}
@@ -83,7 +83,7 @@ index 46dfaed12c998c219a20c711a06531aed2c68012..ebeeb63c3dca505a3ce8b88feaa5d2ca
// Paper start - add close param
this.save(progress, flush, skipSave, false);
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index e61fe83479f095e8addbd3e8f1d5179c998ae1eb..0a7e5106a1d39150326e7c323030df5d32ecef1e 100644
index f44600604a7bf68c990cd74a1ac2d7900ff6e88e..69b8074e18775c846d5991f40bc2e0a5186500ac 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -180,6 +180,7 @@ import org.slf4j.Logger;
@@ -95,7 +95,7 @@ index e61fe83479f095e8addbd3e8f1d5179c998ae1eb..0a7e5106a1d39150326e7c323030df5d
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10;
private static final int FLY_STAT_RECORDING_SPEED = 25;
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 5e94dd9e26aa4fd6545dbaae2ae0cb51cb6f13e0..03feaf0adb8ee87e33744a4615dc2507a02f92d7 100644
index 7d1d4abfb04829d8c4722e326c6c6b8fb2ab91f4..5a4960fdbd97d830ac79845697eea9372c48a13b 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -482,6 +482,7 @@ public abstract class PlayerList {

View File

@@ -78,10 +78,10 @@ index 87d4291a3944f706a694536da6de0f28c548ab8d..5576bf1d1d70ab7a010653d3207909b5
profiler.popPush("spawnAndTick");
boolean _boolean = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 0a7e5106a1d39150326e7c323030df5d32ecef1e..a63702dd7e86fc8b9f78c2ae23e23b65b6b2ee24 100644
index 02fb30a3adf92de0795aee213caf94a228b01ca0..67f6e40216e0be063a3cfb61427f095f7c74d785 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -368,6 +368,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -375,6 +375,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
public boolean queueHealthUpdatePacket;
public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket;
// Paper end - cancellable death event

View File

@@ -60,10 +60,10 @@ index 5576bf1d1d70ab7a010653d3207909b5de867e70..6540b2d6a1062d883811ce240c49d30d
spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true);
} else {
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index a63702dd7e86fc8b9f78c2ae23e23b65b6b2ee24..6d75a641431c7deb7e8ddbf02cdc919015a3a7dc 100644
index 67f6e40216e0be063a3cfb61427f095f7c74d785..3de65c4025be91d938a350c884975cb6edc234d3 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -372,6 +372,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -379,6 +379,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
public static final int MOBCATEGORY_TOTAL_ENUMS = net.minecraft.world.entity.MobCategory.values().length;
public final int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS];
// Paper end - Optional per player mob spawns

View File

@@ -48,10 +48,10 @@ index 0000000000000000000000000000000000000000..24a2090e068ad3c0d08705050944abdf
+ }
+}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 6dbae12bbfd47cd4e75bc3089561e8e226e9e604..9c859025302ddb2c20cf6457fa4e4eaf7fbafdd7 100644
index cc2d442682496197d29ace79b22e6cf6fb7edf5e..ae220a732c78ab076261f20b5a54c71d7fceb407 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1707,6 +1707,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1708,6 +1708,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
@@ -60,10 +60,10 @@ index 6dbae12bbfd47cd4e75bc3089561e8e226e9e604..9c859025302ddb2c20cf6457fa4e4eaf
/* Drop global time updates
if (this.tickCount % 20 == 0) {
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
index c255e11cb0981bd7e0456d4fd401beb5257be597..d6361863d6a1e364de262d6199373cbd68d1c699 100644
index b393be76bead3c66ab0bd8a0e6fd9b9ef81d8e28..76f50437396f8f856381d0fbef52953ef7c263f6 100644
--- a/net/minecraft/world/item/ItemStack.java
+++ b/net/minecraft/world/item/ItemStack.java
@@ -808,10 +808,16 @@ public final class ItemStack implements DataComponentHolder {
@@ -827,10 +827,16 @@ public final class ItemStack implements DataComponentHolder {
}
public ItemStack copy() {

View File

@@ -6,10 +6,10 @@ Subject: [PATCH] Optimise collision checking in player move packet handling
Move collision logic to just the hasNewCollision call instead of getCubes + hasNewCollision
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 650126e6445c0458c6a6649c235908bfeea428cd..d248671b2e1c6256fc4d74320bdb29ca078bad0b 100644
index 12c83cb084563a4e3f7f357d8b600941544ef2b0..90e582ca30851857add5e2d830e9876667fd1807 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -561,7 +561,7 @@ public class ServerGamePacketListenerImpl
@@ -563,7 +563,7 @@ public class ServerGamePacketListenerImpl
return;
}
@@ -18,7 +18,7 @@ index 650126e6445c0458c6a6649c235908bfeea428cd..d248671b2e1c6256fc4d74320bdb29ca
d3 = d - this.vehicleLastGoodX; // Paper - diff on change, used for checking large move vectors above
d4 = d1 - this.vehicleLastGoodY; // Paper - diff on change, used for checking large move vectors above
d5 = d2 - this.vehicleLastGoodZ; // Paper - diff on change, used for checking large move vectors above
@@ -571,6 +571,7 @@ public class ServerGamePacketListenerImpl
@@ -573,6 +573,7 @@ public class ServerGamePacketListenerImpl
}
rootVehicle.move(MoverType.PLAYER, new Vec3(d3, d4, d5));
@@ -26,7 +26,7 @@ index 650126e6445c0458c6a6649c235908bfeea428cd..d248671b2e1c6256fc4d74320bdb29ca
double verticalDelta = d4; // Paper - Decompile fix, was named d11 previously, is now gone in the source
d3 = d - rootVehicle.getX();
d4 = d1 - rootVehicle.getY();
@@ -582,14 +583,22 @@ public class ServerGamePacketListenerImpl
@@ -584,14 +585,22 @@ public class ServerGamePacketListenerImpl
d7 = d3 * d3 + d4 * d4 + d5 * d5;
boolean flag2 = false;
if (d7 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot
@@ -52,7 +52,7 @@ index 650126e6445c0458c6a6649c235908bfeea428cd..d248671b2e1c6256fc4d74320bdb29ca
rootVehicle.absMoveTo(x, y, z, f, f1);
this.player.absMoveTo(x, y, z, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
this.send(ClientboundMoveVehiclePacket.fromEntity(rootVehicle));
@@ -667,9 +676,32 @@ public class ServerGamePacketListenerImpl
@@ -669,9 +678,32 @@ public class ServerGamePacketListenerImpl
}
private boolean noBlocksAround(Entity entity) {
@@ -88,7 +88,7 @@ index 650126e6445c0458c6a6649c235908bfeea428cd..d248671b2e1c6256fc4d74320bdb29ca
}
@Override
@@ -1361,7 +1393,7 @@ public class ServerGamePacketListenerImpl
@@ -1371,7 +1403,7 @@ public class ServerGamePacketListenerImpl
}
}
@@ -97,7 +97,7 @@ index 650126e6445c0458c6a6649c235908bfeea428cd..d248671b2e1c6256fc4d74320bdb29ca
d3 = d - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above
d4 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above
d5 = d2 - this.lastGoodZ; // Paper - diff on change, used for checking large move vectors above
@@ -1400,6 +1432,7 @@ public class ServerGamePacketListenerImpl
@@ -1410,6 +1442,7 @@ public class ServerGamePacketListenerImpl
boolean flag1 = this.player.verticalCollisionBelow;
this.player.move(MoverType.PLAYER, new Vec3(d3, d4, d5));
this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
@@ -105,7 +105,7 @@ index 650126e6445c0458c6a6649c235908bfeea428cd..d248671b2e1c6256fc4d74320bdb29ca
// Paper start - prevent position desync
if (this.awaitingPositionFromClient != null) {
return; // ... thanks Mojang for letting move calls teleport across dimensions.
@@ -1432,7 +1465,17 @@ public class ServerGamePacketListenerImpl
@@ -1442,7 +1475,17 @@ public class ServerGamePacketListenerImpl
}
// Paper start - Add fail move event
@@ -124,7 +124,7 @@ index 650126e6445c0458c6a6649c235908bfeea428cd..d248671b2e1c6256fc4d74320bdb29ca
if (teleportBack) {
io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.CLIPPED_INTO_BLOCK,
toX, toY, toZ, toYaw, toPitch, false);
@@ -1568,7 +1611,7 @@ public class ServerGamePacketListenerImpl
@@ -1578,7 +1621,7 @@ public class ServerGamePacketListenerImpl
private boolean updateAwaitingTeleport() {
if (this.awaitingPositionFromClient != null) {
@@ -133,7 +133,7 @@ index 650126e6445c0458c6a6649c235908bfeea428cd..d248671b2e1c6256fc4d74320bdb29ca
this.awaitingTeleportTime = this.tickCount;
this.teleport(
this.awaitingPositionFromClient.x,
@@ -1587,6 +1630,33 @@ public class ServerGamePacketListenerImpl
@@ -1597,6 +1640,33 @@ public class ServerGamePacketListenerImpl
}
}

View File

@@ -0,0 +1,34 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Mon, 20 Jan 2025 13:30:34 -0800
Subject: [PATCH] Flush regionfiles on save configuration option
The windows file system does not write metadata unless
the FileChannel is explicitly flushed with metaData=true.
Note: Setting SYNC (not DSYNC) on the FileChannel does not appear
to write the metadata.
Specifically, we are interested in writing the last modified
timestamp so that fs watchers can detect when RegionFiles are
modified.
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java
index 1acea58838f057ab87efd103cbecb6f5aeaef393..98fbc5c8044bd945d64569f13412a6e7e49a4e7f 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java
@@ -1258,6 +1258,14 @@ public final class MoonriseRegionFileIO {
try {
this.regionDataController.finishWrite(this.chunkX, this.chunkZ, writeData);
+ // Paper start - flush regionfiles on save
+ if (this.world.paperConfig().chunks.flushRegionsOnSave) {
+ final RegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ);
+ if (regionFile != null) {
+ regionFile.flush();
+ } // else: evicted from cache, which should have called flush
+ }
+ // Paper end - flush regionfiles on save
} catch (final Throwable thr) {
failedWrite = thr instanceof IOException;
LOGGER.error("Failed to write chunk data for task: " + this.toString(), thr);

View File

@@ -0,0 +1,34 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Sun, 2 Feb 2025 10:57:48 -0800
Subject: [PATCH] Do not record movement for vehicles/players unaffected by
blocks
If the player is not affected by movement through blocks, then
storing the movement would eventually invoke logic to apply effects
caused by moving through such blocks. For example, moving through
a portal in spectator mode and then later switching to creative mode
would portal the player.
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 90e582ca30851857add5e2d830e9876667fd1807..c569cdfa4cba4f65892ffd4045c611837049f440 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -659,7 +659,7 @@ public class ServerGamePacketListenerImpl
// CraftBukkit end
this.player.serverLevel().getChunkSource().move(this.player);
- rootVehicle.recordMovementThroughBlocks(new Vec3(x, y, z), rootVehicle.position());
+ if (!rootVehicle.isSpectator() && rootVehicle.isAffectedByBlocks()) rootVehicle.recordMovementThroughBlocks(new Vec3(x, y, z), rootVehicle.position()); // Paper - Do not record movement for vehicles/players unaffected by blocks
Vec3 vec3 = new Vec3(rootVehicle.getX() - x, rootVehicle.getY() - y, rootVehicle.getZ() - z);
this.handlePlayerKnownMovement(vec3);
rootVehicle.setOnGroundWithMovement(packet.onGround(), vec3);
@@ -1577,7 +1577,7 @@ public class ServerGamePacketListenerImpl
Vec3 vec3 = new Vec3(this.player.getX() - x, this.player.getY() - y, this.player.getZ() - z);
this.player.setOnGroundWithMovement(packet.isOnGround(), packet.horizontalCollision(), vec3);
this.player.doCheckFallDamage(vec3.x, vec3.y, vec3.z, packet.isOnGround());
- this.player.recordMovementThroughBlocks(new Vec3(x, y, z), this.player.position());
+ if (!this.player.isSpectator() && this.player.isAffectedByBlocks()) this.player.recordMovementThroughBlocks(new Vec3(x, y, z), this.player.position()); // Paper - Do not record movement for vehicles/players unaffected by blocks
this.handlePlayerKnownMovement(vec3);
if (flag) {
this.player.resetFallDistance();

View File

@@ -0,0 +1,19 @@
--- a/com/mojang/brigadier/suggestion/IntegerSuggestion.java
+++ b/com/mojang/brigadier/suggestion/IntegerSuggestion.java
@@ -53,7 +_,7 @@
@Override
public int compareTo(final Suggestion o) {
- if (o instanceof IntegerSuggestion) {
+ if (false && o instanceof IntegerSuggestion) { // Paper - fix unstable Suggestion comparison
return Integer.compare(value, ((IntegerSuggestion) o).value);
}
return super.compareTo(o);
@@ -61,6 +_,6 @@
@Override
public int compareToIgnoreCase(final Suggestion b) {
- return compareTo(b);
+ return super.compareToIgnoreCase(b); // Paper - fix unstable Suggestion comparison
}
}

View File

@@ -0,0 +1,32 @@
--- a/com/mojang/brigadier/suggestion/Suggestion.java
+++ b/com/mojang/brigadier/suggestion/Suggestion.java
@@ -76,13 +_,27 @@
'}';
}
+ // Paper start - fix unstable Suggestion comparison
+ private static int compare0(final Suggestion lhs, final Suggestion rhs, final java.util.Comparator<String> textComparator) {
+ if (lhs instanceof final IntegerSuggestion lis && rhs instanceof final IntegerSuggestion ris) {
+ return Integer.compare(lis.getValue(), ris.getValue());
+ } else if (lhs instanceof IntegerSuggestion) {
+ return -1;
+ } else if (rhs instanceof IntegerSuggestion) {
+ return 1;
+ } else {
+ return textComparator.compare(lhs.text, rhs.text);
+ }
+ }
+ // Paper end - fix unstable Suggestion comparison
+
@Override
public int compareTo(final Suggestion o) {
- return text.compareTo(o.text);
+ return compare0(this, o, java.util.Comparator.naturalOrder()); // Paper - fix unstable Suggestion comparison
}
public int compareToIgnoreCase(final Suggestion b) {
- return text.compareToIgnoreCase(b.text);
+ return compare0(this, b, String.CASE_INSENSITIVE_ORDER); // Paper - fix unstable Suggestion comparison
}
public Suggestion expand(final String command, final StringRange range) {

View File

@@ -1,6 +1,6 @@
--- a/com/mojang/brigadier/tree/CommandNode.java
+++ b/com/mojang/brigadier/tree/CommandNode.java
@@ -27,11 +_,21 @@
@@ -27,11 +_,22 @@
private final Map<String, CommandNode<S>> children = new LinkedHashMap<>();
private final Map<String, LiteralCommandNode<S>> literals = new LinkedHashMap<>();
private final Map<String, ArgumentCommandNode<S, ?>> arguments = new LinkedHashMap<>();
@@ -13,6 +13,7 @@
+ public CommandNode<net.minecraft.commands.CommandSourceStack> clientNode; // Paper - Brigadier API
+ public CommandNode<io.papermc.paper.command.brigadier.CommandSourceStack> unwrappedCached = null; // Paper - Brigadier Command API
+ public CommandNode<io.papermc.paper.command.brigadier.CommandSourceStack> wrappedCached = null; // Paper - Brigadier Command API
+ public io.papermc.paper.command.brigadier.PluginCommandMeta pluginCommandMeta; // Paper - Brigadier Command API
+ // CraftBukkit start
+ public void removeCommand(String name) {
+ this.children.remove(name);

View File

@@ -18,6 +18,37 @@
public CommandSourceStack(
CommandSource source,
@@ -187,6 +_,30 @@
this.chatMessageChainer
);
}
+
+ // Paper start - Expose 'with' functions from the CommandSourceStack
+ @Override
+ public CommandSourceStack withLocation(org.bukkit.Location location) {
+ return this.getLocation().equals(location)
+ ? this
+ : new CommandSourceStack(
+ this.source,
+ new Vec3(location.x(), location.y(), location.z()),
+ new Vec2(location.getPitch(), location.getYaw()),
+ ((org.bukkit.craftbukkit.CraftWorld) location.getWorld()).getHandle(),
+ this.permissionLevel,
+ this.textName,
+ this.displayName,
+ this.server,
+ this.entity,
+ this.silent,
+ this.resultCallback,
+ this.anchor,
+ this.signingContext,
+ this.chatMessageChainer
+ );
+ }
+ // Paper end - Expose 'with' functions from the CommandSourceStack
public CommandSourceStack withRotation(Vec2 rotation) {
return this.rotation.equals(rotation)
@@ -391,9 +_,44 @@
@Override
@@ -92,6 +123,15 @@
}
}
@@ -523,7 +_,7 @@
@Override
public Collection<String> getOnlinePlayerNames() {
- return Lists.newArrayList(this.server.getPlayerNames());
+ return this.entity instanceof ServerPlayer sourcePlayer && !sourcePlayer.getBukkitEntity().hasPermission("paper.bypass-visibility.tab-completion") ? this.getServer().getPlayerList().getPlayers().stream().filter(serverPlayer -> sourcePlayer.getBukkitEntity().canSee(serverPlayer.getBukkitEntity())).map(serverPlayer -> serverPlayer.getGameProfile().getName()).toList() : Lists.newArrayList(this.server.getPlayerNames()); // Paper - Make CommandSourceStack respect hidden players
}
@Override
@@ -598,4 +_,16 @@
public boolean isSilent() {
return this.silent;

View File

@@ -1,6 +1,18 @@
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -251,6 +_,30 @@
@@ -150,6 +_,11 @@
private final CommandDispatcher<CommandSourceStack> dispatcher = new CommandDispatcher<>();
public Commands(Commands.CommandSelection selection, CommandBuildContext context) {
+ // Paper start - Brigadier API - modern minecraft overloads that do not use redirects but are copies instead
+ this(selection, context, false);
+ }
+ public Commands(Commands.CommandSelection selection, CommandBuildContext context, final boolean modern) {
+ // Paper end - Brigadier API - modern minecraft overloads that do not use redirects but are copies instead
AdvancementCommands.register(this.dispatcher);
AttributeCommand.register(this.dispatcher, context);
ExecuteCommand.register(this.dispatcher, context);
@@ -251,6 +_,40 @@
PublishCommand.register(this.dispatcher);
}
@@ -14,9 +26,20 @@
+ // Paper start - Brigadier Command API
+ // Create legacy minecraft namespace commands
+ for (final CommandNode<CommandSourceStack> node : new java.util.ArrayList<>(this.dispatcher.getRoot().getChildren())) {
+ // The brigadier dispatcher is not able to resolve nested redirects.
+ // E.g. registering the alias minecraft:tp cannot redirect to tp, as tp itself redirects to teleport.
+ // Instead, target the first none redirecting node.
+ if (modern) {
+ // Modern behaviour that simply creates a full copy of the commands node.
+ // Avoids plenty of issues around registering redirects *to* these nodes from the API
+ this.dispatcher.getRoot().addChild(
+ io.papermc.paper.command.brigadier.PaperBrigadier.copyLiteral(
+ "minecraft:" + node.getName(),
+ (com.mojang.brigadier.tree.LiteralCommandNode<CommandSourceStack>) node
+ )
+ );
+ continue;
+ }
+
+ // Legacy behaviour of creating a flattened redirecting node.
+ // Used by CommandArgumentUpgrader
+ CommandNode<CommandSourceStack> flattenedAliasTarget = node;
+ while (flattenedAliasTarget.getRedirect() != null) flattenedAliasTarget = flattenedAliasTarget.getRedirect();
+
@@ -24,8 +47,7 @@
+ com.mojang.brigadier.builder.LiteralArgumentBuilder.<CommandSourceStack>literal("minecraft:" + node.getName())
+ .executes(flattenedAliasTarget.getCommand())
+ .requires(flattenedAliasTarget.getRequirement())
+ .redirect(flattenedAliasTarget)
+ );
+ .redirect(flattenedAliasTarget));
+ }
+ // Paper end - Brigadier Command API
this.dispatcher.setConsumer(ExecutionCommandSource.resultConsumer());
@@ -150,11 +172,10 @@
}
return null;
@@ -360,25 +_,130 @@
@@ -360,26 +_,120 @@
}
public void sendCommands(ServerPlayer player) {
- Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> map = Maps.newHashMap();
+ // Paper start - Send empty commands if tab completion is disabled
+ if (org.spigotmc.SpigotConfig.tabComplete < 0) {
+ player.connection.send(new ClientboundCommandsPacket(new RootCommandNode<>()));
@@ -182,7 +203,7 @@
+
+ private void sendAsync(ServerPlayer player, java.util.Collection<CommandNode<CommandSourceStack>> dispatcherRootChildren) {
+ // Paper end - Perf: Async command map building
+ Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> map = Maps.newIdentityHashMap(); // Use identity to prevent aliasing issues
Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> map = Maps.newHashMap();
RootCommandNode<SharedSuggestionProvider> rootCommandNode = new RootCommandNode<>();
map.put(this.dispatcher.getRoot(), rootCommandNode);
- this.fillUsableCommands(this.dispatcher.getRoot(), rootCommandNode, player.createCommandSourceStack(), map);
@@ -224,7 +245,6 @@
Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> commandNodeToSuggestionNode
) {
- for (CommandNode<CommandSourceStack> commandNode : rootCommandSource.getChildren()) {
+ commandNodeToSuggestionNode.keySet().removeIf((node) -> !org.spigotmc.SpigotConfig.sendNamespaced && node.getName().contains(":")); // Paper - Remove namedspaced from result nodes to prevent redirect trimming ~ see comment below
+ for (CommandNode<CommandSourceStack> commandNode : children) { // Paper - Perf: Async command map building; pass copy of children
+ // Paper start - Brigadier API
+ if (commandNode.clientNode != null) {
@@ -249,12 +269,11 @@
+ - Don't allow command nodes to be deleted
+ - Do this :)
+ */
+
+ // Is there an invalid command redirect?
+ if (argumentBuilder.getRedirect() != null && commandNodeToSuggestionNode.get(argumentBuilder.getRedirect()) == null) {
+ // Create the argument builder with the same values as the specified node, but with a different literal and populated children
+
+ CommandNode<SharedSuggestionProvider> redirect = argumentBuilder.getRedirect();
+ final CommandNode<SharedSuggestionProvider> redirect = argumentBuilder.getRedirect();
+ // Diff copied from LiteralCommand#createBuilder
+ final com.mojang.brigadier.builder.LiteralArgumentBuilder<SharedSuggestionProvider> builder = com.mojang.brigadier.builder.LiteralArgumentBuilder.literal(commandNode.getName());
+ builder.requires(redirect.getRequirement());
@@ -263,7 +282,7 @@
+ builder.executes(redirect.getCommand());
+ }
+ // Diff copied from LiteralCommand#createBuilder
+ for (CommandNode<SharedSuggestionProvider> child : redirect.getChildren()) {
+ for (final CommandNode<SharedSuggestionProvider> child : redirect.getChildren()) {
+ builder.then(child);
+ }
+
@@ -271,21 +290,15 @@
+ }
+ // Paper end
argumentBuilder.requires(suggestions -> true);
if (argumentBuilder.getCommand() != null) {
- if (argumentBuilder.getCommand() != null) {
- argumentBuilder.executes(commandContext -> 0);
+ // Paper start - fix suggestions due to falsely equal nodes
+ // Always create a new instance
+ //noinspection Convert2Lambda
+ argumentBuilder.executes(new com.mojang.brigadier.Command<>() {
+ @Override
+ public int run(com.mojang.brigadier.context.CommandContext<SharedSuggestionProvider> commandContext) {
+ return 0;
+ }
+ });
+ // Paper end - fix suggestions due to falsely equal nodes
}
- }
+ // Paper - don't replace Command instance on suggestion node
+ // we want the exact command instance to be used for equality checks
+ // when assigning serialization ids to each command node
if (argumentBuilder instanceof RequiredArgumentBuilder) {
RequiredArgumentBuilder<SharedSuggestionProvider, ?> requiredArgumentBuilder = (RequiredArgumentBuilder<SharedSuggestionProvider, ?>)argumentBuilder;
@@ -396,7 +_,7 @@
commandNodeToSuggestionNode.put(commandNode, commandNode1);
rootSuggestion.addChild(commandNode1);

View File

@@ -1,5 +1,34 @@
--- a/net/minecraft/core/component/DataComponentPatch.java
+++ b/net/minecraft/core/component/DataComponentPatch.java
@@ -86,6 +_,11 @@
buffer.writeVarInt(0);
buffer.writeVarInt(0);
} else {
+ // Paper start - data sanitization for items
+ final io.papermc.paper.util.ItemObfuscationSession itemObfuscationSession = value.map.isEmpty()
+ ? null // Avoid thread local lookup of current session if it won't be needed anyway.
+ : io.papermc.paper.util.ItemObfuscationSession.currentSession();
+ // Paper end - data sanitization for items
int i = 0;
int i1 = 0;
@@ -93,7 +_,7 @@
value.map
)) {
if (entry.getValue().isPresent()) {
- i++;
+ if (!io.papermc.paper.util.ItemComponentSanitizer.shouldDrop(itemObfuscationSession, entry.getKey())) i++; // Paper - data sanitization for items
} else {
i1++;
}
@@ -106,6 +_,7 @@
value.map
)) {
Optional<?> optional = entryx.getValue();
+ optional = io.papermc.paper.util.ItemComponentSanitizer.override(itemObfuscationSession, entryx.getKey(), entryx.getValue()); // Paper - data sanitization for items
if (optional.isPresent()) {
DataComponentType<?> dataComponentType = entryx.getKey();
DataComponentType.STREAM_CODEC.encode(buffer, dataComponentType);
@@ -125,7 +_,13 @@
}

View File

@@ -5,11 +5,11 @@
);
public static final DataComponentType<ChargedProjectiles> CHARGED_PROJECTILES = register(
- "charged_projectiles", builder -> builder.persistent(ChargedProjectiles.CODEC).networkSynchronized(ChargedProjectiles.STREAM_CODEC).cacheEncoding()
+ "charged_projectiles", builder -> builder.persistent(ChargedProjectiles.CODEC).networkSynchronized(io.papermc.paper.util.DataSanitizationUtil.CHARGED_PROJECTILES).cacheEncoding() // Paper - sanitize charged projectiles
+ "charged_projectiles", builder -> builder.persistent(ChargedProjectiles.CODEC).networkSynchronized(io.papermc.paper.util.OversizedItemComponentSanitizer.CHARGED_PROJECTILES).cacheEncoding() // Paper - sanitize charged projectiles
);
public static final DataComponentType<BundleContents> BUNDLE_CONTENTS = register(
- "bundle_contents", builder -> builder.persistent(BundleContents.CODEC).networkSynchronized(BundleContents.STREAM_CODEC).cacheEncoding()
+ "bundle_contents", builder -> builder.persistent(BundleContents.CODEC).networkSynchronized(io.papermc.paper.util.DataSanitizationUtil.BUNDLE_CONTENTS).cacheEncoding() // Paper - sanitize bundle contents
+ "bundle_contents", builder -> builder.persistent(BundleContents.CODEC).networkSynchronized(io.papermc.paper.util.OversizedItemComponentSanitizer.BUNDLE_CONTENTS).cacheEncoding() // Paper - sanitize bundle contents
);
public static final DataComponentType<PotionContents> POTION_CONTENTS = register(
"potion_contents", builder -> builder.persistent(PotionContents.CODEC).networkSynchronized(PotionContents.STREAM_CODEC).cacheEncoding()
@@ -18,7 +18,7 @@
);
public static final DataComponentType<ItemContainerContents> CONTAINER = register(
- "container", builder -> builder.persistent(ItemContainerContents.CODEC).networkSynchronized(ItemContainerContents.STREAM_CODEC).cacheEncoding()
+ "container", builder -> builder.persistent(ItemContainerContents.CODEC).networkSynchronized(io.papermc.paper.util.DataSanitizationUtil.CONTAINER).cacheEncoding() // Paper - sanitize container contents
+ "container", builder -> builder.persistent(ItemContainerContents.CODEC).networkSynchronized(io.papermc.paper.util.OversizedItemComponentSanitizer.CONTAINER).cacheEncoding() // Paper - sanitize container contents
);
public static final DataComponentType<BlockItemStateProperties> BLOCK_STATE = register(
"block_state", builder -> builder.persistent(BlockItemStateProperties.CODEC).networkSynchronized(BlockItemStateProperties.STREAM_CODEC).cacheEncoding()

View File

@@ -1,6 +1,6 @@
--- a/net/minecraft/network/FriendlyByteBuf.java
+++ b/net/minecraft/network/FriendlyByteBuf.java
@@ -70,6 +_,7 @@
@@ -70,14 +_,20 @@
public class FriendlyByteBuf extends ByteBuf {
public static final int DEFAULT_NBT_QUOTA = 2097152;
private final ByteBuf source;
@@ -8,8 +8,13 @@
public static final short MAX_STRING_LENGTH = 32767;
public static final int MAX_COMPONENT_STRING_LENGTH = 262144;
private static final int PUBLIC_KEY_SIZE = 256;
@@ -78,6 +_,7 @@
private static final int MAX_PUBLIC_KEY_HEADER_SIZE = 256;
private static final int MAX_PUBLIC_KEY_LENGTH = 512;
private static final Gson GSON = new Gson();
+ // Paper start - Track codec depth
+ public boolean trackCodecDepth;
+ public byte codecDepth;
+ // Paper end - Track codec depth
public FriendlyByteBuf(ByteBuf source) {
+ this.adventure$locale = PacketEncoder.ADVENTURE_LOCALE.get(); // Paper - track player's locale for server-side translations

View File

@@ -0,0 +1,51 @@
--- a/net/minecraft/network/codec/ByteBufCodecs.java
+++ b/net/minecraft/network/codec/ByteBufCodecs.java
@@ -378,6 +_,48 @@
};
}
+ // Paper start - Track codec depth
+ static <B extends FriendlyByteBuf, V> StreamCodec<B, V> trackDepth(final StreamCodec<B, V> codec) {
+ return new StreamCodec<>() {
+ @Override
+ public V decode(B buffer) {
+ buffer.trackCodecDepth = true;
+ try {
+ return codec.decode(buffer);
+ } finally {
+ buffer.trackCodecDepth = false;
+ buffer.codecDepth = 0;
+ }
+ }
+
+ @Override
+ public void encode(B buffer, V value) {
+ codec.encode(buffer, value);
+ }
+ };
+ }
+
+ static <B extends FriendlyByteBuf, V> StreamCodec<B, V> increaseDepth(final StreamCodec<B, V> codec) {
+ return new StreamCodec<>() {
+ @Override
+ public V decode(B buffer) {
+ if (!buffer.trackCodecDepth) {
+ return codec.decode(buffer);
+ }
+ if (++buffer.codecDepth > 64) {
+ throw new DecoderException("Too deep");
+ }
+ return codec.decode(buffer);
+ }
+
+ @Override
+ public void encode(B buffer, V value) {
+ codec.encode(buffer, value);
+ }
+ };
+ }
+ // Paper end - Track codec depth
+
static <B extends ByteBuf, V> StreamCodec<B, Optional<V>> optional(final StreamCodec<B, V> codec) {
return new StreamCodec<B, Optional<V>>() {
@Override

View File

@@ -1,21 +1,26 @@
--- a/net/minecraft/network/protocol/common/custom/DiscardedPayload.java
+++ b/net/minecraft/network/protocol/common/custom/DiscardedPayload.java
@@ -4,13 +_,14 @@
@@ -4,13 +_,19 @@
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.ResourceLocation;
-public record DiscardedPayload(ResourceLocation id) implements CustomPacketPayload {
+public record DiscardedPayload(ResourceLocation id, io.netty.buffer.ByteBuf data) implements CustomPacketPayload { // CraftBukkit - store data
+public record DiscardedPayload(ResourceLocation id, byte[] data) implements CustomPacketPayload { // Paper - store data
public static <T extends FriendlyByteBuf> StreamCodec<T, DiscardedPayload> codec(ResourceLocation id, int maxSize) {
- return CustomPacketPayload.codec((value, output) -> {}, buffer -> {
+ return CustomPacketPayload.codec((value, output) -> {
+ output.writeBytes(value.data); // CraftBukkit - serialize
+ // Paper start
+ // Always write data
+ output.writeBytes(value.data);
+ }, buffer -> {
int i = buffer.readableBytes();
if (i >= 0 && i <= maxSize) {
- buffer.skipBytes(i);
- return new DiscardedPayload(id);
+ return new DiscardedPayload(id, buffer.readBytes(i)); // CraftBukkit
+ final byte[] data = new byte[i];
+ buffer.readBytes(data);
+ return new DiscardedPayload(id, data);
+ // Paper end
} else {
throw new IllegalArgumentException("Payload may not be larger than " + maxSize + " bytes");
}

View File

@@ -4,7 +4,7 @@
}
private static void pack(List<SynchedEntityData.DataValue<?>> dataValues, RegistryFriendlyByteBuf buffer) {
+ try (io.papermc.paper.util.DataSanitizationUtil.DataSanitizer ignored = io.papermc.paper.util.DataSanitizationUtil.start(true)) { // Paper - data sanitization
+ try (io.papermc.paper.util.ItemObfuscationSession ignored = io.papermc.paper.util.ItemObfuscationSession.start(io.papermc.paper.configuration.GlobalConfiguration.get().anticheat.obfuscation.items.binding.level)) { // Paper - data sanitization
for (SynchedEntityData.DataValue<?> dataValue : dataValues) {
dataValue.write(buffer);
}

View File

@@ -18,7 +18,7 @@
buffer.writeVarInt(this.entity);
int size = this.slots.size();
+ try (io.papermc.paper.util.DataSanitizationUtil.DataSanitizer ignored = io.papermc.paper.util.DataSanitizationUtil.start(this.sanitize)) { // Paper - data sanitization
+ try (final io.papermc.paper.util.ItemObfuscationSession ignored = io.papermc.paper.util.ItemObfuscationSession.start(this.sanitize ? io.papermc.paper.configuration.GlobalConfiguration.get().anticheat.obfuscation.items.binding.level : io.papermc.paper.util.ItemObfuscationSession.ObfuscationLevel.NONE)) { // Paper - data sanitization
for (int i = 0; i < size; i++) {
Pair<EquipmentSlot, ItemStack> pair = this.slots.get(i);
EquipmentSlot equipmentSlot = pair.getFirst();

View File

@@ -0,0 +1,20 @@
--- a/net/minecraft/network/protocol/game/ServerboundContainerClickPacket.java
+++ b/net/minecraft/network/protocol/game/ServerboundContainerClickPacket.java
@@ -17,7 +_,7 @@
);
private static final int MAX_SLOT_COUNT = 128;
private static final StreamCodec<RegistryFriendlyByteBuf, Int2ObjectMap<ItemStack>> SLOTS_STREAM_CODEC = ByteBufCodecs.map(
- Int2ObjectOpenHashMap::new, ByteBufCodecs.SHORT.map(Short::intValue, Integer::shortValue), ItemStack.OPTIONAL_STREAM_CODEC, 128
+ Int2ObjectOpenHashMap::new, ByteBufCodecs.SHORT.map(Short::intValue, Integer::shortValue), ItemStack.OPTIONAL_STREAM_CODEC.apply(ByteBufCodecs::trackDepth), 128 // Paper - Track codec depth
);
private final int containerId;
private final int stateId;
@@ -46,7 +_,7 @@
this.buttonNum = buffer.readByte();
this.clickType = buffer.readEnum(ClickType.class);
this.changedSlots = Int2ObjectMaps.unmodifiable(SLOTS_STREAM_CODEC.decode(buffer));
- this.carriedItem = ItemStack.OPTIONAL_STREAM_CODEC.decode(buffer);
+ this.carriedItem = ItemStack.OPTIONAL_STREAM_CODEC.apply(ByteBufCodecs::trackDepth).decode(buffer); // Paper - Track codec depth
}
private void write(RegistryFriendlyByteBuf buffer) {

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/network/protocol/game/ServerboundSetCreativeModeSlotPacket.java
+++ b/net/minecraft/network/protocol/game/ServerboundSetCreativeModeSlotPacket.java
@@ -11,7 +_,7 @@
public static final StreamCodec<RegistryFriendlyByteBuf, ServerboundSetCreativeModeSlotPacket> STREAM_CODEC = StreamCodec.composite(
ByteBufCodecs.SHORT,
ServerboundSetCreativeModeSlotPacket::slotNum,
- ItemStack.validatedStreamCodec(ItemStack.OPTIONAL_STREAM_CODEC),
+ ItemStack.validatedStreamCodec(ItemStack.OPTIONAL_STREAM_CODEC).apply(ByteBufCodecs::trackDepth), // Paper - Track codec depth
ServerboundSetCreativeModeSlotPacket::itemStack,
ServerboundSetCreativeModeSlotPacket::new
);

View File

@@ -23,7 +23,7 @@
public boolean isDirty() {
return this.isDirty;
}
@@ -169,6 +_,20 @@
@@ -169,6 +_,19 @@
return new SynchedEntityData(this.entity, this.itemsById);
}
}
@@ -31,9 +31,8 @@
+ // Paper start
+ // We need to pack all as we cannot rely on "non default values" or "dirty" ones.
+ // Because these values can possibly be desynced on the client.
+ @Nullable
+ public List<SynchedEntityData.DataValue<?>> packAll() {
+ final List<SynchedEntityData.DataValue<?>> list = new ArrayList<>();
+ final List<SynchedEntityData.DataValue<?>> list = new ArrayList<>(this.itemsById.length);
+ for (final DataItem<?> dataItem : this.itemsById) {
+ list.add(dataItem.value());
+ }

View File

@@ -984,7 +984,7 @@
ObjectArrayList<GameProfile> list = new ObjectArrayList<>(min);
int randomInt = Mth.nextInt(this.random, 0, players.size() - min);
@@ -1046,17 +_,65 @@
@@ -1046,17 +_,66 @@
protected void tickChildren(BooleanSupplier hasTimeLeft) {
ProfilerFiller profilerFiller = Profiler.get();
this.getPlayerList().getPlayers().forEach(serverPlayer1 -> serverPlayer1.connection.suspendFlushing());
@@ -1027,8 +1027,9 @@
+ }
+ ServerPlayer entityplayer = (ServerPlayer) entityhuman;
+ long playerTime = entityplayer.getPlayerTime();
+ ClientboundSetTimePacket packet = (playerTime == dayTime) ? worldPacket :
+ new ClientboundSetTimePacket(worldTime, playerTime, doDaylight);
+ boolean relativeTime = entityplayer.relativeTime;
+ ClientboundSetTimePacket packet = ((relativeTime || !doDaylight) && playerTime == dayTime) ? worldPacket :
+ new ClientboundSetTimePacket(worldTime, playerTime, relativeTime && doDaylight);
+ entityplayer.connection.send(packet); // Add support for per player time
+ // Paper end - Perf: Optimize time updates
+ }
@@ -1262,11 +1263,12 @@
}
}
@@ -1652,10 +_,11 @@
@@ -1651,11 +_,12 @@
public void kickUnlistedPlayers(CommandSourceStack commandSource) {
if (this.isEnforceWhitelist()) {
PlayerList playerList = commandSource.getServer().getPlayerList();
+ if (!playerList.isUsingWhitelist()) return; // Paper - whitelist not enabled
UserWhiteList whiteList = playerList.getWhiteList();
+ if (!((net.minecraft.server.dedicated.DedicatedServer) this).getProperties().whiteList.get()) return; // Paper - whitelist not enabled
for (ServerPlayer serverPlayer : Lists.newArrayList(playerList.getPlayers())) {
- if (!whiteList.isWhiteListed(serverPlayer.getGameProfile())) {

View File

@@ -67,3 +67,12 @@
}
});
}
@@ -247,7 +_,7 @@
public void flushDirty(ServerPlayer serverPlayer) {
if (this.isFirstPacket || !this.rootsToUpdate.isEmpty() || !this.progressChanged.isEmpty()) {
Map<ResourceLocation, AdvancementProgress> map = new HashMap<>();
- Set<AdvancementHolder> set = new HashSet<>();
+ Set<AdvancementHolder> set = new java.util.TreeSet<>(java.util.Comparator.comparing(adv -> adv.id().toString())); // Paper - Changed from HashSet to TreeSet ordered alphabetically.
Set<ResourceLocation> set1 = new HashSet<>();
for (AdvancementNode advancementNode : this.rootsToUpdate) {

View File

@@ -1,9 +1,11 @@
--- a/net/minecraft/server/ReloadableServerResources.java
+++ b/net/minecraft/server/ReloadableServerResources.java
@@ -39,6 +_,7 @@
@@ -38,7 +_,8 @@
this.fullRegistryHolder = new ReloadableServerRegistries.Holder(registryAccess.compositeAccess());
this.postponedTags = postponedTags;
this.recipes = new RecipeManager(registries);
this.commands = new Commands(commandSelection, CommandBuildContext.simple(registries, enabledFeatures));
- this.commands = new Commands(commandSelection, CommandBuildContext.simple(registries, enabledFeatures));
+ this.commands = new Commands(commandSelection, CommandBuildContext.simple(registries, enabledFeatures), true); // Paper - Brigadier Command API - use modern alias registration
+ io.papermc.paper.command.brigadier.PaperCommands.INSTANCE.setDispatcher(this.commands, CommandBuildContext.simple(registries, enabledFeatures)); // Paper - Brigadier Command API
this.advancements = new ServerAdvancementManager(registries);
this.functionLibrary = new ServerFunctionLibrary(functionCompilationLevel, this.commands.getDispatcher());

View File

@@ -0,0 +1,36 @@
--- a/net/minecraft/server/ServerTickRateManager.java
+++ b/net/minecraft/server/ServerTickRateManager.java
@@ -14,6 +_,7 @@
private long scheduledCurrentSprintTicks = 0L;
private boolean previousIsFrozen = false;
private final MinecraftServer server;
+ private boolean silent; // Paper - silence feedback when API requests sprint
public ServerTickRateManager(MinecraftServer server) {
this.server = server;
@@ -67,6 +_,13 @@
}
public boolean requestGameToSprint(int sprintTime) {
+ // Paper start - silence feedback when API requests sprint
+ return requestGameToSprint(sprintTime, false);
+ }
+
+ public boolean requestGameToSprint(int sprintTime, boolean silent) {
+ if (!isSprinting()) this.silent = silent;
+ // Paper end - silence feedback when API requests sprint
boolean flag = this.remainingSprintTicks > 0L;
this.sprintTimeSpend = 0L;
this.scheduledCurrentSprintTicks = sprintTime;
@@ -83,7 +_,10 @@
String string = String.format("%.2f", l == 0L ? this.millisecondsPerTick() : d / l);
this.scheduledCurrentSprintTicks = 0L;
this.sprintTimeSpend = 0L;
- this.server.createCommandSourceStack().sendSuccess(() -> Component.translatable("commands.tick.sprint.report", i, string), true);
+ // Paper start - silence feedback when API requests sprint
+ if (!this.silent) this.server.createCommandSourceStack().sendSuccess(() -> Component.translatable("commands.tick.sprint.report", i, string), true);
+ this.silent = false;
+ // Paper end - silence feedback when API requests sprint
this.remainingSprintTicks = 0L;
this.setFrozen(this.previousIsFrozen);
this.server.onTickRateChanged();

View File

@@ -5,7 +5,7 @@
private int value;
private int max = 100;
+ // CraftBukkit start
+ private org.bukkit.boss.KeyedBossBar bossBar;
+ private @javax.annotation.Nullable org.bukkit.boss.KeyedBossBar bossBar;
+
+ public org.bukkit.boss.KeyedBossBar getBukkitEntity() {
+ if (this.bossBar == null) {

View File

@@ -0,0 +1,10 @@
--- a/net/minecraft/server/commands/LocateCommand.java
+++ b/net/minecraft/server/commands/LocateCommand.java
@@ -202,6 +_,6 @@
private static float dist(int x1, int z1, int x2, int z2) {
int i = x2 - x1;
int i1 = z2 - z1;
- return Mth.sqrt(i * i + i1 * i1);
+ return (float) Math.hypot(i, i1); // Paper - Fix MC-177381
}
}

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/server/commands/RideCommand.java
+++ b/net/minecraft/server/commands/RideCommand.java
@@ -58,7 +_,7 @@
Entity vehicle1 = target.getVehicle();
if (vehicle1 != null) {
throw ERROR_ALREADY_RIDING.create(target.getDisplayName(), vehicle1.getDisplayName());
- } else if (vehicle.getType() == EntityType.PLAYER) {
+ } else if (vehicle.getType() == EntityType.PLAYER && !io.papermc.paper.configuration.GlobalConfiguration.get().commands.rideCommandAllowPlayerAsVehicle) { // Paper - allow player as vehicle
throw ERROR_MOUNTING_PLAYER.create();
} else if (target.getSelfAndPassengers().anyMatch(passenger -> passenger == vehicle)) {
throw ERROR_MOUNTING_LOOP.create();

View File

@@ -361,7 +361,7 @@
}
@Override
@@ -515,14 +_,52 @@
@@ -515,14 +_,54 @@
@Override
public String getPluginNames() {
@@ -402,6 +402,8 @@
+ }
+
+ public String runCommand(RconConsoleSource rconConsoleSource, String s) {
+ if (s.isBlank()) return ""; // Paper - Do not process empty rcon commands
+
+ rconConsoleSource.prepareForCommand();
+ this.executeBlocking(() -> {
+ CommandSourceStack wrapper = rconConsoleSource.createCommandSourceStack();

View File

@@ -122,7 +122,7 @@
Properties map = Settings.this.cloneProperties();
map.put(this.key, this.serializer.apply(newValue));
- return Settings.this.reload(registryAccess, map);
+ return Settings.this.reload(registryAccess, properties, Settings.this.options); // CraftBukkit
+ return Settings.this.reload(registryAccess, map, Settings.this.options); // CraftBukkit
}
}
}

View File

@@ -204,15 +204,19 @@
chunkGenerator,
this.chunkSource.randomState(),
this,
@@ -281,7 +_,7 @@
@@ -280,9 +_,9 @@
seed,
fixerUpper
);
this.structureManager = new StructureManager(this, server.getWorldData().worldGenOptions(), this.structureCheck);
- this.structureManager = new StructureManager(this, server.getWorldData().worldGenOptions(), this.structureCheck);
- if (this.dimension() == Level.END && this.dimensionTypeRegistration().is(BuiltinDimensionTypes.END)) {
- this.dragonFight = new EndDragonFight(this, seed, server.getWorldData().endDragonFightData());
+ this.structureManager = new StructureManager(this, this.serverLevelData.worldGenOptions(), this.structureCheck); // CraftBukkit
+ if (this.dimension() == Level.END && this.dimensionTypeRegistration().is(BuiltinDimensionTypes.END) || env == org.bukkit.World.Environment.THE_END) { // CraftBukkit - Allow to create EnderDragonBattle in default and custom END
this.dragonFight = new EndDragonFight(this, seed, server.getWorldData().endDragonFightData());
+ this.dragonFight = new EndDragonFight(this, this.serverLevelData.worldGenOptions().seed(), this.serverLevelData.endDragonFightData()); // CraftBukkit
} else {
this.dragonFight = null;
}
@@ -292,7 +_,15 @@
this.randomSequences = Objects.requireNonNullElseGet(
randomSequences, () -> this.getDataStorage().computeIfAbsent(RandomSequences.factory(seed), "random_sequences")
@@ -456,7 +460,7 @@
}
public void resetEmptyTime() {
@@ -746,18 +_,45 @@
@@ -746,18 +_,46 @@
}
}
@@ -483,6 +487,7 @@
entity.setOldPosAndRot();
ProfilerFiller profilerFiller = Profiler.get();
entity.tickCount++;
+ entity.totalEntityAge++; // Paper - age-like counter for all entities
profilerFiller.push(() -> BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString());
profilerFiller.incrementCounter("tickNonPassenger");
entity.tick();
@@ -502,7 +507,12 @@
}
private void tickPassenger(Entity ridingEntity, Entity passengerEntity) {
@@ -770,6 +_,7 @@
@@ -766,10 +_,12 @@
} else if (passengerEntity instanceof Player || this.entityTickList.contains(passengerEntity)) {
passengerEntity.setOldPosAndRot();
passengerEntity.tickCount++;
+ passengerEntity.totalEntityAge++; // Paper - age-like counter for all entities
ProfilerFiller profilerFiller = Profiler.get();
profilerFiller.push(() -> BuiltInRegistries.ENTITY_TYPE.getKey(passengerEntity.getType()).toString());
profilerFiller.incrementCounter("tickPassenger");
passengerEntity.rideTick();
@@ -860,11 +870,11 @@
double zOffset,
double speed
) {
+ // CraftBukkit start - visibility api support
+ // Paper start - visibility api support
+ return this.sendParticlesSource(null, type, overrideLimiter, alwaysShow, posX, posY, posZ, particleCount, xOffset, yOffset, zOffset, speed);
+ }
+ public <T extends ParticleOptions> int sendParticlesSource(
+ @javax.annotation.Nullable ServerPlayer sender,
+ @javax.annotation.Nullable Entity sender,
+ T type,
+ boolean overrideLimiter,
+ boolean alwaysShow,
@@ -881,7 +891,7 @@
+ }
+ public <T extends ParticleOptions> int sendParticlesSource(
+ List<ServerPlayer> receivers,
+ @javax.annotation.Nullable ServerPlayer sender,
+ @javax.annotation.Nullable Entity sender,
+ T type,
+ boolean overrideLimiter,
+ boolean alwaysShow,
@@ -894,7 +904,7 @@
+ double zOffset,
+ double speed
+ ) {
+ // CraftBukkit end - visibility api support
+ // Paper end - visibility api support
ClientboundLevelParticlesPacket clientboundLevelParticlesPacket = new ClientboundLevelParticlesPacket(
type, overrideLimiter, alwaysShow, posX, posY, posZ, (float)xOffset, (float)yOffset, (float)zOffset, (float)speed, particleCount
);
@@ -1062,6 +1072,14 @@
@Override
public CrashReportCategory fillReportDetails(CrashReport report) {
CrashReportCategory crashReportCategory = super.fillReportDetails(report);
@@ -1714,6 +_,7 @@
final class EntityCallbacks implements LevelCallback<Entity> {
@Override
public void onCreated(Entity entity) {
+ entity.setOldPosAndRot(); // Paper - update old pos / rot for new entities as it will default to Vec3.ZERO
}
@Override
@@ -1723,24 +_,32 @@
@Override

View File

@@ -10,7 +10,7 @@
@Nullable
private Vec3 startingToFallPosition;
@Nullable
@@ -258,6 +_,13 @@
@@ -258,6 +_,20 @@
}
}
@@ -20,6 +20,13 @@
+ ServerPlayer.this.connection.send(new ClientboundContainerSetSlotPacket(ServerPlayer.this.inventoryMenu.containerId, ServerPlayer.this.inventoryMenu.incrementStateId(), net.minecraft.world.inventory.InventoryMenu.SHIELD_SLOT, ServerPlayer.this.inventoryMenu.getSlot(net.minecraft.world.inventory.InventoryMenu.SHIELD_SLOT).getItem().copy()));
+ }
+ // Paper end - Sync offhand slot in menus
+
+ // Paper start - add flag to simplify remote matching logic
+ @Override
+ public ServerPlayer player() {
+ return ServerPlayer.this;
+ }
+ // Paper end - add flag to simplify remote matching logic
+
@Override
public void sendSlotChange(AbstractContainerMenu container, int slot, ItemStack itemStack) {
@@ -1213,7 +1220,7 @@
+ if (this.getMainArm() != clientInformation.mainHand()) {
+ org.bukkit.event.player.PlayerChangedMainHandEvent event = new org.bukkit.event.player.PlayerChangedMainHandEvent(
+ this.getBukkitEntity(),
+ this.getMainArm() == HumanoidArm.LEFT ? org.bukkit.inventory.MainHand.LEFT : org.bukkit.inventory.MainHand.RIGHT
+ clientInformation.mainHand() == HumanoidArm.LEFT ? org.bukkit.inventory.MainHand.LEFT : org.bukkit.inventory.MainHand.RIGHT
+ );
+ this.server.server.getPluginManager().callEvent(event);
+ }

View File

@@ -95,7 +95,7 @@
}
}
@@ -88,30 +_,119 @@
@@ -88,30 +_,123 @@
public void handlePong(ServerboundPongPacket packet) {
}
@@ -105,64 +105,68 @@
@Override
public void handleCustomPayload(ServerboundCustomPayloadPacket packet) {
- }
+ // CraftBukkit start
+ // Paper start - Brand support
+ // Paper start
+ if (packet.payload() instanceof net.minecraft.network.protocol.common.custom.BrandPayload(String brand)) {
+ this.player.clientBrandName = brand;
+ }
+ // Paper end - Brand support
+
+ if (!(packet.payload() instanceof final net.minecraft.network.protocol.common.custom.DiscardedPayload discardedPayload)) {
+ return;
+ }
+ PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
+ net.minecraft.resources.ResourceLocation identifier = packet.payload().type().id();
+ io.netty.buffer.ByteBuf payload = discardedPayload.data();
+
+ if (identifier.equals(ServerCommonPacketListenerImpl.CUSTOM_REGISTER)) {
+ try {
+ String channels = payload.toString(com.google.common.base.Charsets.UTF_8);
+ for (String channel : channels.split("\0")) {
+ this.getCraftPlayer().addChannel(channel);
+ }
+ } catch (Exception ex) {
+ ServerGamePacketListenerImpl.LOGGER.error("Couldn't register custom payload", ex);
+ this.disconnect(Component.literal("Invalid payload REGISTER!"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PAYLOAD); // Paper - kick event cause
+ }
+ } else if (identifier.equals(ServerCommonPacketListenerImpl.CUSTOM_UNREGISTER)) {
+ try {
+ String channels = payload.toString(com.google.common.base.Charsets.UTF_8);
+ for (String channel : channels.split("\0")) {
+ this.getCraftPlayer().removeChannel(channel);
+ }
+ } catch (Exception ex) {
+ ServerGamePacketListenerImpl.LOGGER.error("Couldn't unregister custom payload", ex);
+ this.disconnect(Component.literal("Invalid payload UNREGISTER!"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PAYLOAD); // Paper - kick event cause
+ }
+ } else {
+ try {
+ byte[] data = new byte[payload.readableBytes()];
+ payload.readBytes(data);
+ // Paper start - Brand support; Retain this incase upstream decides to 'break' the new mechanism in favour of backwards compat...
+ if (identifier.equals(MINECRAFT_BRAND)) {
+ try {
+ this.player.clientBrandName = new net.minecraft.network.FriendlyByteBuf(io.netty.buffer.Unpooled.copiedBuffer(data)).readUtf(256);
+ } catch (StringIndexOutOfBoundsException ex) {
+ this.player.clientBrandName = "illegal";
+ PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
+
+ final net.minecraft.resources.ResourceLocation identifier = packet.payload().type().id();
+ final byte[] data = discardedPayload.data();
+ try {
+ final boolean registerChannel = ServerCommonPacketListenerImpl.CUSTOM_REGISTER.equals(identifier);
+ if (registerChannel || ServerCommonPacketListenerImpl.CUSTOM_UNREGISTER.equals(identifier)) {
+ // Strings separated by zeros instead of length prefixes
+ int startIndex = 0;
+ for (int i = 0; i < data.length; i++) {
+ final byte b = data[i];
+ if (b != 0) {
+ continue;
+ }
+
+ readChannelIdentifier(data, startIndex, i, registerChannel);
+ startIndex = i + 1;
+ }
+ // Paper end - Brand support
+ this.cserver.getMessenger().dispatchIncomingMessage(this.player.getBukkitEntity(), identifier.toString(), data);
+ } catch (Exception ex) {
+ ServerGamePacketListenerImpl.LOGGER.error("Couldn't dispatch custom payload", ex);
+ this.disconnect(Component.literal("Invalid custom payload!"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PAYLOAD); // Paper - kick event cause
+
+ // Read the last one
+ readChannelIdentifier(data, startIndex, data.length, registerChannel);
+ return;
+ }
+
+ if (identifier.equals(MINECRAFT_BRAND)) {
+ this.player.clientBrandName = new net.minecraft.network.FriendlyByteBuf(io.netty.buffer.Unpooled.wrappedBuffer(data)).readUtf(256);
+ }
+
+ this.cserver.getMessenger().dispatchIncomingMessage(this.player.getBukkitEntity(), identifier.toString(), data);
+ } catch (final Exception e) {
+ ServerGamePacketListenerImpl.LOGGER.error("Couldn't handle custom payload on channel {}", identifier, e);
+ this.disconnect(Component.literal("Invalid custom payload payload!"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PAYLOAD); // Paper - kick event cause
+ }
+ }
+
+ private void readChannelIdentifier(final byte[] data, final int from, final int to, final boolean register) {
+ final int length = to - from;
+ if (length == 0) {
+ return;
+ }
+
+ final String channel = new String(data, from, length, java.nio.charset.StandardCharsets.US_ASCII);
+ if (register) {
+ this.getCraftPlayer().addChannel(channel);
+ } else {
+ this.getCraftPlayer().removeChannel(channel);
+ }
+ }
+
+ public final boolean isDisconnected() {
+ return (!this.player.joining && !this.connection.isConnected()) || this.processedDisconnect; // Paper - Fix duplication bugs
+ }
+ // CraftBukkit end
+ // Paper end
@Override
public void handleResourcePackResponse(ServerboundResourcePackPacket packet) {

View File

@@ -70,7 +70,7 @@
private double firstGoodX;
private double firstGoodY;
private double firstGoodZ;
@@ -236,22 +_,39 @@
@@ -236,22 +_,41 @@
private int receivedMovePacketCount;
private int knownMovePacketCount;
private boolean receivedMovementThisTick;
@@ -98,6 +98,7 @@
private final FutureChain chatMessageChain;
private boolean waitingForSwitchToConfig;
+ private static final int MAX_SIGN_LINE_LENGTH = Integer.getInteger("Paper.maxSignLength", 80); // Paper - Limit client sign length
+ private final io.papermc.paper.event.packet.ClientTickEndEvent tickEndEvent; // Paper - add client tick end event
public ServerGamePacketListenerImpl(MinecraftServer server, Connection connection, ServerPlayer player, CommonListenerCookie cookie) {
- super(server, connection, cookie);
@@ -109,6 +110,7 @@
this.signedMessageDecoder = SignedMessageChain.Decoder.unsigned(player.getUUID(), server::enforceSecureProfile);
- this.chatMessageChain = new FutureChain(server);
+ this.chatMessageChain = new FutureChain(server.chatExecutor); // CraftBukkit - async chat
+ this.tickEndEvent = new io.papermc.paper.event.packet.ClientTickEndEvent(player.getBukkitEntity()); // Paper - add client tick end event
}
@Override
@@ -373,7 +375,7 @@
this.awaitingPositionFromClient.x,
this.awaitingPositionFromClient.y,
this.awaitingPositionFromClient.z,
@@ -495,6 +_,7 @@
@@ -495,12 +_,20 @@
this.lastGoodZ = this.awaitingPositionFromClient.z;
this.player.hasChangedDimension();
this.awaitingPositionFromClient = null;
@@ -381,6 +383,19 @@
}
}
@Override
public void handleAcceptPlayerLoad(ServerboundPlayerLoadedPacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
+ // Paper start - PlayerLoadedWorldEvent
+ if (this.player.hasClientLoaded()) {
+ return;
+ }
+ final io.papermc.paper.event.player.PlayerClientLoadedWorldEvent event = new io.papermc.paper.event.player.PlayerClientLoadedWorldEvent(this.player.getBukkitEntity(), false);
+ event.callEvent();
+ // Paper end - PlayerLoadedWorldEvent
this.player.setClientLoaded(true);
}
@@ -521,6 +_,7 @@
@Override
public void handleRecipeBookChangeSettingsPacket(ServerboundRecipeBookChangeSettingsPacket packet) {
@@ -532,7 +547,7 @@
addBlockDataToItem(blockState, serverLevel, blockPos, cloneItemStack);
}
@@ -685,14 +_,24 @@
@@ -685,18 +_,29 @@
if (stack.isItemEnabled(this.player.level().enabledFeatures())) {
Inventory inventory = this.player.getInventory();
int i = inventory.findSlotMatchingItem(stack);
@@ -561,6 +576,11 @@
}
this.player.connection.send(new ClientboundSetHeldSlotPacket(inventory.selected));
this.player.inventoryMenu.broadcastChanges();
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdatesPublic(); // Paper - Force update attributes.
}
}
@@ -814,6 +_,13 @@
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
int item = packet.getItem();
@@ -1057,7 +1077,7 @@
if (this.player.hasClientLoaded()) {
BlockPos pos = packet.getPos();
this.player.resetLastActionTime();
@@ -1101,14 +_,46 @@
@@ -1101,32 +_,95 @@
case SWAP_ITEM_WITH_OFFHAND:
if (!this.player.isSpectator()) {
ItemStack itemInHand = this.player.getItemInHand(InteractionHand.OFF_HAND);
@@ -1083,6 +1103,7 @@
+ }
+ // CraftBukkit end
this.player.stopUsingItem();
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdatesPublic(); // Paper - Force update attributes.
}
return;
@@ -1104,14 +1125,27 @@
+ }
+ // CraftBukkit end
this.player.drop(false);
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdatesPublic(); // Paper - Force update attributes.
}
@@ -1125,8 +_,34 @@
return;
case DROP_ALL_ITEMS:
if (!this.player.isSpectator()) {
this.player.drop(true);
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdatesPublic(); // Paper - Force update attributes.
}
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
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdatesPublic(); // Paper - Force update attributes.
return;
case START_DESTROY_BLOCK:
case ABORT_DESTROY_BLOCK:
case STOP_DESTROY_BLOCK:
+ // Paper start - Don't allow digging into unloaded chunks
+ if (this.player.level().getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4) == null) {
+ if (this.player.level().getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4) == null || !this.player.canInteractWithBlock(pos, 1.0)) {
+ this.player.connection.ackBlockChangesUpTo(packet.getSequence());
+ return;
+ }
@@ -1138,6 +1172,7 @@
+ }
+ }
+ // Paper end - Send block entities after destroy prediction
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdatesPublic(); // Paper - Force update attributes.
return;
default:
throw new IllegalArgumentException("Invalid player action");
@@ -1208,6 +1243,14 @@
} else {
Component component1 = Component.translatable("build.tooHigh", maxY).withStyle(ChatFormatting.RED);
this.player.sendSystemMessage(component1, true);
@@ -1187,6 +_,7 @@
this.player.connection.send(new ClientboundBlockUpdatePacket(serverLevel, blockPos));
this.player.connection.send(new ClientboundBlockUpdatePacket(serverLevel, blockPos.relative(direction)));
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdatesPublic(); // Paper - Force update attributes.
} else {
LOGGER.warn(
"Rejecting UseItemOnPacket from {}: Location {} too far away from hit block {}.",
@@ -1203,6 +_,8 @@
@Override
public void handleUseItem(ServerboundUseItemPacket packet) {
@@ -1333,7 +1376,7 @@
throw new IllegalArgumentException("Expected packet sequence nr >= 0");
} else {
this.ackBlockChangesUpTo = Math.max(sequence, this.ackBlockChangesUpTo);
@@ -1275,7 +_,17 @@
@@ -1275,20 +_,38 @@
@Override
public void handleSetCarriedItem(ServerboundSetCarriedItemPacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
@@ -1351,8 +1394,10 @@
if (this.player.getInventory().selected != packet.getSlot() && this.player.getUsedItemHand() == InteractionHand.MAIN_HAND) {
this.player.stopUsingItem();
}
@@ -1284,11 +_,18 @@
this.player.getInventory().selected = packet.getSlot();
this.player.resetLastActionTime();
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdatesPublic(); // Paper - Force update attributes.
} else {
LOGGER.warn("{} tried to set an invalid carried item", this.player.getName().getString());
+ this.disconnect(Component.literal("Invalid hotbar selection (Hacking?)"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // CraftBukkit // Paper - kick event cause
@@ -1516,7 +1561,7 @@
}
return optional;
@@ -1451,22 +_,155 @@
@@ -1451,22 +_,157 @@
return false;
}
@@ -1662,9 +1707,11 @@
+ // Spigot start - spam exclusions
+ private void detectRateSpam(String message) {
+ // CraftBukkit start - replaced with thread safe throttle
+ for (String exclude : org.spigotmc.SpigotConfig.spamExclusions) {
+ if (exclude != null && message.startsWith(exclude)) {
+ return;
+ if (org.spigotmc.SpigotConfig.enableSpamExclusions) {
+ for (String exclude : org.spigotmc.SpigotConfig.spamExclusions) {
+ if (exclude != null && message.startsWith(exclude)) {
+ return;
+ }
+ }
+ }
+ // Spigot end
@@ -1935,7 +1982,7 @@
ServerGamePacketListenerImpl.LOGGER
.warn("Player {} tried to attack an invalid entity", ServerGamePacketListenerImpl.this.player.getName().getString());
}
@@ -1656,6 +_,26 @@
@@ -1656,6 +_,27 @@
);
}
}
@@ -1959,6 +2006,7 @@
+ });
+ }
+ // Paper end - PlayerUseUnknownEntityEvent
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdatesPublic(); // Paper - Force update attributes.
}
}
@@ -2017,7 +2065,7 @@
this.player.containerMenu.sendAllDataToRemote();
} else if (!this.player.containerMenu.stillValid(this.player)) {
LOGGER.debug("Player {} interacted with invalid menu {}", this.player, this.player.containerMenu);
@@ -1713,7 +_,313 @@
@@ -1713,7 +_,341 @@
} else {
boolean flag = packet.getStateId() != this.player.containerMenu.getStateId();
this.player.containerMenu.suppressRemoteUpdates();
@@ -2056,11 +2104,19 @@
+ ItemStack cursor = this.player.containerMenu.getCarried();
+ if (clickedItem.isEmpty()) {
+ if (!cursor.isEmpty()) {
+ action = packet.getButtonNum() == 0 ? InventoryAction.PLACE_ALL : InventoryAction.PLACE_ONE;
+ if (cursor.getItem() instanceof net.minecraft.world.item.BundleItem && cursor.has(DataComponents.BUNDLE_CONTENTS) && packet.getButtonNum() != 0) {
+ action = cursor.get(DataComponents.BUNDLE_CONTENTS).isEmpty() ? InventoryAction.NOTHING : InventoryAction.PLACE_FROM_BUNDLE;
+ } else {
+ action = packet.getButtonNum() == 0 ? InventoryAction.PLACE_ALL : InventoryAction.PLACE_ONE;
+ }
+ }
+ } else if (slot.mayPickup(this.player)) {
+ if (cursor.isEmpty()) {
+ action = packet.getButtonNum() == 0 ? InventoryAction.PICKUP_ALL : InventoryAction.PICKUP_HALF;
+ if (slot.getItem().getItem() instanceof net.minecraft.world.item.BundleItem && slot.getItem().has(DataComponents.BUNDLE_CONTENTS) && packet.getButtonNum() != 0) {
+ action = slot.getItem().get(DataComponents.BUNDLE_CONTENTS).isEmpty() ? InventoryAction.NOTHING : InventoryAction.PICKUP_FROM_BUNDLE;
+ } else {
+ action = packet.getButtonNum() == 0 ? InventoryAction.PICKUP_ALL : InventoryAction.PICKUP_HALF;
+ }
+ } else if (slot.mayPlace(cursor)) {
+ if (ItemStack.isSameItemSameComponents(clickedItem, cursor)) {
+ int toPlace = packet.getButtonNum() == 0 ? cursor.getCount() : 1;
@@ -2076,7 +2132,27 @@
+ action = InventoryAction.PLACE_SOME;
+ }
+ } else if (cursor.getCount() <= slot.getMaxStackSize()) {
+ action = InventoryAction.SWAP_WITH_CURSOR;
+ if (cursor.getItem() instanceof net.minecraft.world.item.BundleItem && cursor.has(DataComponents.BUNDLE_CONTENTS) && packet.getButtonNum() == 0) {
+ int toPickup = cursor.get(DataComponents.BUNDLE_CONTENTS).getMaxAmountToAdd(slot.getItem());
+ if (toPickup >= slot.getItem().getCount()) {
+ action = InventoryAction.PICKUP_ALL_INTO_BUNDLE;
+ } else if (toPickup == 0) {
+ action = InventoryAction.NOTHING;
+ } else {
+ action = InventoryAction.PICKUP_SOME_INTO_BUNDLE;
+ }
+ } else if (slot.getItem().getItem() instanceof net.minecraft.world.item.BundleItem && slot.getItem().has(DataComponents.BUNDLE_CONTENTS) && packet.getButtonNum() == 0) {
+ int toPickup = slot.getItem().get(DataComponents.BUNDLE_CONTENTS).getMaxAmountToAdd(cursor);
+ if (toPickup >= cursor.getCount()) {
+ action = InventoryAction.PLACE_ALL_INTO_BUNDLE;
+ } else if (toPickup == 0) {
+ action = InventoryAction.NOTHING;
+ } else {
+ action = InventoryAction.PLACE_SOME_INTO_BUNDLE;
+ }
+ } else {
+ action = InventoryAction.SWAP_WITH_CURSOR;
+ }
+ }
+ } else if (ItemStack.isSameItemSameComponents(cursor, clickedItem)) {
+ if (clickedItem.getCount() >= 0) {
@@ -2332,6 +2408,14 @@
for (Entry<ItemStack> entry : Int2ObjectMaps.fastIterable(packet.getChangedSlots())) {
this.player.containerMenu.setRemoteSlotNoCopy(entry.getIntKey(), entry.getValue());
@@ -1726,6 +_,7 @@
} else {
this.player.containerMenu.broadcastChanges();
}
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdatesPublic(); // Paper - Force update attributes.
}
}
}
@@ -1733,6 +_,14 @@
@Override
@@ -2401,7 +2485,15 @@
this.player.resetLastActionTime();
if (this.player.containerMenu.containerId == packet.containerId() && !this.player.isSpectator()) {
if (!this.player.containerMenu.stillValid(this.player)) {
@@ -1792,6 +_,43 @@
@@ -1776,6 +_,7 @@
if (flag) {
this.player.containerMenu.broadcastChanges();
}
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdatesPublic(); // Paper - Force update attributes.
}
}
}
@@ -1792,10 +_,48 @@
boolean flag1 = packet.slotNum() >= 1 && packet.slotNum() <= 45;
boolean flag2 = itemStack.isEmpty() || itemStack.getCount() <= itemStack.getMaxStackSize();
@@ -2445,6 +2537,11 @@
if (flag1 && flag2) {
this.player.inventoryMenu.getSlot(packet.slotNum()).setByPlayer(itemStack);
this.player.inventoryMenu.setRemoteSlot(packet.slotNum(), itemStack);
this.player.inventoryMenu.broadcastChanges();
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdatesPublic(); // Paper - Force update attributes.
} else if (flag && flag2) {
if (this.dropSpamThrottler.isUnderThreshold()) {
this.dropSpamThrottler.increment();
@@ -1809,11 +_,24 @@
@Override
@@ -2551,7 +2648,7 @@
this.signedMessageDecoder = chatSession.createMessageDecoder(this.player.getUUID());
this.chatMessageChain
.append(
@@ -1919,15 +_,17 @@
@@ -1919,19 +_,22 @@
this.server
.getPlayerList()
.broadcastAll(
@@ -2573,6 +2670,11 @@
@Override
public void handleClientTickEnd(ServerboundClientTickEndPacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
+ this.tickEndEvent.callEvent(); // Paper - add client tick end event
if (!this.receivedMovementThisTick) {
this.player.setKnownMovement(Vec3.ZERO);
}
@@ -1957,4 +_,17 @@
interface EntityInteraction {
InteractionResult run(ServerPlayer player, Entity entity, InteractionHand hand);

View File

@@ -931,14 +931,19 @@
}
player.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.LEVEL_CHUNKS_LOAD_START, 0.0F));
@@ -671,8 +_,16 @@
@@ -671,8 +_,21 @@
public void sendAllPlayerInfo(ServerPlayer player) {
player.inventoryMenu.sendAllDataToRemote();
- player.resetSentInfo();
+ // entityplayer.resetSentInfo();
+ player.getBukkitEntity().updateScaledHealth(); // CraftBukkit - Update scaled health on respawn and worldchange
+ player.refreshEntityData(player); // CraftBukkkit - SPIGOT-7218: sync metadata
+ // Paper start - send all attributes
+ // needs to be done because the ServerPlayer instance is being reused on respawn instead of getting replaced like on vanilla
+ java.util.Collection<net.minecraft.world.entity.ai.attributes.AttributeInstance> syncableAttributes = player.getAttributes().getSyncableAttributes();
+ player.getBukkitEntity().injectScaledMaxHealth(syncableAttributes, true);
+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundUpdateAttributesPacket(player.getId(), syncableAttributes));
+ // Paper end - send all attributes
+ player.refreshEntityData(player); // CraftBukkit - SPIGOT-7218: sync metadata
player.connection.send(new ClientboundSetHeldSlotPacket(player.getInventory().selected));
+ // CraftBukkit start - from GameRules
+ int i = player.serverLevel().getGameRules().getBoolean(GameRules.RULE_REDUCEDDEBUGINFO) ? 22 : 23;

View File

@@ -9,7 +9,7 @@
this.setLootTable(lootTable);
this.setLootTableSeed(seed);
}
@@ -50,14 +_,15 @@
@@ -50,15 +_,17 @@
default boolean tryLoadLootTable(CompoundTag tag) {
if (tag.contains("LootTable", 8)) {
@@ -25,8 +25,10 @@
- return true;
+ return this.lootableData() == null; // Paper - only track the loot table if there is chance for replenish
} else {
+ setLootTable(null); // Paper - Fix removing loottable from nbt not updating block entity, MC-279196
return false;
}
}
@@ -69,26 +_,42 @@
return false;
} else {

View File

@@ -1,127 +1,95 @@
--- a/net/minecraft/world/damagesource/DamageSource.java
+++ b/net/minecraft/world/damagesource/DamageSource.java
@@ -20,6 +_,105 @@
@@ -20,6 +_,92 @@
private final Entity directEntity;
@Nullable
private final Vec3 damageSourcePosition;
+ // CraftBukkit start
+ @Nullable
+ private org.bukkit.block.Block directBlock; // The block that caused the damage. damageSourcePosition is not used for all block damages
+ private org.bukkit.event.entity.EntityDamageEvent.DamageCause knownCause; // When the damage event cause is known by the context of the call rather than the damage source data
+ @Nullable
+ private org.bukkit.block.BlockState directBlockState; // The block state of the block relevant to this damage source
+ private boolean sweep = false;
+ private boolean melting = false;
+ private boolean poison = false;
+ private Entity eventEntityDamager = null; // Relevant entity set when the game doesn't normally set a causingEntity/directEntity
+ @Nullable
+ private Entity customEventDamager = null; // This field is a helper for when causing entity damage is not set by vanilla // Paper - fix DamageSource API
+
+ public DamageSource sweep() {
+ this.sweep = true;
+ return this;
+ }
+
+ public boolean isSweep() {
+ return this.sweep;
+ }
+
+ public DamageSource melting() {
+ this.melting = true;
+ return this;
+ }
+
+ public boolean isMelting() {
+ return this.melting;
+ }
+
+ public DamageSource poison() {
+ this.poison = true;
+ return this;
+ }
+
+ public boolean isPoison() {
+ return this.poison;
+ }
+
+ // Paper start - fix DamageSource API
+ private org.bukkit.block.Block eventBlockDamager; // Relevant block set. damageSourcePosition is only used for bad respawn point explosion or custom damage
+ @Nullable
+ public Entity getCustomEventDamager() {
+ return (this.customEventDamager != null) ? this.customEventDamager : this.directEntity;
+ private org.bukkit.block.BlockState fromBlockSnapshot; // Captured block snapshot when the eventBlockDamager is not relevant (e.g. for bad respawn point explosions the block is already removed)
+ private boolean critical; // Supports arrows and sweeping damage
+
+ public DamageSource knownCause(final org.bukkit.event.entity.EntityDamageEvent.DamageCause cause) {
+ final DamageSource damageSource = this.copy();
+ damageSource.knownCause = cause;
+ return damageSource;
+ }
+
+ public DamageSource customEventDamager(Entity entity) {
+ @Nullable
+ public org.bukkit.event.entity.EntityDamageEvent.DamageCause knownCause() {
+ return this.knownCause;
+ }
+
+ @Nullable
+ public Entity eventEntityDamager() {
+ return this.eventEntityDamager;
+ }
+
+ public DamageSource eventEntityDamager(final Entity entity) {
+ if (this.directEntity != null) {
+ throw new IllegalStateException("Cannot set custom event damager when direct entity is already set (report a bug to Paper)");
+ throw new IllegalStateException("Cannot set an event damager when a direct entity is already set (report a bug to Paper)");
+ }
+ DamageSource damageSource = this.cloneInstance();
+ damageSource.customEventDamager = entity;
+ // Paper end - fix DamageSource API
+ final DamageSource damageSource = this.copy();
+ damageSource.eventEntityDamager = entity;
+ return damageSource;
+ }
+
+ public org.bukkit.block.Block getDirectBlock() {
+ return this.directBlock;
+ @Nullable
+ public org.bukkit.block.Block eventBlockDamager() {
+ return this.eventBlockDamager;
+ }
+
+ public DamageSource directBlock(net.minecraft.world.level.Level world, net.minecraft.core.BlockPos blockPosition) {
+ if (blockPosition == null || world == null) {
+ public DamageSource eventBlockDamager(final @Nullable net.minecraft.world.level.LevelAccessor level, final @Nullable net.minecraft.core.BlockPos pos) {
+ if (pos == null) {
+ return this;
+ }
+ return this.directBlock(org.bukkit.craftbukkit.block.CraftBlock.at(world, blockPosition));
+ }
+
+ public DamageSource directBlock(org.bukkit.block.Block block) {
+ if (block == null) {
+ return this;
+ }
+ // Cloning the instance lets us return unique instances of DamageSource without affecting constants defined in DamageSources
+ DamageSource damageSource = this.cloneInstance();
+ damageSource.directBlock = block;
+ final DamageSource damageSource = this.copy();
+ damageSource.eventBlockDamager = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos);
+ return damageSource;
+ }
+
+ public org.bukkit.block.BlockState getDirectBlockState() {
+ return this.directBlockState;
+ @Nullable
+ public org.bukkit.block.BlockState causingBlockSnapshot() {
+ return this.fromBlockSnapshot;
+ }
+
+ public DamageSource directBlockState(org.bukkit.block.BlockState blockState) {
+ if (blockState == null) {
+ return this;
+ public DamageSource causingBlockSnapshot(final @Nullable org.bukkit.block.BlockState blockState) {
+ if (this.eventBlockDamager != null) {
+ throw new IllegalStateException("Cannot set a block snapshot when an event block damager is already set (report a bug to Paper)");
+ }
+ // Cloning the instance lets us return unique instances of DamageSource without affecting constants defined in DamageSources
+ DamageSource damageSource = this.cloneInstance();
+ damageSource.directBlockState = blockState;
+ final DamageSource damageSource = this.copy();
+ damageSource.fromBlockSnapshot = blockState;
+ return damageSource;
+ }
+
+ private DamageSource cloneInstance() {
+ DamageSource damageSource = new DamageSource(this.type, this.directEntity, this.causingEntity, this.damageSourcePosition);
+ damageSource.directBlock = this.getDirectBlock();
+ damageSource.directBlockState = this.getDirectBlockState();
+ damageSource.sweep = this.isSweep();
+ damageSource.poison = this.isPoison();
+ damageSource.melting = this.isMelting();
+ public boolean isCritical() {
+ return this.critical;
+ }
+
+ public DamageSource critical() {
+ final DamageSource damageSource = this.copy();
+ damageSource.critical = true;
+ return damageSource;
+ }
+
+ // Cloning the instance lets us return unique instances of DamageSource without affecting constants defined in DamageSources
+ private DamageSource copy() {
+ final DamageSource damageSource = new DamageSource(this.type, this.directEntity, this.causingEntity, this.damageSourcePosition);
+ damageSource.knownCause = this.knownCause;
+ damageSource.eventEntityDamager = this.eventEntityDamager;
+ damageSource.eventBlockDamager = this.eventBlockDamager;
+ damageSource.fromBlockSnapshot = this.fromBlockSnapshot;
+ damageSource.critical = this.critical;
+ return damageSource;
+ }
+ // CraftBukkit end
@Override
public String toString() {
@@ -134,4 +_,18 @@
public Holder<DamageType> typeHolder() {
return this.type;
}
+
+ // Paper start - add critical damage API
+ private boolean critical;
+ public boolean isCritical() {
+ return this.critical;
+ }
+ public DamageSource critical() {
+ return this.critical(true);
+ }
+ public DamageSource critical(boolean critical) {
+ this.critical = critical;
+ return this;
+ }
+ // Paper end - add critical damage API
}

View File

@@ -1,50 +0,0 @@
--- a/net/minecraft/world/damagesource/DamageSources.java
+++ b/net/minecraft/world/damagesource/DamageSources.java
@@ -42,9 +_,15 @@
private final DamageSource stalagmite;
private final DamageSource outsideBorder;
private final DamageSource genericKill;
+ // CraftBukkit start
+ private final DamageSource melting;
+ private final DamageSource poison;
public DamageSources(RegistryAccess registry) {
this.damageTypes = registry.lookupOrThrow(Registries.DAMAGE_TYPE);
+ this.melting = this.source(DamageTypes.ON_FIRE).melting();
+ this.poison = this.source(DamageTypes.MAGIC).poison();
+ // CraftBukkit end
this.inFire = this.source(DamageTypes.IN_FIRE);
this.campfire = this.source(DamageTypes.CAMPFIRE);
this.lightningBolt = this.source(DamageTypes.LIGHTNING_BOLT);
@@ -84,6 +_,16 @@
return new DamageSource(this.damageTypes.getOrThrow(damageTypeKey), causingEntity, directEntity);
}
+ // CraftBukkit start
+ public DamageSource melting() {
+ return this.melting;
+ }
+
+ public DamageSource poison() {
+ return this.poison;
+ }
+ // CraftBukkit end
+
public DamageSource inFire() {
return this.inFire;
}
@@ -261,7 +_,13 @@
}
public DamageSource badRespawnPointExplosion(Vec3 position) {
- return new DamageSource(this.damageTypes.getOrThrow(DamageTypes.BAD_RESPAWN_POINT), position);
+ // CraftBukkit start
+ return this.badRespawnPointExplosion(position, null);
+ }
+
+ public DamageSource badRespawnPointExplosion(Vec3 position, org.bukkit.block.BlockState blockState) {
+ return new DamageSource(this.damageTypes.getOrThrow(DamageTypes.BAD_RESPAWN_POINT), position).directBlockState(blockState);
+ // CraftBukkit end
}
public DamageSource outOfBorder() {

View File

@@ -9,8 +9,11 @@
} else {
entity.hurtServer(level, entity.damageSources().magic(), 6 << amplifier);
}
@@ -30,7 +_,7 @@
@@ -28,9 +_,10 @@
public void applyInstantenousEffect(
ServerLevel level, @Nullable Entity source, @Nullable Entity indirectSource, LivingEntity entity, int amplifier, double health
) {
+ if (!new io.papermc.paper.event.entity.EntityEffectTickEvent(entity.getBukkitLivingEntity(), org.bukkit.craftbukkit.potion.CraftPotionEffectType.minecraftToBukkit(this), amplifier).callEvent()) { return; } // Paper - Add EntityEffectTickEvent
if (this.isHarm == entity.isInvertedHealAndHarm()) {
int i = (int)(health * (4 << amplifier) + 0.5);
- entity.heal(i);

View File

@@ -0,0 +1,10 @@
--- a/net/minecraft/world/effect/MobEffect.java
+++ b/net/minecraft/world/effect/MobEffect.java
@@ -76,6 +_,7 @@
public void applyInstantenousEffect(
ServerLevel level, @Nullable Entity source, @Nullable Entity indirectSource, LivingEntity entity, int amplifier, double health
) {
+ if (!new io.papermc.paper.event.entity.EntityEffectTickEvent(entity.getBukkitLivingEntity(), org.bukkit.craftbukkit.potion.CraftPotionEffectType.minecraftToBukkit(this), amplifier).callEvent()) { return; } // Paper - Add EntityEffectTickEvent
this.applyEffectTick(level, entity, amplifier);
}

View File

@@ -0,0 +1,28 @@
--- a/net/minecraft/world/effect/MobEffectInstance.java
+++ b/net/minecraft/world/effect/MobEffectInstance.java
@@ -216,6 +_,7 @@
int i = this.isInfiniteDuration() ? entity.tickCount : this.duration;
if (entity.level() instanceof ServerLevel serverLevel
&& this.effect.value().shouldApplyEffectTickThisTick(i, this.amplifier)
+ && new io.papermc.paper.event.entity.EntityEffectTickEvent(entity.getBukkitLivingEntity(), org.bukkit.craftbukkit.potion.CraftPotionEffectType.minecraftHolderToBukkit(this.effect), this.amplifier).callEvent() // Paper - Add EntityEffectTickEvent
&& !this.effect.value().applyEffectTick(serverLevel, entity, this.amplifier)) {
entity.removeEffect(this.effect);
}
@@ -408,7 +_,7 @@
.apply(instance, MobEffectInstance.Details::create)
)
);
- public static final StreamCodec<ByteBuf, MobEffectInstance.Details> STREAM_CODEC = StreamCodec.recursive(
+ public static final StreamCodec<net.minecraft.network.FriendlyByteBuf, MobEffectInstance.Details> STREAM_CODEC = StreamCodec.recursive( // Paper - Track codec depth
codec -> StreamCodec.composite(
ByteBufCodecs.VAR_INT,
MobEffectInstance.Details::amplifier,
@@ -420,7 +_,7 @@
MobEffectInstance.Details::showParticles,
ByteBufCodecs.BOOL,
MobEffectInstance.Details::showIcon,
- codec.apply(ByteBufCodecs::optional),
+ codec.apply(ByteBufCodecs::increaseDepth).apply(ByteBufCodecs::optional), // Paper - Track codec depth
MobEffectInstance.Details::hiddenEffect,
MobEffectInstance.Details::new
)

View File

@@ -5,7 +5,7 @@
public boolean applyEffectTick(ServerLevel level, LivingEntity entity, int amplifier) {
if (entity.getHealth() > 1.0F) {
- entity.hurtServer(level, entity.damageSources().magic(), 1.0F);
+ entity.hurtServer(level, entity.damageSources().poison(), 1.0F); // CraftBukkit - DamageSource.MAGIC -> CraftEventFactory.POISON
+ entity.hurtServer(level, entity.damageSources().magic().knownCause(org.bukkit.event.entity.EntityDamageEvent.DamageCause.POISON), 1.0F); // CraftBukkit
}
return true;

View File

@@ -86,7 +86,7 @@
+ // Paper end - Share random for entities to make them more random
+ public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; // Paper - Entity#getEntitySpawnReason
+
+ private org.bukkit.craftbukkit.entity.CraftEntity bukkitEntity;
+ private @Nullable org.bukkit.craftbukkit.entity.CraftEntity bukkitEntity;
+
+ public org.bukkit.craftbukkit.entity.CraftEntity getBukkitEntity() {
+ if (this.bukkitEntity == null) {
@@ -101,7 +101,7 @@
+ return this.bukkitEntity;
+ }
+ // Paper start
+ public org.bukkit.craftbukkit.entity.CraftEntity getBukkitEntityRaw() {
+ public @Nullable org.bukkit.craftbukkit.entity.CraftEntity getBukkitEntityRaw() {
+ return this.bukkitEntity;
+ }
+ // Paper end
@@ -127,7 +127,7 @@
private final double[] pistonDeltas = new double[]{0.0, 0.0, 0.0};
private long pistonDeltasGameTime;
private EntityDimensions dimensions;
@@ -250,6 +_,63 @@
@@ -250,6 +_,60 @@
private final List<Entity.Movement> movementThisTick = new ArrayList<>();
private final Set<BlockState> blocksInside = new ReferenceArraySet<>();
private final LongSet visitedBlocks = new LongOpenHashSet();
@@ -158,6 +158,7 @@
+ public boolean freezeLocked = false; // Paper - Freeze Tick Lock API
+ public boolean fixedPose = false; // Paper - Expand Pose API
+ private final int despawnTime; // Paper - entity despawn time limit
+ public int totalEntityAge; // Paper - age-like counter for all entities
+ public final io.papermc.paper.entity.activation.ActivationType activationType = io.papermc.paper.entity.activation.ActivationType.activationTypeFor(this); // Paper - EAR 2/tracking ranges
+
+ public void setOrigin(@javax.annotation.Nonnull org.bukkit.Location location) {
@@ -178,10 +179,6 @@
+ public float getBukkitYaw() {
+ return this.yRot;
+ }
+
+ public boolean isChunkLoaded() {
+ return this.level.hasChunk((int) Math.floor(this.getX()) >> 4, (int) Math.floor(this.getZ()) >> 4);
+ }
+ // CraftBukkit end
+ // Paper start
+ public final AABB getBoundingBoxAt(double x, double y, double z) {
@@ -195,7 +192,7 @@
this.entityData = builder.build();
this.setPos(0.0, 0.0, 0.0);
this.eyeHeight = this.dimensions.eyeHeight();
+ this.despawnTime = type == EntityType.PLAYER ? -1 : level.paperConfig().entities.spawning.despawnTime.getOrDefault(type, io.papermc.paper.configuration.type.number.IntOr.Disabled.DISABLED).or(-1); // Paper - entity despawn time limit
+ this.despawnTime = level == null || type == EntityType.PLAYER ? -1 : level.paperConfig().entities.spawning.despawnTime.getOrDefault(type, io.papermc.paper.configuration.type.number.IntOr.Disabled.DISABLED).or(-1); // Paper - entity despawn time limit
}
public boolean isColliding(BlockPos pos, BlockState state) {
@@ -373,7 +370,7 @@
public void tick() {
+ // Paper start - entity despawn time limit
+ if (this.despawnTime >= 0 && this.tickCount >= this.despawnTime) {
+ if (this.despawnTime >= 0 && this.totalEntityAge >= this.despawnTime) {
+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN);
+ return;
+ }
@@ -463,7 +460,7 @@
+ // CraftBukkit end
if (this.level() instanceof ServerLevel serverLevel
- && this.hurtServer(serverLevel, this.damageSources().lava(), 4.0F)
+ && this.hurtServer(serverLevel, this.damageSources().lava().directBlock(this.level, this.lastLavaContact), 4.0F) // CraftBukkit - we also don't throw an event unless the object in lava is living, to save on some event calls
+ && this.hurtServer(serverLevel, this.damageSources().lava().eventBlockDamager(this.level, this.lastLavaContact), 4.0F) // CraftBukkit - we also don't throw an event unless the object in lava is living, to save on some event calls
&& this.shouldPlayLavaHurtSound()
&& !this.isSilent()) {
serverLevel.playSound(
@@ -802,7 +799,7 @@
+ if (this.maxAirTicks != this.getDefaultMaxAirSupply()) {
+ compound.putInt("Bukkit.MaxAirSupply", this.getMaxAirSupply());
+ }
+ compound.putInt("Spigot.ticksLived", this.tickCount);
+ compound.putInt("Spigot.ticksLived", this.totalEntityAge); // Paper
+ // CraftBukkit end
Component customName = this.getCustomName();
if (customName != null) {
@@ -864,7 +861,7 @@
+ // CraftBukkit start
+ // Spigot start
+ if (this instanceof net.minecraft.world.entity.LivingEntity) {
+ this.tickCount = compound.getInt("Spigot.ticksLived");
+ this.totalEntityAge = compound.getInt("Spigot.ticksLived"); // Paper
+ }
+ // Spigot end
+ this.persist = !compound.contains("Bukkit.persist") || compound.getBoolean("Bukkit.persist");
@@ -1304,7 +1301,7 @@
+ return;
+ }
+
+ if (!this.hurtServer(level, this.damageSources().lightningBolt().customEventDamager(lightning), 5.0F)) { // Paper - fix DamageSource API
+ if (!this.hurtServer(level, this.damageSources().lightningBolt().eventEntityDamager(lightning), 5.0F)) { // Paper - fix DamageSource API
+ return;
+ }
+ // CraftBukkit end

View File

@@ -5,7 +5,7 @@
public boolean skipAttackInteraction(Entity entity) {
if (entity instanceof Player player) {
+ // CraftBukkit start
+ DamageSource source = player.damageSources().playerAttack(player);
+ DamageSource source = player.damageSources().generic().eventEntityDamager(entity);
+ org.bukkit.event.entity.EntityDamageEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNonLivingEntityDamageEvent(this, source, 1.0F, false);
+ if (event.isCancelled()) {
+ return true;
@@ -14,7 +14,7 @@
this.attack = new Interaction.PlayerAction(player.getUUID(), this.level().getGameTime());
if (player instanceof ServerPlayer serverPlayer) {
- CriteriaTriggers.PLAYER_HURT_ENTITY.trigger(serverPlayer, this, player.damageSources().generic(), 1.0F, 1.0F, false);
+ CriteriaTriggers.PLAYER_HURT_ENTITY.trigger(serverPlayer, this, player.damageSources().generic(), 1.0F, (float) event.getFinalDamage(), false); // CraftBukkit // Paper - use correct source and fix taken/dealt param order
+ CriteriaTriggers.PLAYER_HURT_ENTITY.trigger(serverPlayer, this, source, 1.0F, (float) event.getFinalDamage(), false); // CraftBukkit // Paper - use correct source and fix taken/dealt param order
}
return !this.getResponse();

View File

@@ -678,7 +678,7 @@
+ event.setCancelled(itemStack == null);
+ this.level().getCraftServer().getPluginManager().callEvent(event);
+ if (event.isCancelled()) {
+ // Set death protection to null as the event was cancelled. Prevent any attempt at ressurection.
+ // Set death protection to null as the event was cancelled. Prevent any attempt at resurrection.
+ deathProtection = null;
+ } else {
+ if (!itemInHand.isEmpty() && itemStack != null) { // Paper - only reduce item if actual totem was found
@@ -691,7 +691,7 @@
- if (this instanceof ServerPlayer serverPlayer) {
+ }
+ // Paper start - fix NPE when pre-cancelled EntityResurrectEvent is uncancelled
+ // restore the previous behavior in that case by defaulting to vanillas totem of undying efect
+ // restore the previous behavior in that case by defaulting to vanillas totem of undying effect
+ if (deathProtection == null) {
+ deathProtection = DeathProtection.TOTEM_OF_UNDYING;
+ }
@@ -971,7 +971,7 @@
int i = (this.getEffect(MobEffects.DAMAGE_RESISTANCE).getAmplifier() + 1) * 5;
int i1 = 25 - i;
float f = damageAmount * i1;
@@ -1768,24 +_,212 @@
@@ -1768,24 +_,219 @@
}
}
@@ -984,7 +984,11 @@
+ if (invulnerabilityRelatedLastDamage == 0) return 0D; // no last damage, no reduction
+ // last damage existed, this means the reduction *technically* is (new damage - last damage).
+ // If the event damage was changed to something less than invul damage, hard lock it at 0.
+ if (d < invulnerabilityRelatedLastDamage) return 0D;
+ //
+ // Cast the passed in double down to a float as double -> float -> double is lossy.
+ // If last damage is a (float) 3.2D (since the events use doubles), we cannot compare
+ // the new damage value of this damage instance by upcasting it again to a double as 3.2D != (double) (float) 3.2D.
+ if (d.floatValue() < invulnerabilityRelatedLastDamage) return 0D;
+ return (double) -invulnerabilityRelatedLastDamage;
+ };
+ final float originalInvulnerabilityReduction = invulnerabilityReductionEquation.apply((double) amount).floatValue();
@@ -1118,7 +1122,10 @@
+
+ // Apply damage to armor
+ if (!damageSource.is(DamageTypeTags.BYPASSES_ARMOR)) {
+ float armorDamage = (float) (event.getDamage() + event.getDamage(DamageModifier.BLOCKING) + event.getDamage(DamageModifier.HARD_HAT));
+ float armorDamage = (float) event.getDamage();
+ armorDamage += (float) event.getDamage(DamageModifier.INVULNERABILITY_REDUCTION);
+ armorDamage += (float) event.getDamage(DamageModifier.BLOCKING);
+ armorDamage += (float) event.getDamage(DamageModifier.HARD_HAT);
+ this.hurtArmor(damageSource, armorDamage);
+ }
+
@@ -1336,20 +1343,57 @@
Map<EquipmentSlot, ItemStack> map = this.collectEquipmentChanges();
if (map != null) {
this.handleHandSwap(map);
@@ -2595,6 +_,13 @@
@@ -2586,6 +_,20 @@
@Nullable
private Map<EquipmentSlot, ItemStack> collectEquipmentChanges() {
Map<EquipmentSlot, ItemStack> map = null;
+ // Paper start - EntityEquipmentChangedEvent
+ record EquipmentChangeImpl(org.bukkit.inventory.ItemStack oldItem, org.bukkit.inventory.ItemStack newItem) implements io.papermc.paper.event.entity.EntityEquipmentChangedEvent.EquipmentChange {
+ @Override
+ public org.bukkit.inventory.ItemStack oldItem() {
+ return this.oldItem.clone();
+ }
+
+ @Override
+ public org.bukkit.inventory.ItemStack newItem() {
+ return this.newItem.clone();
+ }
+ }
+ Map<org.bukkit.inventory.EquipmentSlot, io.papermc.paper.event.entity.EntityEquipmentChangedEvent.EquipmentChange> equipmentChanges = null;
+ // Paper end - EntityEquipmentChangedEvent
for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) {
ItemStack itemStack = switch (equipmentSlot.getType()) {
@@ -2595,11 +_,20 @@
};
ItemStack itemBySlot = this.getItemBySlot(equipmentSlot);
if (this.equipmentHasChanged(itemStack, itemBySlot)) {
+ // Paper start - PlayerArmorChangeEvent
+ // Paper start - EntityEquipmentChangedEvent, PlayerArmorChangeEvent
+ final org.bukkit.inventory.ItemStack oldItem = CraftItemStack.asBukkitCopy(itemStack);
+ final org.bukkit.inventory.ItemStack newItem = CraftItemStack.asBukkitCopy(itemBySlot);
+ if (this instanceof ServerPlayer && equipmentSlot.getType() == EquipmentSlot.Type.HUMANOID_ARMOR) {
+ final org.bukkit.inventory.ItemStack oldItem = CraftItemStack.asBukkitCopy(itemStack);
+ final org.bukkit.inventory.ItemStack newItem = CraftItemStack.asBukkitCopy(itemBySlot);
+ new com.destroystokyo.paper.event.player.PlayerArmorChangeEvent((org.bukkit.entity.Player) this.getBukkitEntity(), com.destroystokyo.paper.event.player.PlayerArmorChangeEvent.SlotType.valueOf(equipmentSlot.name()), oldItem, newItem).callEvent();
+ }
+ // Paper end - PlayerArmorChangeEvent
+ // Paper end - EntityEquipmentChangedEvent, PlayerArmorChangeEvent
if (map == null) {
map = Maps.newEnumMap(EquipmentSlot.class);
+ equipmentChanges = Maps.newEnumMap(org.bukkit.inventory.EquipmentSlot.class); // Paper - EntityEquipmentChangedEvent
}
map.put(equipmentSlot, itemBySlot);
+ equipmentChanges.put(org.bukkit.craftbukkit.CraftEquipmentSlot.getSlot(equipmentSlot), new EquipmentChangeImpl(oldItem, newItem)); // Paper - EntityEquipmentChangedEvent
AttributeMap attributes = this.getAttributes();
if (!itemStack.isEmpty()) {
this.stopLocationBasedEffects(itemStack, equipmentSlot, attributes);
@@ -2624,6 +_,8 @@
}
}
}
+
+ new io.papermc.paper.event.entity.EntityEquipmentChangedEvent(this.getBukkitLivingEntity(), equipmentChanges).callEvent(); // Paper - EntityEquipmentChangedEvent
}
return map;
@@ -2664,7 +_,7 @@
this.lastBodyItemStack = itemStack;
}

View File

@@ -326,6 +326,16 @@
}
}
}
@@ -981,7 +_,9 @@
double d = this.getEquipmentDropChance(equipmentSlot);
if (d > 1.0) {
this.setItemSlot(equipmentSlot, ItemStack.EMPTY);
+ this.forceDrops = true; // Paper - Add missing forceDrop toggles
this.spawnAtLocation(level, itemBySlot);
+ this.forceDrops = false; // Paper - Add missing forceDrop toggles
}
}
}
@@ -1269,6 +_,22 @@
public <T extends Mob> T convertTo(
EntityType<T> entityType, ConversionParams conversionParams, EntitySpawnReason spawnReason, ConversionParams.AfterConversion<T> afterConversion

View File

@@ -0,0 +1,42 @@
--- a/net/minecraft/world/entity/ai/behavior/PoiCompetitorScan.java
+++ b/net/minecraft/world/entity/ai/behavior/PoiCompetitorScan.java
@@ -22,13 +_,32 @@
level.getPoiManager()
.getType(globalPos.pos())
.ifPresent(
- poi -> instance.<List<LivingEntity>>get(nearestLivingEntities)
- .stream()
- .filter(entity -> entity instanceof Villager && entity != villager)
- .map(entity -> (Villager)entity)
- .filter(LivingEntity::isAlive)
- .filter(v -> competesForSameJobsite(globalPos, poi, v))
- .reduce(villager, PoiCompetitorScan::selectWinner)
+ // Paper start - Improve performance of PoiCompetitorScan by unrolling stream
+ // The previous logic used Stream#reduce to simulate a form of single-iteration bubble sort
+ // in which the "winning" villager would maintain MemoryModuleType.JOB_SITE while all others
+ // would lose said memory module type by passing each "current winner" and incoming next
+ // villager to #selectWinner.
+ poi -> {
+ final List<LivingEntity> livingEntities = instance.get(nearestLivingEntities);
+
+ Villager winner = villager;
+ for (final LivingEntity other : livingEntities) {
+ if (other == villager) {
+ continue;
+ }
+ if (!(other instanceof final net.minecraft.world.entity.npc.Villager otherVillager)) {
+ continue;
+ }
+ if (!other.isAlive()) {
+ continue;
+ }
+ if (!competesForSameJobsite(globalPos, poi, otherVillager)) {
+ continue;
+ }
+ winner = selectWinner(winner, otherVillager);
+ }
+ }
+ // Paper end - Improve performance of PoiCompetitorScan by unrolling stream
);
return true;
}

View File

@@ -17,7 +17,7 @@
+ parent.setAge(6000);
+ partner.setAge(6000);
+ level.addFreshEntityWithPassengers(breedOffspring, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING);
+ // CraftBukkit end
+ // CraftBukkit end - call EntityBreedEvent
level.broadcastEntityEvent(breedOffspring, (byte)12);
return Optional.of(breedOffspring);
}

View File

@@ -0,0 +1,13 @@
--- a/net/minecraft/world/entity/animal/AgeableWaterCreature.java
+++ b/net/minecraft/world/entity/animal/AgeableWaterCreature.java
@@ -68,6 +_,10 @@
) {
int seaLevel = level.getSeaLevel();
int i = seaLevel - 13;
+ // Paper start - Make water animal spawn height configurable
+ seaLevel = level.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.maximum.or(seaLevel);
+ i = level.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.minimum.or(i);
+ // Paper end - Make water animal spawn height configurable
return pos.getY() >= i
&& pos.getY() <= seaLevel
&& level.getFluidState(pos.below()).is(FluidTags.WATER)

View File

@@ -63,7 +63,7 @@
this.level().broadcastEntityEvent(this, (byte)18);
}
@@ -220,23 +_,45 @@
@@ -220,23 +_,44 @@
if (breedOffspring != null) {
breedOffspring.setBaby(true);
breedOffspring.moveTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F);
@@ -74,43 +74,43 @@
+ int experience = this.getRandom().nextInt(7) + 1;
+ org.bukkit.event.entity.EntityBreedEvent entityBreedEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreedEvent(breedOffspring, this, mate, breeder, this.breedItem, experience);
+ if (entityBreedEvent.isCancelled()) {
+ this.resetLove();
+ mate.resetLove();
+ return;
+ }
+ experience = entityBreedEvent.getExperience();
+ this.finalizeSpawnChildFromBreeding(level, mate, breedOffspring, experience);
+ level.addFreshEntityWithPassengers(breedOffspring, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING);
+ // CraftBukkit end
+ // CraftBukkit end - call EntityBreedEvent
}
}
public void finalizeSpawnChildFromBreeding(ServerLevel level, Animal animal, @Nullable AgeableMob baby) {
- Optional.ofNullable(this.getLoveCause()).or(() -> Optional.ofNullable(animal.getLoveCause())).ifPresent(player -> {
+ // CraftBukkit start
+ // CraftBukkit start - call EntityBreedEvent
+ this.finalizeSpawnChildFromBreeding(level, animal, baby, this.getRandom().nextInt(7) + 1);
+ }
+
+ public void finalizeSpawnChildFromBreeding(ServerLevel level, Animal animal, @Nullable AgeableMob baby, int experience) {
+ // CraftBukkit end
+ // Paper start
+ // CraftBukkit end - call EntityBreedEvent
+ // Paper start - call EntityBreedEvent
+ ServerPlayer player = this.getLoveCause();
+ if (player == null) player = animal.getLoveCause();
+ if (player != null) {
+ // Paper end
+ // Paper end - call EntityBreedEvent
player.awardStat(Stats.ANIMALS_BRED);
CriteriaTriggers.BRED_ANIMALS.trigger(player, this, animal, baby);
- });
+ } // Paper
+ } // Paper - call EntityBreedEvent
this.setAge(6000);
animal.setAge(6000);
this.resetLove();
animal.resetLove();
level.broadcastEntityEvent(this, (byte)18);
if (level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
- if (level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
- level.addFreshEntity(new ExperienceOrb(level, this.getX(), this.getY(), this.getZ(), this.getRandom().nextInt(7) + 1));
+ // CraftBukkit start - use event experience
+ if (experience > 0) {
+ level.addFreshEntity(new ExperienceOrb(level, this.getX(), this.getY(), this.getZ(), experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, player, baby)); // Paper
+ }
+ // CraftBukkit end
+ if (experience > 0 && level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { // Paper - call EntityBreedEvent
+ level.addFreshEntity(new ExperienceOrb(level, this.getX(), this.getY(), this.getZ(), experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, player, baby)); // Paper - call EntityBreedEvent, add spawn context
}
}

View File

@@ -93,7 +93,7 @@
}
public static boolean isPathClear(Fox fox, LivingEntity livingEntity) {
@@ -853,6 +_,14 @@
@@ -853,6 +_,18 @@
if (loveCause1 != null && loveCause != loveCause1) {
fox.addTrustedUUID(loveCause1.getUUID());
}
@@ -102,13 +102,17 @@
+ fox.moveTo(this.animal.getX(), this.animal.getY(), this.animal.getZ(), 0.0F, 0.0F);
+ int experience = this.animal.getRandom().nextInt(7) + 1;
+ org.bukkit.event.entity.EntityBreedEvent entityBreedEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreedEvent(fox, this.animal, this.partner, loveCause, this.animal.breedItem, experience);
+ if (entityBreedEvent.isCancelled()) return;
+ if (entityBreedEvent.isCancelled()) {
+ this.animal.resetLove();
+ this.partner.resetLove();
+ return;
+ }
+ experience = entityBreedEvent.getExperience();
+ // CraftBukkit end
+ // CraftBukkit end - call EntityBreedEvent
if (serverPlayer != null) {
serverPlayer.awardStat(Stats.ANIMALS_BRED);
@@ -863,15 +_,17 @@
@@ -863,14 +_,12 @@
this.partner.setAge(6000);
this.animal.resetLove();
this.partner.resetLove();
@@ -117,22 +121,15 @@
- serverLevel.addFreshEntityWithPassengers(fox);
+ serverLevel.addFreshEntityWithPassengers(fox, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - added SpawnReason
this.level.broadcastEntityEvent(this.animal, (byte)18);
if (serverLevel.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
- this.level
- .addFreshEntity(
- if (serverLevel.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
+ if (experience > 0 && serverLevel.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { // Paper - call EntityBreedEvent
this.level
.addFreshEntity(
- new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), this.animal.getRandom().nextInt(7) + 1)
- );
+ // CraftBukkit start - use event experience
+ if (experience > 0) {
+ this.level
+ .addFreshEntity(
+ new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, loveCause, fox) // Paper
+ );
+ }
+ // CraftBukkit end
+ new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, loveCause, fox) // Paper - call EntityBreedEvent, add spawn context
);
}
}
}
@@ -934,6 +_,7 @@
private void pickSweetBerries(BlockState state) {
int ageValue = state.getValue(SweetBerryBushBlock.AGE);

View File

@@ -5,7 +5,7 @@
if (this.level() instanceof ServerLevel serverLevel) {
if (this.level().getBiome(this.blockPosition()).is(BiomeTags.SNOW_GOLEM_MELTS)) {
- this.hurtServer(serverLevel, this.damageSources().onFire(), 1.0F);
+ this.hurtServer(serverLevel, this.damageSources().melting(), 1.0F); // CraftBukkit - DamageSources.ON_FIRE -> CraftEventFactory.MELTING
+ this.hurtServer(serverLevel, this.damageSources().onFire().knownCause(org.bukkit.event.entity.EntityDamageEvent.DamageCause.MELTING), 1.0F); // CraftBukkit
}
if (!serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {

View File

@@ -15,7 +15,7 @@
@Override
public void thunderHit(ServerLevel level, LightningBolt lightning) {
- this.hurtServer(level, this.damageSources().lightningBolt(), Float.MAX_VALUE);
+ this.hurtServer(level, this.damageSources().lightningBolt().customEventDamager(lightning), Float.MAX_VALUE); // CraftBukkit // Paper - fix DamageSource API
+ this.hurtServer(level, this.damageSources().lightningBolt().eventEntityDamager(lightning), Float.MAX_VALUE); // CraftBukkit // Paper - fix DamageSource API
}
@Override

View File

@@ -19,7 +19,7 @@
+ public boolean actuallyHurt(ServerLevel level, DamageSource damageSource, float amount, org.bukkit.event.entity.EntityDamageEvent event) { // CraftBukkit - void -> boolean
if (!this.canArmorAbsorb(damageSource)) {
- super.actuallyHurt(level, damageSource, amount);
+ super.actuallyHurt(level, damageSource, amount, event); // CraftBukkit
+ return super.actuallyHurt(level, damageSource, amount, event); // CraftBukkit
} else {
+ if (event.isCancelled()) return false; // CraftBukkit - SPIGOT-7815: if the damage was cancelled, no need to run the wolf armor behaviour
ItemStack bodyArmorItem = this.getBodyArmorItem();

View File

@@ -25,10 +25,11 @@
this.playEatingSound();
}
@@ -350,7 +_,7 @@
@@ -349,8 +_,7 @@
double d1 = Mth.randomBetween(this.random, 0.3F, 0.7F);
double d2 = Mth.randomBetween(this.random, -0.2F, 0.2F);
ItemEntity itemEntity = new ItemEntity(this.level(), vec3.x(), vec3.y(), vec3.z(), itemStack, d, d1, d2);
this.level().addFreshEntity(itemEntity);
- this.level().addFreshEntity(itemEntity);
- return true;
+ return this.spawnAtLocation((net.minecraft.server.level.ServerLevel) this.level(), itemEntity) != null; // Paper - Call EntityDropItemEvent
}

View File

@@ -191,7 +191,7 @@
}
@Override
@@ -423,12 +_,18 @@
@@ -423,13 +_,19 @@
if (compound.contains("DrownedConversionTime", 99) && compound.getInt("DrownedConversionTime") > -1) {
this.startUnderWaterConversion(compound.getInt("DrownedConversionTime"));
}
@@ -206,11 +206,13 @@
public boolean killedEntity(ServerLevel level, LivingEntity entity) {
boolean flag = super.killedEntity(level, entity);
- if ((level.getDifficulty() == Difficulty.NORMAL || level.getDifficulty() == Difficulty.HARD) && entity instanceof Villager villager) {
+ final double fallbackChance = level.getDifficulty() == Difficulty.HARD ? 100 : level.getDifficulty() == Difficulty.NORMAL ? 50 : 0; // Paper - Configurable chance of villager zombie infection
- if (level.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) {
+ final double fallbackChance = level.getDifficulty() == Difficulty.HARD ? 100 : level.getDifficulty() == Difficulty.NORMAL ? 50 : 0; // Paper - Configurable chance of villager zombie infection - moved up from belows if
+ if (this.random.nextDouble() * 100 < level.paperConfig().entities.behavior.zombieVillagerInfectionChance.or(fallbackChance) && entity instanceof Villager villager) { // Paper - Configurable chance of villager zombie infection
if (level.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) {
+ if (false && level.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) { // Paper - Configurable chance of villager zombie infection - moved to "fallbackChance"
return flag;
}
@@ -465,7 +_,7 @@
spawnGroupData = super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData);
float specialMultiplier = difficulty.getSpecialMultiplier();

View File

@@ -57,14 +57,6 @@
EntityType.VILLAGER,
ConversionParams.single(this, false, false),
villager -> {
@@ -223,6 +_,7 @@
SlotAccess slot = villager.getSlot(equipmentSlot.getIndex() + 300);
slot.set(this.getItemBySlot(equipmentSlot));
}
+ this.forceDrops = false; // CraftBukkit
villager.setVillagerData(this.getVillagerData());
if (this.gossips != null) {
@@ -237,19 +_,24 @@
villager.finalizeSpawn(serverLevel, serverLevel.getCurrentDifficultyAt(villager.blockPosition()), EntitySpawnReason.CONVERSION, null);
villager.refreshBrain(serverLevel);

View File

@@ -314,7 +314,7 @@
&& !this.isSprinting();
+ flag2 = flag2 && !this.level().paperConfig().entities.behavior.disablePlayerCrits; // Paper - Toggleable player crits
if (flag2) {
+ damageSource = damageSource.critical(true); // Paper start - critical damage API
+ damageSource = damageSource.critical(); // Paper - critical damage API
f *= 1.5F;
}
@@ -342,12 +342,14 @@
}
if (flag3) {
@@ -1212,43 +_,62 @@
@@ -1212,43 +_,64 @@
&& (!(livingEntity2 instanceof ArmorStand) || !((ArmorStand)livingEntity2).isMarker())
&& this.distanceToSqr(livingEntity2) < 9.0) {
float f6 = this.getEnchantedDamage(livingEntity2, f5, damageSource) * attackStrengthScale;
+ // CraftBukkit start - Only apply knockback if the damage hits
+ if (!livingEntity2.hurtServer((ServerLevel) this.level(), this.damageSources().playerAttack(this).sweep().critical(flag2), f6)) { // Paper - add critical damage API
+ // CraftBukkit start - Only apply knockback if the event is not cancelled
+ livingEntity2.lastDamageCancelled = false;
+ livingEntity2.hurtServer((ServerLevel) this.level(), damageSource.knownCause(org.bukkit.event.entity.EntityDamageEvent.DamageCause.ENTITY_SWEEP_ATTACK), f6);
+ if (livingEntity2.lastDamageCancelled) {
+ continue;
+ }
+ // CraftBukkit end
@@ -643,18 +645,21 @@
}
@Override
@@ -1988,17 +_,28 @@
@@ -1988,17 +_,32 @@
return ImmutableList.of(Pose.STANDING, Pose.CROUCHING, Pose.SWIMMING);
}
+ // Paper start - PlayerReadyArrowEvent
+ protected boolean tryReadyArrow(ItemStack bow, ItemStack itemstack) {
+ return !(this instanceof ServerPlayer) ||
+ new com.destroystokyo.paper.event.player.PlayerReadyArrowEvent(
+ ((ServerPlayer) this).getBukkitEntity(),
+ org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(bow),
+ org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)
+ ).callEvent();
+ // We pass a result mutable boolean in to allow the caller of this method to know if the event was cancelled.
+ protected boolean tryReadyArrow(ItemStack bow, ItemStack itemstack, final org.apache.commons.lang3.mutable.MutableBoolean cancelled) {
+ if (!(this instanceof final ServerPlayer serverPlayer)) return true;
+ final boolean notCancelled = new com.destroystokyo.paper.event.player.PlayerReadyArrowEvent(
+ serverPlayer.getBukkitEntity(),
+ org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(bow),
+ org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)
+ ).callEvent();
+ if (!notCancelled) cancelled.setValue(true);
+ return notCancelled;
+ }
+ // Paper end - PlayerReadyArrowEvent
+
@@ -664,13 +669,44 @@
return ItemStack.EMPTY;
} else {
- Predicate<ItemStack> supportedHeldProjectiles = ((ProjectileWeaponItem)shootable.getItem()).getSupportedHeldProjectiles();
+ Predicate<ItemStack> supportedHeldProjectiles = ((ProjectileWeaponItem)shootable.getItem()).getSupportedHeldProjectiles().and(item -> this.tryReadyArrow(shootable, item)); // Paper - PlayerReadyArrowEvent
+ final org.apache.commons.lang3.mutable.MutableBoolean anyEventCancelled = new org.apache.commons.lang3.mutable.MutableBoolean(); // Paper - PlayerReadyArrowEvent
+ Predicate<ItemStack> supportedHeldProjectiles = ((ProjectileWeaponItem)shootable.getItem()).getSupportedHeldProjectiles().and(item -> this.tryReadyArrow(shootable, item, anyEventCancelled)); // Paper - PlayerReadyArrowEvent
ItemStack heldProjectile = ProjectileWeaponItem.getHeldProjectile(this, supportedHeldProjectiles);
if (!heldProjectile.isEmpty()) {
return heldProjectile;
} else {
- supportedHeldProjectiles = ((ProjectileWeaponItem)shootable.getItem()).getAllSupportedProjectiles();
+ supportedHeldProjectiles = ((ProjectileWeaponItem)shootable.getItem()).getAllSupportedProjectiles().and(item -> this.tryReadyArrow(shootable, item)); // Paper - PlayerReadyArrowEvent
+ supportedHeldProjectiles = ((ProjectileWeaponItem)shootable.getItem()).getAllSupportedProjectiles().and(item -> this.tryReadyArrow(shootable, item, anyEventCancelled)); // Paper - PlayerReadyArrowEvent
for (int i = 0; i < this.inventory.getContainerSize(); i++) {
ItemStack item = this.inventory.getItem(i);
@@ -2007,6 +_,7 @@
}
}
+ if (anyEventCancelled.booleanValue() && !this.abilities.instabuild && this instanceof final ServerPlayer player) this.resyncUsingItem(player); // Paper - resync if no item matched the Predicate
return this.abilities.instabuild ? new ItemStack(Items.ARROW) : ItemStack.EMPTY;
}
}
@@ -2089,12 +_,20 @@
}
public boolean hasClientLoaded() {
- return this.clientLoaded || this.clientLoadedTimeoutTimer <= 0;
+ return this.clientLoaded; // Paper - Add PlayerLoadedWorldEvent
}
public void tickClientLoadTimeout() {
if (!this.clientLoaded) {
this.clientLoadedTimeoutTimer--;
+ // Paper start - Add PlayerLoadedWorldEvent
+ if (this.clientLoadedTimeoutTimer <= 0) {
+ this.clientLoaded = true;
+
+ final io.papermc.paper.event.player.PlayerClientLoadedWorldEvent event = new io.papermc.paper.event.player.PlayerClientLoadedWorldEvent((org.bukkit.craftbukkit.entity.CraftPlayer) getBukkitEntity(), true);
+ event.callEvent();
+ }
+ // Paper end - Add PlayerLoadedWorldEvent
}
}

View File

@@ -77,7 +77,7 @@
this.hasImpulse = true;
if (this.getPierceLevel() > 0 && projectileDeflection == ProjectileDeflection.NONE) {
continue;
@@ -313,6 +_,19 @@
@@ -313,13 +_,26 @@
}
}
@@ -97,6 +97,14 @@
@Override
protected double getDefaultGravity() {
return 0.05;
}
private boolean shouldFall() {
- return this.isInGround() && this.level().noCollision(new AABB(this.position(), this.position()).inflate(0.06));
+ return this.isInGround() && this.level().noCollision(new AABB(this.position(), this.position()).inflate(0.06)); // Paper - getAttachedBlocks api; diff on change
}
private void startFalling() {
@@ -329,7 +_,7 @@
this.life = 0;
}

View File

@@ -14,7 +14,7 @@
if (target.isAlive() && !target.isInvulnerable() && target != owner) {
if (owner == null) {
- target.hurt(this.damageSources().magic(), 6.0F);
+ target.hurt(this.damageSources().magic().customEventDamager(this), 6.0F); // CraftBukkit // Paper - fix DamageSource API
+ target.hurt(this.damageSources().magic().eventEntityDamager(this), 6.0F); // CraftBukkit // Paper - fix DamageSource API
} else {
if (owner.isAlliedTo(target)) {
return;

View File

@@ -22,11 +22,11 @@
if (this.life > this.lifetime && this.level() instanceof ServerLevel serverLevel) {
- this.explode(serverLevel);
+ // CraftBukkit start
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this).isCancelled()) {
+ // Paper start - Call FireworkExplodeEvent
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this)) {
+ this.explode(serverLevel);
+ }
+ // CraftBukkit end
+ // Paper end - Call FireworkExplodeEvent
}
}
@@ -43,11 +43,11 @@
super.onHitEntity(result);
if (this.level() instanceof ServerLevel serverLevel) {
- this.explode(serverLevel);
+ // CraftBukkit start
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this).isCancelled()) {
+ // Paper start - Call FireworkExplodeEvent
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this)) {
+ this.explode(serverLevel);
+ }
+ // CraftBukkit end
+ // Paper end - Call FireworkExplodeEvent
}
}
@@ -56,11 +56,11 @@
this.level().getBlockState(blockPos).entityInside(this.level(), blockPos, this);
if (this.level() instanceof ServerLevel serverLevel && this.hasExplosion()) {
- this.explode(serverLevel);
+ // CraftBukkit start
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this).isCancelled()) {
+ // Paper start - Call FireworkExplodeEvent
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this)) {
+ this.explode(serverLevel);
+ }
+ // CraftBukkit end
+ // Paper end - Call FireworkExplodeEvent
}
super.onHitBlock(result);

View File

@@ -54,11 +54,14 @@
}
this.leftOwner = compound.getBoolean("LeftOwner");
@@ -175,13 +_,22 @@
@@ -175,13 +_,25 @@
float f2 = Mth.cos(y * (float) (Math.PI / 180.0)) * Mth.cos(x * (float) (Math.PI / 180.0));
this.shoot(f, f1, f2, velocity, inaccuracy);
Vec3 knownMovement = shooter.getKnownMovement();
+ // Paper start - allow disabling relative velocity
+ if (Double.isNaN(knownMovement.x) || Double.isNaN(knownMovement.y) || Double.isNaN(knownMovement.z)) {
+ knownMovement = new Vec3(0, 0, 0);
+ }
+ if (!shooter.level().paperConfig().misc.disableRelativeProjectileVelocity) {
this.setDeltaMovement(this.getDeltaMovement().add(knownMovement.x, shooter.onGround() ? 0.0 : knownMovement.y, knownMovement.z));
+ }

View File

@@ -40,7 +40,7 @@
serverPlayer1.resetFallDistance();
serverPlayer1.resetCurrentImpulseContext();
- serverPlayer1.hurtServer(serverPlayer.serverLevel(), this.damageSources().enderPearl(), 5.0F);
+ serverPlayer1.hurtServer(serverPlayer.serverLevel(), this.damageSources().enderPearl().customEventDamager(this), 5.0F); // CraftBukkit // Paper - fix DamageSource API
+ serverPlayer1.hurtServer(serverPlayer.serverLevel(), this.damageSources().enderPearl().eventEntityDamager(this), 5.0F); // CraftBukkit // Paper - fix DamageSource API
}
this.playSound(serverLevel, vec3);

View File

@@ -1,14 +1,6 @@
--- a/net/minecraft/world/entity/projectile/ThrownPotion.java
+++ b/net/minecraft/world/entity/projectile/ThrownPotion.java
@@ -9,6 +_,7 @@
import net.minecraft.core.Holder;
import net.minecraft.core.component.DataComponents;
import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.effect.MobEffect;
@@ -82,51 +_,87 @@
@@ -82,51 +_,86 @@
@Override
protected void onHit(HitResult result) {
super.onHit(result);
@@ -28,12 +20,12 @@
+ } else if (true || potionContents.hasEffects()) { // CraftBukkit - Call event even if no effects to apply
if (this.isLingering()) {
- this.makeAreaOfEffectCloud(potionContents);
+ showParticles = this.makeAreaOfEffectCloud(potionContents, result); // CraftBukkit - Pass MovingObjectPosition // Paper
+ showParticles = this.makeAreaOfEffectCloud(potionContents, result); // CraftBukkit - Pass HitResult // Paper
} else {
- this.applySplash(
- serverLevel, potionContents.getAllEffects(), result.getType() == HitResult.Type.ENTITY ? ((EntityHitResult)result).getEntity() : null
+ showParticles = this.applySplash(
+ serverLevel, potionContents.getAllEffects(), result != null && result.getType() == HitResult.Type.ENTITY ? ((EntityHitResult)result).getEntity() : null, result // CraftBukkit - Pass MovingObjectPosition // Paper - More projectile API
+ showParticles = this.applySplash( // Paper - Fix potions splash events
+ serverLevel, potionContents.getAllEffects(), result != null && result.getType() == HitResult.Type.ENTITY ? ((EntityHitResult)result).getEntity() : null, result // CraftBukkit - Pass HitResult // Paper - More projectile API
);
}
}
@@ -48,7 +40,7 @@
}
- private void applyWater(ServerLevel level) {
+ private static final Predicate<net.minecraft.world.entity.LivingEntity> APPLY_WATER_GET_ENTITIES_PREDICATE = ThrownPotion.WATER_SENSITIVE_OR_ON_FIRE.or(Axolotl.class::isInstance); // Paper - Fix potions splash events
+ private static final Predicate<LivingEntity> APPLY_WATER_GET_ENTITIES_PREDICATE = ThrownPotion.WATER_SENSITIVE_OR_ON_FIRE.or(Axolotl.class::isInstance); // Paper - Fix potions splash events
+
+ private boolean applyWater(ServerLevel level, @Nullable HitResult result) { // Paper - Fix potions splash events
AABB aabb = this.getBoundingBox().inflate(4.0, 2.0, 4.0);
@@ -67,20 +59,19 @@
if (d < 16.0) {
if (livingEntity.isSensitiveToWater()) {
- livingEntity.hurtServer(level, this.damageSources().indirectMagic(this, this.getOwner()), 1.0F);
+ affected.put(livingEntity.getBukkitLivingEntity(), 1.0);
+ // livingEntity.hurtServer(level, this.damageSources().indirectMagic(this, this.getOwner()), 1.0F);
+ affected.put(livingEntity.getBukkitLivingEntity(), 1.0); // Paper - Fix potions splash events
}
if (livingEntity.isOnFire() && livingEntity.isAlive()) {
- livingEntity.extinguishFire();
+ extinguish.add(livingEntity.getBukkitLivingEntity());
+ // livingEntity.extinguishFire();
+ extinguish.add(livingEntity.getBukkitLivingEntity()); // Paper - Fix potions splash events
}
}
}
- for (Axolotl axolotl : this.level().getEntitiesOfClass(Axolotl.class, aabb)) {
- axolotl.rehydrate();
+ // Paper start - Fix potions splash events
+ io.papermc.paper.event.entity.WaterBottleSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callWaterBottleSplashEvent(
+ this, result, affected, rehydrate, extinguish
+ );
@@ -102,14 +93,14 @@
}
- private void applySplash(ServerLevel level, Iterable<MobEffectInstance> effects, @Nullable Entity entity) {
+ private boolean applySplash(ServerLevel level, Iterable<MobEffectInstance> effects, @Nullable Entity entity, @Nullable HitResult result) { // CraftBukkit - Pass MovingObjectPosition // Paper - Fix potions splash events & More projectile API
+ private boolean applySplash(ServerLevel level, Iterable<MobEffectInstance> effects, @Nullable Entity entity, @Nullable HitResult result) { // CraftBukkit - Pass HitResult // Paper - Fix potions splash events & More projectile API
AABB aabb = this.getBoundingBox().inflate(4.0, 2.0, 4.0);
List<LivingEntity> entitiesOfClass = level.getEntitiesOfClass(LivingEntity.class, aabb);
+ java.util.Map<org.bukkit.entity.LivingEntity, Double> affected = new java.util.HashMap<>(); // CraftBukkit
if (!entitiesOfClass.isEmpty()) {
Entity effectSource = this.getEffectSource();
@@ -135,33 +_,57 @@
@@ -135,12 +_,31 @@
double d = this.distanceToSqr(livingEntity);
if (d < 16.0) {
double d1;
@@ -120,69 +111,45 @@
d1 = 1.0 - Math.sqrt(d) / 4.0;
}
- for (MobEffectInstance mobEffectInstance : effects) {
- Holder<MobEffect> effect = mobEffectInstance.getEffect();
- if (effect.value().isInstantenous()) {
- effect.value().applyInstantenousEffect(level, this, this.getOwner(), livingEntity, mobEffectInstance.getAmplifier(), d1);
- } else {
- int i = mobEffectInstance.mapDuration(i1 -> (int)(d1 * i1 + 0.5));
- MobEffectInstance mobEffectInstance1 = new MobEffectInstance(
- effect, i, mobEffectInstance.getAmplifier(), mobEffectInstance.isAmbient(), mobEffectInstance.isVisible()
- );
- if (!mobEffectInstance1.endsWithin(20)) {
- livingEntity.addEffect(mobEffectInstance1, effectSource);
- }
- }
- }
- }
- }
- }
- }
+ affected.put(livingEntity.getBukkitLivingEntity(), d1);
+ // CraftBukkit start
+ }
+ }
+ }
+ }
+ org.bukkit.event.entity.PotionSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPotionSplashEvent(this, result, affected);
+ if (!event.isCancelled() && entitiesOfClass != null && !entitiesOfClass.isEmpty()) { // do not process effects if there are no effects to process
+ if (!event.isCancelled() && !entitiesOfClass.isEmpty()) { // do not process effects if there are no effects to process
+ Entity effectSource = this.getEffectSource();
+ for (org.bukkit.entity.LivingEntity victim : event.getAffectedEntities()) {
+ if (!(victim instanceof org.bukkit.craftbukkit.entity.CraftLivingEntity craftLivingEntity)) {
+ continue;
+ }
+ net.minecraft.world.entity.LivingEntity livingEntity = craftLivingEntity.getHandle();
+ LivingEntity livingEntity = craftLivingEntity.getHandle();
+ double d1 = event.getIntensity(victim);
+ // CraftBukkit end
+ for (MobEffectInstance mobEffectInstance : effects) {
+ Holder<MobEffect> effect = mobEffectInstance.getEffect();
+ // CraftBukkit start - Abide by PVP settings - for players only!
+ if (!this.level().pvpMode && this.getOwner() instanceof ServerPlayer && livingEntity instanceof ServerPlayer && livingEntity != this.getOwner()) {
+ MobEffect mobEffect = effect.value();
+ if (mobEffect == net.minecraft.world.effect.MobEffects.MOVEMENT_SLOWDOWN || mobEffect == net.minecraft.world.effect.MobEffects.DIG_SLOWDOWN || mobEffect == net.minecraft.world.effect.MobEffects.HARM || mobEffect == net.minecraft.world.effect.MobEffects.BLINDNESS
+ || mobEffect == net.minecraft.world.effect.MobEffects.HUNGER || mobEffect == net.minecraft.world.effect.MobEffects.WEAKNESS || mobEffect == net.minecraft.world.effect.MobEffects.POISON) {
+ continue;
+ }
+ }
+ {
+ {
+ // CraftBukkit end
+ if (effect.value().isInstantenous()) {
+ effect.value().applyInstantenousEffect(level, this, this.getOwner(), livingEntity, mobEffectInstance.getAmplifier(), d1);
+ } else {
+ int i = mobEffectInstance.mapDuration(i1 -> (int)(d1 * i1 + 0.5));
+ MobEffectInstance mobEffectInstance1 = new MobEffectInstance(
+ effect, i, mobEffectInstance.getAmplifier(), mobEffectInstance.isAmbient(), mobEffectInstance.isVisible()
+ );
+ if (!mobEffectInstance1.endsWithin(20)) {
+ livingEntity.addEffect(mobEffectInstance1, effectSource, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.POTION_SPLASH); // CraftBukkit
+ }
+ }
+ }
+ }
+ }
for (MobEffectInstance mobEffectInstance : effects) {
Holder<MobEffect> effect = mobEffectInstance.getEffect();
if (effect.value().isInstantenous()) {
@@ -151,7 +_,7 @@
effect, i, mobEffectInstance.getAmplifier(), mobEffectInstance.isAmbient(), mobEffectInstance.isVisible()
);
if (!mobEffectInstance1.endsWithin(20)) {
- livingEntity.addEffect(mobEffectInstance1, effectSource);
+ livingEntity.addEffect(mobEffectInstance1, effectSource, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.POTION_SPLASH); // CraftBukkit
}
}
}
@@ -159,9 +_,10 @@
}
}
}
+ return !event.isCancelled(); // Paper - Fix potions splash events
}
- private void makeAreaOfEffectCloud(PotionContents potionContents) {
+ private boolean makeAreaOfEffectCloud(PotionContents potionContents, @Nullable HitResult result) { // CraftBukkit - Pass MovingObjectPosition // Paper - More projectile API
+ private boolean makeAreaOfEffectCloud(PotionContents potionContents, @Nullable HitResult result) { // CraftBukkit - Pass HitResult // Paper - More projectile API
AreaEffectCloud areaEffectCloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ());
if (this.getOwner() instanceof LivingEntity livingEntity) {
areaEffectCloud.setOwner(livingEntity);
@@ -197,41 +164,30 @@
+ if (!(event.isCancelled() || areaEffectCloud.isRemoved() || (!event.allowsEmptyCreation() && (noEffects && !areaEffectCloud.potionContents.hasEffects())))) { // Paper - don't spawn area effect cloud if the effects were empty and not changed during the event handling
+ this.level().addFreshEntity(areaEffectCloud);
+ } else {
+ areaEffectCloud.discard(null); // CraftBukkit - add Bukkit remove cause
+ areaEffectCloud.discard(null); // add Bukkit remove cause
+ }
+ // CraftBukkit end
+ return !event.isCancelled(); // Paper - Fix potions splash events
}
public boolean isLingering() {
@@ -182,13 +_,25 @@
@@ -182,13 +_,19 @@
private void dowseFire(BlockPos pos) {
BlockState blockState = this.level().getBlockState(pos);
if (blockState.is(BlockTags.FIRE)) {
- this.level().destroyBlock(pos, false, this);
+ // CraftBukkit start
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, pos, blockState.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state
+ this.level().destroyBlock(pos, false, this);
+ }
+ // CraftBukkit end
this.level().destroyBlock(pos, false, this);
+ } // CraftBukkit
} else if (AbstractCandleBlock.isLit(blockState)) {
- AbstractCandleBlock.extinguish(null, blockState, this.level(), pos);
+ // CraftBukkit start
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, pos, blockState.setValue(AbstractCandleBlock.LIT, false))) {
+ AbstractCandleBlock.extinguish(null, blockState, this.level(), pos);
+ }
+ // CraftBukkit end
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, pos, blockState.setValue(AbstractCandleBlock.LIT, Boolean.valueOf(false)))) { // CraftBukkit
AbstractCandleBlock.extinguish(null, blockState, this.level(), pos);
+ } // CraftBukkit
} else if (CampfireBlock.isLitCampfire(blockState)) {
- this.level().levelEvent(null, 1009, pos, 0);
- CampfireBlock.dowse(this.getOwner(), this.level(), pos, blockState);
- this.level().setBlockAndUpdate(pos, blockState.setValue(CampfireBlock.LIT, Boolean.valueOf(false)));
+ // CraftBukkit start
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, pos, blockState.setValue(CampfireBlock.LIT, false))) {
+ this.level().levelEvent(null, 1009, pos, 0);
+ CampfireBlock.dowse(this.getOwner(), this.level(), pos, blockState);
+ this.level().setBlockAndUpdate(pos, blockState.setValue(CampfireBlock.LIT, false));
+ }
+ // CraftBukkit end
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, pos, blockState.setValue(CampfireBlock.LIT, Boolean.valueOf(false)))) { // CraftBukkit
this.level().levelEvent(null, 1009, pos, 0);
CampfireBlock.dowse(this.getOwner(), this.level(), pos, blockState);
this.level().setBlockAndUpdate(pos, blockState.setValue(CampfireBlock.LIT, Boolean.valueOf(false)));
+ } // CraftBukkit
}
}

View File

@@ -10,7 +10,7 @@
}
} else {
- flag = var8.hurtServer(serverLevel, this.damageSources().magic(), 5.0F);
+ flag = var8.hurtServer(serverLevel, this.damageSources().magic().customEventDamager(this), 5.0F); // Paper - Fire EntityDamageByEntityEvent for unowned wither skulls // Paper - fix DamageSource API
+ flag = var8.hurtServer(serverLevel, this.damageSources().magic().eventEntityDamager(this), 5.0F); // Paper - Fire EntityDamageByEntityEvent for unowned wither skulls // Paper - fix DamageSource API
}
if (flag && var8 instanceof LivingEntity livingEntityx) {

View File

@@ -0,0 +1,26 @@
--- a/net/minecraft/world/entity/projectile/windcharge/BreezeWindCharge.java
+++ b/net/minecraft/world/entity/projectile/windcharge/BreezeWindCharge.java
@@ -20,6 +_,12 @@
@Override
public void explode(Vec3 pos) {
+ // Paper start - Fire event for WindCharge explosions
+ org.bukkit.event.entity.ExplosionPrimeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExplosionPrimeEvent(this, RADIUS, false);
+ if (event.isCancelled()) {
+ return;
+ }
+ // Paper end - Fire event for WindCharge explosions
this.level()
.explode(
this,
@@ -28,8 +_,8 @@
pos.x(),
pos.y(),
pos.z(),
- 3.0F,
- false,
+ event.getRadius(), // Paper - Fire event for WindCharge explosions
+ event.getFire(), // Paper - Fire event for WindCharge explosions
Level.ExplosionInteraction.TRIGGER,
ParticleTypes.GUST_EMITTER_SMALL,
ParticleTypes.GUST_EMITTER_LARGE,

View File

@@ -0,0 +1,26 @@
--- a/net/minecraft/world/entity/projectile/windcharge/WindCharge.java
+++ b/net/minecraft/world/entity/projectile/windcharge/WindCharge.java
@@ -52,6 +_,12 @@
@Override
public void explode(Vec3 pos) {
+ // Paper start - Fire event for WindCharge explosions
+ org.bukkit.event.entity.ExplosionPrimeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExplosionPrimeEvent(this, RADIUS, false);
+ if (event.isCancelled()) {
+ return;
+ }
+ // Paper end - Fire event for WindCharge explosions
this.level()
.explode(
this,
@@ -60,8 +_,8 @@
pos.x(),
pos.y(),
pos.z(),
- 1.2F,
- false,
+ event.getRadius(), // Paper - Fire event for WindCharge explosions
+ event.getFire(), // Paper - Fire event for WindCharge explosions
Level.ExplosionInteraction.TRIGGER,
ParticleTypes.GUST_EMITTER_SMALL,
ParticleTypes.GUST_EMITTER_LARGE,

View File

@@ -99,42 +99,20 @@
this.stop();
return;
}
@@ -491,6 +_,10 @@
@@ -486,7 +_,7 @@
private void spawnGroup(BlockPos pos) {
boolean flag = false;
- int i = this.groupsSpawned + 1;
+ int i = this.groupsSpawned + 1; final int wave = i; // Paper - OBFHELPER
this.totalHealth = 0.0F;
DifficultyInstance currentDifficultyAt = this.level.getCurrentDifficultyAt(pos);
boolean shouldSpawnBonusGroup = this.shouldSpawnBonusGroup();
+ // CraftBukkit start
+ Raider leader = null;
+ List<Raider> raiders = new java.util.ArrayList<>();
+ // CraftBukkit end
for (Raid.RaiderType raiderType : Raid.RaiderType.VALUES) {
int i1 = this.getDefaultNumSpawns(raiderType, i, shouldSpawnBonusGroup)
+ this.getPotentialBonusSpawns(raiderType, this.random, i, currentDifficultyAt, shouldSpawnBonusGroup);
@@ -506,9 +_,11 @@
raider.setPatrolLeader(true);
this.setLeader(i, raider);
flag = true;
+ leader = raider; // CraftBukkit
}
this.joinRaid(i, raider, pos, false);
+ raiders.add(raider); // CraftBukkit
if (raiderType.entityType == EntityType.RAVAGER) {
Raider raider1 = null;
if (i == this.getNumGroups(Difficulty.NORMAL)) {
@@ -526,6 +_,7 @@
this.joinRaid(i, raider1, pos, false);
raider1.moveTo(pos, 0.0F, 0.0F);
raider1.startRiding(raider);
+ raiders.add(raider); // CraftBukkit
}
}
}
@@ -535,6 +_,7 @@
this.groupsSpawned++;
this.updateBossbar();
this.setDirty();
+ org.bukkit.craftbukkit.event.CraftEventFactory.callRaidSpawnWaveEvent(this, leader, raiders); // CraftBukkit
+ org.bukkit.craftbukkit.event.CraftEventFactory.callRaidSpawnWaveEvent(this, java.util.Objects.requireNonNull(this.getLeader(wave)), this.groupRaiderMap.get(wave)); // CraftBukkit
}
public void joinRaid(int wave, Raider raider, @Nullable BlockPos pos, boolean isRecruited) {

View File

@@ -9,7 +9,7 @@
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.Container;
@@ -63,6 +_,31 @@
@@ -63,6 +_,32 @@
@Nullable
private ContainerSynchronizer synchronizer;
private boolean suppressRemoteUpdates;
@@ -37,6 +37,7 @@
+ com.google.common.base.Preconditions.checkState(this.title == null, "Title already set");
+ this.title = title;
+ }
+ public void startOpen() {}
+ // CraftBukkit end
protected AbstractContainerMenu(@Nullable MenuType<?> menuType, int containerId) {
@@ -71,6 +72,41 @@
}
}
}
@@ -243,7 +_,7 @@
private void synchronizeSlotToRemote(int slotIndex, ItemStack stack, Supplier<ItemStack> supplier) {
if (!this.suppressRemoteUpdates) {
ItemStack itemStack = this.remoteSlots.get(slotIndex);
- if (!ItemStack.matches(itemStack, stack)) {
+ if (!this.matchesRemote(itemStack, stack)) { // Paper - add flag to simplify remote matching logic
ItemStack itemStack1 = supplier.get();
this.remoteSlots.set(slotIndex, itemStack1);
if (this.synchronizer != null) {
@@ -267,7 +_,7 @@
private void synchronizeCarriedToRemote() {
if (!this.suppressRemoteUpdates) {
- if (!ItemStack.matches(this.getCarried(), this.remoteCarried)) {
+ if (!this.matchesRemote(this.getCarried(), this.remoteCarried)) { // Paper - add flag to simplify remote matching logic
this.remoteCarried = this.getCarried().copy();
if (this.synchronizer != null) {
this.synchronizer.sendCarriedChange(this, this.remoteCarried);
@@ -276,6 +_,16 @@
}
}
+ // Paper start - add flag to simplify remote matching logic
+ private boolean matchesRemote(final ItemStack stack, final ItemStack other) {
+ if (this.synchronizer != null && this.synchronizer.player() != null && this.synchronizer.player().getBukkitEntity().simplifyContainerDesyncCheck()) {
+ // Only check the item type and count
+ return stack == other || (stack.getCount() == other.getCount() && ItemStack.isSameItem(stack, other));
+ }
+ return ItemStack.matches(stack, other);
+ }
+ // Paper end - add flag to simplify remote matching logic
+
public void setRemoteSlot(int slot, ItemStack stack) {
this.remoteSlots.set(slot, stack.copy());
}
@@ -343,6 +_,7 @@
this.resetQuickCraft();
}

View File

@@ -1,6 +1,6 @@
--- a/net/minecraft/world/inventory/ChestMenu.java
+++ b/net/minecraft/world/inventory/ChestMenu.java
@@ -9,6 +_,29 @@
@@ -9,6 +_,34 @@
public class ChestMenu extends AbstractContainerMenu {
private final Container container;
private final int containerRows;
@@ -26,14 +26,21 @@
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+
+ @Override
+ public void startOpen() {
+ this.container.startOpen(this.player.player);
+ }
+ // CraftBukkit end
private ChestMenu(MenuType<?> type, int containerId, Inventory playerInventory, int rows) {
this(type, containerId, playerInventory, new SimpleContainer(9 * rows), rows);
@@ -52,6 +_,9 @@
@@ -51,7 +_,10 @@
checkContainerSize(container, rows * 9);
this.container = container;
this.containerRows = rows;
container.startOpen(playerInventory.player);
- container.startOpen(playerInventory.player);
+ // container.startOpen(playerInventory.player); // Paper - don't startOpen until menu actually opens
+ // CraftBukkit start - Save player
+ this.player = playerInventory;
+ // CraftBukkit end

View File

@@ -1,9 +1,15 @@
--- a/net/minecraft/world/inventory/ContainerSynchronizer.java
+++ b/net/minecraft/world/inventory/ContainerSynchronizer.java
@@ -11,4 +_,6 @@
@@ -11,4 +_,12 @@
void sendCarriedChange(AbstractContainerMenu containerMenu, ItemStack stack);
void sendDataChange(AbstractContainerMenu container, int id, int value);
+
+ default void sendOffHandSlotChange() {} // Paper - Sync offhand slot in menus
+
+ // Paper start - add flag to simplify remote matching logic
+ default net.minecraft.server.level.@org.jspecify.annotations.Nullable ServerPlayer player() {
+ return null;
+ }
+ // Paper end - add flag to simplify remote matching logic
}

View File

@@ -97,7 +97,7 @@
+ .bukkitToMinecraftHolder(offer.getEnchantment()));
+ this.levelClue[j] = offer.getEnchantmentLevel();
+ } else {
+ this.costs[j] = 0;
+ if (enchantClue[j] != -1) this.costs[j] = 0;
+ this.enchantClue[j] = -1;
+ this.levelClue[j] = -1;
+ }
@@ -107,7 +107,7 @@
this.broadcastChanges();
});
} else {
@@ -145,19 +_,51 @@
@@ -145,19 +_,53 @@
return false;
} else {
this.access.execute((level, blockPos) -> {
@@ -124,7 +124,9 @@
+ enchants.put(org.bukkit.craftbukkit.enchantments.CraftEnchantment.minecraftHolderToBukkit(instance.enchantment), instance.level);
+ }
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack);
+ org.bukkit.enchantments.Enchantment hintedEnchantment = org.bukkit.craftbukkit.enchantments.CraftEnchantment.minecraftHolderToBukkit(registry.byId(this.enchantClue[id]));
+ Holder<Enchantment> holder = registry.byId(this.enchantClue[id]);
+ if (holder == null) return;
+ org.bukkit.enchantments.Enchantment hintedEnchantment = org.bukkit.craftbukkit.enchantments.CraftEnchantment.minecraftHolderToBukkit(holder);
+ int hintedEnchantmentLevel = this.levelClue[id];
+ org.bukkit.event.enchantment.EnchantItemEvent event = new org.bukkit.event.enchantment.EnchantItemEvent((org.bukkit.entity.Player) player.getBukkitEntity(), this.getBukkitView(), this.access.getLocation().getBlock(), craftItemStack, this.costs[id], enchants, hintedEnchantment, hintedEnchantmentLevel, id);
+ level.getCraftServer().getPluginManager().callEvent(event);

View File

@@ -1,7 +1,7 @@
--- a/net/minecraft/world/inventory/HorseInventoryMenu.java
+++ b/net/minecraft/world/inventory/HorseInventoryMenu.java
@@ -19,9 +_,23 @@
private final AbstractHorse horse;
public final AbstractHorse horse;
public static final int SLOT_BODY_ARMOR = 1;
private static final int SLOT_HORSE_INVENTORY_START = 2;
+ // CraftBukkit start

View File

@@ -27,6 +27,14 @@
this.addStandardInventorySlots(playerInventory, 108, 84);
}
@@ -61,6 +_,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!checkReachable) return true; // Paper - checkReachable
return this.trader.stillValid(player);
}
@@ -105,12 +_,12 @@
ItemStack item = slot.getItem();
itemStack = item.copy();

View File

@@ -1,6 +1,6 @@
--- a/net/minecraft/world/inventory/ShulkerBoxMenu.java
+++ b/net/minecraft/world/inventory/ShulkerBoxMenu.java
@@ -9,6 +_,20 @@
@@ -9,6 +_,25 @@
public class ShulkerBoxMenu extends AbstractContainerMenu {
private static final int CONTAINER_SIZE = 27;
private final Container container;
@@ -17,18 +17,25 @@
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.CraftInventoryView(this.player.player.getBukkitEntity(), new org.bukkit.craftbukkit.inventory.CraftInventory(this.container), this);
+ return this.bukkitEntity;
+ }
+
+ @Override
+ public void startOpen() {
+ container.startOpen(player.player);
+ }
+ // CraftBukkit end
public ShulkerBoxMenu(int containerId, Inventory playerInventory) {
this(containerId, playerInventory, new SimpleContainer(27));
@@ -18,6 +_,7 @@
@@ -18,7 +_,8 @@
super(MenuType.SHULKER_BOX, containerId);
checkContainerSize(container, 27);
this.container = container;
- container.startOpen(playerInventory.player);
+ this.player = playerInventory; // CraftBukkit - save player
container.startOpen(playerInventory.player);
+ // container.startOpen(playerInventory.player); // Paper - don't startOpen until menu actually opens
int i = 3;
int i1 = 9;
@@ -33,6 +_,7 @@
@Override

View File

@@ -1,6 +1,6 @@
--- a/net/minecraft/world/item/EnderpearlItem.java
+++ b/net/minecraft/world/item/EnderpearlItem.java
@@ -21,22 +_,38 @@
@@ -21,22 +_,42 @@
@Override
public InteractionResult use(Level level, Player player, InteractionHand hand) {
ItemStack itemInHand = player.getItemInHand(hand);
@@ -39,7 +39,11 @@
+ );
+ player.awardStat(Stats.ITEM_USED.get(this));
+ } else {
+ // Paper end - PlayerLaunchProjectileEvent
+ if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer) {
+ serverPlayer.deregisterEnderPearl(thrownEnderpearl.projectile());
+ serverPlayer.connection.send(new net.minecraft.network.protocol.game.ClientboundCooldownPacket(player.getCooldowns().getCooldownGroup(itemInHand), 0)); // prevent visual desync of cooldown on the slot
+ }
+ // Paper end - PlayerLaunchProjectileEvent
+ player.containerMenu.sendAllDataToRemote();
+ return InteractionResult.FAIL;
+ }

View File

@@ -1,6 +1,6 @@
--- a/net/minecraft/world/item/HangingEntityItem.java
+++ b/net/minecraft/world/item/HangingEntityItem.java
@@ -66,6 +_,19 @@
@@ -66,6 +_,20 @@
if (hangingEntity.survives()) {
if (!level.isClientSide) {
@@ -14,6 +14,7 @@
+ level.getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ if (player != null) player.containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync
+ return InteractionResult.FAIL;
+ }
+ // CraftBukkit end

View File

@@ -5,7 +5,7 @@
Player player = context.getPlayer();
ItemStack itemInHand = context.getItemInHand();
+ // Paper start - EntityChangeBlockEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, clickedPos, blockState)) {
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, clickedPos, blockState1)) {
+ if (!player.isCreative()) {
+ player.containerMenu.sendAllDataToRemote();
+ }

Some files were not shown because too many files have changed in this diff Show More