Compare commits

..
Author SHA1 Message Date
Owen1212055 7f778ba634 PlayerMoveVehicleEvent 2025-03-03 12:07:30 -05:00
Owen1212055 2c7b5c8036 Reworked Vehicle PlayerMoveEvent Handling 2025-03-03 11:46:49 -05:00
46 changed files with 231 additions and 468 deletions

No files matched your search

-1
View File
@@ -5,4 +5,3 @@ gradlew text eol=lf
*.bat text eol=crlf
*.jar binary
.gitea/CODEOWNERS linguist-detectable=false
-3
View File
@@ -1,3 +0,0 @@
# Pull requests request review from the eligible staff team(s).
# One approval from either an Admin or Developer satisfies branch protection.
* @trueog/Admins @trueog/Developers
+1
View File
@@ -227,6 +227,7 @@ public net.minecraft.world.entity.LivingEntity detectEquipmentUpdates()V
public net.minecraft.world.entity.LivingEntity effectsDirty
public net.minecraft.world.entity.LivingEntity entityEventForEquipmentBreak(Lnet/minecraft/world/entity/EquipmentSlot;)B
public net.minecraft.world.entity.LivingEntity getDeathSound()Lnet/minecraft/sounds/SoundEvent;
public net.minecraft.world.entity.LivingEntity getRiddenSpeed(Lnet/minecraft/world/entity/player/Player;)F
public net.minecraft.world.entity.LivingEntity getSoundVolume()F
public net.minecraft.world.entity.LivingEntity jumping
public net.minecraft.world.entity.LivingEntity lastHurt
@@ -1,29 +0,0 @@
package io.papermc.paper.event.packet;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
/**
* Called when a {@code minecraft:client_tick_end} packet is received by the server.
*/
@NullMarked
public class ClientTickEndEvent extends PlayerEvent {
private static final HandlerList HANDLER_LIST = new HandlerList();
@ApiStatus.Internal
public ClientTickEndEvent(final Player player) {
super(player);
}
@Override
public HandlerList getHandlers() {
return HANDLER_LIST;
}
public static HandlerList getHandlerList() {
return HANDLER_LIST;
}
}
@@ -0,0 +1,81 @@
package io.papermc.paper.event.player;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
/**
* Runs when a player attempts to move a vehicle to a new position.
*/
@NullMarked
public class PlayerMoveVehicleEvent extends PlayerEvent implements Cancellable {
private static final HandlerList HANDLER_LIST = new HandlerList();
private final Location from;
private final Location to;
private final Entity vehicle;
private boolean cancelled;
@ApiStatus.Internal
public PlayerMoveVehicleEvent(final Player player, final Entity vehicle, final Location from, final Location to) {
super(player);
this.vehicle = vehicle;
this.from = from;
this.to = to;
}
/**
* Gets the location the vehicle moved from
*
* @return Location the vehicle moved from
*/
public Location getFrom() {
return this.from.clone();
}
/**
* Gets the location the vehicle is moving to
*
* @return Location the vehicle is moving to
*/
public Location getTo() {
return this.to.clone();
}
/**
* Gets the vehicle this player is currently moving.
* Note: You should use {@link PlayerMoveVehicleEvent#getTo()} for getting the previous and
* new location of the vehicle.
* <p>
* The behavior of getting the location of the vehicle in this event is undefined.
*
* @return vehicle
*/
public Entity getVehicle() {
return vehicle;
}
@Override
public HandlerList getHandlers() {
return HANDLER_LIST;
}
public static HandlerList getHandlerList() {
return HANDLER_LIST;
}
@Override
public boolean isCancelled() {
return this.cancelled;
}
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
}
@@ -83,12 +83,14 @@ public final class NamespacedKey implements net.kyori.adventure.key.Key, com.des
* @see #NamespacedKey(Plugin, String)
*/
public NamespacedKey(@NotNull String namespace, @NotNull String key) {
Preconditions.checkArgument(namespace != null, "Namespace cannot be null");
Preconditions.checkArgument(key != null, "Key cannot be null");
Preconditions.checkArgument(namespace != null && isValidNamespace(namespace), "Invalid namespace. Must be [a-z0-9._-]: %s", namespace);
Preconditions.checkArgument(key != null && isValidKey(key), "Invalid key. Must be [a-z0-9/._-]: %s", key);
this.namespace = namespace;
this.key = key;
this.validate();
String string = toString();
Preconditions.checkArgument(string.length() <= Short.MAX_VALUE, "NamespacedKey must be less than 32768 characters", string); // Paper - Fix improper length validation
}
/**
@@ -106,17 +108,16 @@ public final class NamespacedKey implements net.kyori.adventure.key.Key, com.des
public NamespacedKey(@NotNull Plugin plugin, @NotNull String key) {
Preconditions.checkArgument(plugin != null, "Plugin cannot be null");
Preconditions.checkArgument(key != null, "Key cannot be null");
this.namespace = plugin.getName().toLowerCase(Locale.ROOT);
this.key = key.toLowerCase(Locale.ROOT);
// Check validity after normalization
this.validate();
}
private void validate() {
Preconditions.checkArgument(this.namespace.length() + 1 + this.key.length() <= Short.MAX_VALUE, "NamespacedKey must be less than 32768 characters");
Preconditions.checkArgument(isValidNamespace(this.namespace), "Invalid namespace. Must be [a-z0-9._-]: %s", this.namespace);
Preconditions.checkArgument(isValidKey(this.key), "Invalid key. Must be [a-z0-9/._-]: %s", this.key);
String string = toString();
Preconditions.checkArgument(string.length() <= Short.MAX_VALUE, "NamespacedKey must be less than 32768 characters", string); // Paper - Fix improper length validation
}
@NotNull
@@ -64,7 +64,7 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
@SuppressWarnings("removal")
@Deprecated(forRemoval = true, since = "1.21.4")
private static <A extends Keyed> Registry<A> legacyRegistryFor(final Class<A> clazz) {
return Objects.requireNonNull(RegistryAccess.registryAccess().getRegistry(clazz), () -> "No registry present for " + clazz.getSimpleName() + ". This is a bug.");
return Objects.requireNonNull(RegistryAccess.registryAccess().getRegistry(clazz), "No registry present for " + clazz.getSimpleName() + ". This is a bug.");
}
/**
@@ -3902,20 +3902,4 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM
* @return the result of this method, holding leftovers and spawned items.
*/
PlayerGiveResult give(Collection<ItemStack> items, boolean dropIfFull);
/**
* Get the score that shows in the death screen of the player.
* <p>This amount is added to when the player gains experience.</p>
*
* @return Death screen score of player
*/
int getDeathScreenScore();
/**
* Set the score that shows in the death screen of the player.
* <p>This amount is added to when the player gains experience.</p>
*
* @param score New death screen score of player
*/
void setDeathScreenScore(int score);
}
@@ -33,11 +33,11 @@ public class BlockFadeEvent extends BlockEvent implements Cancellable {
}
/**
* Gets the state of the new block that will replace the block
* fading, melting or disappearing.
* Gets the state of the block that will be fading, melting or
* disappearing.
*
* @return The block state of the new block that replaces the block
* fading, melting or disappearing
* @return The block state of the block that will be fading, melting or
* disappearing
*/
@NotNull
public BlockState getNewState() {
@@ -211,10 +211,6 @@ public class CreatureSpawnEvent extends EntitySpawnEvent {
* When an entity spawns from an ominous item spawner
*/
OMINOUS_ITEM_SPAWNER,
/**
* When an entity spawns from a bucket
*/
BUCKET,
// Paper end - Fixes and additions to the SpawnReason API
/**
* When a creature is spawned by a potion effect, for example:
@@ -327,7 +327,7 @@ public interface ItemFactory {
*
* <p>If the provided ItemStack is already enchanted, the existing enchants will be removed before enchanting.</p>
*
* <p>Enchantment tables use levels in the range {@code [1, 30]}.</p>
* <p>Levels must be in range {@code [1, 30]}.</p>
*
* @param itemStack ItemStack to enchant
* @param levels levels to use for enchanting
@@ -336,7 +336,7 @@ public interface ItemFactory {
* @return enchanted copy of the provided ItemStack
* @throws IllegalArgumentException on bad arguments
*/
@NotNull ItemStack enchantWithLevels(@NotNull ItemStack itemStack, int levels, boolean allowTreasure, @NotNull java.util.Random random);
@NotNull ItemStack enchantWithLevels(@NotNull ItemStack itemStack, @org.jetbrains.annotations.Range(from = 1, to = 30) int levels, boolean allowTreasure, @NotNull java.util.Random random);
// Paper end - enchantWithLevels API
// Paper start - enchantWithLevels with tag specification
/**
@@ -344,7 +344,7 @@ public interface ItemFactory {
*
* <p>If the provided ItemStack is already enchanted, the existing enchants will be removed before enchanting.</p>
*
* <p>Enchantment tables use levels in the range {@code [1, 30]}.</p>
* <p>Levels must be in range {@code [1, 30]}.</p>
*
* @param itemStack ItemStack to enchant
* @param levels levels to use for enchanting
@@ -353,6 +353,6 @@ public interface ItemFactory {
* @return enchanted copy of the provided ItemStack
* @throws IllegalArgumentException on bad arguments
*/
@NotNull ItemStack enchantWithLevels(@NotNull ItemStack itemStack, int levels, @NotNull io.papermc.paper.registry.set.RegistryKeySet<@NotNull Enchantment> keySet, @NotNull java.util.Random random);
@NotNull ItemStack enchantWithLevels(@NotNull ItemStack itemStack, @org.jetbrains.annotations.Range(from = 1, to = 30) int levels, @NotNull io.papermc.paper.registry.set.RegistryKeySet<@NotNull Enchantment> keySet, @NotNull java.util.Random random);
// Paper end - enchantWithLevels with tag specification
}
@@ -57,7 +57,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
*/
@org.jetbrains.annotations.Contract(value = "_, _ -> new", pure = true)
public static @NotNull ItemStack of(final @NotNull Material type, final int amount) {
Preconditions.checkArgument(type.asItemType() != null, "%s isn't an item", type);
Preconditions.checkArgument(type.asItemType() != null, type + " isn't an item");
Preconditions.checkArgument(amount > 0, "amount must be greater than 0");
return java.util.Objects.requireNonNull(type.asItemType(), type + " is not an item").createItemStack(amount); // Paper - delegate
}
@@ -683,7 +683,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
*
* <p>If this ItemStack is already enchanted, the existing enchants will be removed before enchanting.</p>
*
* <p>Enchantment tables use levels in the range {@code [1, 30]}.</p>
* <p>Levels must be in range {@code [1, 30]}.</p>
*
* @param levels levels to use for enchanting
* @param allowTreasure whether to allow enchantments where {@link org.bukkit.enchantments.Enchantment#isTreasure()} returns true
@@ -692,7 +692,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
* @throws IllegalArgumentException on bad arguments
*/
@NotNull
public ItemStack enchantWithLevels(final int levels, final boolean allowTreasure, final @NotNull java.util.Random random) {
public ItemStack enchantWithLevels(final @org.jetbrains.annotations.Range(from = 1, to = 30) int levels, final boolean allowTreasure, final @NotNull java.util.Random random) {
return Bukkit.getServer().getItemFactory().enchantWithLevels(this, levels, allowTreasure, random);
}
@@ -701,7 +701,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
*
* <p>If the provided ItemStack is already enchanted, the existing enchants will be removed before enchanting.</p>
*
* <p>Enchantment tables use levels in the range {@code [1, 30]}.</p>
* <p>Levels must be in range {@code [1, 30]}.</p>
*
* @param levels levels to use for enchanting
* @param keySet registry key set defining the set of possible enchantments, e.g. {@link io.papermc.paper.registry.keys.tags.EnchantmentTagKeys#IN_ENCHANTING_TABLE}.
@@ -709,7 +709,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
* @return enchanted copy of the provided ItemStack
* @throws IllegalArgumentException on bad arguments
*/
public @NotNull ItemStack enchantWithLevels(final int levels, final @NotNull io.papermc.paper.registry.set.RegistryKeySet<@NotNull Enchantment> keySet, final @NotNull java.util.Random random) {
public @NotNull ItemStack enchantWithLevels(final @org.jetbrains.annotations.Range(from = 1, to = 30) int levels, final @NotNull io.papermc.paper.registry.set.RegistryKeySet<@NotNull Enchantment> keySet, final @NotNull java.util.Random random) {
return Bukkit.getItemFactory().enchantWithLevels(this, levels, keySet, random);
}
@@ -116,7 +116,7 @@ public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDepe
*/
MenuType.Typed<InventoryView, LocationInventoryViewBuilder<InventoryView>> SHULKER_BOX = get("shulker_box");
/**
* A MenuType which represents a smithing table.
* A MenuType which represents a stonecutter.
*/
MenuType.Typed<InventoryView, LocationInventoryViewBuilder<InventoryView>> SMITHING = get("smithing");
/**
+1 -1
View File
@@ -137,7 +137,7 @@ dependencies {
runtimeOnly(log4jPlugins.output)
alsoShade(log4jPlugins.output)
implementation("com.velocitypowered:velocity-native:3.4.0-SNAPSHOT") {
implementation("com.velocitypowered:velocity-native:3.4.0-20250222.161222-36") {
isTransitive = false
}
implementation("io.netty:netty-codec-haproxy:4.1.115.Final") // Add support for proxy protocol
@@ -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..2040b9555c430420a8a8697cc131d42eafb96fa1 100644
index 42f44c7cb0bd55ddfacd18acb0e596e7a953870e..161ee86d67b9a23368a18481fde9768c022d913d 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..2040b9555c430420a8a8697cc131d42e
// 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,97 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -797,4 +888,96 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
public void setBandwidthLogger(LocalSampleLogger bandwithLogger) {
this.bandwidthDebugMonitor = new BandwidthDebugMonitor(bandwithLogger);
}
@@ -293,8 +293,7 @@ index 42f44c7cb0bd55ddfacd18acb0e596e7a953870e..2040b9555c430420a8a8697cc131d42e
+ packet instanceof net.minecraft.network.protocol.game.ClientboundLevelParticlesPacket ||
+ 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;
+ packet instanceof net.minecraft.network.protocol.game.ClientboundBossEventPacket;
+ }
+ }
+
@@ -23751,7 +23751,7 @@ index 841a41485af62470d833aba578069b19a0bd1e8d..409c1134327bfcc338c3ac5e658a83cc
// CraftBukkit start
public boolean isDebugging() {
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
index ac7bc193f7ea63cbbba73df49f54a17ef7cdec40..d2db6e3a4af13984b0a790fb38e83c253914a973 100644
index f8c81d795b19e73d56d6e0196c75e441ab4c2bef..97a294d2f5c1ddf0af7ffec3e1425eb329c5751b 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 d1f235ebd835f58cf0c703c3a64d29825d98e183..080091efc19bc768bb9a660f366c42e831225505 100644
index 400b56657414177cd76a7b94c426dc7c886aa957..a275b17d0852d9d9bc850614713244e580ae81f1 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;
@@ -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 7eebb494e38b57e81b4f92f0a96d3a4c610d86df..065f4c810439dde464529b54ae300ecfcb1c2c31 100644
index 5d88b2790710a885957ffcffc02fb99c917123c5..7d1d4abfb04829d8c4722e326c6c6b8fb2ab91f4 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -1317,7 +1317,7 @@ public abstract class PlayerList {
@@ -1312,7 +1312,7 @@ public abstract class PlayerList {
public void setViewDistance(int viewDistance) {
this.viewDistance = viewDistance;
@@ -27988,7 +27988,7 @@ index 7eebb494e38b57e81b4f92f0a96d3a4c610d86df..065f4c810439dde464529b54ae300ecf
for (ServerLevel serverLevel : this.server.getAllLevels()) {
if (serverLevel != null) {
@@ -1328,7 +1328,7 @@ public abstract class PlayerList {
@@ -1323,7 +1323,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 9b3b770f6986dd132da78fdc3626d334166ec52a..b2b61203438bb1fad1ee807729781718d2467155 100644
index 994791a83ca6712db3e74ca9aba4bfcd95a0ec6d..1b54cf07616a10d93e9336dbd299ba5f09678a28 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;
@@ -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 12c83cb084563a4e3f7f357d8b600941544ef2b0..90e582ca30851857add5e2d830e9876667fd1807 100644
index 2e838877ce1da44c0dbe2c3275a76fc97e640fa3..2389fbf02ca593829f91185ffa6c790c0d6ebb12 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -563,7 +563,7 @@ public class ServerGamePacketListenerImpl
@@ -554,7 +554,7 @@ public class ServerGamePacketListenerImpl
return;
}
@@ -18,7 +18,7 @@ index 12c83cb084563a4e3f7f357d8b600941544ef2b0..90e582ca30851857add5e2d830e98766
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
@@ -573,6 +573,7 @@ public class ServerGamePacketListenerImpl
@@ -564,6 +564,7 @@ public class ServerGamePacketListenerImpl
}
rootVehicle.move(MoverType.PLAYER, new Vec3(d3, d4, d5));
@@ -26,7 +26,7 @@ index 12c83cb084563a4e3f7f357d8b600941544ef2b0..90e582ca30851857add5e2d830e98766
double verticalDelta = d4; // Paper - Decompile fix, was named d11 previously, is now gone in the source
d3 = d - rootVehicle.getX();
d4 = d1 - rootVehicle.getY();
@@ -584,14 +585,22 @@ public class ServerGamePacketListenerImpl
@@ -575,15 +576,20 @@ public class ServerGamePacketListenerImpl
d7 = d3 * d3 + d4 * d4 + d5 * d5;
boolean flag2 = false;
if (d7 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot
@@ -36,23 +36,21 @@ index 12c83cb084563a4e3f7f357d8b600941544ef2b0..90e582ca30851857add5e2d830e98766
}
rootVehicle.absMoveTo(d, d1, d2, f, f1);
this.player.absMoveTo(d, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
- boolean flag3 = serverLevel.noCollision(rootVehicle, rootVehicle.getBoundingBox().deflate(0.0625));
- if (flag && (flag2 || !flag3)) {
+ // Paper start - optimise out extra getCubes
// Paper start
- boolean teleportBack = flag && (flag2 || !flag3);
+ boolean teleportBack = flag2; // violating this is always a fail
+ if (!teleportBack) {
if (!teleportBack) {
+ // note: only call after setLocation, or else getBoundingBox is wrong
+ AABB newBox = rootVehicle.getBoundingBox();
+ if (didCollide || !oldBox.equals(newBox)) {
+ teleportBack = this.hasNewCollision(serverLevel, rootVehicle, oldBox, newBox);
+ } // else: no collision at all detected, why do we care?
+ }
+ if (teleportBack) { // Paper end - optimise out extra getCubes
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));
@@ -669,9 +678,32 @@ public class ServerGamePacketListenerImpl
+
// Move event - emulating from the vehicle
org.bukkit.entity.Entity rootVehicleBukkit = rootVehicle.getBukkitEntity();
Location from = new Location(rootVehicleBukkit.getWorld(), x, y, z, f, f1); // Copy from #absMoveTo on teleportBack
@@ -637,9 +643,32 @@ public class ServerGamePacketListenerImpl
}
private boolean noBlocksAround(Entity entity) {
@@ -88,7 +86,7 @@ index 12c83cb084563a4e3f7f357d8b600941544ef2b0..90e582ca30851857add5e2d830e98766
}
@Override
@@ -1371,7 +1403,7 @@ public class ServerGamePacketListenerImpl
@@ -1338,7 +1367,7 @@ public class ServerGamePacketListenerImpl
}
}
@@ -97,7 +95,7 @@ index 12c83cb084563a4e3f7f357d8b600941544ef2b0..90e582ca30851857add5e2d830e98766
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
@@ -1410,6 +1442,7 @@ public class ServerGamePacketListenerImpl
@@ -1377,6 +1406,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 +103,7 @@ index 12c83cb084563a4e3f7f357d8b600941544ef2b0..90e582ca30851857add5e2d830e98766
// Paper start - prevent position desync
if (this.awaitingPositionFromClient != null) {
return; // ... thanks Mojang for letting move calls teleport across dimensions.
@@ -1442,7 +1475,17 @@ public class ServerGamePacketListenerImpl
@@ -1409,7 +1439,17 @@ public class ServerGamePacketListenerImpl
}
// Paper start - Add fail move event
@@ -124,7 +122,7 @@ index 12c83cb084563a4e3f7f357d8b600941544ef2b0..90e582ca30851857add5e2d830e98766
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);
@@ -1578,7 +1621,7 @@ public class ServerGamePacketListenerImpl
@@ -1545,7 +1585,7 @@ public class ServerGamePacketListenerImpl
private boolean updateAwaitingTeleport() {
if (this.awaitingPositionFromClient != null) {
@@ -133,7 +131,7 @@ index 12c83cb084563a4e3f7f357d8b600941544ef2b0..90e582ca30851857add5e2d830e98766
this.awaitingTeleportTime = this.tickCount;
this.teleport(
this.awaitingPositionFromClient.x,
@@ -1597,6 +1640,33 @@ public class ServerGamePacketListenerImpl
@@ -1564,6 +1604,33 @@ public class ServerGamePacketListenerImpl
}
}
@@ -11,11 +11,11 @@ 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
index 2389fbf02ca593829f91185ffa6c790c0d6ebb12..ae2ca486db1e689862fc446dc1d051fb058a1187 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -659,7 +659,7 @@ public class ServerGamePacketListenerImpl
// CraftBukkit end
@@ -624,7 +624,7 @@ public class ServerGamePacketListenerImpl
}
this.player.serverLevel().getChunkSource().move(this.player);
- rootVehicle.recordMovementThroughBlocks(new Vec3(x, y, z), rootVehicle.position());
@@ -23,7 +23,7 @@ index 90e582ca30851857add5e2d830e9876667fd1807..c569cdfa4cba4f65892ffd4045c61183
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
@@ -1541,7 +1541,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());
@@ -1,36 +0,0 @@
--- 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();
@@ -1072,14 +1072,6 @@
@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
@@ -10,7 +10,7 @@
@Nullable
private Vec3 startingToFallPosition;
@Nullable
@@ -258,6 +_,20 @@
@@ -258,6 +_,13 @@
}
}
@@ -20,13 +20,6 @@
+ 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) {
@@ -70,7 +70,7 @@
private double firstGoodX;
private double firstGoodY;
private double firstGoodZ;
@@ -236,22 +_,41 @@
@@ -236,22 +_,39 @@
private int receivedMovePacketCount;
private int knownMovePacketCount;
private boolean receivedMovementThisTick;
@@ -98,7 +98,6 @@
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);
@@ -110,7 +109,6 @@
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
@@ -169,7 +167,7 @@
this.player.setLastClientInput(packet.input());
}
@@ -390,17 +_,29 @@
@@ -390,17 +_,22 @@
public void handleMoveVehicle(ServerboundMoveVehiclePacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
if (containsInvalidValues(packet.position().x(), packet.position().y(), packet.position().z(), packet.yRot(), packet.xRot())) {
@@ -184,13 +182,6 @@
+ // Paper end - Don't allow vehicle movement from players while teleporting
if (rootVehicle != this.player && rootVehicle.getControllingPassenger() == this.player && rootVehicle == this.lastVehicle) {
ServerLevel serverLevel = this.player.serverLevel();
+ // CraftBukkit - store current player position
+ double prevX = this.player.getX();
+ double prevY = this.player.getY();
+ double prevZ = this.player.getZ();
+ float prevYaw = this.player.getYRot();
+ float prevPitch = this.player.getXRot();
+ // CraftBukkit end
double x = rootVehicle.getX();
double y = rootVehicle.getY();
double z = rootVehicle.getZ();
@@ -278,7 +269,7 @@
d3 = d - rootVehicle.getX();
d4 = d1 - rootVehicle.getY();
if (d4 > -0.5 || d4 < 0.5) {
@@ -435,18 +_,71 @@
@@ -435,14 +_,44 @@
d5 = d2 - rootVehicle.getZ();
d7 = d3 * d3 + d4 * d4 + d5 * d5;
boolean flag2 = false;
@@ -289,68 +280,42 @@
}
rootVehicle.absMoveTo(d, d1, d2, f, f1);
+ this.player.absMoveTo(d, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
boolean flag3 = serverLevel.noCollision(rootVehicle, rootVehicle.getBoundingBox().deflate(0.0625));
if (flag && (flag2 || !flag3)) {
- if (flag && (flag2 || !flag3)) {
+ // Paper start
+ boolean teleportBack = flag && (flag2 || !flag3);
+ if (!teleportBack) {
+ // Move event - emulating from the vehicle
+ org.bukkit.entity.Entity rootVehicleBukkit = rootVehicle.getBukkitEntity();
+ Location from = new Location(rootVehicleBukkit.getWorld(), x, y, z, f, f1); // Copy from #absMoveTo on teleportBack
+ Location to = rootVehicleBukkit.getLocation();
+
+ // Prevent 40 event-calls for less than a single pixel of movement >.>
+ double delta = Math.pow(from.getX() - to.getX(), 2) + Math.pow(from.getY() - to.getY(), 2) + Math.pow(from.getZ() - to.getZ(), 2);
+ float deltaAngle = Math.abs(from.getYaw() - to.getYaw()) + Math.abs(from.getPitch() - to.getPitch());
+
+ if ((delta > 1f / 256 || deltaAngle > 10f) && !this.player.isImmobile()) {
+ Location oldLoc = to.clone();
+ io.papermc.paper.event.player.PlayerMoveVehicleEvent event = new io.papermc.paper.event.player.PlayerMoveVehicleEvent(this.player.getBukkitEntity(), rootVehicleBukkit, from, to);
+ if (event.callEvent()) {
+ if (event.getTo() != to || !oldLoc.equals(event.getTo())) { // If instance changed or value change, resync
+ Location newTo = event.getTo();
+ rootVehicle.absMoveTo(newTo.x(), newTo.y(), newTo.z(), newTo.getYaw(), newTo.getPitch()); // move the vehicle to the new location
+ this.send(ClientboundMoveVehiclePacket.fromEntity(rootVehicle)); // resync the vehicle
+ }
+ } else {
+ teleportBack = true;
+ // Reset the above tick -- as ignore checks that they are flying
+ // Most notable if they are in air.
+ this.aboveGroundTickCount = 0;
+ }
+ }
+ }
+ if (teleportBack) {
+ // Paper end
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));
return;
}
+
+ // CraftBukkit start - fire PlayerMoveEvent
+ org.bukkit.entity.Player player = this.getCraftPlayer();
+ if (!this.hasMoved) {
+ this.lastPosX = prevX;
+ this.lastPosY = prevY;
+ this.lastPosZ = prevZ;
+ this.lastYaw = prevYaw;
+ this.lastPitch = prevPitch;
+ this.hasMoved = true;
+ }
+ Location from = new Location(player.getWorld(), this.lastPosX, this.lastPosY, this.lastPosZ, this.lastYaw, this.lastPitch); // Get the Players previous Event location.
+ Location to = CraftLocation.toBukkit(packet.position(), player.getWorld(), packet.yRot(), packet.xRot());
+
+ // Prevent 40 event-calls for less than a single pixel of movement >.>
+ double delta = Math.pow(this.lastPosX - to.getX(), 2) + Math.pow(this.lastPosY - to.getY(), 2) + Math.pow(this.lastPosZ - to.getZ(), 2);
+ float deltaAngle = Math.abs(this.lastYaw - to.getYaw()) + Math.abs(this.lastPitch - to.getPitch());
+
+ if ((delta > 1f / 256 || deltaAngle > 10f) && !this.player.isImmobile()) {
+ this.lastPosX = to.getX();
+ this.lastPosY = to.getY();
+ this.lastPosZ = to.getZ();
+ this.lastYaw = to.getYaw();
+ this.lastPitch = to.getPitch();
+
+ Location oldTo = to.clone();
+ PlayerMoveEvent event = new PlayerMoveEvent(player, from, to);
+ this.cserver.getPluginManager().callEvent(event);
+
+ // If the event is cancelled we move the player back to their old location.
+ if (event.isCancelled()) {
+ this.teleport(from);
+ return;
+ }
+
+ // If a Plugin has changed the To destination then we teleport the Player
+ // there to avoid any 'Moved wrongly' or 'Moved too quickly' errors.
+ // We only do this if the Event was not cancelled.
+ if (!oldTo.equals(event.getTo()) && !event.isCancelled()) {
+ this.player.getBukkitEntity().teleport(event.getTo(), PlayerTeleportEvent.TeleportCause.PLUGIN);
+ return;
+ }
+
+ // Check to see if the Players Location has some how changed during the call of the event.
+ // This can happen due to a plugin teleporting the player instead of using .setTo()
+ if (!from.equals(this.getCraftPlayer().getLocation()) && this.justTeleported) {
+ this.justTeleported = false;
+ return;
+ }
+ }
+ // CraftBukkit end
this.player.serverLevel().getChunkSource().move(this.player);
rootVehicle.recordMovementThroughBlocks(new Vec3(x, y, z), rootVehicle.position());
@@ -455,7 +_,7 @@
rootVehicle.setOnGroundWithMovement(packet.onGround(), vec3);
rootVehicle.doCheckFallDamage(vec3.x, vec3.y, vec3.z, packet.onGround());
@@ -547,7 +512,7 @@
addBlockDataToItem(blockState, serverLevel, blockPos, cloneItemStack);
}
@@ -685,18 +_,29 @@
@@ -685,14 +_,24 @@
if (stack.isItemEnabled(this.player.level().enabledFeatures())) {
Inventory inventory = this.player.getInventory();
int i = inventory.findSlotMatchingItem(stack);
@@ -576,11 +541,6 @@
}
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();
@@ -1077,7 +1037,7 @@
if (this.player.hasClientLoaded()) {
BlockPos pos = packet.getPos();
this.player.resetLastActionTime();
@@ -1101,32 +_,95 @@
@@ -1101,14 +_,46 @@
case SWAP_ITEM_WITH_OFFHAND:
if (!this.player.isSpectator()) {
ItemStack itemInHand = this.player.getItemInHand(InteractionHand.OFF_HAND);
@@ -1103,7 +1063,6 @@
+ }
+ // CraftBukkit end
this.player.stopUsingItem();
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdatesPublic(); // Paper - Force update attributes.
}
return;
@@ -1125,27 +1084,20 @@
+ }
+ // CraftBukkit end
this.player.drop(false);
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdatesPublic(); // Paper - Force update attributes.
}
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.
}
@@ -1120,13 +_,39 @@
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 || !this.player.canInteractWithBlock(pos, 1.0)) {
+ if (this.player.level().getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4) == null) {
+ this.player.connection.ackBlockChangesUpTo(packet.getSequence());
+ return;
+ }
@@ -1172,7 +1124,6 @@
+ }
+ }
+ // 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");
@@ -1243,14 +1194,6 @@
} 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) {
@@ -1376,7 +1319,7 @@
throw new IllegalArgumentException("Expected packet sequence nr >= 0");
} else {
this.ackBlockChangesUpTo = Math.max(sequence, this.ackBlockChangesUpTo);
@@ -1275,20 +_,38 @@
@@ -1275,7 +_,17 @@
@Override
public void handleSetCarriedItem(ServerboundSetCarriedItemPacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
@@ -1394,10 +1337,8 @@
if (this.player.getInventory().selected != packet.getSlot() && this.player.getUsedItemHand() == InteractionHand.MAIN_HAND) {
this.player.stopUsingItem();
}
this.player.getInventory().selected = packet.getSlot();
@@ -1284,11 +_,18 @@
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
@@ -1980,7 +1921,7 @@
ServerGamePacketListenerImpl.LOGGER
.warn("Player {} tried to attack an invalid entity", ServerGamePacketListenerImpl.this.player.getName().getString());
}
@@ -1656,6 +_,27 @@
@@ -1656,6 +_,26 @@
);
}
}
@@ -2004,7 +1945,6 @@
+ });
+ }
+ // Paper end - PlayerUseUnknownEntityEvent
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdatesPublic(); // Paper - Force update attributes.
}
}
@@ -2406,14 +2346,6 @@
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
@@ -2483,15 +2415,7 @@
this.player.resetLastActionTime();
if (this.player.containerMenu.containerId == packet.containerId() && !this.player.isSpectator()) {
if (!this.player.containerMenu.stillValid(this.player)) {
@@ -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 @@
@@ -1792,6 +_,43 @@
boolean flag1 = packet.slotNum() >= 1 && packet.slotNum() <= 45;
boolean flag2 = itemStack.isEmpty() || itemStack.getCount() <= itemStack.getMaxStackSize();
@@ -2535,11 +2459,6 @@
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
@@ -2646,7 +2565,7 @@
this.signedMessageDecoder = chatSession.createMessageDecoder(this.player.getUUID());
this.chatMessageChain
.append(
@@ -1919,19 +_,22 @@
@@ -1919,15 +_,17 @@
this.server
.getPlayerList()
.broadcastAll(
@@ -2668,11 +2587,6 @@
@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);
@@ -931,18 +931,13 @@
}
player.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.LEVEL_CHUNKS_LOAD_START, 0.0F));
@@ -671,8 +_,21 @@
@@ -671,8 +_,16 @@
public void sendAllPlayerInfo(ServerPlayer player) {
player.inventoryMenu.sendAllDataToRemote();
- player.resetSentInfo();
+ // entityplayer.resetSentInfo();
+ // 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.getBukkitEntity().updateScaledHealth(); // CraftBukkit - Update scaled health on respawn and worldchange
+ player.refreshEntityData(player); // CraftBukkit - SPIGOT-7218: sync metadata
player.connection.send(new ClientboundSetHeldSlotPacket(player.getInventory().selected));
+ // CraftBukkit start - from GameRules
@@ -192,7 +192,7 @@
this.entityData = builder.build();
this.setPos(0.0, 0.0, 0.0);
this.eyeHeight = this.dimensions.eyeHeight();
+ 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
+ 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
}
public boolean isColliding(BlockPos pos, BlockState state) {
@@ -326,16 +326,6 @@
}
}
}
@@ -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
@@ -57,6 +57,14 @@
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);
@@ -72,41 +72,6 @@
}
}
}
@@ -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();
}
@@ -1,15 +1,9 @@
--- a/net/minecraft/world/inventory/ContainerSynchronizer.java
+++ b/net/minecraft/world/inventory/ContainerSynchronizer.java
@@ -11,4 +_,12 @@
@@ -11,4 +_,6 @@
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
}
@@ -1,6 +1,6 @@
--- a/net/minecraft/world/item/EnderpearlItem.java
+++ b/net/minecraft/world/item/EnderpearlItem.java
@@ -21,22 +_,42 @@
@@ -21,22 +_,38 @@
@Override
public InteractionResult use(Level level, Player player, InteractionHand hand) {
ItemStack itemInHand = player.getItemInHand(hand);
@@ -39,11 +39,7 @@
+ );
+ player.awardStat(Stats.ITEM_USED.get(this));
+ } else {
+ 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
+ // Paper end - PlayerLaunchProjectileEvent
+ player.containerMenu.sendAllDataToRemote();
+ return InteractionResult.FAIL;
+ }
@@ -15,12 +15,3 @@
ServerLevel serverLevel = (ServerLevel)attacker.level();
attacker.setDeltaMovement(attacker.getDeltaMovement().with(Direction.Axis.Y, 0.01F));
if (attacker instanceof ServerPlayer serverPlayer) {
@@ -139,7 +_,7 @@
double knockbackPower = getKnockbackPower(attacker, livingEntity, vec3);
Vec3 vec31 = vec3.normalize().scale(knockbackPower);
if (knockbackPower > 0.0) {
- livingEntity.push(vec31.x, 0.7F, vec31.z);
+ livingEntity.push(vec31.x, 0.7F, vec31.z, attacker); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent
if (livingEntity instanceof ServerPlayer serverPlayer) {
serverPlayer.connection.send(new ClientboundSetEntityMotionPacket(serverPlayer));
}
@@ -1,11 +0,0 @@
--- a/net/minecraft/world/item/MobBucketItem.java
+++ b/net/minecraft/world/item/MobBucketItem.java
@@ -58,7 +_,7 @@
}
if (mob != null) {
- serverLevel.addFreshEntityWithPassengers(mob);
+ serverLevel.addFreshEntityWithPassengers(mob, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BUCKET); // Paper - Add SpawnReason
mob.playAmbientSound();
}
}
@@ -34,7 +34,7 @@
f = Direction.WEST.toYRot();
set = Relative.union(Relative.DELTA, Set.of(Relative.X_ROT));
if (entity instanceof ServerPlayer) {
@@ -88,15 +_,23 @@
@@ -88,15 +_,21 @@
f = 0.0F;
set = Relative.union(Relative.DELTA, Relative.ROTATION);
if (entity instanceof ServerPlayer serverPlayer) {
@@ -49,15 +49,13 @@
- level1, bottomCenter, Vec3.ZERO, f, 0.0F, set, TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET)
- );
+ // CraftBukkit start
+ set.removeAll(Relative.ROTATION); // remove relative rotation flags to simplify event mutation
+ float absoluteYaw = flag ? f : entity.getYRot() + f;
+ org.bukkit.craftbukkit.event.CraftPortalEvent event = entity.callPortalEvent(entity, org.bukkit.craftbukkit.util.CraftLocation.toBukkit(bottomCenter, level1.getWorld(), absoluteYaw, entity.getXRot()), org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_PORTAL, 0, 0);
+ org.bukkit.craftbukkit.event.CraftPortalEvent event = entity.callPortalEvent(entity, org.bukkit.craftbukkit.util.CraftLocation.toBukkit(bottomCenter, level1.getWorld(), f, entity.getXRot()), org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_PORTAL, 0, 0);
+ if (event == null) {
+ return null;
+ }
+ org.bukkit.Location to = event.getTo();
+
+ return new TeleportTransition(((org.bukkit.craftbukkit.CraftWorld) to.getWorld()).getHandle(), org.bukkit.craftbukkit.util.CraftLocation.toVec3D(to), Vec3.ZERO, to.getYaw(), to.getPitch(), set, TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET), org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_PORTAL);
+ return new TeleportTransition(((org.bukkit.craftbukkit.CraftWorld) to.getWorld()).getHandle(), org.bukkit.craftbukkit.util.CraftLocation.toVec3D(to), entity.getDeltaMovement(), to.getYaw(), to.getPitch(), set, TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET), org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_PORTAL);
+ // CraftBukkit end
}
}
@@ -30,6 +30,6 @@ public class CraftGameEventTag extends CraftTag<net.minecraft.world.level.gameev
@Override
public @NotNull Set<GameEvent> getValues() {
return getHandle().stream().map((nms) -> Objects.requireNonNull(GameEvent.getByKey(CraftNamespacedKey.fromMinecraft(BuiltInRegistries.GAME_EVENT.getKey(nms.value()))), () -> nms + " is not a recognized game event")).collect(Collectors.toUnmodifiableSet());
return getHandle().stream().map((nms) -> Objects.requireNonNull(GameEvent.getByKey(CraftNamespacedKey.fromMinecraft(BuiltInRegistries.GAME_EVENT.getKey(nms.value()))), nms + " is not a recognized game event")).collect(Collectors.toUnmodifiableSet());
}
}
@@ -184,10 +184,6 @@ public class GlobalConfiguration extends ConfigurationPart {
public boolean skipVanillaDamageTickWhenShieldBlocked = false;
@Comment("This setting controls what compression format is used for region files.")
public CompressionFormat compressionFormat = CompressionFormat.ZLIB;
@Comment("This setting controls if equipment should be updated when handling certain player actions.")
public boolean updateEquipmentOnPlayerActions = true;
@Comment("Only checks an item's amount and type instead of its full data during inventory desync checks.")
public boolean simplifyRemoteItemMatching = false;
public enum CompressionFormat {
GZIP,
@@ -15,18 +15,10 @@ public record DataComponentAdapter<NMS, API>(
) {
static final Function<Void, Unit> API_TO_UNIT_CONVERTER = $ -> Unit.INSTANCE;
static final Function API_TO_UNIMPLEMENTED_CONVERTER = $ -> {
throw new UnsupportedOperationException("Cannot convert an API value to an unimplemented type");
};
public boolean isValued() {
return this.apiToVanilla != API_TO_UNIT_CONVERTER;
}
public boolean isUnimplemented() {
return this.apiToVanilla == API_TO_UNIMPLEMENTED_CONVERTER;
}
public NMS toVanilla(final API value) {
final NMS nms = this.apiToVanilla.apply(value);
if (this.codecValidation) {
@@ -63,10 +63,6 @@ public final class DataComponentAdapters {
throw new UnsupportedOperationException("Cannot convert the Unit type to an API value");
};
static final Function UNIMPLEMENTED_TO_API_CONVERTER = $ -> {
throw new UnsupportedOperationException("Cannot convert the an unimplemented type to an API value");
};
static final Map<ResourceKey<DataComponentType<?>>, DataComponentAdapter<?, ?>> ADAPTERS = new HashMap<>();
public static void bootstrap() {
@@ -140,9 +136,10 @@ public final class DataComponentAdapters {
// register(DataComponents.LOCK, PaperLockCode::new);
register(DataComponents.CONTAINER_LOOT, PaperSeededContainerLoot::new);
// TODO: REMOVE THIS... we want to build the PR... so lets just make things UNTYPED!
for (final Map.Entry<ResourceKey<DataComponentType<?>>, DataComponentType<?>> componentType : BuiltInRegistries.DATA_COMPONENT_TYPE.entrySet()) {
if (!ADAPTERS.containsKey(componentType.getKey())) {
registerUnimplemented(componentType.getValue());
registerUntyped((DataComponentType<Unit>) componentType.getValue());
}
}
}
@@ -155,10 +152,6 @@ public final class DataComponentAdapters {
registerInternal(type, Function.identity(), Function.identity(), true);
}
public static <NMS> void registerUnimplemented(final DataComponentType<NMS> type) {
registerInternal(type, UNIMPLEMENTED_TO_API_CONVERTER, DataComponentAdapter.API_TO_UNIMPLEMENTED_CONVERTER, false);
}
private static <NMS, API extends Handleable<NMS>> void register(final DataComponentType<NMS> type, final Function<NMS, API> vanillaToApi) {
registerInternal(type, vanillaToApi, Handleable::getHandle, false);
}
@@ -77,9 +77,7 @@ public abstract class PaperDataComponentType<T, NMS> implements DataComponentTyp
if (adapter == null) {
throw new IllegalArgumentException("No adapter found for " + key);
}
if (adapter.isUnimplemented()) {
return new Unimplemented<>(key, type, adapter);
} else if (adapter.isValued()) {
if (adapter.isValued()) {
return new ValuedImpl<>(key, type, adapter);
} else {
return new NonValuedImpl<>(key, type, adapter);
@@ -107,15 +105,4 @@ public abstract class PaperDataComponentType<T, NMS> implements DataComponentTyp
super(key, type, adapter);
}
}
public static final class Unimplemented<T, NMS> extends PaperDataComponentType<T, NMS> {
public Unimplemented(
final NamespacedKey key,
final net.minecraft.core.component.DataComponentType<NMS> type,
final DataComponentAdapter<NMS, T> adapter
) {
super(key, type, adapter);
}
}
}
@@ -40,7 +40,7 @@ public record PaperCustomModelData(
@Override
public List<Color> colors() {
return MCUtil.transformUnmodifiable(this.impl.colors(), color -> Color.fromRGB(color & 0x00FFFFFF)); // skip alpha channel
return MCUtil.transformUnmodifiable(this.impl.colors(), Color::fromRGB);
}
static final class BuilderImpl implements CustomModelData.Builder {
@@ -153,12 +153,12 @@ public final class PaperRegistries {
@SuppressWarnings("unchecked")
public static <M, T> RegistryKey<T> registryFromNms(final ResourceKey<? extends Registry<M>> registryResourceKey) {
return (RegistryKey<T>) Objects.requireNonNull(BY_RESOURCE_KEY.get(registryResourceKey), () -> registryResourceKey + " doesn't have an api RegistryKey").apiKey();
return (RegistryKey<T>) Objects.requireNonNull(BY_RESOURCE_KEY.get(registryResourceKey), registryResourceKey + " doesn't have an api RegistryKey").apiKey();
}
@SuppressWarnings("unchecked")
public static <M, T> ResourceKey<? extends Registry<M>> registryToNms(final RegistryKey<T> registryKey) {
return (ResourceKey<? extends Registry<M>>) Objects.requireNonNull(BY_REGISTRY_KEY.get(registryKey), () -> registryKey + " doesn't have an mc registry ResourceKey").mcKey();
return (ResourceKey<? extends Registry<M>>) Objects.requireNonNull(BY_REGISTRY_KEY.get(registryKey), registryKey + " doesn't have an mc registry ResourceKey").mcKey();
}
public static <M, T> TypedKey<T> fromNms(final ResourceKey<M> resourceKey) {
@@ -60,7 +60,7 @@ public sealed interface RegistryEntryMeta<M, A extends Keyed> permits RegistryEn
) implements ServerSide<M, A> { // TODO remove Keyed
public Craft {
Preconditions.checkArgument(!classToPreload.getPackageName().startsWith("net.minecraft"), "%s should not be in the net.minecraft package as the class-to-preload", classToPreload);
Preconditions.checkArgument(!classToPreload.getPackageName().startsWith("net.minecraft"), classToPreload + " should not be in the net.minecraft package as the class-to-preload");
}
}
@@ -34,7 +34,7 @@ public final class RegistryEventMap {
@SuppressWarnings("unchecked")
public <T, E extends LifecycleEvent> LifecycleEventType<BootstrapContext, E, ?> getEventType(final RegistryKey<T> registryKey) {
return (LifecycleEventType<BootstrapContext, E, ?>) Objects.requireNonNull(this.eventTypes.get(registryKey), () -> "No hook for " + registryKey);
return (LifecycleEventType<BootstrapContext, E, ?>) Objects.requireNonNull(this.eventTypes.get(registryKey), "No hook for " + registryKey);
}
public boolean hasHandlers(final RegistryKey<?> registryKey) {
@@ -1725,7 +1725,6 @@ public final class CraftServer implements Server {
if (recipe.isPresent()) {
RecipeHolder<CraftingRecipe> recipeCrafting = recipe.get();
inventoryCrafting.setCurrentRecipe(recipeCrafting);
if (craftResult.setRecipeUsed(craftPlayer.getHandle(), recipeCrafting)) {
itemstack = recipeCrafting.value().assemble(inventoryCrafting.asCraftInput(), craftWorld.getHandle().registryAccess());
}
@@ -72,7 +72,7 @@ final class CraftServerTickManager implements ServerTickManager {
@Override
public boolean requestGameToSprint(final int ticks) {
return this.manager.requestGameToSprint(ticks, true);
return this.manager.requestGameToSprint(ticks);
}
@Override
@@ -8,7 +8,6 @@ import com.mojang.authlib.GameProfile;
import com.mojang.datafixers.util.Pair;
import io.netty.buffer.Unpooled;
import io.papermc.paper.FeatureHooks;
import io.papermc.paper.configuration.GlobalConfiguration;
import io.papermc.paper.entity.LookAnchor;
import io.papermc.paper.entity.PaperPlayerGiveResult;
import io.papermc.paper.entity.PlayerGiveResult;
@@ -226,7 +225,6 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
private BorderChangeListener clientWorldBorderListener = this.createWorldBorderListener();
public org.bukkit.event.player.PlayerResourcePackStatusEvent.Status resourcePackStatus; // Paper - more resource pack API
private static final boolean DISABLE_CHANNEL_LIMIT = System.getProperty("paper.disableChannelLimit") != null; // Paper - add a flag to disable the channel limit
private boolean simplifyContainerDesyncCheck = GlobalConfiguration.get().unsupportedSettings.simplifyRemoteItemMatching;
private long lastSaveTime; // Paper - getLastPlayed replacement API
public CraftPlayer(CraftServer server, ServerPlayer entity) {
@@ -2829,9 +2827,14 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
}
public void updateScaledHealth(boolean sendHealth) {
AttributeMap attributemapserver = this.getHandle().getAttributes();
Collection<AttributeInstance> set = attributemapserver.getSyncableAttributes();
this.injectScaledMaxHealth(set, true);
// SPIGOT-3813: Attributes before health
if (this.getHandle().connection != null) {
this.getHandle().connection.send(new ClientboundUpdateAttributesPacket(this.getHandle().getId(), Set.of(this.getScaledMaxHealth())));
this.getHandle().connection.send(new ClientboundUpdateAttributesPacket(this.getHandle().getId(), set));
if (sendHealth) {
this.sendHealthUpdate();
}
@@ -2871,11 +2874,8 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
break;
}
}
collection.add(getScaledMaxHealth());
}
public AttributeInstance getScaledMaxHealth() {
AttributeInstance dummy = new AttributeInstance(Attributes.MAX_HEALTH, (attribute) -> { });
// Spigot start
double healthMod = this.scaledHealth ? this.healthScale : this.getMaxHealth();
if ( healthMod >= Float.MAX_VALUE || healthMod <= 0 )
{
@@ -2883,7 +2883,8 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
this.getServer().getLogger().warning( this.getName() + " tried to crash the server with a large health attribute" );
}
dummy.setBaseValue(healthMod);
return dummy;
// Spigot end
collection.add(dummy);
}
@Override
@@ -3598,30 +3599,4 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
return forwardMovement == backwardMovement ? 0 : forwardMovement ? 1 : -1;
}
@Override
public int getDeathScreenScore() {
return getHandle().getScore();
}
@Override
public void setDeathScreenScore(final int score) {
getHandle().setScore(score);
}
/**
* Returns whether container desync checks should skip the full item comparison of remote carried and changed slots
* and should instead only check their type and amount.
* <p>
* This is useful if the client is not able to produce the same item stack (or as of 1.21.5, its data hashes) as the server.
*
* @return whether to simplify container desync checks
*/
public boolean simplifyContainerDesyncCheck() {
return simplifyContainerDesyncCheck;
}
public void setSimplifyContainerDesyncCheck(final boolean simplifyContainerDesyncCheck) {
this.simplifyContainerDesyncCheck = simplifyContainerDesyncCheck;
}
}
@@ -349,6 +349,7 @@ public final class CraftItemFactory implements ItemFactory {
) {
Preconditions.checkArgument(itemStack != null, "Argument 'itemStack' must not be null");
Preconditions.checkArgument(!itemStack.isEmpty(), "Argument 'itemStack' cannot be empty");
Preconditions.checkArgument(levels > 0 && levels <= 30, "Argument 'levels' must be in range [1, 30] (attempted " + levels + ")");
Preconditions.checkArgument(random != null, "Argument 'random' must not be null");
final net.minecraft.world.item.ItemStack internalStack = CraftItemStack.asNMSCopy(itemStack);
if (internalStack.isEnchanted()) {
@@ -1,5 +1,6 @@
package org.bukkit.craftbukkit.inventory.components;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
@@ -56,7 +57,7 @@ public final class CraftCustomModelDataComponent implements CustomModelDataCompo
@Override
public void setFloats(List<Float> floats) {
this.handle = new CustomModelData(List.copyOf(floats), this.handle.flags(), this.handle.strings(), this.handle.colors());
this.handle = new CustomModelData(new ArrayList<>(floats), this.handle.flags(), this.handle.strings(), this.handle.colors());
}
@Override
@@ -66,7 +67,7 @@ public final class CraftCustomModelDataComponent implements CustomModelDataCompo
@Override
public void setFlags(List<Boolean> flags) {
this.handle = new CustomModelData(this.handle.floats(), List.copyOf(flags), this.handle.strings(), this.handle.colors());
this.handle = new CustomModelData(this.handle.floats(), List.copyOf(flags), this.handle.strings(), this.handle.colors()); // Paper
}
@Override
@@ -76,17 +77,17 @@ public final class CraftCustomModelDataComponent implements CustomModelDataCompo
@Override
public void setStrings(List<String> strings) {
this.handle = new CustomModelData(this.handle.floats(), this.handle.flags(), List.copyOf(strings), this.handle.colors());
this.handle = new CustomModelData(this.handle.floats(), this.handle.flags(), List.copyOf(strings), this.handle.colors()); // Paper
}
@Override
public List<Color> getColors() {
return this.getHandle().colors().stream().map(color -> Color.fromRGB(color & 0x00FFFFFF)).toList(); // skip alpha channel
return this.getHandle().colors().stream().map(Color::fromRGB).toList();
}
@Override
public void setColors(List<Color> colors) {
this.handle = new CustomModelData(this.handle.floats(), this.handle.flags(), this.handle.strings(), colors.stream().map(Color::asRGB).toList());
this.handle = new CustomModelData(this.handle.floats(), this.handle.flags(), this.handle.strings(), colors.stream().map(Color::asRGB).toList()); // Paper
}
@Override
@@ -94,11 +95,14 @@ public final class CraftCustomModelDataComponent implements CustomModelDataCompo
if (this == obj) {
return true;
}
if (obj == null || this.getClass() != obj.getClass()) {
if (obj == null) {
return false;
}
if (this.getClass() != obj.getClass()) {
return false;
}
final CraftCustomModelDataComponent other = (CraftCustomModelDataComponent) obj;
return this.handle.equals(other.handle);
return Objects.equals(this.handle, other.handle);
}
@Override
@@ -110,6 +114,6 @@ public final class CraftCustomModelDataComponent implements CustomModelDataCompo
@Override
public String toString() {
return "CraftCustomModelDataComponent{component=" + this.handle + '}';
return "CraftCustomModelDataComponent{" + "handle=" + this.handle + '}';
}
}