1000
This commit is contained in:
parent
35e01d7a80
commit
7616ebccd8
11 changed files with 115 additions and 115 deletions
|
@ -0,0 +1,64 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 6 May 2020 05:00:57 -0400
|
||||
Subject: [PATCH] Handle Oversized block entities in chunks
|
||||
|
||||
Splits out Extra Packets if too many TE's are encountered to prevent
|
||||
creating too large of a packet to sed.
|
||||
|
||||
Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
index 1e75cd33c32f0e2923681da64b9b73b279933c1b..0a8d07bf68b0ceabd13c70196d357fce79dcc2c3 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
@@ -27,6 +27,14 @@ public class ClientboundLevelChunkPacketData {
|
||||
private final CompoundTag heightmaps;
|
||||
private final byte[] buffer;
|
||||
private final List<ClientboundLevelChunkPacketData.BlockEntityInfo> blockEntitiesData;
|
||||
+ // Paper start - Handle oversized block entities in chunks
|
||||
+ private final java.util.List<net.minecraft.network.protocol.Packet<?>> extraPackets = new java.util.ArrayList<>();
|
||||
+ private static final int TE_LIMIT = Integer.getInteger("Paper.excessiveTELimit", 750);
|
||||
+
|
||||
+ public List<net.minecraft.network.protocol.Packet<?>> getExtraPackets() {
|
||||
+ return this.extraPackets;
|
||||
+ }
|
||||
+ // Paper end - Handle oversized block entities in chunks
|
||||
|
||||
// Paper start - Anti-Xray - Add chunk packet info
|
||||
@Deprecated @io.papermc.paper.annotation.DoNotUse public ClientboundLevelChunkPacketData(LevelChunk chunk) { this(chunk, null); }
|
||||
@@ -50,8 +58,18 @@ public class ClientboundLevelChunkPacketData {
|
||||
extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), chunk, chunkPacketInfo);
|
||||
// Paper end
|
||||
this.blockEntitiesData = Lists.newArrayList();
|
||||
+ int totalTileEntities = 0; // Paper - Handle oversized block entities in chunks
|
||||
|
||||
for (Entry<BlockPos, BlockEntity> entry2 : chunk.getBlockEntities().entrySet()) {
|
||||
+ // Paper start - Handle oversized block entities in chunks
|
||||
+ if (++totalTileEntities > TE_LIMIT) {
|
||||
+ var packet = entry2.getValue().getUpdatePacket();
|
||||
+ if (packet != null) {
|
||||
+ this.extraPackets.add(packet);
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Handle oversized block entities in chunks
|
||||
this.blockEntitiesData.add(ClientboundLevelChunkPacketData.BlockEntityInfo.create(entry2.getValue()));
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
||||
index 8ead66c134688b11dca15f6509147e726f182e6a..cfcac0fdc130120cb1f8d97c6353d93db7ddf81b 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
||||
@@ -83,4 +83,11 @@ public class ClientboundLevelChunkWithLightPacket implements Packet<ClientGamePa
|
||||
public ClientboundLightUpdatePacketData getLightData() {
|
||||
return this.lightData;
|
||||
}
|
||||
+
|
||||
+ // Paper start - Handle oversized block entities in chunks
|
||||
+ @Override
|
||||
+ public java.util.List<Packet<?>> getExtraPackets() {
|
||||
+ return this.chunkData.getExtraPackets();
|
||||
+ }
|
||||
+ // Paper end - Handle oversized block entities in chunks
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 2 Aug 2021 10:10:40 +0200
|
||||
Subject: [PATCH] Check distance in entity interactions
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
|
||||
index 60e523f4de1cbafc2c58a5d568fe3989b7b07c34..dd2037fe9389765f79330036ec7fa3c5e7c7327a 100644
|
||||
--- a/src/main/java/net/minecraft/Util.java
|
||||
+++ b/src/main/java/net/minecraft/Util.java
|
||||
@@ -128,6 +128,7 @@ public class Util {
|
||||
.filter(fileSystemProvider -> fileSystemProvider.getScheme().equalsIgnoreCase("jar"))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("No jar file system provider found"));
|
||||
+ public static final double COLLISION_EPSILON = 1.0E-7; // Paper - Check distance in entity interactions
|
||||
private static Consumer<String> thePauser = message -> {
|
||||
};
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 6195b207159c638e98a33c3142ed6b0720c8e14d..f12c59d3bb15f482969cc9d0d2aff0718972675b 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -1469,7 +1469,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
if (!source.is(DamageTypeTags.IS_PROJECTILE)) {
|
||||
Entity entity = source.getDirectEntity();
|
||||
|
||||
- if (entity instanceof LivingEntity) {
|
||||
+ if (entity instanceof LivingEntity && entity.distanceToSqr(this) <= (200.0D * 200.0D)) { // Paper - Check distance in entity interactions
|
||||
LivingEntity entityliving = (LivingEntity) entity;
|
||||
|
||||
this.blockUsingShield(entityliving);
|
||||
@@ -1593,6 +1593,14 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
d0 = source.getSourcePosition().x() - this.getX();
|
||||
d1 = source.getSourcePosition().z() - this.getZ();
|
||||
}
|
||||
+ // Paper start - Check distance in entity interactions; see for loop in knockback method
|
||||
+ if (Math.abs(d0) > 200) {
|
||||
+ d0 = Math.random() - Math.random();
|
||||
+ }
|
||||
+ if (Math.abs(d1) > 200) {
|
||||
+ d1 = Math.random() - Math.random();
|
||||
+ }
|
||||
+ // Paper end - Check distance in entity interactions
|
||||
|
||||
this.knockback(0.4000000059604645D, d0, d1, entity1, entity1 == null ? io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.DAMAGE : io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events
|
||||
if (!flag) {
|
||||
@@ -2428,7 +2436,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
this.hurtCurrentlyUsedShield((float) -event.getDamage(DamageModifier.BLOCKING));
|
||||
Entity entity = damagesource.getDirectEntity();
|
||||
|
||||
- if (!damagesource.is(DamageTypeTags.IS_PROJECTILE) && entity instanceof LivingEntity) { // Paper - Fix shield disable inconsistency
|
||||
+ if (!damagesource.is(DamageTypeTags.IS_PROJECTILE) && entity instanceof LivingEntity && entity.distanceToSqr(this) <= (200.0D * 200.0D)) { // Paper - Fix shield disable inconsistency & Check distance in entity interactions
|
||||
this.blockUsingShield((LivingEntity) entity);
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractBoat.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractBoat.java
|
||||
index 57ea01469ddd180a0c2121cce2807bcccf93bf48..b8d231225a9f5c2e6af1727d15c8819adbc13cba 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractBoat.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractBoat.java
|
||||
@@ -674,7 +674,7 @@ public abstract class AbstractBoat extends VehicleEntity implements Leashable {
|
||||
double d2 = (double) (this.getWaterLevelAbove() - this.getBbHeight()) + 0.101D;
|
||||
|
||||
if (this.level().noCollision(this, this.getBoundingBox().move(0.0D, d2 - this.getY(), 0.0D))) {
|
||||
- this.setPos(this.getX(), d2, this.getZ());
|
||||
+ this.move(MoverType.SELF, new Vec3(0.0D, d2 - this.getY(), 0.0D)); // Paper - Check distance in entity interactions // TODO Still needed??
|
||||
this.setDeltaMovement(this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D));
|
||||
this.lastYd = 0.0D;
|
||||
}
|
19
patches/server/0992-Configurable-Sand-Duping.patch
Normal file
19
patches/server/0992-Configurable-Sand-Duping.patch
Normal file
|
@ -0,0 +1,19 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
|
||||
Date: Sat, 15 Jun 2024 22:01:39 -0400
|
||||
Subject: [PATCH] Configurable Sand Duping
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
index c228ca3ee911d25932932564b73e182840963e7d..d405ec0a6bb1e813cdf42d8e12db143df2d173b4 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
@@ -435,7 +435,7 @@ public class FallingBlockEntity extends Entity {
|
||||
boolean flag = (resourcekey1 == Level.END || resourcekey == Level.END) && resourcekey1 != resourcekey;
|
||||
Entity entity = super.teleport(teleportTarget);
|
||||
|
||||
- this.forceTickAfterTeleportToDuplicate = entity != null && flag;
|
||||
+ this.forceTickAfterTeleportToDuplicate = entity != null && flag && io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowUnsafeEndPortalTeleportation; // Paper
|
||||
return entity;
|
||||
}
|
||||
}
|
272
patches/server/0993-Properly-resend-entities.patch
Normal file
272
patches/server/0993-Properly-resend-entities.patch
Normal file
|
@ -0,0 +1,272 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
|
||||
Date: Wed, 7 Dec 2022 17:25:19 -0500
|
||||
Subject: [PATCH] Properly resend entities
|
||||
|
||||
This resolves some issues which caused entities to not be resent correctly.
|
||||
Entities that are interacted with need to be resent to the client, so we resend all the entity
|
||||
data to the player whilst making sure not to clear dirty entries from the tracker. This makes
|
||||
sure that values will be correctly updated to other players.
|
||||
|
||||
This also adds utilities to aid in further preventing entity desyncs.
|
||||
|
||||
This also also fixes the bug causing cancelling PlayerInteractEvent to cause items to continue
|
||||
to be used despite being cancelled on the server.
|
||||
|
||||
For example, items being consumed but never finishing, shields being put up, etc.
|
||||
The underlying issue of this is that the client modifies their synced data values,
|
||||
and so we have to (forcibly) resend them in order for the client to reset their using item state.
|
||||
|
||||
See: https://github.com/PaperMC/Paper/pull/1896
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.server.level.ChunkMap$TrackedEntity serverEntity
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java b/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
|
||||
index 02bf2705ca1c99023a83a22d92e1962181102297..0f99733660f91280e4c6262cf75b3c9cae86f65a 100644
|
||||
--- a/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
|
||||
+++ b/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
|
||||
@@ -50,7 +50,7 @@ public class SynchedEntityData {
|
||||
}
|
||||
}
|
||||
|
||||
- private <T> SynchedEntityData.DataItem<T> getItem(EntityDataAccessor<T> key) {
|
||||
+ public <T> SynchedEntityData.DataItem<T> getItem(EntityDataAccessor<T> key) { // Paper - public
|
||||
return (SynchedEntityData.DataItem<T>) this.itemsById[key.id()]; // CraftBukkit - decompile error
|
||||
}
|
||||
|
||||
@@ -151,6 +151,20 @@ public class SynchedEntityData {
|
||||
}
|
||||
}
|
||||
|
||||
+ // 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<>();
|
||||
+ for (final DataItem<?> dataItem : this.itemsById) {
|
||||
+ list.add(dataItem.value());
|
||||
+ }
|
||||
+
|
||||
+ return list;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public static class DataItem<T> {
|
||||
|
||||
final EntityDataAccessor<T> accessor;
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
index f2dd272a01b4e946a6746865d55ebc9861f8361b..5d189ba60d40f5c42b2dacc339594ed067418e95 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
@@ -567,6 +567,7 @@ public class ServerPlayerGameMode {
|
||||
}
|
||||
// Paper end - extend Player Interact cancellation
|
||||
player.getBukkitEntity().updateInventory(); // SPIGOT-2867
|
||||
+ this.player.resyncUsingItem(this.player); // Paper - Properly cancel usable items
|
||||
return (event.useItemInHand() != Event.Result.ALLOW) ? InteractionResult.SUCCESS : InteractionResult.PASS;
|
||||
} else if (this.gameModeForPlayer == GameType.SPECTATOR) {
|
||||
MenuProvider itileinventory = iblockdata.getMenuProvider(world, blockposition);
|
||||
@@ -618,6 +619,11 @@ public class ServerPlayerGameMode {
|
||||
|
||||
return enuminteractionresult;
|
||||
} else {
|
||||
+ // Paper start - Properly cancel usable items; Cancel only if cancelled + if the interact result is different from default response
|
||||
+ if (this.interactResult && this.interactResult != cancelledItem) {
|
||||
+ this.player.resyncUsingItem(this.player);
|
||||
+ }
|
||||
+ // Paper end - Properly cancel usable items
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 46f4d7a05d4febd1f8fd3cc2cae635a9e3da0e9e..14a8e05420ae4ca2f1d9028e19379d162a3e6971 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1966,6 +1966,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
}
|
||||
|
||||
if (cancelled) {
|
||||
+ this.player.resyncUsingItem(this.player); // Paper - Properly cancel usable items
|
||||
this.player.getBukkitEntity().updateInventory(); // SPIGOT-2524
|
||||
return;
|
||||
}
|
||||
@@ -2737,7 +2738,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
|
||||
// Entity in bucket - SPIGOT-4048 and SPIGOT-6859a
|
||||
if ((entity instanceof Bucketable && entity instanceof LivingEntity && origItem != null && origItem.asItem() == Items.WATER_BUCKET) && (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null || ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem() != origItem)) {
|
||||
- entity.getBukkitEntity().update(ServerGamePacketListenerImpl.this.player);
|
||||
+ entity.resendPossiblyDesyncedEntityData(ServerGamePacketListenerImpl.this.player); // Paper - The entire mob gets deleted, so resend it
|
||||
ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote();
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 4b9761e58f404eedf9db835fc923a88fc1896e96..682b8926027945066921086b6773b31e626cc941 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -397,7 +397,7 @@ public abstract class PlayerList {
|
||||
((ServerLevel)player.level()).getChunkSource().chunkMap.addEntity(player); // Paper - Fire PlayerJoinEvent when Player is actually ready; track entity now
|
||||
// CraftBukkit end
|
||||
|
||||
- player.refreshEntityData(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn
|
||||
+ //player.refreshEntityData(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn // Paper - THIS IS NOT NEEDED ANYMORE
|
||||
|
||||
this.sendLevelInfo(player, worldserver1);
|
||||
|
||||
@@ -908,12 +908,17 @@ public abstract class PlayerList {
|
||||
}
|
||||
|
||||
public void sendActiveEffects(LivingEntity entity, ServerGamePacketListenerImpl networkHandler) {
|
||||
+ // Paper start - collect packets
|
||||
+ this.sendActiveEffects(entity, networkHandler::send);
|
||||
+ }
|
||||
+ public void sendActiveEffects(LivingEntity entity, java.util.function.Consumer<Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> packetConsumer) {
|
||||
+ // Paper end - collect packets
|
||||
Iterator iterator = entity.getActiveEffects().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
MobEffectInstance mobeffect = (MobEffectInstance) iterator.next();
|
||||
|
||||
- networkHandler.send(new ClientboundUpdateMobEffectPacket(entity.getId(), mobeffect, false));
|
||||
+ packetConsumer.accept(new ClientboundUpdateMobEffectPacket(entity.getId(), mobeffect, false)); // Paper - collect packets
|
||||
}
|
||||
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index ea7100c8ac5da730d55136ac2ab608c2a7ac0ba8..4f0ff0d333d2de1b4f6beac1ce25e214b971e387 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -598,13 +598,45 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
||||
// CraftBukkit start
|
||||
public void refreshEntityData(ServerPlayer to) {
|
||||
- List<SynchedEntityData.DataValue<?>> list = this.getEntityData().getNonDefaultValues();
|
||||
+ List<SynchedEntityData.DataValue<?>> list = this.entityData.packAll(); // Paper - Update EVERYTHING not just not default
|
||||
|
||||
- if (list != null) {
|
||||
+ if (list != null && to.getBukkitEntity().canSee(this.getBukkitEntity())) { // Paper
|
||||
to.connection.send(new ClientboundSetEntityDataPacket(this.getId(), list));
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ // Paper start
|
||||
+ // This method should only be used if the data of an entity could have become desynced
|
||||
+ // due to interactions on the client.
|
||||
+ public void resendPossiblyDesyncedEntityData(net.minecraft.server.level.ServerPlayer player) {
|
||||
+ if (player.getBukkitEntity().canSee(this.getBukkitEntity())) {
|
||||
+ ServerLevel world = (net.minecraft.server.level.ServerLevel)this.level();
|
||||
+ net.minecraft.server.level.ChunkMap.TrackedEntity tracker = world == null ? null : world.getChunkSource().chunkMap.entityMap.get(this.getId());
|
||||
+ if (tracker == null) {
|
||||
+ return;
|
||||
+ }
|
||||
+ final net.minecraft.server.level.ServerEntity serverEntity = tracker.serverEntity;
|
||||
+ final List<net.minecraft.network.protocol.Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> list = new java.util.ArrayList<>();
|
||||
+ serverEntity.sendPairingData(player, list::add);
|
||||
+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundBundlePacket(list));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // This method allows you to specifically resend certain data accessor keys to the client
|
||||
+ public void resendPossiblyDesyncedDataValues(List<EntityDataAccessor<?>> keys, ServerPlayer to) {
|
||||
+ if (!to.getBukkitEntity().canSee(this.getBukkitEntity())) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ final List<SynchedEntityData.DataValue<?>> values = new java.util.ArrayList<>(keys.size());
|
||||
+ for (final EntityDataAccessor<?> key : keys) {
|
||||
+ final SynchedEntityData.DataItem<?> synchedValue = this.entityData.getItem(key);
|
||||
+ values.add(synchedValue.value());
|
||||
+ }
|
||||
+
|
||||
+ to.connection.send(new ClientboundSetEntityDataPacket(this.id, values));
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
public boolean equals(Object object) {
|
||||
return object instanceof Entity ? ((Entity) object).id == this.id : false;
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index f12c59d3bb15f482969cc9d0d2aff0718972675b..f75b66c9ec786bc6f4d3f5cd5127c815f11166c4 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -4031,6 +4031,11 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
return ((Byte) this.entityData.get(LivingEntity.DATA_LIVING_ENTITY_FLAGS) & 2) > 0 ? InteractionHand.OFF_HAND : InteractionHand.MAIN_HAND;
|
||||
}
|
||||
|
||||
+ // Paper start - Properly cancel usable items
|
||||
+ public void resyncUsingItem(ServerPlayer serverPlayer) {
|
||||
+ this.resendPossiblyDesyncedDataValues(java.util.List.of(DATA_LIVING_ENTITY_FLAGS), serverPlayer);
|
||||
+ }
|
||||
+ // Paper end - Properly cancel usable items
|
||||
private void updatingUsingItem() {
|
||||
if (this.isUsingItem()) {
|
||||
if (ItemStack.isSameItem(this.getItemInHand(this.getUsedItemHand()), this.useItem)) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/animal/Bucketable.java b/src/main/java/net/minecraft/world/entity/animal/Bucketable.java
|
||||
index 5a12f4c1de2d020e84af933d491397b38d227824..4eca5996a867086be22d22d99db81ab001467516 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Bucketable.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Bucketable.java
|
||||
@@ -108,8 +108,7 @@ public interface Bucketable {
|
||||
itemstack1 = CraftItemStack.asNMSCopy(playerBucketFishEvent.getEntityBucket());
|
||||
if (playerBucketFishEvent.isCancelled()) {
|
||||
((ServerPlayer) player).containerMenu.sendAllDataToRemote(); // We need to update inventory to resync client's bucket
|
||||
- entity.getBukkitEntity().update((ServerPlayer) player); // We need to play out these packets as the client assumes the fish is gone
|
||||
- entity.refreshEntityData((ServerPlayer) player); // Need to send data such as the display name to client
|
||||
+ entity.resendPossiblyDesyncedEntityData((ServerPlayer) player); // Paper
|
||||
return Optional.of(InteractionResult.FAIL);
|
||||
}
|
||||
entity.playSound(((Bucketable) entity).getPickupSound(), 1.0F, 1.0F);
|
||||
diff --git a/src/main/java/net/minecraft/world/item/component/SuspiciousStewEffects.java b/src/main/java/net/minecraft/world/item/component/SuspiciousStewEffects.java
|
||||
index 04760d8ba7c560bd9d11191c666715ae8c3e4bff..768f90682cd10045c16337fecc2702f57dfe8a50 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/component/SuspiciousStewEffects.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/component/SuspiciousStewEffects.java
|
||||
@@ -47,9 +47,14 @@ public record SuspiciousStewEffects(List<SuspiciousStewEffects.Entry> effects) i
|
||||
// CraftBukkit start
|
||||
@Override
|
||||
public void cancelUsingItem(net.minecraft.server.level.ServerPlayer entityplayer, ItemStack itemstack) {
|
||||
+ final List<net.minecraft.network.protocol.Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> packets = new java.util.ArrayList<>(); // Paper - bundlize packets
|
||||
for (SuspiciousStewEffects.Entry suspicioussteweffects_a : this.effects) {
|
||||
- entityplayer.connection.send(new net.minecraft.network.protocol.game.ClientboundRemoveMobEffectPacket(entityplayer.getId(), suspicioussteweffects_a.effect()));
|
||||
+ packets.add(new net.minecraft.network.protocol.game.ClientboundRemoveMobEffectPacket(entityplayer.getId(), suspicioussteweffects_a.effect())); // Paper - bundlize packets
|
||||
}
|
||||
+ // Paper start - bundlize packets
|
||||
+ entityplayer.server.getPlayerList().sendActiveEffects(entityplayer, packets::add);
|
||||
+ entityplayer.connection.send(new net.minecraft.network.protocol.game.ClientboundBundlePacket(packets));
|
||||
+ // Paper end - bundlize packets
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
index c1d3dd2bd217efd6914bceb1027fa12b06c22a55..ca95a36b0149d4b8a67c3b42316c5d9d0415f5dd 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
@@ -1013,7 +1013,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
return;
|
||||
}
|
||||
|
||||
- entityTracker.broadcast(this.getHandle().getAddEntityPacket(entityTracker.serverEntity));
|
||||
+ // Paper start - resend possibly desynced entity instead of add entity packet
|
||||
+ for (final ServerPlayerConnection connection : entityTracker.seenBy) {
|
||||
+ this.getHandle().resendPossiblyDesyncedEntityData(connection.getPlayer());
|
||||
+ }
|
||||
+ // Paper end - resend possibly desynced entity instead of add entity packet
|
||||
}
|
||||
|
||||
public void update(ServerPlayer player) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java
|
||||
index f3a9b3380246fb2dd4b60a8d1a94c5dfed98d316..350ad61ab3fe66abd528e353b431a4a6dac17506 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java
|
||||
@@ -39,9 +39,11 @@ public class CraftItemFrame extends CraftHanging implements ItemFrame {
|
||||
protected void update() {
|
||||
super.update();
|
||||
|
||||
+ // Paper start, don't mark as dirty as this is handled in super.update()
|
||||
// mark dirty, so that the client gets updated with item and rotation
|
||||
- this.getHandle().getEntityData().markDirty(net.minecraft.world.entity.decoration.ItemFrame.DATA_ITEM);
|
||||
- this.getHandle().getEntityData().markDirty(net.minecraft.world.entity.decoration.ItemFrame.DATA_ROTATION);
|
||||
+ //this.getHandle().getEntityData().markDirty(net.minecraft.world.entity.decoration.ItemFrame.DATA_ITEM);
|
||||
+ //this.getHandle().getEntityData().markDirty(net.minecraft.world.entity.decoration.ItemFrame.DATA_ROTATION);
|
||||
+ // Paper end
|
||||
|
||||
// update redstone
|
||||
if (!this.getHandle().generation) {
|
1499
patches/server/0994-Registry-Modification-API.patch
Normal file
1499
patches/server/0994-Registry-Modification-API.patch
Normal file
File diff suppressed because it is too large
Load diff
484
patches/server/0995-Add-registry-entry-and-builders.patch
Normal file
484
patches/server/0995-Add-registry-entry-and-builders.patch
Normal file
|
@ -0,0 +1,484 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Bjarne Koll <lynxplay101@gmail.com>
|
||||
Date: Thu, 13 Jun 2024 23:45:32 +0200
|
||||
Subject: [PATCH] Add registry entry and builders
|
||||
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/src/main/java/io/papermc/paper/registry/PaperRegistries.java
|
||||
index 5cf598905ed6a7ac2b0d9ced3420adaf20ceb6af..12220f78ffaf06433ada72fd0c7f22b97d55287d 100644
|
||||
--- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java
|
||||
+++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java
|
||||
@@ -1,6 +1,8 @@
|
||||
package io.papermc.paper.registry;
|
||||
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
+import io.papermc.paper.registry.data.PaperEnchantmentRegistryEntry;
|
||||
+import io.papermc.paper.registry.data.PaperGameEventRegistryEntry;
|
||||
import io.papermc.paper.registry.entry.RegistryEntry;
|
||||
import io.papermc.paper.registry.tag.TagKey;
|
||||
import java.util.Collections;
|
||||
@@ -70,7 +72,7 @@ public final class PaperRegistries {
|
||||
static {
|
||||
REGISTRY_ENTRIES = List.of(
|
||||
// built-ins
|
||||
- entry(Registries.GAME_EVENT, RegistryKey.GAME_EVENT, GameEvent.class, CraftGameEvent::new),
|
||||
+ writable(Registries.GAME_EVENT, RegistryKey.GAME_EVENT, GameEvent.class, CraftGameEvent::new, PaperGameEventRegistryEntry.PaperBuilder::new),
|
||||
entry(Registries.STRUCTURE_TYPE, RegistryKey.STRUCTURE_TYPE, StructureType.class, CraftStructureType::new),
|
||||
entry(Registries.INSTRUMENT, RegistryKey.INSTRUMENT, MusicInstrument.class, CraftMusicInstrument::new),
|
||||
entry(Registries.MOB_EFFECT, RegistryKey.MOB_EFFECT, PotionEffectType.class, CraftPotionEffectType::new),
|
||||
@@ -89,7 +91,7 @@ public final class PaperRegistries {
|
||||
entry(Registries.TRIM_PATTERN, RegistryKey.TRIM_PATTERN, TrimPattern.class, CraftTrimPattern::new).delayed(),
|
||||
entry(Registries.DAMAGE_TYPE, RegistryKey.DAMAGE_TYPE, DamageType.class, CraftDamageType::new).delayed(),
|
||||
entry(Registries.WOLF_VARIANT, RegistryKey.WOLF_VARIANT, Wolf.Variant.class, CraftWolf.CraftVariant::new).delayed(),
|
||||
- entry(Registries.ENCHANTMENT, RegistryKey.ENCHANTMENT, Enchantment.class, CraftEnchantment::new).withSerializationUpdater(FieldRename.ENCHANTMENT_RENAME).delayed(),
|
||||
+ writable(Registries.ENCHANTMENT, RegistryKey.ENCHANTMENT, Enchantment.class, CraftEnchantment::new, PaperEnchantmentRegistryEntry.PaperBuilder::new).withSerializationUpdater(FieldRename.ENCHANTMENT_RENAME).delayed(),
|
||||
entry(Registries.JUKEBOX_SONG, RegistryKey.JUKEBOX_SONG, JukeboxSong.class, CraftJukeboxSong::new).delayed(),
|
||||
entry(Registries.BANNER_PATTERN, RegistryKey.BANNER_PATTERN, PatternType.class, CraftPatternType::new).delayed(),
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/registry/data/PaperEnchantmentRegistryEntry.java b/src/main/java/io/papermc/paper/registry/data/PaperEnchantmentRegistryEntry.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..481f5f0cfae1fada3bc3f873fb7e04c3086ea9bf
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/registry/data/PaperEnchantmentRegistryEntry.java
|
||||
@@ -0,0 +1,234 @@
|
||||
+package io.papermc.paper.registry.data;
|
||||
+
|
||||
+import com.google.common.base.Preconditions;
|
||||
+import com.google.common.collect.Iterables;
|
||||
+import com.google.common.collect.Lists;
|
||||
+import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
+import io.papermc.paper.registry.RegistryKey;
|
||||
+import io.papermc.paper.registry.TypedKey;
|
||||
+import io.papermc.paper.registry.data.util.Checks;
|
||||
+import io.papermc.paper.registry.data.util.Conversions;
|
||||
+import io.papermc.paper.registry.set.PaperRegistrySets;
|
||||
+import io.papermc.paper.registry.set.RegistryKeySet;
|
||||
+import java.util.Collections;
|
||||
+import java.util.List;
|
||||
+import java.util.Optional;
|
||||
+import java.util.OptionalInt;
|
||||
+import net.minecraft.core.HolderSet;
|
||||
+import net.minecraft.core.component.DataComponentMap;
|
||||
+import net.minecraft.core.registries.Registries;
|
||||
+import net.minecraft.network.chat.Component;
|
||||
+import net.minecraft.world.entity.EquipmentSlotGroup;
|
||||
+import net.minecraft.world.item.Item;
|
||||
+import net.minecraft.world.item.enchantment.Enchantment;
|
||||
+import org.bukkit.craftbukkit.CraftEquipmentSlot;
|
||||
+import org.bukkit.inventory.ItemType;
|
||||
+import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+import org.jetbrains.annotations.Range;
|
||||
+
|
||||
+import static io.papermc.paper.registry.data.util.Checks.asArgument;
|
||||
+import static io.papermc.paper.registry.data.util.Checks.asArgumentMin;
|
||||
+import static io.papermc.paper.registry.data.util.Checks.asConfigured;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public class PaperEnchantmentRegistryEntry implements EnchantmentRegistryEntry {
|
||||
+
|
||||
+ // Top level
|
||||
+ protected @MonotonicNonNull Component description;
|
||||
+
|
||||
+ // Definition
|
||||
+ protected @MonotonicNonNull HolderSet<Item> supportedItems;
|
||||
+ protected @Nullable HolderSet<Item> primaryItems;
|
||||
+ protected OptionalInt weight = OptionalInt.empty();
|
||||
+ protected OptionalInt maxLevel = OptionalInt.empty();
|
||||
+ protected Enchantment.@MonotonicNonNull Cost minimumCost;
|
||||
+ protected Enchantment.@MonotonicNonNull Cost maximumCost;
|
||||
+ protected OptionalInt anvilCost = OptionalInt.empty();
|
||||
+ protected @MonotonicNonNull List<EquipmentSlotGroup> activeSlots;
|
||||
+
|
||||
+ // Exclusive
|
||||
+ protected HolderSet<Enchantment> exclusiveWith = HolderSet.empty(); // Paper added default to empty.
|
||||
+
|
||||
+ // Effects
|
||||
+ protected DataComponentMap effects;
|
||||
+
|
||||
+ protected final Conversions conversions;
|
||||
+
|
||||
+ public PaperEnchantmentRegistryEntry(
|
||||
+ final Conversions conversions,
|
||||
+ final TypedKey<org.bukkit.enchantments.Enchantment> ignoredKey,
|
||||
+ final @Nullable Enchantment internal
|
||||
+ ) {
|
||||
+ this.conversions = conversions;
|
||||
+ if (internal == null) {
|
||||
+ this.effects = DataComponentMap.EMPTY;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ // top level
|
||||
+ this.description = internal.description();
|
||||
+
|
||||
+ // definition
|
||||
+ final Enchantment.EnchantmentDefinition definition = internal.definition();
|
||||
+ this.supportedItems = definition.supportedItems();
|
||||
+ this.primaryItems = definition.primaryItems().orElse(null);
|
||||
+ this.weight = OptionalInt.of(definition.weight());
|
||||
+ this.maxLevel = OptionalInt.of(definition.maxLevel());
|
||||
+ this.minimumCost = definition.minCost();
|
||||
+ this.maximumCost = definition.maxCost();
|
||||
+ this.anvilCost = OptionalInt.of(definition.anvilCost());
|
||||
+ this.activeSlots = definition.slots();
|
||||
+
|
||||
+ // exclusive
|
||||
+ this.exclusiveWith = internal.exclusiveSet();
|
||||
+
|
||||
+ // effects
|
||||
+ this.effects = internal.effects();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public net.kyori.adventure.text.Component description() {
|
||||
+ return this.conversions.asAdventure(asConfigured(this.description, "description"));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public RegistryKeySet<ItemType> supportedItems() {
|
||||
+ return PaperRegistrySets.convertToApi(RegistryKey.ITEM, asConfigured(this.supportedItems, "supportedItems"));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @Nullable RegistryKeySet<ItemType> primaryItems() {
|
||||
+ return this.primaryItems == null ? null : PaperRegistrySets.convertToApi(RegistryKey.ITEM, this.primaryItems);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @Range(from = 1, to = 1024) int weight() {
|
||||
+ return asConfigured(this.weight, "weight");
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @Range(from = 1, to = 255) int maxLevel() {
|
||||
+ return asConfigured(this.maxLevel, "maxLevel");
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public EnchantmentCost minimumCost() {
|
||||
+ final Enchantment.@MonotonicNonNull Cost cost = asConfigured(this.minimumCost, "minimumCost");
|
||||
+ return EnchantmentRegistryEntry.EnchantmentCost.of(cost.base(), cost.perLevelAboveFirst());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public EnchantmentCost maximumCost() {
|
||||
+ final Enchantment.@MonotonicNonNull Cost cost = asConfigured(this.maximumCost, "maximumCost");
|
||||
+ return EnchantmentRegistryEntry.EnchantmentCost.of(cost.base(), cost.perLevelAboveFirst());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @Range(from = 0, to = Integer.MAX_VALUE) int anvilCost() {
|
||||
+ return asConfigured(this.anvilCost, "anvilCost");
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public List<org.bukkit.inventory.EquipmentSlotGroup> activeSlots() {
|
||||
+ return Collections.unmodifiableList(Lists.transform(asConfigured(this.activeSlots, "activeSlots"), CraftEquipmentSlot::getSlot));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public RegistryKeySet<org.bukkit.enchantments.Enchantment> exclusiveWith() {
|
||||
+ return PaperRegistrySets.convertToApi(RegistryKey.ENCHANTMENT, this.exclusiveWith);
|
||||
+ }
|
||||
+
|
||||
+ public static final class PaperBuilder extends PaperEnchantmentRegistryEntry implements EnchantmentRegistryEntry.Builder,
|
||||
+ PaperRegistryBuilder<Enchantment, org.bukkit.enchantments.Enchantment> {
|
||||
+
|
||||
+ public PaperBuilder(final Conversions conversions, final TypedKey<org.bukkit.enchantments.Enchantment> key, final @Nullable Enchantment internal) {
|
||||
+ super(conversions, key, internal);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Builder description(final net.kyori.adventure.text.Component description) {
|
||||
+ this.description = this.conversions.asVanilla(asArgument(description, "description"));
|
||||
+ return this;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Builder supportedItems(final RegistryKeySet<ItemType> supportedItems) {
|
||||
+ this.supportedItems = PaperRegistrySets.convertToNms(Registries.ITEM, this.conversions.lookup(), asArgument(supportedItems, "supportedItems"));
|
||||
+ return this;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Builder primaryItems(final @Nullable RegistryKeySet<ItemType> primaryItems) {
|
||||
+ this.primaryItems = primaryItems == null ? null : PaperRegistrySets.convertToNms(Registries.ITEM, this.conversions.lookup(), primaryItems);
|
||||
+ return this;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Builder weight(final @Range(from = 1, to = 1024) int weight) {
|
||||
+ this.weight = OptionalInt.of(Checks.asArgumentRange(weight, "weight", 1, 1024));
|
||||
+ return this;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Builder maxLevel(final @Range(from = 1, to = 255) int maxLevel) {
|
||||
+ this.maxLevel = OptionalInt.of(Checks.asArgumentRange(maxLevel, "maxLevel", 1, 255));
|
||||
+ return this;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Builder minimumCost(final EnchantmentCost minimumCost) {
|
||||
+ final EnchantmentCost validCost = asArgument(minimumCost, "minimumCost");
|
||||
+ this.minimumCost = Enchantment.dynamicCost(validCost.baseCost(), validCost.additionalPerLevelCost());
|
||||
+ return this;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Builder maximumCost(final EnchantmentCost maximumCost) {
|
||||
+ final EnchantmentCost validCost = asArgument(maximumCost, "maximumCost");
|
||||
+ this.maximumCost = Enchantment.dynamicCost(validCost.baseCost(), validCost.additionalPerLevelCost());
|
||||
+ return this;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Builder anvilCost(final @Range(from = 0, to = Integer.MAX_VALUE) int anvilCost) {
|
||||
+ Preconditions.checkArgument(anvilCost >= 0, "anvilCost must be non-negative");
|
||||
+ this.anvilCost = OptionalInt.of(asArgumentMin(anvilCost, "anvilCost", 0));
|
||||
+ return this;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Builder activeSlots(final Iterable<org.bukkit.inventory.EquipmentSlotGroup> activeSlots) {
|
||||
+ this.activeSlots = Lists.newArrayList(Iterables.transform(asArgument(activeSlots, "activeSlots"), CraftEquipmentSlot::getNMSGroup));
|
||||
+ return this;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Builder exclusiveWith(final RegistryKeySet<org.bukkit.enchantments.Enchantment> exclusiveWith) {
|
||||
+ this.exclusiveWith = PaperRegistrySets.convertToNms(Registries.ENCHANTMENT, this.conversions.lookup(), asArgument(exclusiveWith, "exclusiveWith"));
|
||||
+ return this;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Enchantment build() {
|
||||
+ final Enchantment.EnchantmentDefinition def = new Enchantment.EnchantmentDefinition(
|
||||
+ asConfigured(this.supportedItems, "supportedItems"),
|
||||
+ Optional.ofNullable(this.primaryItems),
|
||||
+ this.weight(),
|
||||
+ this.maxLevel(),
|
||||
+ asConfigured(this.minimumCost, "minimumCost"),
|
||||
+ asConfigured(this.maximumCost, "maximumCost"),
|
||||
+ this.anvilCost(),
|
||||
+ Collections.unmodifiableList(asConfigured(this.activeSlots, "activeSlots"))
|
||||
+ );
|
||||
+ return new Enchantment(
|
||||
+ asConfigured(this.description, "description"),
|
||||
+ def,
|
||||
+ this.exclusiveWith,
|
||||
+ this.effects
|
||||
+ );
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/registry/data/PaperGameEventRegistryEntry.java b/src/main/java/io/papermc/paper/registry/data/PaperGameEventRegistryEntry.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..18f9463ae23ba2d9c65ffb7531a87c925a5a8d6f
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/registry/data/PaperGameEventRegistryEntry.java
|
||||
@@ -0,0 +1,57 @@
|
||||
+package io.papermc.paper.registry.data;
|
||||
+
|
||||
+import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
+import io.papermc.paper.registry.data.util.Conversions;
|
||||
+import java.util.OptionalInt;
|
||||
+import net.minecraft.world.level.gameevent.GameEvent;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+import org.jetbrains.annotations.Range;
|
||||
+
|
||||
+import static io.papermc.paper.registry.data.util.Checks.asArgumentMin;
|
||||
+import static io.papermc.paper.registry.data.util.Checks.asConfigured;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public class PaperGameEventRegistryEntry implements GameEventRegistryEntry {
|
||||
+
|
||||
+ protected OptionalInt range = OptionalInt.empty();
|
||||
+
|
||||
+ public PaperGameEventRegistryEntry(
|
||||
+ final Conversions ignoredConversions,
|
||||
+ final io.papermc.paper.registry.TypedKey<org.bukkit.GameEvent> ignoredKey,
|
||||
+ final @Nullable GameEvent nms
|
||||
+ ) {
|
||||
+ if (nms == null) return;
|
||||
+
|
||||
+ this.range = OptionalInt.of(nms.notificationRadius());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @Range(from = 0, to = Integer.MAX_VALUE) int range() {
|
||||
+ return asConfigured(this.range, "range");
|
||||
+ }
|
||||
+
|
||||
+ public static final class PaperBuilder extends PaperGameEventRegistryEntry implements GameEventRegistryEntry.Builder,
|
||||
+ PaperRegistryBuilder<GameEvent, org.bukkit.GameEvent> {
|
||||
+
|
||||
+ public PaperBuilder(
|
||||
+ final Conversions conversions,
|
||||
+ final io.papermc.paper.registry.TypedKey<org.bukkit.GameEvent> key,
|
||||
+ final @Nullable GameEvent nms
|
||||
+ ) {
|
||||
+ super(conversions, key, nms);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public GameEventRegistryEntry.Builder range(final @Range(from = 0, to = Integer.MAX_VALUE) int range) {
|
||||
+ this.range = OptionalInt.of(asArgumentMin(range, "range", 0));
|
||||
+ return this;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public GameEvent build() {
|
||||
+ return new GameEvent(this.range());
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/registry/data/util/Checks.java b/src/main/java/io/papermc/paper/registry/data/util/Checks.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..3241a94731fe8163876614efdcf30f8b551535af
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/registry/data/util/Checks.java
|
||||
@@ -0,0 +1,48 @@
|
||||
+package io.papermc.paper.registry.data.util;
|
||||
+
|
||||
+import java.util.OptionalInt;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public final class Checks {
|
||||
+
|
||||
+ public static <T> T asConfigured(final @Nullable T value, final String field) {
|
||||
+ if (value == null) {
|
||||
+ throw new IllegalStateException(field + " has not been configured");
|
||||
+ }
|
||||
+ return value;
|
||||
+ }
|
||||
+
|
||||
+ public static int asConfigured(final OptionalInt value, final String field) {
|
||||
+ if (value.isEmpty()) {
|
||||
+ throw new IllegalStateException(field + " has not been configured");
|
||||
+ }
|
||||
+ return value.getAsInt();
|
||||
+ }
|
||||
+
|
||||
+ public static <T> T asArgument(final @Nullable T value, final String field) {
|
||||
+ if (value == null) {
|
||||
+ throw new IllegalArgumentException("argument " + field + " cannot be null");
|
||||
+ }
|
||||
+ return value;
|
||||
+ }
|
||||
+
|
||||
+ public static int asArgumentRange(final int value, final String field, final int min, final int max) {
|
||||
+ if (value < min || value > max) {
|
||||
+ throw new IllegalArgumentException("argument " + field + " must be [" + min + ", " + max + "]");
|
||||
+ }
|
||||
+ return value;
|
||||
+ }
|
||||
+
|
||||
+ public static int asArgumentMin(final int value, final String field, final int min) {
|
||||
+ if (value < min) {
|
||||
+ throw new IllegalArgumentException("argument " + field + " must be [" + min + ",+inf)");
|
||||
+ }
|
||||
+ return value;
|
||||
+ }
|
||||
+
|
||||
+ private Checks() {
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/gameevent/GameEvent.java b/src/main/java/net/minecraft/world/level/gameevent/GameEvent.java
|
||||
index cc3c56224e64816b885c0131ce2a800a2efe3113..7acd9c71c5c4b487e792b8c36a8e52e10b691e98 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/gameevent/GameEvent.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/gameevent/GameEvent.java
|
||||
@@ -85,7 +85,7 @@ public record GameEvent(int notificationRadius) {
|
||||
}
|
||||
|
||||
private static Holder.Reference<GameEvent> register(String id, int range) {
|
||||
- return Registry.registerForHolder(BuiltInRegistries.GAME_EVENT, ResourceLocation.withDefaultNamespace(id), new GameEvent(range));
|
||||
+ return io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.registerForHolderWithListeners(BuiltInRegistries.GAME_EVENT, ResourceLocation.withDefaultNamespace(id), new GameEvent(range)); // Paper - run with listeners
|
||||
}
|
||||
|
||||
public static record Context(@Nullable Entity sourceEntity, @Nullable BlockState affectedState) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftGameEvent.java b/src/main/java/org/bukkit/craftbukkit/CraftGameEvent.java
|
||||
index ac9b4328cd55a68664a3f71186bc9a7be7cd9658..ea9fe1f8b1a1685ea975eba0ca418a831006065a 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftGameEvent.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftGameEvent.java
|
||||
@@ -18,10 +18,12 @@ public class CraftGameEvent extends GameEvent implements Handleable<net.minecraf
|
||||
}
|
||||
|
||||
private final NamespacedKey key;
|
||||
+ private final net.minecraft.resources.ResourceKey<net.minecraft.world.level.gameevent.GameEvent> handleKey; // Paper
|
||||
private final net.minecraft.world.level.gameevent.GameEvent handle;
|
||||
|
||||
public CraftGameEvent(NamespacedKey key, net.minecraft.world.level.gameevent.GameEvent handle) {
|
||||
this.key = key;
|
||||
+ this.handleKey = net.minecraft.resources.ResourceKey.create(net.minecraft.core.registries.Registries.GAME_EVENT, org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(key)); // Paper
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
@@ -30,6 +32,18 @@ public class CraftGameEvent extends GameEvent implements Handleable<net.minecraf
|
||||
return this.handle;
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public int getRange() {
|
||||
+ return this.handle.notificationRadius();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getVibrationLevel() {
|
||||
+ return net.minecraft.world.level.gameevent.vibrations.VibrationSystem.getGameEventFrequency(this.handleKey);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@NotNull
|
||||
@Override
|
||||
public NamespacedKey getKey() {
|
||||
diff --git a/src/test/java/io/papermc/paper/registry/RegistryBuilderTest.java b/src/test/java/io/papermc/paper/registry/RegistryBuilderTest.java
|
||||
index 47b8ebac8496179008b8932c5ca2aadc274e24e0..814675bf67fd02e8cd2311dce60eeef651ef16f1 100644
|
||||
--- a/src/test/java/io/papermc/paper/registry/RegistryBuilderTest.java
|
||||
+++ b/src/test/java/io/papermc/paper/registry/RegistryBuilderTest.java
|
||||
@@ -1,11 +1,16 @@
|
||||
package io.papermc.paper.registry;
|
||||
|
||||
+import io.papermc.paper.registry.data.PaperEnchantmentRegistryEntry;
|
||||
+import io.papermc.paper.registry.data.PaperGameEventRegistryEntry;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import net.minecraft.core.Registry;
|
||||
+import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.RegistryOps;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
+import net.minecraft.world.item.enchantment.Enchantment;
|
||||
+import net.minecraft.world.level.gameevent.GameEvent;
|
||||
import org.bukkit.support.RegistryHelper;
|
||||
import org.bukkit.support.environment.AllFeatures;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
@@ -14,16 +19,18 @@ import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
+import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||
|
||||
@AllFeatures
|
||||
class RegistryBuilderTest {
|
||||
|
||||
static List<Arguments> registries() {
|
||||
return List.of(
|
||||
+ arguments(Registries.ENCHANTMENT, (PaperRegistryBuilder.Filler<Enchantment, org.bukkit.enchantments.Enchantment, PaperEnchantmentRegistryEntry.PaperBuilder>) PaperEnchantmentRegistryEntry.PaperBuilder::new),
|
||||
+ arguments(Registries.GAME_EVENT, (PaperRegistryBuilder.Filler<GameEvent, org.bukkit.GameEvent, PaperGameEventRegistryEntry.PaperBuilder>) PaperGameEventRegistryEntry.PaperBuilder::new)
|
||||
);
|
||||
}
|
||||
|
||||
- @Disabled
|
||||
@ParameterizedTest
|
||||
@MethodSource("registries")
|
||||
<M, T> void testEquality(final ResourceKey<? extends Registry<M>> resourceKey, final PaperRegistryBuilder.Filler<M, T, ?> filler) {
|
302
patches/server/0996-Proxy-ItemStack-to-CraftItemStack.patch
Normal file
302
patches/server/0996-Proxy-ItemStack-to-CraftItemStack.patch
Normal file
|
@ -0,0 +1,302 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Tue, 14 May 2024 11:57:43 -0700
|
||||
Subject: [PATCH] Proxy ItemStack to CraftItemStack
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
||||
index bb2b4528692aed8e3341428697a60c0abee13779..49d2deac8d42a505b75f2196ef895a5564b62cac 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
||||
@@ -31,15 +31,57 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
@DelegateDeserialization(ItemStack.class)
|
||||
public final class CraftItemStack extends ItemStack {
|
||||
|
||||
- // Paper start - MC Utils
|
||||
- public static net.minecraft.world.item.ItemStack unwrap(ItemStack bukkit) {
|
||||
- if (bukkit instanceof CraftItemStack craftItemStack) {
|
||||
- return craftItemStack.handle != null ? craftItemStack.handle : net.minecraft.world.item.ItemStack.EMPTY;
|
||||
+ // Paper start - delegate api-ItemStack to CraftItemStack
|
||||
+ private static final java.lang.invoke.VarHandle API_ITEM_STACK_CRAFT_DELEGATE_FIELD;
|
||||
+ static {
|
||||
+ try {
|
||||
+ API_ITEM_STACK_CRAFT_DELEGATE_FIELD = java.lang.invoke.MethodHandles.privateLookupIn(
|
||||
+ ItemStack.class,
|
||||
+ java.lang.invoke.MethodHandles.lookup()
|
||||
+ ).findVarHandle(ItemStack.class, "craftDelegate", ItemStack.class);
|
||||
+ } catch (final IllegalAccessException | NoSuchFieldException exception) {
|
||||
+ throw new RuntimeException(exception);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static CraftItemStack getCraftStack(final ItemStack bukkit) {
|
||||
+ if (bukkit instanceof final CraftItemStack craftItemStack) {
|
||||
+ return craftItemStack;
|
||||
} else {
|
||||
- return asNMSCopy(bukkit);
|
||||
+ return (CraftItemStack) API_ITEM_STACK_CRAFT_DELEGATE_FIELD.get(bukkit);
|
||||
}
|
||||
}
|
||||
|
||||
+ @Override
|
||||
+ public int hashCode() {
|
||||
+ if (this.handle == null || this.handle.isEmpty()) {
|
||||
+ return net.minecraft.world.item.ItemStack.EMPTY.hashCode();
|
||||
+ } else {
|
||||
+ int hash = net.minecraft.world.item.ItemStack.hashItemAndComponents(this.handle);
|
||||
+ hash = hash * 31 + this.handle.getCount();
|
||||
+ return hash;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean equals(final Object obj) {
|
||||
+ if (!(obj instanceof final org.bukkit.inventory.ItemStack bukkit)) return false;
|
||||
+ final CraftItemStack craftStack = getCraftStack(bukkit);
|
||||
+ if (this.handle == craftStack.handle) return true;
|
||||
+ else if (this.handle == null || craftStack.handle == null) return false;
|
||||
+ else if (this.handle.isEmpty() && craftStack.handle.isEmpty()) return true;
|
||||
+ else return net.minecraft.world.item.ItemStack.matches(this.handle, craftStack.handle);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
+ // Paper start - MC Utils
|
||||
+ public static net.minecraft.world.item.ItemStack unwrap(ItemStack bukkit) {
|
||||
+ // Paper start - re-implement after delegating all api ItemStack calls to CraftItemStack
|
||||
+ final CraftItemStack craftItemStack = getCraftStack(bukkit);
|
||||
+ return craftItemStack.handle == null ? net.minecraft.world.item.ItemStack.EMPTY : craftItemStack.handle;
|
||||
+ // Paper end - re-implement after delegating all api ItemStack calls to CraftItemStack
|
||||
+ }
|
||||
+
|
||||
public static net.minecraft.world.item.ItemStack getOrCloneOnMutation(ItemStack old, ItemStack newInstance) {
|
||||
return old == newInstance ? unwrap(old) : asNMSCopy(newInstance);
|
||||
}
|
||||
@@ -53,25 +95,13 @@ public final class CraftItemStack extends ItemStack {
|
||||
// Paper end - override isEmpty to use vanilla's impl
|
||||
|
||||
public static net.minecraft.world.item.ItemStack asNMSCopy(ItemStack original) {
|
||||
- if (original instanceof CraftItemStack) {
|
||||
- CraftItemStack stack = (CraftItemStack) original;
|
||||
- return stack.handle == null ? net.minecraft.world.item.ItemStack.EMPTY : stack.handle.copy();
|
||||
- }
|
||||
- if (original == null || original.isEmpty()) { // Paper - override isEmpty to use vanilla's impl; use isEmpty
|
||||
+ // Paper start - re-implement after delegating all api ItemStack calls to CraftItemStack
|
||||
+ if (original == null || original.isEmpty()) {
|
||||
return net.minecraft.world.item.ItemStack.EMPTY;
|
||||
}
|
||||
-
|
||||
- Item item = CraftItemType.bukkitToMinecraft(original.getType());
|
||||
-
|
||||
- if (item == null) {
|
||||
- return net.minecraft.world.item.ItemStack.EMPTY;
|
||||
- }
|
||||
-
|
||||
- net.minecraft.world.item.ItemStack stack = new net.minecraft.world.item.ItemStack(item, original.getAmount());
|
||||
- if (original.hasItemMeta()) {
|
||||
- CraftItemStack.setItemMeta(stack, original.getItemMeta());
|
||||
- }
|
||||
- return stack;
|
||||
+ final CraftItemStack stack = getCraftStack(original);
|
||||
+ return stack.handle == null ? net.minecraft.world.item.ItemStack.EMPTY : stack.handle.copy();
|
||||
+ // Paper end - re-implement after delegating all api ItemStack calls to CraftItemStack
|
||||
}
|
||||
|
||||
// Paper start
|
||||
@@ -94,14 +124,10 @@ public final class CraftItemStack extends ItemStack {
|
||||
* Copies the NMS stack to return as a strictly-Bukkit stack
|
||||
*/
|
||||
public static ItemStack asBukkitCopy(net.minecraft.world.item.ItemStack original) {
|
||||
- if (original.isEmpty()) {
|
||||
- return new ItemStack(Material.AIR);
|
||||
- }
|
||||
- ItemStack stack = new ItemStack(CraftItemType.minecraftToBukkit(original.getItem()), original.getCount());
|
||||
- if (CraftItemStack.hasItemMeta(original)) {
|
||||
- stack.setItemMeta(CraftItemStack.getItemMeta(original));
|
||||
- }
|
||||
- return stack;
|
||||
+ // Paper start - no such thing as a "strictly-Bukkit stack" anymore
|
||||
+ // we copy the stack since it should be a complete copy not a mirror
|
||||
+ return asCraftMirror(original.copy());
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
public static CraftItemStack asCraftMirror(net.minecraft.world.item.ItemStack original) {
|
||||
@@ -329,11 +355,7 @@ public final class CraftItemStack extends ItemStack {
|
||||
|
||||
@Override
|
||||
public CraftItemStack clone() {
|
||||
- CraftItemStack itemStack = (CraftItemStack) super.clone();
|
||||
- if (this.handle != null) {
|
||||
- itemStack.handle = this.handle.copy();
|
||||
- }
|
||||
- return itemStack;
|
||||
+ return new org.bukkit.craftbukkit.inventory.CraftItemStack(this.handle != null ? this.handle.copy() : null); // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -436,22 +458,14 @@ public final class CraftItemStack extends ItemStack {
|
||||
if (stack == this) {
|
||||
return true;
|
||||
}
|
||||
- if (!(stack instanceof CraftItemStack)) {
|
||||
- return stack.getClass() == ItemStack.class && stack.isSimilar(this);
|
||||
- }
|
||||
-
|
||||
- CraftItemStack that = (CraftItemStack) stack;
|
||||
+ final CraftItemStack that = getCraftStack(stack); // Paper - re-implement after delegating all api ItemStack calls to CraftItemStack
|
||||
if (this.handle == that.handle) {
|
||||
return true;
|
||||
}
|
||||
if (this.handle == null || that.handle == null) {
|
||||
return false;
|
||||
}
|
||||
- Material comparisonType = CraftLegacy.fromLegacy(that.getType()); // This may be called from legacy item stacks, try to get the right material
|
||||
- if (!(comparisonType == this.getType() && this.getDurability() == that.getDurability())) {
|
||||
- return false;
|
||||
- }
|
||||
- return this.hasItemMeta() ? that.hasItemMeta() && this.handle.getComponents().equals(that.handle.getComponents()) : !that.hasItemMeta();
|
||||
+ return net.minecraft.world.item.ItemStack.isSameItemSameComponents(this.handle, that.handle); // Paper - re-implement after delegating all api ItemStack calls to CraftItemStack
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java
|
||||
index f4a6ee6dfcb2d516a9a1a9c81494b50a629110e4..96dfcfa12c63c682edcdec98647ca6a94d9fb4ed 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java
|
||||
@@ -100,13 +100,14 @@ public class CraftItemType<M extends ItemMeta> implements ItemType.Typed<M>, Han
|
||||
@NotNull
|
||||
@Override
|
||||
public ItemStack createItemStack(final int amount, @Nullable final Consumer<? super M> metaConfigurator) {
|
||||
- final ItemStack itemStack = new ItemStack(this.asMaterial(), amount);
|
||||
+ // Paper start - re-implement to return CraftItemStack
|
||||
+ final net.minecraft.world.item.ItemStack stack = new net.minecraft.world.item.ItemStack(this.item, amount);
|
||||
+ final CraftItemStack mirror = CraftItemStack.asCraftMirror(stack);
|
||||
if (metaConfigurator != null) {
|
||||
- final ItemMeta itemMeta = itemStack.getItemMeta();
|
||||
- metaConfigurator.accept((M) itemMeta);
|
||||
- itemStack.setItemMeta(itemMeta);
|
||||
+ mirror.editMeta(this.getItemMetaClass(), metaConfigurator);
|
||||
}
|
||||
- return itemStack;
|
||||
+ return mirror;
|
||||
+ // Paper start - reimplement to return CraftItemStack
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java b/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java
|
||||
index 6cc9d7a9e6d4bfdc27e52fc581b2bb832616f121..6930d0afb230a88aa813b02e4d55c95d3a049688 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java
|
||||
@@ -678,4 +678,16 @@ public class MaterialRerouting {
|
||||
return itemStack.withType(material);
|
||||
}
|
||||
// Paper end - register paper API specific material consumers in rerouting
|
||||
+
|
||||
+ // Paper start - methods added post 1.13, no-op
|
||||
+ @RerouteStatic("org/bukkit/inventory/ItemStack")
|
||||
+ public static ItemStack of(final Material material) {
|
||||
+ return ItemStack.of(material);
|
||||
+ }
|
||||
+
|
||||
+ @RerouteStatic("org/bukkit/inventory/ItemStack")
|
||||
+ public static ItemStack of(final Material material, final int amount) {
|
||||
+ return ItemStack.of(material, amount);
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
index 49b898ed5e9de2507a6a6aac61dea4fe902649ca..02745957a08a27af6a032453b8b20a8fed2911b3 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
@@ -689,6 +689,13 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
}
|
||||
// Paper end - hack to get tags for non server-backed registries
|
||||
|
||||
+ // Paper start - proxy ItemStack
|
||||
+ @Override
|
||||
+ public org.bukkit.inventory.ItemStack createEmptyStack() {
|
||||
+ return CraftItemStack.asCraftMirror(null);
|
||||
+ }
|
||||
+ // Paper end - proxy ItemStack
|
||||
+
|
||||
/**
|
||||
* This helper class represents the different NBT Tags.
|
||||
* <p>
|
||||
diff --git a/src/test/java/io/papermc/paper/configuration/ConfigurationSectionTest.java b/src/test/java/io/papermc/paper/configuration/ConfigurationSectionTest.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..ed45bfa577579afcbd54d655c3b5d05d6c6f3e86
|
||||
--- /dev/null
|
||||
+++ b/src/test/java/io/papermc/paper/configuration/ConfigurationSectionTest.java
|
||||
@@ -0,0 +1,53 @@
|
||||
+package io.papermc.paper.configuration;
|
||||
+
|
||||
+import org.bukkit.Material;
|
||||
+import org.bukkit.configuration.ConfigurationSection;
|
||||
+import org.bukkit.inventory.ItemStack;
|
||||
+import org.bukkit.support.environment.VanillaFeature;
|
||||
+import org.junit.jupiter.api.Test;
|
||||
+
|
||||
+import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
+import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
+import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
+import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
+
|
||||
+public abstract class ConfigurationSectionTest {
|
||||
+ public abstract ConfigurationSection getConfigurationSection();
|
||||
+
|
||||
+ @Test
|
||||
+ public void testGetItemStack_String() {
|
||||
+ ConfigurationSection section = getConfigurationSection();
|
||||
+ String key = "exists";
|
||||
+ ItemStack value = new ItemStack(Material.ACACIA_WOOD, 50);
|
||||
+
|
||||
+ section.set(key, value);
|
||||
+
|
||||
+ assertEquals(value, section.getItemStack(key));
|
||||
+ assertNull(section.getString("doesntExist"));
|
||||
+ }
|
||||
+
|
||||
+ @Test
|
||||
+ public void testGetItemStack_String_ItemStack() {
|
||||
+ ConfigurationSection section = getConfigurationSection();
|
||||
+ String key = "exists";
|
||||
+ ItemStack value = new ItemStack(Material.ACACIA_WOOD, 50);
|
||||
+ ItemStack def = new ItemStack(Material.STONE, 1);
|
||||
+
|
||||
+ section.set(key, value);
|
||||
+
|
||||
+ assertEquals(value, section.getItemStack(key, def));
|
||||
+ assertEquals(def, section.getItemStack("doesntExist", def));
|
||||
+ }
|
||||
+
|
||||
+ @Test
|
||||
+ public void testIsItemStack() {
|
||||
+ ConfigurationSection section = getConfigurationSection();
|
||||
+ String key = "exists";
|
||||
+ ItemStack value = new ItemStack(Material.ACACIA_WOOD, 50);
|
||||
+
|
||||
+ section.set(key, value);
|
||||
+
|
||||
+ assertTrue(section.isItemStack(key));
|
||||
+ assertFalse(section.isItemStack("doesntExist"));
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/test/java/io/papermc/paper/configuration/MemorySectionTest.java b/src/test/java/io/papermc/paper/configuration/MemorySectionTest.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..c00085328ce8a00fc274632a556ab27660fa57ed
|
||||
--- /dev/null
|
||||
+++ b/src/test/java/io/papermc/paper/configuration/MemorySectionTest.java
|
||||
@@ -0,0 +1,13 @@
|
||||
+package io.papermc.paper.configuration;
|
||||
+
|
||||
+import org.bukkit.configuration.ConfigurationSection;
|
||||
+import org.bukkit.configuration.MemoryConfiguration;
|
||||
+import org.bukkit.support.environment.Normal;
|
||||
+
|
||||
+@Normal
|
||||
+public class MemorySectionTest extends ConfigurationSectionTest {
|
||||
+ @Override
|
||||
+ public ConfigurationSection getConfigurationSection() {
|
||||
+ return new MemoryConfiguration().createSection("section");
|
||||
+ }
|
||||
+}
|
|
@ -0,0 +1,271 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Wed, 12 Jun 2024 10:29:40 -0700
|
||||
Subject: [PATCH] Make a PDC view accessible directly from ItemStack
|
||||
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/persistence/PaperPersistentDataContainerView.java b/src/main/java/io/papermc/paper/persistence/PaperPersistentDataContainerView.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..122c32e82b299cafd7d0c6a9f4818523470c9f05
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/persistence/PaperPersistentDataContainerView.java
|
||||
@@ -0,0 +1,120 @@
|
||||
+package io.papermc.paper.persistence;
|
||||
+
|
||||
+import com.google.common.base.Preconditions;
|
||||
+import java.io.ByteArrayOutputStream;
|
||||
+import java.io.DataOutputStream;
|
||||
+import java.io.IOException;
|
||||
+import java.util.Collections;
|
||||
+import java.util.HashSet;
|
||||
+import java.util.Set;
|
||||
+import net.minecraft.nbt.CompoundTag;
|
||||
+import net.minecraft.nbt.NbtIo;
|
||||
+import net.minecraft.nbt.Tag;
|
||||
+import org.bukkit.NamespacedKey;
|
||||
+import org.bukkit.craftbukkit.persistence.CraftPersistentDataAdapterContext;
|
||||
+import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer;
|
||||
+import org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry;
|
||||
+import org.bukkit.persistence.PersistentDataAdapterContext;
|
||||
+import org.bukkit.persistence.PersistentDataContainer;
|
||||
+import org.bukkit.persistence.PersistentDataType;
|
||||
+import org.jspecify.annotations.NullMarked;
|
||||
+import org.jspecify.annotations.Nullable;
|
||||
+
|
||||
+@NullMarked
|
||||
+public abstract class PaperPersistentDataContainerView implements PersistentDataContainerView {
|
||||
+
|
||||
+ protected final CraftPersistentDataTypeRegistry registry;
|
||||
+ protected final CraftPersistentDataAdapterContext adapterContext;
|
||||
+
|
||||
+ public PaperPersistentDataContainerView(final CraftPersistentDataTypeRegistry registry) {
|
||||
+ this.registry = registry;
|
||||
+ this.adapterContext = new CraftPersistentDataAdapterContext(this.registry);
|
||||
+ }
|
||||
+
|
||||
+ public abstract @Nullable Tag getTag(final String key);
|
||||
+
|
||||
+ public abstract CompoundTag toTagCompound();
|
||||
+
|
||||
+ @Override
|
||||
+ public <P, C> boolean has(final NamespacedKey key, final PersistentDataType<P, C> type) {
|
||||
+ Preconditions.checkArgument(key != null, "The NamespacedKey key cannot be null");
|
||||
+ Preconditions.checkArgument(type != null, "The provided type cannot be null");
|
||||
+
|
||||
+ final Tag value = this.getTag(key.toString());
|
||||
+ if (value == null) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ return this.registry.isInstanceOf(type, value);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean has(final NamespacedKey key) {
|
||||
+ Preconditions.checkArgument(key != null, "The provided key for the custom value was null"); // Paper
|
||||
+ return this.getTag(key.toString()) != null;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <P, C> @Nullable C get(final NamespacedKey key, final PersistentDataType<P, C> type) {
|
||||
+ Preconditions.checkArgument(key != null, "The NamespacedKey key cannot be null");
|
||||
+ Preconditions.checkArgument(type != null, "The provided type cannot be null");
|
||||
+
|
||||
+ final Tag value = this.getTag(key.toString());
|
||||
+ if (value == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ return type.fromPrimitive(this.registry.extract(type, value), this.adapterContext);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <P, C> C getOrDefault(final NamespacedKey key, final PersistentDataType<P, C> type, final C defaultValue) {
|
||||
+ final C c = this.get(key, type);
|
||||
+ return c != null ? c : defaultValue;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Set<NamespacedKey> getKeys() {
|
||||
+ final Set<String> names = this.toTagCompound().getAllKeys();
|
||||
+ final Set<NamespacedKey> keys = new HashSet<>(names.size());
|
||||
+ names.forEach(key -> {
|
||||
+ final String[] keyPart = key.split(":", 2);
|
||||
+ if (keyPart.length == 2) {
|
||||
+ keys.add(new NamespacedKey(keyPart[0], keyPart[1]));
|
||||
+ }
|
||||
+ });
|
||||
+ return Collections.unmodifiableSet(keys);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isEmpty() {
|
||||
+ return this.toTagCompound().isEmpty();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void copyTo(final PersistentDataContainer other, final boolean replace) {
|
||||
+ Preconditions.checkArgument(other != null, "The target container cannot be null");
|
||||
+ final CraftPersistentDataContainer target = (CraftPersistentDataContainer) other;
|
||||
+ final CompoundTag tag = this.toTagCompound();
|
||||
+ for (final String key : tag.getAllKeys()) {
|
||||
+ if (replace || !target.getRaw().containsKey(key)) {
|
||||
+ target.getRaw().put(key, tag.get(key).copy());
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public PersistentDataAdapterContext getAdapterContext() {
|
||||
+ return this.adapterContext;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public byte[] serializeToBytes() throws IOException {
|
||||
+ final CompoundTag root = this.toTagCompound();
|
||||
+ final ByteArrayOutputStream byteArrayOutput = new ByteArrayOutputStream();
|
||||
+ try (final DataOutputStream dataOutput = new DataOutputStream(byteArrayOutput)) {
|
||||
+ NbtIo.write(root, dataOutput);
|
||||
+ return byteArrayOutput.toByteArray();
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
||||
index 49d2deac8d42a505b75f2196ef895a5564b62cac..756c73a401437566258813946fa10c7caa8f2469 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
||||
@@ -496,4 +496,34 @@ public final class CraftItemStack extends ItemStack {
|
||||
return mirrored;
|
||||
}
|
||||
// Paper end
|
||||
+
|
||||
+ // Paper start - pdc
|
||||
+ private net.minecraft.nbt.CompoundTag getPdcTag() {
|
||||
+ if (this.handle == null) {
|
||||
+ return new net.minecraft.nbt.CompoundTag();
|
||||
+ }
|
||||
+ final net.minecraft.world.item.component.CustomData customData = this.handle.getOrDefault(DataComponents.CUSTOM_DATA, net.minecraft.world.item.component.CustomData.EMPTY);
|
||||
+ // getUnsafe is OK here because we are only ever *reading* the data so immutability is preserved
|
||||
+ //noinspection deprecation
|
||||
+ return customData.getUnsafe().getCompound("PublicBukkitValues");
|
||||
+ }
|
||||
+
|
||||
+ private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry();
|
||||
+ private final io.papermc.paper.persistence.PaperPersistentDataContainerView pdcView = new io.papermc.paper.persistence.PaperPersistentDataContainerView(REGISTRY) {
|
||||
+
|
||||
+ @Override
|
||||
+ public net.minecraft.nbt.CompoundTag toTagCompound() {
|
||||
+ return CraftItemStack.this.getPdcTag();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public net.minecraft.nbt.Tag getTag(final String key) {
|
||||
+ return CraftItemStack.this.getPdcTag().get(key);
|
||||
+ }
|
||||
+ };
|
||||
+ @Override
|
||||
+ public io.papermc.paper.persistence.PersistentDataContainerView getPersistentDataContainer() {
|
||||
+ return this.pdcView;
|
||||
+ }
|
||||
+ // Paper end - pdc
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
|
||||
index f55fdd57ced259ad5a95878840e98ffaa3db2e05..9d867f1659433ea15f281c8b441db7e339013100 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
|
||||
@@ -16,11 +16,10 @@ import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
-public class CraftPersistentDataContainer implements PersistentDataContainer {
|
||||
+public class CraftPersistentDataContainer extends io.papermc.paper.persistence.PaperPersistentDataContainerView implements PersistentDataContainer { // Paper - split up view and mutable
|
||||
|
||||
private final Map<String, Tag> customDataTags = new HashMap<>();
|
||||
- private final CraftPersistentDataTypeRegistry registry;
|
||||
- private final CraftPersistentDataAdapterContext adapterContext;
|
||||
+ // Paper - move to PersistentDataContainerView
|
||||
|
||||
public CraftPersistentDataContainer(Map<String, Tag> customTags, CraftPersistentDataTypeRegistry registry) {
|
||||
this(registry);
|
||||
@@ -28,10 +27,15 @@ public class CraftPersistentDataContainer implements PersistentDataContainer {
|
||||
}
|
||||
|
||||
public CraftPersistentDataContainer(CraftPersistentDataTypeRegistry registry) {
|
||||
- this.registry = registry;
|
||||
- this.adapterContext = new CraftPersistentDataAdapterContext(this.registry);
|
||||
+ super(registry); // Paper - move to PersistentDataContainerView
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public Tag getTag(final String key) {
|
||||
+ return this.customDataTags.get(key);
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
@Override
|
||||
public <T, Z> void set(@NotNull NamespacedKey key, @NotNull PersistentDataType<T, Z> type, @NotNull Z value) {
|
||||
@@ -42,44 +46,7 @@ public class CraftPersistentDataContainer implements PersistentDataContainer {
|
||||
this.customDataTags.put(key.toString(), this.registry.wrap(type, type.toPrimitive(value, this.adapterContext)));
|
||||
}
|
||||
|
||||
- @Override
|
||||
- public <T, Z> boolean has(@NotNull NamespacedKey key, @NotNull PersistentDataType<T, Z> type) {
|
||||
- Preconditions.checkArgument(key != null, "The NamespacedKey key cannot be null");
|
||||
- Preconditions.checkArgument(type != null, "The provided type cannot be null");
|
||||
-
|
||||
- Tag value = this.customDataTags.get(key.toString());
|
||||
- if (value == null) {
|
||||
- return false;
|
||||
- }
|
||||
-
|
||||
- return this.registry.isInstanceOf(type, value);
|
||||
- }
|
||||
-
|
||||
- @Override
|
||||
- public boolean has(NamespacedKey key) {
|
||||
- Preconditions.checkArgument(key != null, "The provided key for the custom value was null"); // Paper
|
||||
- return this.customDataTags.get(key.toString()) != null;
|
||||
- }
|
||||
-
|
||||
- @Override
|
||||
- public <T, Z> Z get(@NotNull NamespacedKey key, @NotNull PersistentDataType<T, Z> type) {
|
||||
- Preconditions.checkArgument(key != null, "The NamespacedKey key cannot be null");
|
||||
- Preconditions.checkArgument(type != null, "The provided type cannot be null");
|
||||
-
|
||||
- Tag value = this.customDataTags.get(key.toString());
|
||||
- if (value == null) {
|
||||
- return null;
|
||||
- }
|
||||
-
|
||||
- return type.fromPrimitive(this.registry.extract(type, value), this.adapterContext);
|
||||
- }
|
||||
-
|
||||
- @NotNull
|
||||
- @Override
|
||||
- public <T, Z> Z getOrDefault(@NotNull NamespacedKey key, @NotNull PersistentDataType<T, Z> type, @NotNull Z defaultValue) {
|
||||
- Z z = this.get(key, type);
|
||||
- return z != null ? z : defaultValue;
|
||||
- }
|
||||
+ // Paper - move to PersistentDataContainerView
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -186,16 +153,7 @@ public class CraftPersistentDataContainer implements PersistentDataContainer {
|
||||
// Paper end
|
||||
|
||||
// Paper start - byte array serialization
|
||||
- @Override
|
||||
- public byte[] serializeToBytes() throws java.io.IOException {
|
||||
- final net.minecraft.nbt.CompoundTag root = this.toTagCompound();
|
||||
- final java.io.ByteArrayOutputStream byteArrayOutput = new java.io.ByteArrayOutputStream();
|
||||
- try (final java.io.DataOutputStream dataOutput = new java.io.DataOutputStream(byteArrayOutput)) {
|
||||
- net.minecraft.nbt.NbtIo.write(root, dataOutput);
|
||||
- return byteArrayOutput.toByteArray();
|
||||
- }
|
||||
- }
|
||||
-
|
||||
+ // Paper - move to PersistentDataContainerView
|
||||
@Override
|
||||
public void readFromBytes(final byte[] bytes, final boolean clear) throws java.io.IOException {
|
||||
if (clear) {
|
|
@ -0,0 +1,135 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
|
||||
Date: Mon, 1 Jul 2024 11:58:49 -0700
|
||||
Subject: [PATCH] Prioritize Minecraft commands in function parsing and command
|
||||
blocks
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/mojang/brigadier/CommandDispatcher.java b/src/main/java/com/mojang/brigadier/CommandDispatcher.java
|
||||
index a4d5d7017e0be79844b996de85a63cad5f8488bc..770aec1976bd391eb5712b57b6c6a0290b4723a8 100644
|
||||
--- a/src/main/java/com/mojang/brigadier/CommandDispatcher.java
|
||||
+++ b/src/main/java/com/mojang/brigadier/CommandDispatcher.java
|
||||
@@ -298,7 +298,7 @@ public class CommandDispatcher<S> {
|
||||
List<ParseResults<S>> potentials = null;
|
||||
final int cursor = originalReader.getCursor();
|
||||
|
||||
- for (final CommandNode<S> child : node.getRelevantNodes(originalReader)) {
|
||||
+ for (final CommandNode<S> child : node.getRelevantNodes(originalReader, source)) { // Paper - prioritize mc commands in function parsing
|
||||
if (!child.canUse(source)) {
|
||||
continue;
|
||||
}
|
||||
diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java
|
||||
index 03ce8a2abb6dceaa922dcce7f3adbc228bbde4bc..dc76fcf4c6cc6cd65ce117b1855c15ede60f30ab 100644
|
||||
--- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java
|
||||
+++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java
|
||||
@@ -173,6 +173,12 @@ public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
|
||||
protected abstract String getSortedKey();
|
||||
|
||||
public Collection<? extends CommandNode<S>> getRelevantNodes(final StringReader input) {
|
||||
+ // Paper start - prioritize mc commands in function parsing
|
||||
+ return this.getRelevantNodes(input, null);
|
||||
+ }
|
||||
+ @org.jetbrains.annotations.ApiStatus.Internal
|
||||
+ public Collection<? extends CommandNode<S>> getRelevantNodes(final StringReader input, final Object source) {
|
||||
+ // Paper end - prioritize mc commands in function parsing
|
||||
if (this.literals.size() > 0) {
|
||||
final int cursor = input.getCursor();
|
||||
while (input.canRead() && input.peek() != ' ') {
|
||||
@@ -180,7 +186,21 @@ public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
|
||||
}
|
||||
final String text = input.getString().substring(cursor, input.getCursor());
|
||||
input.setCursor(cursor);
|
||||
- final LiteralCommandNode<S> literal = this.literals.get(text);
|
||||
+ // Paper start - prioritize mc commands in function parsing
|
||||
+ LiteralCommandNode<S> literal = null;
|
||||
+ if (source instanceof CommandSourceStack css && css.source == net.minecraft.commands.CommandSource.NULL) {
|
||||
+ if (!text.contains(":")) {
|
||||
+ literal = this.literals.get("minecraft:" + text);
|
||||
+ }
|
||||
+ } else if (source instanceof CommandSourceStack css && css.source instanceof net.minecraft.world.level.BaseCommandBlock) {
|
||||
+ if (css.getServer().server.getCommandBlockOverride(text) && !text.contains(":")) {
|
||||
+ literal = this.literals.get("minecraft:" + text);
|
||||
+ }
|
||||
+ }
|
||||
+ if (literal == null) {
|
||||
+ literal = this.literals.get(text);
|
||||
+ }
|
||||
+ // Paper end - prioritize mc commands in function parsing
|
||||
if (literal != null) {
|
||||
return Collections.singleton(literal);
|
||||
} else {
|
||||
diff --git a/src/main/java/com/mojang/brigadier/tree/LiteralCommandNode.java b/src/main/java/com/mojang/brigadier/tree/LiteralCommandNode.java
|
||||
index 85a890403645f0f9d381e85b48efcae126673945..bcc27fec043a57eb5064934c967982deff9cdee4 100644
|
||||
--- a/src/main/java/com/mojang/brigadier/tree/LiteralCommandNode.java
|
||||
+++ b/src/main/java/com/mojang/brigadier/tree/LiteralCommandNode.java
|
||||
@@ -23,11 +23,19 @@ import java.util.function.Predicate;
|
||||
public class LiteralCommandNode<S> extends CommandNode<S> {
|
||||
private final String literal;
|
||||
private final String literalLowerCase;
|
||||
+ private final String nonPrefixed; // Paper - prioritize mc commands in function parsing
|
||||
|
||||
public LiteralCommandNode(final String literal, final Command<S> command, final Predicate<S> requirement, final CommandNode<S> redirect, final RedirectModifier<S> modifier, final boolean forks) {
|
||||
super(command, requirement, redirect, modifier, forks);
|
||||
this.literal = literal;
|
||||
this.literalLowerCase = literal.toLowerCase(Locale.ROOT);
|
||||
+ // Paper start - prioritize mc commands in function parsing
|
||||
+ if (literal.startsWith("minecraft:")) {
|
||||
+ this.nonPrefixed = literal.substring("minecraft:".length());
|
||||
+ } else {
|
||||
+ this.nonPrefixed = null;
|
||||
+ }
|
||||
+ // Paper end - prioritize mc commands in function parsing
|
||||
}
|
||||
|
||||
public String getLiteral() {
|
||||
@@ -42,7 +50,12 @@ public class LiteralCommandNode<S> extends CommandNode<S> {
|
||||
@Override
|
||||
public void parse(final StringReader reader, final CommandContextBuilder<S> contextBuilder) throws CommandSyntaxException {
|
||||
final int start = reader.getCursor();
|
||||
- final int end = parse(reader);
|
||||
+ // Paper start - prioritize mc commands in function parsing
|
||||
+ int end = parse(reader, false);
|
||||
+ if (end == -1 && this.nonPrefixed != null) {
|
||||
+ end = parse(reader, true);
|
||||
+ }
|
||||
+ // Paper end - prioritize mc commands in function parsing
|
||||
if (end > -1) {
|
||||
contextBuilder.withNode(this, StringRange.between(start, end));
|
||||
return;
|
||||
@@ -51,7 +64,10 @@ public class LiteralCommandNode<S> extends CommandNode<S> {
|
||||
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.literalIncorrect().createWithContext(reader, literal);
|
||||
}
|
||||
|
||||
- private int parse(final StringReader reader) {
|
||||
+ // Paper start - prioritize mc commands in function parsing
|
||||
+ private int parse(final StringReader reader, final boolean secondPass) {
|
||||
+ String literal = secondPass ? this.nonPrefixed : this.literal;
|
||||
+ // Paper end - prioritize mc commands in function parsing
|
||||
final int start = reader.getCursor();
|
||||
if (reader.canRead(literal.length())) {
|
||||
final int end = start + literal.length();
|
||||
@@ -78,7 +94,7 @@ public class LiteralCommandNode<S> extends CommandNode<S> {
|
||||
|
||||
@Override
|
||||
public boolean isValidInput(final String input) {
|
||||
- return parse(new StringReader(input)) > -1;
|
||||
+ return parse(new StringReader(input), false) > -1; // Paper - prioritize mc commands in function parsing
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
|
||||
index 1e7b99a82184f73aa31cb2e0d4e52a806240926f..260350422fc724ba5cd5769cbb387b6007f36a84 100644
|
||||
--- a/src/main/java/net/minecraft/commands/Commands.java
|
||||
+++ b/src/main/java/net/minecraft/commands/Commands.java
|
||||
@@ -315,10 +315,7 @@ public class Commands {
|
||||
|
||||
// Paper - Fix permission levels for command blocks
|
||||
|
||||
- // Handle vanilla commands;
|
||||
- if (sender.getLevel().getCraftServer().getCommandBlockOverride(args[0])) {
|
||||
- args[0] = "minecraft:" + args[0];
|
||||
- }
|
||||
+ // Handle vanilla commands; // Paper - handled in CommandNode/CommandDispatcher
|
||||
|
||||
String newCommand = joiner.join(args);
|
||||
this.performPrefixedCommand(sender, newCommand, newCommand);
|
78
patches/server/0999-optimize-dirt-and-snow-spreading.patch
Normal file
78
patches/server/0999-optimize-dirt-and-snow-spreading.patch
Normal file
|
@ -0,0 +1,78 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: lukas81298 <lukas81298@gommehd.net>
|
||||
Date: Fri, 22 Jan 2021 21:50:18 +0100
|
||||
Subject: [PATCH] optimize dirt and snow spreading
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java b/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
|
||||
index b4b826c53548bcf6952f6d0ee8037975ceb8c6e1..a94c164fbf8fc3bb7669799a53f7e5528d921e7c 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
|
||||
@@ -18,8 +18,13 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
|
||||
}
|
||||
|
||||
private static boolean canBeGrass(BlockState state, LevelReader world, BlockPos pos) {
|
||||
+ // Paper start - Perf: optimize dirt and snow spreading
|
||||
+ return canBeGrass(world.getChunk(pos), state, world, pos);
|
||||
+ }
|
||||
+ private static boolean canBeGrass(net.minecraft.world.level.chunk.ChunkAccess chunk, BlockState state, LevelReader world, BlockPos pos) {
|
||||
+ // Paper end - Perf: optimize dirt and snow spreading
|
||||
BlockPos blockposition1 = pos.above();
|
||||
- BlockState iblockdata1 = world.getBlockState(blockposition1);
|
||||
+ BlockState iblockdata1 = chunk.getBlockState(blockposition1); // Paper - Perf: optimize dirt and snow spreading
|
||||
|
||||
if (iblockdata1.is(Blocks.SNOW) && (Integer) iblockdata1.getValue(SnowLayerBlock.LAYERS) == 1) {
|
||||
return true;
|
||||
@@ -36,15 +41,27 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
|
||||
protected abstract MapCodec<? extends SpreadingSnowyDirtBlock> codec();
|
||||
|
||||
private static boolean canPropagate(BlockState state, LevelReader world, BlockPos pos) {
|
||||
+ // Paper start - Perf: optimize dirt and snow spreading
|
||||
+ return canPropagate(world.getChunk(pos), state, world, pos);
|
||||
+ }
|
||||
+
|
||||
+ private static boolean canPropagate(net.minecraft.world.level.chunk.ChunkAccess chunk, BlockState state, LevelReader world, BlockPos pos) {
|
||||
+ // Paper end - Perf: optimize dirt and snow spreading
|
||||
BlockPos blockposition1 = pos.above();
|
||||
|
||||
- return SpreadingSnowyDirtBlock.canBeGrass(state, world, pos) && !world.getFluidState(blockposition1).is(FluidTags.WATER);
|
||||
+ return SpreadingSnowyDirtBlock.canBeGrass(chunk, state, world, pos) && !chunk.getFluidState(blockposition1).is(FluidTags.WATER); // Paper - Perf: optimize dirt and snow spreading
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
|
||||
if (this instanceof GrassBlock && world.paperConfig().tickRates.grassSpread != 1 && (world.paperConfig().tickRates.grassSpread < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % world.paperConfig().tickRates.grassSpread != 0)) { return; } // Paper - Configurable random tick rates for blocks
|
||||
- if (!SpreadingSnowyDirtBlock.canBeGrass(state, world, pos)) {
|
||||
+ // Paper start - Perf: optimize dirt and snow spreading
|
||||
+ final net.minecraft.world.level.chunk.ChunkAccess cachedBlockChunk = world.getChunkIfLoaded(pos);
|
||||
+ if (cachedBlockChunk == null) { // Is this needed?
|
||||
+ return;
|
||||
+ }
|
||||
+ if (!SpreadingSnowyDirtBlock.canBeGrass(cachedBlockChunk, state, world, pos)) {
|
||||
+ // Paper end - Perf: optimize dirt and snow spreading
|
||||
// CraftBukkit start
|
||||
if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, Blocks.DIRT.defaultBlockState()).isCancelled()) {
|
||||
return;
|
||||
@@ -57,9 +74,19 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
BlockPos blockposition1 = pos.offset(random.nextInt(3) - 1, random.nextInt(5) - 3, random.nextInt(3) - 1);
|
||||
-
|
||||
- if (world.getBlockState(blockposition1).is(Blocks.DIRT) && SpreadingSnowyDirtBlock.canPropagate(iblockdata1, world, blockposition1)) {
|
||||
- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition1, (BlockState) iblockdata1.setValue(SpreadingSnowyDirtBlock.SNOWY, world.getBlockState(blockposition1.above()).is(Blocks.SNOW))); // CraftBukkit
|
||||
+ // Paper start - Perf: optimize dirt and snow spreading
|
||||
+ if (pos.getX() == blockposition1.getX() && pos.getY() == blockposition1.getY() && pos.getZ() == blockposition1.getZ()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ net.minecraft.world.level.chunk.ChunkAccess access;
|
||||
+ if (cachedBlockChunk.locX == blockposition1.getX() >> 4 && cachedBlockChunk.locZ == blockposition1.getZ() >> 4) {
|
||||
+ access = cachedBlockChunk;
|
||||
+ } else {
|
||||
+ access = world.getChunkAt(blockposition1);
|
||||
+ }
|
||||
+ if (access.getBlockState(blockposition1).is(Blocks.DIRT) && SpreadingSnowyDirtBlock.canPropagate(access, iblockdata1, world, blockposition1)) {
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition1, (BlockState) iblockdata1.setValue(SpreadingSnowyDirtBlock.SNOWY, access.getBlockState(blockposition1.above()).is(Blocks.SNOW))); // CraftBukkit
|
||||
+ // Paper end - Perf: optimize dirt and snow spreading
|
||||
}
|
||||
}
|
||||
}
|
20
patches/server/1000-Fix-NPE-for-Jukebox-setRecord.patch
Normal file
20
patches/server/1000-Fix-NPE-for-Jukebox-setRecord.patch
Normal file
|
@ -0,0 +1,20 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Mon, 17 Jun 2024 17:41:09 -0700
|
||||
Subject: [PATCH] Fix NPE for Jukebox#setRecord
|
||||
|
||||
Fallback to the global registry if no level exists
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/JukeboxBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/JukeboxBlockEntity.java
|
||||
index 69fb6f5cfc8654995d7c78e8f7e9470b601e8ec7..c3bbe5e9e0cc37f3f22fc1d839fa2652966f1266 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/JukeboxBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/JukeboxBlockEntity.java
|
||||
@@ -199,7 +199,7 @@ public class JukeboxBlockEntity extends BlockEntity implements ContainerSingleIt
|
||||
public void setSongItemWithoutPlaying(ItemStack itemstack, long ticksSinceSongStarted) { // CraftBukkit - add argument
|
||||
this.item = itemstack;
|
||||
this.jukeboxSongPlayer.song = null; // CraftBukkit - reset
|
||||
- JukeboxSong.fromStack(this.level.registryAccess(), itemstack).ifPresent((holder) -> {
|
||||
+ JukeboxSong.fromStack(this.level != null ? this.level.registryAccess() : org.bukkit.craftbukkit.CraftRegistry.getMinecraftRegistry(), itemstack).ifPresent((holder) -> { // Paper - fallback to other RegistyrAccess if no level
|
||||
this.jukeboxSongPlayer.setSongWithoutPlaying(holder, ticksSinceSongStarted); // CraftBukkit - add argument
|
||||
});
|
||||
// CraftBukkit start - add null check for level
|
Loading…
Add table
Add a link
Reference in a new issue