This commit is contained in:
@ -15,7 +15,7 @@ plugins {
|
||||
val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/"
|
||||
|
||||
dependencies {
|
||||
mache("io.papermc:mache:1.21.5+build.1")
|
||||
mache("io.papermc:mache:1.21.5+build.2")
|
||||
paperclip("io.papermc:paperclip:3.0.3")
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||
}
|
||||
@ -135,7 +135,7 @@ dependencies {
|
||||
implementation("org.jline:jline-terminal-ffm:3.27.1") // use ffm on java 22+
|
||||
implementation("org.jline:jline-terminal-jni:3.27.1") // fall back to jni on java 21
|
||||
implementation("net.minecrell:terminalconsoleappender:1.3.0")
|
||||
implementation("io.papermc.adventure:adventure-text-serializer-ansi:4.21.0-mc1215-SNAPSHOT") // Keep in sync with adventureVersion from Paper-API build file // FIXME back to release
|
||||
implementation("net.kyori:adventure-text-serializer-ansi:4.21.0") // Keep in sync with adventureVersion from Paper-API build file
|
||||
runtimeConfiguration(sourceSets.main.map { it.runtimeClasspath })
|
||||
|
||||
/*
|
||||
|
||||
@ -143,7 +143,7 @@ index 3a384175f8e7f204234bbaf3081bdc20c47a0d4b..5699bc15eba92e22433a20cb8326b59f
|
||||
|
||||
private ClientboundLevelChunkWithLightPacket(RegistryFriendlyByteBuf buffer) {
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index ef201f4add358fbf1818f3b2ec9e75fe2cce4c8b..fe9b4484d683fe48f435a053c9c90557fdf80e7b 100644
|
||||
index 6b67cc939851745718f919488c997eb6719a16fc..085040aa98704f2874bcd95b751b0a81dcdb15ad 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -343,7 +343,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@ -186,7 +186,7 @@ index 342bc843c384761e883de861044f4f8930ae8763..14878690a88fd4de3e2c127086607e6c
|
||||
if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
||||
new io.papermc.paper.event.packet.PlayerChunkLoadEvent(new org.bukkit.craftbukkit.CraftChunk(chunk), packetListener.getPlayer().getBukkitEntity()).callEvent();
|
||||
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||
index a2a4dbcfb77d44657b3dfbe97cb629de215c29eb..73717609fccd9af12e2cc39824106f49426b581c 100644
|
||||
index 9b2ee3e16e2c443e8ff03faec59dd55d729e9274..5ec9e3b37e575e9805bf9f0ce5cae5c1284461d8 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -407,7 +407,7 @@ public abstract class PlayerList {
|
||||
@ -199,7 +199,7 @@ index a2a4dbcfb77d44657b3dfbe97cb629de215c29eb..73717609fccd9af12e2cc39824106f49
|
||||
}
|
||||
// Paper end - Send empty chunk
|
||||
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||
index 1f26826b2161cfeb27e5b2060e178b493e9142d9..63f8b0c47e3321b74f4b6bcbc1e28cd751911198 100644
|
||||
index 1bb40f18b671d63719d96a58ff283767c2cfe383..ba50f21707a69bbf720345996d7c83d2064e5246 100644
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
+++ b/net/minecraft/world/level/Level.java
|
||||
@@ -132,6 +132,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
||||
@ -209,10 +209,10 @@ index 1f26826b2161cfeb27e5b2060e178b493e9142d9..63f8b0c47e3321b74f4b6bcbc1e28cd7
|
||||
+ public final io.papermc.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
|
||||
private final CraftWorld world;
|
||||
public boolean pvpMode;
|
||||
public org.bukkit.generator.ChunkGenerator generator;
|
||||
public @Nullable org.bukkit.generator.ChunkGenerator generator;
|
||||
@@ -201,7 +202,8 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
||||
org.bukkit.generator.BiomeProvider biomeProvider, // CraftBukkit
|
||||
org.bukkit.World.Environment env, // CraftBukkit
|
||||
@Nullable org.bukkit.generator.BiomeProvider biomeProvider, // Paper
|
||||
org.bukkit.World.Environment environment, // Paper
|
||||
java.util.function.Function<org.spigotmc.SpigotWorldConfig, // Spigot - create per world config
|
||||
- io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator // Paper - create paper world config
|
||||
+ io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, // Paper - create paper world config
|
||||
|
||||
@ -3874,10 +3874,10 @@ index 0000000000000000000000000000000000000000..1c82dcd38f789707e15e8cbec72ef9cd
|
||||
+}
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..7554c109c35397bc1a43dd80e87764fd78645bbf
|
||||
index 0000000000000000000000000000000000000000..2d24d03bbdb5ee0d862cbfff2219f58afffafe12
|
||||
--- /dev/null
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java
|
||||
@@ -0,0 +1,1002 @@
|
||||
@@ -0,0 +1,1006 @@
|
||||
+package ca.spottedleaf.moonrise.patches.chunk_system.level.entity;
|
||||
+
|
||||
+import ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable;
|
||||
@ -4059,6 +4059,10 @@ index 0000000000000000000000000000000000000000..7554c109c35397bc1a43dd80e87764fd
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public Iterable<Entity> getAllMapped() {
|
||||
+ return this.entityByUUID.values();
|
||||
+ }
|
||||
+
|
||||
+ public int getEntityCount() {
|
||||
+ synchronized (this.accessibleEntities) {
|
||||
+ return this.accessibleEntities.size();
|
||||
@ -26798,7 +26802,7 @@ index c50a1a01d167696134bd65b2d28db323d81d6ebd..5d63bf024cbcbd2f627c64fee77553c9
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java
|
||||
index 3f83a589442a80e9c16b5e9cd0f50792defd12bc..0005a1784ccaa00e5d6d67e7be98445150487982 100644
|
||||
index 69fbcd734c269bbc9858b0ad0b3b268ddb81fcc6..a1ae77b70f69852d9e4332bf1cb3409c33b21de0 100644
|
||||
--- a/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -104,6 +104,11 @@ public class ServerEntity {
|
||||
@ -26814,7 +26818,7 @@ index 3f83a589442a80e9c16b5e9cd0f50792defd12bc..0005a1784ccaa00e5d6d67e7be984451
|
||||
if (!passengers.equals(this.lastPassengers)) {
|
||||
List<UUID> list = this.mountedOrDismounted(passengers).map(Entity::getUUID).toList();
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index fe9b4484d683fe48f435a053c9c90557fdf80e7b..8afe96bfdc37e57129f1bb4af5b6d5cc22c11aee 100644
|
||||
index 085040aa98704f2874bcd95b751b0a81dcdb15ad..cd72273468f596b640bd2d10d846fbe8813846a6 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -166,7 +166,7 @@ import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
@ -27565,10 +27569,10 @@ index fe9b4484d683fe48f435a053c9c90557fdf80e7b..8afe96bfdc37e57129f1bb4af5b6d5cc
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index a8c73bdf8fb130eed8922cb537a35cda07e66da5..3e73c69c9db8cbded28a001b20d9989acb11c638 100644
|
||||
index 57af8cd7629fa14176c6e7a29956617ec9506999..63fecebe6048b0d3372ea84ac74dc74744de3273 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -187,7 +187,7 @@ import net.minecraft.world.scores.Team;
|
||||
@@ -186,7 +186,7 @@ import net.minecraft.world.scores.Team;
|
||||
import net.minecraft.world.scores.criteria.ObjectiveCriteria;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
@ -27577,7 +27581,7 @@ index a8c73bdf8fb130eed8922cb537a35cda07e66da5..3e73c69c9db8cbded28a001b20d9989a
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32;
|
||||
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10;
|
||||
@@ -423,6 +423,36 @@ public class ServerPlayer extends Player {
|
||||
@@ -415,6 +415,36 @@ public class ServerPlayer extends Player {
|
||||
public @Nullable String clientBrandName = null; // Paper - Brand support
|
||||
public @Nullable org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - Add API for quit reason; there are a lot of changes to do if we change all methods leading to the event
|
||||
|
||||
@ -28202,10 +28206,10 @@ index b30f56fbc1fd17259a1d05dc9155fffcab292ca1..11fed81a4696ba18440e755c3b8a5ca3
|
||||
this.generatingStep = generatingStep;
|
||||
this.cache = cache;
|
||||
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||
index 5ec9e3b37e575e9805bf9f0ce5cae5c1284461d8..78201407a37eced73998b97d5d5c412eaba69af1 100644
|
||||
index eda176c96bcf3d67650722ffce33863edfbdea9e..a7a07ebe6ceed99fa768b6834e350fe2f51a6950 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -1320,7 +1320,7 @@ public abstract class PlayerList {
|
||||
@@ -1332,7 +1332,7 @@ public abstract class PlayerList {
|
||||
|
||||
public void setViewDistance(int viewDistance) {
|
||||
this.viewDistance = viewDistance;
|
||||
@ -28214,7 +28218,7 @@ index 5ec9e3b37e575e9805bf9f0ce5cae5c1284461d8..78201407a37eced73998b97d5d5c412e
|
||||
|
||||
for (ServerLevel serverLevel : this.server.getAllLevels()) {
|
||||
if (serverLevel != null) {
|
||||
@@ -1331,7 +1331,7 @@ public abstract class PlayerList {
|
||||
@@ -1343,7 +1343,7 @@ public abstract class PlayerList {
|
||||
|
||||
public void setSimulationDistance(int simulationDistance) {
|
||||
this.simulationDistance = simulationDistance;
|
||||
@ -28597,7 +28601,7 @@ index 8cc5c0716392ba06501542ff5cbe71ee43979e5d..09fd99c9cbd23b5f3c899bfb00c9b896
|
||||
+ // Paper end - block counting
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 24f3fa347c889b4e2b7b2ce69cda0f68e9bbc346..48477efbd01bb1f8987d9a3ae195710e36b7294f 100644
|
||||
index 663fb13233afb51f935c30ac2acae808809754c6..81a18b8e605bd4c28b48a32c80be231609182970 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -140,7 +140,7 @@ import net.minecraft.world.scores.ScoreHolder;
|
||||
@ -28950,7 +28954,7 @@ index 24f3fa347c889b4e2b7b2ce69cda0f68e9bbc346..48477efbd01bb1f8987d9a3ae195710e
|
||||
}
|
||||
|
||||
private static float[] collectCandidateStepUpHeights(AABB box, List<VoxelShape> colliders, float deltaY, float maxUpStep) {
|
||||
@@ -2599,21 +2747,110 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
@@ -2616,21 +2764,110 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
|
||||
public boolean isInWall() {
|
||||
@ -29072,7 +29076,7 @@ index 24f3fa347c889b4e2b7b2ce69cda0f68e9bbc346..48477efbd01bb1f8987d9a3ae195710e
|
||||
}
|
||||
|
||||
public InteractionResult interact(Player player, InteractionHand hand) {
|
||||
@@ -4061,15 +4298,17 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
@@ -4078,15 +4315,17 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
|
||||
public Iterable<Entity> getIndirectPassengers() {
|
||||
@ -29098,7 +29102,7 @@ index 24f3fa347c889b4e2b7b2ce69cda0f68e9bbc346..48477efbd01bb1f8987d9a3ae195710e
|
||||
}
|
||||
|
||||
public int countPlayerPassengers() {
|
||||
@@ -4212,77 +4451,136 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
@@ -4229,77 +4468,136 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
return Mth.lerp(partialTick, this.yRotO, this.yRot);
|
||||
}
|
||||
|
||||
@ -29289,7 +29293,7 @@ index 24f3fa347c889b4e2b7b2ce69cda0f68e9bbc346..48477efbd01bb1f8987d9a3ae195710e
|
||||
|
||||
public boolean touchingUnloadedChunk() {
|
||||
AABB aabb = this.getBoundingBox().inflate(1.0);
|
||||
@@ -4437,6 +4735,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
@@ -4454,6 +4752,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
|
||||
public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) {
|
||||
@ -29305,7 +29309,7 @@ index 24f3fa347c889b4e2b7b2ce69cda0f68e9bbc346..48477efbd01bb1f8987d9a3ae195710e
|
||||
if (!checkPosition(this, x, y, z)) {
|
||||
return;
|
||||
}
|
||||
@@ -4570,6 +4877,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
@@ -4587,6 +4894,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
||||
@Override
|
||||
public final void setRemoved(Entity.RemovalReason removalReason, @Nullable org.bukkit.event.entity.EntityRemoveEvent.Cause cause) { // CraftBukkit - add Bukkit remove cause
|
||||
@ -29318,7 +29322,7 @@ index 24f3fa347c889b4e2b7b2ce69cda0f68e9bbc346..48477efbd01bb1f8987d9a3ae195710e
|
||||
org.bukkit.craftbukkit.event.CraftEventFactory.callEntityRemoveEvent(this, cause); // CraftBukkit
|
||||
final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers
|
||||
if (this.removalReason == null) {
|
||||
@@ -4580,7 +4893,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
@@ -4597,7 +4910,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
this.stopRiding();
|
||||
}
|
||||
|
||||
@ -29327,7 +29331,7 @@ index 24f3fa347c889b4e2b7b2ce69cda0f68e9bbc346..48477efbd01bb1f8987d9a3ae195710e
|
||||
this.levelCallback.onRemove(removalReason);
|
||||
this.onRemoval(removalReason);
|
||||
// Paper start - Folia schedulers
|
||||
@@ -4614,7 +4927,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
@@ -4631,7 +4944,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
public boolean shouldBeSaved() {
|
||||
return (this.removalReason == null || this.removalReason.shouldSave())
|
||||
&& !this.isPassenger()
|
||||
@ -29576,7 +29580,7 @@ index b766b4281aecb3b96e2c263664d81da3425e3653..c3bcb494afe464207e805f8c40b03c70
|
||||
this(setDirty, true, ImmutableList.of());
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/decoration/ArmorStand.java b/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
index 75bf15ccd8a12153951f886ed87be9f3bece3133..6f601a0a300bbf01f77d835576d15e25c8ba10b8 100644
|
||||
index f5ce8151bb1bae9be638ced7f74899d452d517e1..5248f3c22abb608d7d7b338f169f13bfbf4cd2d6 100644
|
||||
--- a/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
+++ b/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
@@ -245,7 +245,7 @@ public class ArmorStand extends LivingEntity {
|
||||
@ -29725,7 +29729,7 @@ index 300f3ed58109219d97846082941b860585f66fed..892a7c1eb1b321ca6d5ca709142e7fea
|
||||
|
||||
// Paper start - Affects Spawning API
|
||||
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||
index 63f8b0c47e3321b74f4b6bcbc1e28cd751911198..eb4d03cfdb34243901cfba832d35559d5be9e876 100644
|
||||
index ba50f21707a69bbf720345996d7c83d2064e5246..e9751a95ffd88f365185d53f8764291d9d2473e2 100644
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
+++ b/net/minecraft/world/level/Level.java
|
||||
@@ -81,6 +81,7 @@ import net.minecraft.world.level.storage.LevelData;
|
||||
@ -30399,7 +30403,7 @@ index 63f8b0c47e3321b74f4b6bcbc1e28cd751911198..eb4d03cfdb34243901cfba832d35559d
|
||||
+ // Paper end - getblock optimisations - cache world height/sections
|
||||
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName()); // Spigot
|
||||
this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config
|
||||
this.generator = gen;
|
||||
this.generator = generator;
|
||||
@@ -281,6 +914,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
||||
});
|
||||
// CraftBukkit end
|
||||
|
||||
@ -50,7 +50,7 @@ index 094ef7f54ad71795a2d8c2a8d03a32bef6ff2164..79bc1b7d9f640d2322814177eb3e921d
|
||||
ProfilerFiller profilerFiller = Profiler.get();
|
||||
this.runAllTasks(); // Paper - move runAllTasks() into full server tick (previously for timings)
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 32db2b9e375c12cbf7abab69cc01e8ac2c7c3b6e..d50d2928ad9f8b34a14621b1fe5c188547e04bd1 100644
|
||||
index 32c8d4675de341d5edad7dbd9c0bf4bce5037733..bfbfbaa9660d21071c420b60b10be0a02a1bc87e 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1317,6 +1317,28 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@ -64,7 +64,7 @@ index 32db2b9e375c12cbf7abab69cc01e8ac2c7c3b6e..d50d2928ad9f8b34a14621b1fe5c1885
|
||||
+ }
|
||||
+
|
||||
+ if (doFull) {
|
||||
+ this.saveLevelData(true);
|
||||
+ this.saveLevelData(false);
|
||||
+ }
|
||||
+ // chunk autosave is already called by the ChunkSystem during unload processing (ChunkMap#processUnloads)
|
||||
+ // Copied from save()
|
||||
@ -83,10 +83,10 @@ index 32db2b9e375c12cbf7abab69cc01e8ac2c7c3b6e..d50d2928ad9f8b34a14621b1fe5c1885
|
||||
// Paper start - add close param
|
||||
this.save(progress, flush, skipSave, false);
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index 3e73c69c9db8cbded28a001b20d9989acb11c638..d1de5aff81da465be79f2f747466734e80ec50dc 100644
|
||||
index 5a60f2598560571e156612bf256c1c340d92a922..57e7d0a8b5f2a5bc65b0f290fb655625b1481f31 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -189,6 +189,7 @@ import org.slf4j.Logger;
|
||||
@@ -188,6 +188,7 @@ import org.slf4j.Logger;
|
||||
|
||||
public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer { // Paper - rewrite chunk system
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
@ -95,7 +95,7 @@ index 3e73c69c9db8cbded28a001b20d9989acb11c638..d1de5aff81da465be79f2f747466734e
|
||||
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10;
|
||||
private static final int FLY_STAT_RECORDING_SPEED = 25;
|
||||
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||
index 78201407a37eced73998b97d5d5c412eaba69af1..f057e682ccd378f11710dc2e7129cba95788bb18 100644
|
||||
index a7a07ebe6ceed99fa768b6834e350fe2f51a6950..9ca3c55a3b5b1a532b86b08eb92460df4cb54f2a 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -486,6 +486,7 @@ public abstract class PlayerList {
|
||||
@ -106,7 +106,7 @@ index 78201407a37eced73998b97d5d5c412eaba69af1..f057e682ccd378f11710dc2e7129cba9
|
||||
this.playerIo.save(player);
|
||||
ServerStatsCounter serverStatsCounter = player.getStats(); // CraftBukkit
|
||||
if (serverStatsCounter != null) {
|
||||
@@ -1067,9 +1068,23 @@ public abstract class PlayerList {
|
||||
@@ -1079,9 +1080,23 @@ public abstract class PlayerList {
|
||||
}
|
||||
|
||||
public void saveAll() {
|
||||
|
||||
@ -78,10 +78,10 @@ index 5d63bf024cbcbd2f627c64fee77553c9a512bd15..f863377a807b672f49f7140688f378ec
|
||||
profiler.popPush("tickSpawningChunks");
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index 8e7ee4dc951eb53ccf65ab71214a0b89bd932ba0..73a450e045eba5dbfc7a4e861e4c614c8f60d6b4 100644
|
||||
index 4b2801749328f250ce5735fbe7f6941a6bede01a..af04fcdba1e57b4eac678235b56ad3e1c70169b7 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -403,6 +403,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
@@ -395,6 +395,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
public boolean queueHealthUpdatePacket;
|
||||
public @Nullable net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket;
|
||||
// Paper end - cancellable death event
|
||||
|
||||
@ -60,10 +60,10 @@ index f863377a807b672f49f7140688f378eca2cf650b..59e8a5e1b35c81883c9b1ca00c6e55d7
|
||||
spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true);
|
||||
} else {
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index 73a450e045eba5dbfc7a4e861e4c614c8f60d6b4..105d6b3a40067f9e8ae5bbd9f2872171f73b3d07 100644
|
||||
index af04fcdba1e57b4eac678235b56ad3e1c70169b7..3781d9cc174b7aecacb9b9855d52c7b1ff05835c 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -407,6 +407,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
@@ -399,6 +399,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
public static final int MOBCATEGORY_TOTAL_ENUMS = net.minecraft.world.entity.MobCategory.values().length;
|
||||
public final int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS];
|
||||
// Paper end - Optional per player mob spawns
|
||||
@ -72,7 +72,7 @@ index 73a450e045eba5dbfc7a4e861e4c614c8f60d6b4..105d6b3a40067f9e8ae5bbd9f2872171
|
||||
public org.bukkit.craftbukkit.entity.CraftPlayer.TransferCookieConnection transferCookieConnection;
|
||||
public String displayName;
|
||||
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
|
||||
index 17b13baa3465530b11ff918c806c772eb5c39a2c..afd6da5c361e1dcf311a9afe8a7efe2faef2556a 100644
|
||||
index c710e08ab48075ce7854e56826adb8f0364b025b..14a2514a408a66a83f7b5fb43b4c4dc8f23fd5f4 100644
|
||||
--- a/net/minecraft/world/level/NaturalSpawner.java
|
||||
+++ b/net/minecraft/world/level/NaturalSpawner.java
|
||||
@@ -279,6 +279,11 @@ public final class NaturalSpawner {
|
||||
|
||||
@ -6,7 +6,7 @@ Subject: [PATCH] Optimise collision checking in player move packet handling
|
||||
Move collision logic to just the hasNewCollision call instead of getCubes + hasNewCollision
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 5e921c490814be31fc2843327c0e2cc76bda6620..f49a2c18ec20a7181951389066b7d062b48d43fa 100644
|
||||
index 0be741820fc7da2aac4f4aad85c4238ef49a0f57..337976c5c1ead87c36daa4e741b06e5a195b8302 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -555,7 +555,7 @@ public class ServerGamePacketListenerImpl
|
||||
@ -88,7 +88,7 @@ index 5e921c490814be31fc2843327c0e2cc76bda6620..f49a2c18ec20a7181951389066b7d062
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1430,7 +1462,7 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -1432,7 +1464,7 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,7 +97,7 @@ index 5e921c490814be31fc2843327c0e2cc76bda6620..f49a2c18ec20a7181951389066b7d062
|
||||
d3 = d - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above
|
||||
d4 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above
|
||||
d5 = d2 - this.lastGoodZ; // Paper - diff on change, used for checking large move vectors above
|
||||
@@ -1469,6 +1501,7 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -1471,6 +1503,7 @@ public class ServerGamePacketListenerImpl
|
||||
boolean flag1 = this.player.verticalCollisionBelow;
|
||||
this.player.move(MoverType.PLAYER, new Vec3(d3, d4, d5));
|
||||
this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
|
||||
@ -105,7 +105,7 @@ index 5e921c490814be31fc2843327c0e2cc76bda6620..f49a2c18ec20a7181951389066b7d062
|
||||
// Paper start - prevent position desync
|
||||
if (this.awaitingPositionFromClient != null) {
|
||||
return; // ... thanks Mojang for letting move calls teleport across dimensions.
|
||||
@@ -1501,7 +1534,17 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -1503,7 +1536,17 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
|
||||
// Paper start - Add fail move event
|
||||
@ -124,7 +124,7 @@ index 5e921c490814be31fc2843327c0e2cc76bda6620..f49a2c18ec20a7181951389066b7d062
|
||||
if (teleportBack) {
|
||||
io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.CLIPPED_INTO_BLOCK,
|
||||
toX, toY, toZ, toYaw, toPitch, false);
|
||||
@@ -1638,7 +1681,7 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -1640,7 +1683,7 @@ public class ServerGamePacketListenerImpl
|
||||
|
||||
private boolean updateAwaitingTeleport() {
|
||||
if (this.awaitingPositionFromClient != null) {
|
||||
@ -133,7 +133,7 @@ index 5e921c490814be31fc2843327c0e2cc76bda6620..f49a2c18ec20a7181951389066b7d062
|
||||
this.awaitingTeleportTime = this.tickCount;
|
||||
this.teleport(
|
||||
this.awaitingPositionFromClient.x,
|
||||
@@ -1657,6 +1700,33 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -1659,6 +1702,33 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
+ public CommandNode<net.minecraft.commands.CommandSourceStack> clientNode; // Paper - Brigadier API
|
||||
+ public CommandNode<io.papermc.paper.command.brigadier.CommandSourceStack> unwrappedCached = null; // Paper - Brigadier Command API
|
||||
+ public CommandNode<io.papermc.paper.command.brigadier.CommandSourceStack> wrappedCached = null; // Paper - Brigadier Command API
|
||||
+ public io.papermc.paper.command.brigadier.PluginCommandMeta pluginCommandMeta; // Paper - Brigadier Command API
|
||||
+ public io.papermc.paper.command.brigadier.APICommandMeta apiCommandMeta; // Paper - Brigadier Command API
|
||||
+ // CraftBukkit start
|
||||
+ public void removeCommand(String name) {
|
||||
+ this.children.remove(name);
|
||||
|
||||
@ -172,7 +172,7 @@
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -359,26 +_,120 @@
|
||||
@@ -359,26 +_,121 @@
|
||||
}
|
||||
|
||||
public void sendCommands(ServerPlayer player) {
|
||||
@ -252,6 +252,7 @@
|
||||
+ }
|
||||
+ // Paper end - Brigadier API
|
||||
+ if (!org.spigotmc.SpigotConfig.sendNamespaced && commandNode.getName().contains(":")) continue; // Spigot
|
||||
+ if (commandNode.wrappedCached != null && commandNode.wrappedCached.apiCommandMeta != null && commandNode.wrappedCached.apiCommandMeta.serverSideOnly()) continue; // Paper
|
||||
if (commandNode.canUse(source)) {
|
||||
ArgumentBuilder<SharedSuggestionProvider, ?> argumentBuilder = (ArgumentBuilder) commandNode.createBuilder();
|
||||
+ // Paper start
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
--- a/net/minecraft/core/ClientAsset.java
|
||||
+++ b/net/minecraft/core/ClientAsset.java
|
||||
@@ -12,6 +_,6 @@
|
||||
public static final StreamCodec<ByteBuf, ClientAsset> STREAM_CODEC = StreamCodec.composite(ResourceLocation.STREAM_CODEC, ClientAsset::id, ClientAsset::new);
|
||||
|
||||
public ClientAsset(ResourceLocation id) {
|
||||
- this(id, id.withPath(string -> "textures/" + string + ".png"));
|
||||
+ this(id, id.withPath(string -> "textures/" + string + ".png")); // Paper - diff on change - io.papermc.paper.registry.data.client.ClientAssetImpl#pathFromIdentifier
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
--- a/net/minecraft/network/HashedStack.java
|
||||
+++ b/net/minecraft/network/HashedStack.java
|
||||
@@ -17,7 +_,7 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
- public boolean matches(ItemStack stack, HashedPatchMap.HashGenerator hashGenerator) {
|
||||
+ public boolean matches(ItemStack stack, HashedPatchMap.HashGenerator hashGenerator, final boolean simplifyMatching) { // Paper - add flag to simplify remote matching logic
|
||||
return stack.isEmpty();
|
||||
}
|
||||
};
|
||||
@@ -27,7 +_,7 @@
|
||||
hashedStack -> hashedStack instanceof HashedStack.ActualItem actualItem ? Optional.of(actualItem) : Optional.empty()
|
||||
);
|
||||
|
||||
- boolean matches(ItemStack stack, HashedPatchMap.HashGenerator hashGenerator);
|
||||
+ boolean matches(ItemStack stack, HashedPatchMap.HashGenerator hashGenerator, final boolean simplifyMatching); // Paper - add flag to simplify remote matching logic
|
||||
|
||||
static HashedStack create(ItemStack stack, HashedPatchMap.HashGenerator hashGenerator) {
|
||||
return (HashedStack)(stack.isEmpty()
|
||||
@@ -47,10 +_,10 @@
|
||||
);
|
||||
|
||||
@Override
|
||||
- public boolean matches(ItemStack stack, HashedPatchMap.HashGenerator hashGenerator) {
|
||||
+ public boolean matches(ItemStack stack, HashedPatchMap.HashGenerator hashGenerator, final boolean simplifyMatching) { // Paper - add flag to simplify remote matching logic
|
||||
return this.count == stack.getCount()
|
||||
&& this.item.equals(stack.getItemHolder())
|
||||
- && this.components.matches(stack.getComponentsPatch(), hashGenerator);
|
||||
+ && (simplifyMatching || this.components.matches(stack.getComponentsPatch(), hashGenerator)); // Paper - add flag to simplify remote matching logic
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
--- a/net/minecraft/network/syncher/EntityDataSerializers.java
|
||||
+++ b/net/minecraft/network/syncher/EntityDataSerializers.java
|
||||
@@ -51,10 +_,27 @@
|
||||
public static final EntityDataSerializer<Optional<Component>> OPTIONAL_COMPONENT = EntityDataSerializer.forValueType(
|
||||
ComponentSerialization.TRUSTED_OPTIONAL_STREAM_CODEC
|
||||
);
|
||||
+ // Paper start - do not obfuscate items sent as entity data
|
||||
+ public static final StreamCodec<RegistryFriendlyByteBuf, ItemStack> OVERSIZED_ITEM_CODEC = new net.minecraft.network.codec.StreamCodec<>() {
|
||||
+ @Override
|
||||
+ public net.minecraft.world.item.ItemStack decode(final net.minecraft.network.RegistryFriendlyByteBuf buffer) {
|
||||
+ return ItemStack.OPTIONAL_STREAM_CODEC.decode(buffer);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void encode(final net.minecraft.network.RegistryFriendlyByteBuf buffer, final net.minecraft.world.item.ItemStack value) {
|
||||
+ // If the codec is called during an obfuscation session, downgrade the context's obf level to OVERSIZED if it isn't already.
|
||||
+ // Entity data cannot be fully obfuscated as entities might render out specific values (e.g. count or custom name).
|
||||
+ try (final io.papermc.paper.util.SafeAutoClosable ignored = io.papermc.paper.util.sanitizer.ItemObfuscationSession.withContext(c -> c.level(io.papermc.paper.util.sanitizer.ItemObfuscationSession.ObfuscationLevel.OVERSIZED))) {
|
||||
+ ItemStack.OPTIONAL_STREAM_CODEC.encode(buffer, value);
|
||||
+ }
|
||||
+ }
|
||||
+ };
|
||||
+ // Paper end - do not obfuscate items sent as entity data
|
||||
public static final EntityDataSerializer<ItemStack> ITEM_STACK = new EntityDataSerializer<ItemStack>() {
|
||||
@Override
|
||||
public StreamCodec<? super RegistryFriendlyByteBuf, ItemStack> codec() {
|
||||
- return ItemStack.OPTIONAL_STREAM_CODEC;
|
||||
+ return OVERSIZED_ITEM_CODEC; // Paper - do not obfuscate items sent as entity data
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1,12 +1,13 @@
|
||||
--- a/net/minecraft/server/ReloadableServerResources.java
|
||||
+++ b/net/minecraft/server/ReloadableServerResources.java
|
||||
@@ -38,7 +_,8 @@
|
||||
@@ -38,7 +_,9 @@
|
||||
this.fullRegistryHolder = new ReloadableServerRegistries.Holder(registryAccess.compositeAccess());
|
||||
this.postponedTags = postponedTags;
|
||||
this.recipes = new RecipeManager(registries);
|
||||
- this.commands = new Commands(commandSelection, CommandBuildContext.simple(registries, enabledFeatures));
|
||||
+ this.commands = new Commands(commandSelection, CommandBuildContext.simple(registries, enabledFeatures), true); // Paper - Brigadier Command API - use modern alias registration
|
||||
+ io.papermc.paper.command.brigadier.PaperCommands.INSTANCE.setDispatcher(this.commands, CommandBuildContext.simple(registries, enabledFeatures)); // Paper - Brigadier Command API
|
||||
+ io.papermc.paper.command.PaperCommands.registerCommands(); // Paper
|
||||
this.advancements = new ServerAdvancementManager(registries);
|
||||
this.functionLibrary = new ServerFunctionLibrary(functionCompilationLevel, this.commands.getDispatcher());
|
||||
}
|
||||
|
||||
@ -1,5 +1,13 @@
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -65,7 +_,6 @@
|
||||
import net.minecraft.network.protocol.game.ClientboundHurtAnimationPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundMerchantOffersPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundOpenBookPacket;
|
||||
-import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundOpenSignEditorPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundPlayerAbilitiesPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundPlayerCombatEndPacket;
|
||||
@@ -235,7 +_,8 @@
|
||||
private int levitationStartTime;
|
||||
private boolean disconnected;
|
||||
@ -10,7 +18,7 @@
|
||||
@Nullable
|
||||
private Vec3 startingToFallPosition;
|
||||
@Nullable
|
||||
@@ -281,6 +_,20 @@
|
||||
@@ -281,6 +_,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,26 +28,10 @@
|
||||
+ ServerPlayer.this.connection.send(new ClientboundContainerSetSlotPacket(ServerPlayer.this.inventoryMenu.containerId, ServerPlayer.this.inventoryMenu.incrementStateId(), net.minecraft.world.inventory.InventoryMenu.SHIELD_SLOT, ServerPlayer.this.inventoryMenu.getSlot(net.minecraft.world.inventory.InventoryMenu.SHIELD_SLOT).getItem().copy()));
|
||||
+ }
|
||||
+ // Paper end - Sync offhand slot in menus
|
||||
+
|
||||
+ // Paper start - add flag to simplify remote matching logic
|
||||
+ @Override
|
||||
+ public ServerPlayer player() {
|
||||
+ return ServerPlayer.this;
|
||||
+ }
|
||||
+ // Paper end - add flag to simplify remote matching logic
|
||||
+
|
||||
@Override
|
||||
public void sendSlotChange(AbstractContainerMenu container, int slot, ItemStack itemStack) {
|
||||
ServerPlayer.this.connection.send(new ClientboundContainerSetSlotPacket(container.containerId, container.incrementStateId(), slot, itemStack));
|
||||
@@ -302,7 +_,7 @@
|
||||
|
||||
@Override
|
||||
public RemoteSlot createSlot() {
|
||||
- return new RemoteSlot.Synchronized(this.cache::getUnchecked);
|
||||
+ return new RemoteSlot.Synchronized(this.cache::getUnchecked, ServerPlayer.this.getBukkitEntity().simplifyContainerDesyncCheck()); // Paper - add flag to simplify remote matching logic
|
||||
}
|
||||
};
|
||||
private final ContainerListener containerListener = new ContainerListener() {
|
||||
@@ -316,6 +_,32 @@
|
||||
}
|
||||
}
|
||||
@ -316,12 +308,19 @@
|
||||
}
|
||||
|
||||
float saturationLevel = this.foodData.getSaturationLevel();
|
||||
@@ -793,15 +_,84 @@
|
||||
@@ -793,15 +_,36 @@
|
||||
}
|
||||
|
||||
private void updateScoreForCriteria(ObjectiveCriteria criteria, int points) {
|
||||
- this.getScoreboard().forAllObjectives(criteria, this, score -> score.set(points));
|
||||
- }
|
||||
-
|
||||
- @Override
|
||||
- public void die(DamageSource cause) {
|
||||
- this.gameEvent(GameEvent.ENTITY_DIE);
|
||||
- boolean _boolean = this.serverLevel().getGameRules().getBoolean(GameRules.RULE_SHOWDEATHMESSAGES);
|
||||
- if (_boolean) {
|
||||
- Component deathMessage = this.getCombatTracker().getDeathMessage();
|
||||
+ this.level().getCraftServer().getScoreboardManager().forAllObjectives(criteria, this, score -> score.set(points)); // CraftBukkit - Use our scores instead
|
||||
+ }
|
||||
+
|
||||
@ -348,13 +347,24 @@
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end - PlayerDeathEvent#getItemsToKeep
|
||||
|
||||
@Override
|
||||
public void die(DamageSource cause) {
|
||||
- this.gameEvent(GameEvent.ENTITY_DIE);
|
||||
- boolean _boolean = this.serverLevel().getGameRules().getBoolean(GameRules.RULE_SHOWDEATHMESSAGES);
|
||||
- if (_boolean) {
|
||||
- Component deathMessage = this.getCombatTracker().getDeathMessage();
|
||||
+ // Paper start - Expand PlayerDeathEvent API
|
||||
+ private void sendClientboundPlayerCombatKillPacket(boolean displayMessage, Component deathMessage) {
|
||||
+ if (displayMessage && deathMessage != CommonComponents.EMPTY) {
|
||||
+ // Paper - moved from below die(DamageSource) method
|
||||
this.connection
|
||||
.send(
|
||||
new ClientboundPlayerCombatKillPacket(this.getId(), deathMessage),
|
||||
@@ -818,6 +_,65 @@
|
||||
}
|
||||
)
|
||||
);
|
||||
+ } else {
|
||||
+ this.connection.send(new ClientboundPlayerCombatKillPacket(this.getId(), CommonComponents.EMPTY));
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Expand PlayerDeathEvent API
|
||||
+ @Override
|
||||
+ public void die(DamageSource cause) {
|
||||
+ // this.gameEvent(GameEvent.ENTITY_DIE); // Paper - move below event cancellation check
|
||||
+ boolean _boolean = this.serverLevel().getGameRules().getBoolean(GameRules.RULE_SHOWDEATHMESSAGES); final boolean showDeathMessage = _boolean; // Paper - OBFHELPER
|
||||
+ // CraftBukkit start - fire PlayerDeathEvent
|
||||
@ -382,7 +392,7 @@
|
||||
+
|
||||
+ String deathmessage = defaultMessage.getString();
|
||||
+ this.keepLevel = keepInventory; // SPIGOT-2222: pre-set keepLevel
|
||||
+ org.bukkit.event.entity.PlayerDeathEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerDeathEvent(this, cause, loot, io.papermc.paper.adventure.PaperAdventure.asAdventure(defaultMessage), keepInventory); // Paper - Adventure
|
||||
+ org.bukkit.event.entity.PlayerDeathEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerDeathEvent(this, cause, loot, io.papermc.paper.adventure.PaperAdventure.asAdventure(defaultMessage), showDeathMessage, keepInventory); // Paper - Adventure; Expand PlayerDeathEvent API
|
||||
+ // Paper start - cancellable death event
|
||||
+ if (event.isCancelled()) {
|
||||
+ // make compatible with plugins that might have already set the health in an event listener
|
||||
@ -400,13 +410,25 @@
|
||||
+ }
|
||||
+
|
||||
+ net.kyori.adventure.text.Component apiDeathMessage = event.deathMessage() != null ? event.deathMessage() : net.kyori.adventure.text.Component.empty(); // Paper - Adventure
|
||||
+ Component deathScreenMessage = io.papermc.paper.adventure.PaperAdventure.asVanilla(event.deathScreenMessageOverride() != null ? event.deathScreenMessageOverride() : apiDeathMessage); // Paper - Expand PlayerDeathEvent API
|
||||
+
|
||||
+ if (apiDeathMessage != null && apiDeathMessage != net.kyori.adventure.text.Component.empty() && showDeathMessage) { // Paper - Adventure // TODO: allow plugins to override?
|
||||
+ if (apiDeathMessage != null && apiDeathMessage != net.kyori.adventure.text.Component.empty() && event.getShowDeathMessages()) { // Paper - Adventure; Expand PlayerDeathEvent API
|
||||
+ Component deathMessage = io.papermc.paper.adventure.PaperAdventure.asVanilla(apiDeathMessage); // Paper - Adventure
|
||||
+
|
||||
this.connection
|
||||
.send(
|
||||
new ClientboundPlayerCombatKillPacket(this.getId(), deathMessage),
|
||||
+ // Paper - moved up to sendClientboundPlayerCombatKillPacket()
|
||||
+ sendClientboundPlayerCombatKillPacket(event.getShowDeathMessages(), deathScreenMessage); // Paper - Expand PlayerDeathEvent
|
||||
Team team = this.getTeam();
|
||||
if (team == null || team.getDeathMessageVisibility() == Team.Visibility.ALWAYS) {
|
||||
this.server.getPlayerList().broadcastSystemMessage(deathMessage, false);
|
||||
@@ -827,7 +_,7 @@
|
||||
this.server.getPlayerList().broadcastSystemToAllExceptTeam(this, deathMessage);
|
||||
}
|
||||
} else {
|
||||
- this.connection.send(new ClientboundPlayerCombatKillPacket(this.getId(), CommonComponents.EMPTY));
|
||||
+ sendClientboundPlayerCombatKillPacket(event.getShowDeathMessages(), deathScreenMessage); // Paper - Expand PlayerDeathEvent
|
||||
}
|
||||
|
||||
this.removeEntitiesOnShoulder();
|
||||
@@ -835,11 +_,35 @@
|
||||
this.tellNeutralMobsThatIDied();
|
||||
}
|
||||
@ -491,7 +513,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -914,23 +_,82 @@
|
||||
@@ -914,23 +_,77 @@
|
||||
}
|
||||
|
||||
private boolean isPvpAllowed() {
|
||||
@ -541,18 +563,13 @@
|
||||
+ );
|
||||
+
|
||||
+ // Paper start - respawn flags
|
||||
+ com.google.common.collect.ImmutableSet.Builder<org.bukkit.event.player.PlayerRespawnEvent.RespawnFlag> builder = com.google.common.collect.ImmutableSet.builder();
|
||||
+ if (respawnReason == org.bukkit.event.player.PlayerRespawnEvent.RespawnReason.END_PORTAL) {
|
||||
+ builder.add(org.bukkit.event.player.PlayerRespawnEvent.RespawnFlag.END_PORTAL);
|
||||
+ }
|
||||
+ org.bukkit.event.player.PlayerRespawnEvent respawnEvent = new org.bukkit.event.player.PlayerRespawnEvent(
|
||||
+ respawnPlayer,
|
||||
+ location,
|
||||
+ isBedSpawn,
|
||||
+ isAnchorSpawn,
|
||||
+ teleportTransition.missingRespawnBlock(),
|
||||
+ respawnReason,
|
||||
+ builder
|
||||
+ respawnReason
|
||||
+ );
|
||||
+ // Paper end - respawn flags
|
||||
+ this.level().getCraftServer().getPluginManager().callEvent(respawnEvent);
|
||||
|
||||
@ -523,7 +523,7 @@
|
||||
this.player.sendSystemMessage(Component.translatable("advMode.notAllowed"));
|
||||
} else {
|
||||
BaseCommandBlock commandBlock = packet.getCommandBlock(this.player.level());
|
||||
@@ -661,7 +_,7 @@
|
||||
@@ -661,11 +_,11 @@
|
||||
boolean flag = this.player.hasInfiniteMaterials() && packet.includeData();
|
||||
ItemStack cloneItemStack = blockState.getCloneItemStack(serverLevel, blockPos, flag);
|
||||
if (!cloneItemStack.isEmpty()) {
|
||||
@ -532,7 +532,23 @@
|
||||
addBlockDataToItem(blockState, serverLevel, blockPos, cloneItemStack);
|
||||
}
|
||||
|
||||
@@ -698,18 +_,29 @@
|
||||
- this.tryPickItem(cloneItemStack);
|
||||
+ this.tryPickItem(cloneItemStack, blockPos, null, packet.includeData()); // Paper - Extend PlayerPickItemEvent API
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -689,27 +_,40 @@
|
||||
if (entityOrPart != null && this.player.canInteractWithEntity(entityOrPart, 3.0)) {
|
||||
ItemStack pickResult = entityOrPart.getPickResult();
|
||||
if (pickResult != null && !pickResult.isEmpty()) {
|
||||
- this.tryPickItem(pickResult);
|
||||
+ this.tryPickItem(pickResult, null, entityOrPart, packet.includeData()); // Paper - Extend PlayerPickItemEvent API
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- private void tryPickItem(ItemStack stack) {
|
||||
+ private void tryPickItem(ItemStack stack, @Nullable BlockPos blockPos, @Nullable Entity entity, boolean includeData) { // Paper - Extend PlayerPickItemEvent API
|
||||
if (stack.isItemEnabled(this.player.level().enabledFeatures())) {
|
||||
Inventory inventory = this.player.getInventory();
|
||||
int i = inventory.findSlotMatchingItem(stack);
|
||||
@ -540,7 +556,9 @@
|
||||
+ final int sourceSlot = i;
|
||||
+ final int targetSlot = Inventory.isHotbarSlot(sourceSlot) ? sourceSlot : inventory.getSuitableHotbarSlot();
|
||||
+ final org.bukkit.entity.Player bukkitPlayer = this.player.getBukkitEntity();
|
||||
+ final io.papermc.paper.event.player.PlayerPickItemEvent event = new io.papermc.paper.event.player.PlayerPickItemEvent(bukkitPlayer, targetSlot, sourceSlot);
|
||||
+ final io.papermc.paper.event.player.PlayerPickItemEvent event = entity != null
|
||||
+ ? new io.papermc.paper.event.player.PlayerPickEntityEvent(bukkitPlayer, entity.getBukkitEntity(), includeData, targetSlot, sourceSlot)
|
||||
+ : new io.papermc.paper.event.player.PlayerPickBlockEvent(bukkitPlayer, org.bukkit.craftbukkit.block.CraftBlock.at(this.player.level(), blockPos), includeData, targetSlot, sourceSlot);
|
||||
+ if (!event.callEvent()) {
|
||||
+ return;
|
||||
+ }
|
||||
@ -2468,7 +2486,7 @@
|
||||
} else if (flag && flag2) {
|
||||
if (this.dropSpamThrottler.isUnderThreshold()) {
|
||||
this.dropSpamThrottler.increment();
|
||||
@@ -1895,11 +_,24 @@
|
||||
@@ -1895,15 +_,38 @@
|
||||
|
||||
@Override
|
||||
public void handleSignUpdate(ServerboundSignUpdatePacket packet) {
|
||||
@ -2494,6 +2512,20 @@
|
||||
this.player.resetLastActionTime();
|
||||
ServerLevel serverLevel = this.player.serverLevel();
|
||||
BlockPos pos = packet.getPos();
|
||||
if (serverLevel.hasChunkAt(pos)) {
|
||||
+ // Paper start - Add API for client-side signs
|
||||
+ if (!new io.papermc.paper.event.packet.UncheckedSignChangeEvent(
|
||||
+ this.player.getBukkitEntity(),
|
||||
+ io.papermc.paper.util.MCUtil.toPosition(pos),
|
||||
+ packet.isFrontText() ? org.bukkit.block.sign.Side.FRONT : org.bukkit.block.sign.Side.BACK,
|
||||
+ filteredText.stream().<net.kyori.adventure.text.Component>map(line -> net.kyori.adventure.text.Component.text(line.raw())).toList())
|
||||
+ .callEvent()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Add API for client-side signs
|
||||
if (!(serverLevel.getBlockEntity(pos) instanceof SignBlockEntity signBlockEntity)) {
|
||||
return;
|
||||
}
|
||||
@@ -1915,14 +_,32 @@
|
||||
@Override
|
||||
public void handlePlayerAbilities(ServerboundPlayerAbilitiesPacket packet) {
|
||||
|
||||
@ -9,10 +9,10 @@
|
||||
+ static final java.util.regex.Pattern HOST_PATTERN = java.util.regex.Pattern.compile("[0-9a-f\\.:]{0,45}");
|
||||
+ static final java.util.regex.Pattern PROP_PATTERN = java.util.regex.Pattern.compile("\\w{0,16}");
|
||||
+ // Spigot end
|
||||
+ // CraftBukkit start - add fields
|
||||
+ private static final java.util.HashMap<java.net.InetAddress, Long> throttleTracker = new java.util.HashMap<>();
|
||||
+ // Paper start - Connection throttle
|
||||
+ private static final java.util.Map<java.net.InetAddress, Long> throttleTracker = new java.util.HashMap<>();
|
||||
+ private static int throttleCounter = 0;
|
||||
+ // CraftBukkit end
|
||||
+ // Paper end - Connection throttle
|
||||
+ private static final boolean BYPASS_HOSTCHECK = Boolean.getBoolean("Paper.bypassHostCheck"); // Paper
|
||||
private final MinecraftServer server;
|
||||
private final Connection connection;
|
||||
@ -29,7 +29,7 @@
|
||||
switch (packet.intention()) {
|
||||
case LOGIN:
|
||||
this.beginLogin(packet, false);
|
||||
@@ -50,22 +_,117 @@
|
||||
@@ -50,22 +_,118 @@
|
||||
default:
|
||||
throw new UnsupportedOperationException("Invalid intention " + packet.intention());
|
||||
}
|
||||
@ -42,17 +42,18 @@
|
||||
|
||||
private void beginLogin(ClientIntentionPacket packet, boolean transferred) {
|
||||
this.connection.setupOutboundProtocol(LoginProtocols.CLIENTBOUND);
|
||||
+ // CraftBukkit start - Connection throttle
|
||||
+ // Paper start - Connection throttle
|
||||
+ try {
|
||||
+ if (!(this.connection.channel.localAddress() instanceof io.netty.channel.unix.DomainSocketAddress)) { // Paper - Unix domain socket support; the connection throttle is useless when you have a Unix domain socket
|
||||
+ final long connectionThrottle = this.server.server.getConnectionThrottle();
|
||||
+ final boolean isUnixDomainSocket = this.connection.channel.localAddress() instanceof io.netty.channel.unix.DomainSocketAddress; // Paper - Unix domain socket support; the connection throttle is useless when you have a Unix domain socket
|
||||
+ if (connectionThrottle > 0 && !isUnixDomainSocket && this.connection.getRemoteAddress() instanceof java.net.InetSocketAddress socketAddress && !socketAddress.isUnresolved() && !socketAddress.getAddress().isLoopbackAddress()) {
|
||||
+ long currentTime = System.currentTimeMillis();
|
||||
+ long connectionThrottle = this.server.server.getConnectionThrottle();
|
||||
+ java.net.InetAddress address = ((java.net.InetSocketAddress) this.connection.getRemoteAddress()).getAddress();
|
||||
+ java.net.InetAddress address = socketAddress.getAddress();
|
||||
+
|
||||
+ synchronized (ServerHandshakePacketListenerImpl.throttleTracker) {
|
||||
+ if (ServerHandshakePacketListenerImpl.throttleTracker.containsKey(address) && !"127.0.0.1".equals(address.getHostAddress()) && currentTime - ServerHandshakePacketListenerImpl.throttleTracker.get(address) < connectionThrottle) {
|
||||
+ if (ServerHandshakePacketListenerImpl.throttleTracker.containsKey(address) && currentTime - ServerHandshakePacketListenerImpl.throttleTracker.get(address) < connectionThrottle) {
|
||||
+ ServerHandshakePacketListenerImpl.throttleTracker.put(address, currentTime);
|
||||
+ Component chatmessage = io.papermc.paper.adventure.PaperAdventure.asVanilla(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.connectionThrottle); // Paper - Configurable connection throttle kick message
|
||||
+ Component chatmessage = io.papermc.paper.adventure.PaperAdventure.asVanilla(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.connectionThrottle);
|
||||
+ this.connection.send(new ClientboundLoginDisconnectPacket(chatmessage));
|
||||
+ this.connection.disconnect(chatmessage);
|
||||
+ return;
|
||||
@ -67,11 +68,11 @@
|
||||
+ ServerHandshakePacketListenerImpl.throttleTracker.values().removeIf(time -> time > connectionThrottle);
|
||||
+ }
|
||||
+ }
|
||||
+ } // Paper - Unix domain socket support
|
||||
+ }
|
||||
+ } catch (Throwable t) {
|
||||
+ org.apache.logging.log4j.LogManager.getLogger().debug("Failed to check connection throttle", t);
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+ // Paper end - Connection throttle
|
||||
if (packet.protocolVersion() != SharedConstants.getCurrentVersion().getProtocolVersion()) {
|
||||
- Component component;
|
||||
- if (packet.protocolVersion() < 754) {
|
||||
|
||||
@ -524,7 +524,7 @@
|
||||
IpBanListEntry ipBanListEntry = this.ipBans.get(socketAddress);
|
||||
MutableComponent mutableComponent = Component.translatable("multiplayer.disconnect.banned_ip.reason", ipBanListEntry.getReason());
|
||||
if (ipBanListEntry.getExpires() != null) {
|
||||
@@ -381,69 +_,130 @@
|
||||
@@ -381,69 +_,131 @@
|
||||
);
|
||||
}
|
||||
|
||||
@ -649,6 +649,7 @@
|
||||
+ // Paper start - Add PlayerPostRespawnEvent
|
||||
+ boolean isBedSpawn = false;
|
||||
+ boolean isRespawn = false;
|
||||
+ boolean isAnchorSpawn = false;
|
||||
+ // Paper end - Add PlayerPostRespawnEvent
|
||||
+
|
||||
+ // CraftBukkit start - fire PlayerRespawnEvent
|
||||
@ -714,13 +715,17 @@
|
||||
serverPlayer.setHealth(serverPlayer.getHealth());
|
||||
ServerPlayer.RespawnConfig respawnConfig = serverPlayer.getRespawnConfig();
|
||||
if (!keepInventory && respawnConfig != null) {
|
||||
@@ -477,8 +_,41 @@
|
||||
@@ -477,8 +_,52 @@
|
||||
)
|
||||
);
|
||||
}
|
||||
+ // Paper start - Add PlayerPostRespawnEvent
|
||||
+ if (blockState.is(net.minecraft.tags.BlockTags.BEDS) && !teleportTransition.missingRespawnBlock()) {
|
||||
+ isBedSpawn = true;
|
||||
+ if (!teleportTransition.missingRespawnBlock()) {
|
||||
+ if (blockState.is(net.minecraft.tags.BlockTags.BEDS)) {
|
||||
+ isBedSpawn = true;
|
||||
+ } else if (blockState.is(Blocks.RESPAWN_ANCHOR)) {
|
||||
+ isAnchorSpawn = true;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Add PlayerPostRespawnEvent
|
||||
}
|
||||
@ -748,7 +753,14 @@
|
||||
+
|
||||
+ // Paper start - Add PlayerPostRespawnEvent
|
||||
+ if (isRespawn) {
|
||||
+ cserver.getPluginManager().callEvent(new com.destroystokyo.paper.event.player.PlayerPostRespawnEvent(player.getBukkitEntity(), location, isBedSpawn));
|
||||
+ new com.destroystokyo.paper.event.player.PlayerPostRespawnEvent(
|
||||
+ player.getBukkitEntity(),
|
||||
+ location,
|
||||
+ isBedSpawn,
|
||||
+ isAnchorSpawn,
|
||||
+ teleportTransition.missingRespawnBlock(),
|
||||
+ eventReason
|
||||
+ ).callEvent();
|
||||
+ }
|
||||
+ // Paper end - Add PlayerPostRespawnEvent
|
||||
+
|
||||
|
||||
@ -1,16 +1,22 @@
|
||||
--- a/net/minecraft/util/datafix/DataFixers.java
|
||||
+++ b/net/minecraft/util/datafix/DataFixers.java
|
||||
@@ -541,6 +_,18 @@
|
||||
@@ -541,6 +_,24 @@
|
||||
Schema schema44 = builder.addSchema(1456, SAME_NAMESPACED);
|
||||
builder.addFixer(new EntityItemFrameDirectionFix(schema44, false));
|
||||
Schema schema45 = builder.addSchema(1458, V1458::new);
|
||||
+ // CraftBukkit start
|
||||
+ builder.addFixer(new com.mojang.datafixers.DataFix(schema45, false) {
|
||||
+ // API allows setting player custom names, so we need to convert them.
|
||||
+ // This does *not* handle upgrades in any other version, but generally those shouldn't need conversion.
|
||||
+ builder.addFixer(new DataFix(schema45, false) {
|
||||
+ @Override
|
||||
+ protected com.mojang.datafixers.TypeRewriteRule makeRule() {
|
||||
+ return this.fixTypeEverywhereTyped("Player CustomName", this.getInputSchema().getType(References.PLAYER), (typed) -> {
|
||||
+ return typed.update(DSL.remainderFinder(), (dynamic) -> {
|
||||
+ return EntityCustomNameToComponentFix.fixCustomName(dynamic.getOps(), dynamic.get("CustomName").asString(""), "minecraft:player");
|
||||
+ protected TypeRewriteRule makeRule() {
|
||||
+ return this.fixTypeEverywhereTyped("Player CustomName", this.getInputSchema().getType(References.PLAYER), typed -> {
|
||||
+ return typed.update(DSL.remainderFinder(), dynamic -> {
|
||||
+ final String customName = dynamic.get("CustomName").asString("");
|
||||
+ if (customName.isEmpty()) {
|
||||
+ return dynamic.remove("CustomName");
|
||||
+ }
|
||||
+ return dynamic.set("CustomName", LegacyComponentDataFixUtils.createPlainTextComponent(dynamic.getOps(), customName));
|
||||
+ });
|
||||
+ });
|
||||
+ }
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
--- a/net/minecraft/util/datafix/fixes/RaidRenamesDataFix.java
|
||||
+++ b/net/minecraft/util/datafix/fixes/RaidRenamesDataFix.java
|
||||
@@ -39,6 +_,6 @@
|
||||
.renameField("PostRaidTicks", "post_raid_ticks")
|
||||
.renameField("TotalHealth", "total_health")
|
||||
.renameField("NumGroups", "group_count")
|
||||
- .renameField("Status", "status");
|
||||
+ .renameField("Status", "status").renameField("HeroesOfTheVillage", "heroes_of_the_village"); // Paper - Add missing rename
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
--- a/net/minecraft/world/damagesource/CombatTracker.java
|
||||
+++ b/net/minecraft/world/damagesource/CombatTracker.java
|
||||
@@ -29,15 +_,24 @@
|
||||
private int combatEndTime;
|
||||
public boolean inCombat;
|
||||
public boolean takingDamage;
|
||||
+ public final io.papermc.paper.world.damagesource.PaperCombatTrackerWrapper paperCombatTracker; // Paper - Combat tracker API
|
||||
|
||||
public CombatTracker(LivingEntity mob) {
|
||||
this.mob = mob;
|
||||
+ this.paperCombatTracker = new io.papermc.paper.world.damagesource.PaperCombatTrackerWrapper(this); // Paper - Combat tracker API
|
||||
}
|
||||
|
||||
public void recordDamage(DamageSource source, float damage) {
|
||||
this.recheckStatus();
|
||||
FallLocation currentFallLocation = FallLocation.getCurrentFallLocation(this.mob);
|
||||
CombatEntry combatEntry = new CombatEntry(source, damage, currentFallLocation, (float)this.mob.fallDistance);
|
||||
+ // Paper start - Combat tracker API
|
||||
+ recordDamageAndCheckCombatState(combatEntry);
|
||||
+ }
|
||||
+
|
||||
+ public void recordDamageAndCheckCombatState(final CombatEntry combatEntry) {
|
||||
+ final DamageSource source = combatEntry.source();
|
||||
+ // Paper end - Combat tracker API
|
||||
this.entries.add(combatEntry);
|
||||
this.lastDamageTime = this.mob.tickCount;
|
||||
this.takingDamage = true;
|
||||
@@ -147,6 +_,13 @@
|
||||
public void recheckStatus() {
|
||||
int i = this.inCombat ? 300 : 100;
|
||||
if (this.takingDamage && (!this.mob.isAlive() || this.mob.tickCount - this.lastDamageTime > i)) {
|
||||
+ // Paper start - Combat tracker API
|
||||
+ resetCombatState();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void resetCombatState() {{
|
||||
+ // Paper end - Combat tracker API
|
||||
boolean flag = this.inCombat;
|
||||
this.takingDamage = false;
|
||||
this.inCombat = false;
|
||||
@ -126,6 +126,15 @@
|
||||
private final double[] pistonDeltas = new double[]{0.0, 0.0, 0.0};
|
||||
private long pistonDeltasGameTime;
|
||||
private EntityDimensions dimensions;
|
||||
@@ -251,7 +_,7 @@
|
||||
private boolean onGroundNoBlocks = false;
|
||||
private float crystalSoundIntensity;
|
||||
private int lastCrystalSoundPlayTick;
|
||||
- public boolean hasVisualFire;
|
||||
+ public net.kyori.adventure.util.TriState visualFire = net.kyori.adventure.util.TriState.NOT_SET; // Paper - improve visual fire API
|
||||
@Nullable
|
||||
private BlockState inBlockState = null;
|
||||
private final List<List<Entity.Movement>> movementThisTick = new ObjectArrayList<>();
|
||||
@@ -259,6 +_,41 @@
|
||||
private final LongSet visitedBlocks = new LongOpenHashSet();
|
||||
private final InsideBlockEffectApplier.StepBasedCollector insideEffectCollector = new InsideBlockEffectApplier.StepBasedCollector();
|
||||
@ -392,7 +401,12 @@
|
||||
}
|
||||
|
||||
this.checkBelowWorld();
|
||||
@@ -504,7 +_,12 @@
|
||||
@@ -500,11 +_,16 @@
|
||||
}
|
||||
|
||||
public void setSharedFlagOnFire(boolean isOnFire) {
|
||||
- this.setSharedFlag(0, isOnFire || this.hasVisualFire);
|
||||
+ this.setSharedFlag(0, this.visualFire.toBooleanOrElse(isOnFire)); // Paper - improve visual fire API
|
||||
}
|
||||
|
||||
public void checkBelowWorld() {
|
||||
@ -694,7 +708,7 @@
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1805,14 +_,34 @@
|
||||
@@ -1805,14 +_,35 @@
|
||||
}
|
||||
|
||||
public CompoundTag saveWithoutId(CompoundTag compound) {
|
||||
@ -715,6 +729,7 @@
|
||||
}
|
||||
+ } // CraftBukkit
|
||||
|
||||
+ this.setDeltaMovement(io.papermc.paper.util.MCUtil.sanitizeNanInf(this.deltaMovement, 0D)); // Paper - remove NaN values before usage in saving
|
||||
compound.store("Motion", Vec3.CODEC, this.getDeltaMovement());
|
||||
+ // CraftBukkit start - Checking for NaN pitch/yaw and resetting to zero
|
||||
+ // TODO: make sure this is the best way to address this.
|
||||
@ -760,6 +775,21 @@
|
||||
Component customName = this.getCustomName();
|
||||
if (customName != null) {
|
||||
RegistryOps<Tag> registryOps = this.registryAccess().createSerializationContext(NbtOps.INSTANCE);
|
||||
@@ -1848,9 +_,12 @@
|
||||
compound.putInt("TicksFrozen", this.getTicksFrozen());
|
||||
}
|
||||
|
||||
- if (this.hasVisualFire) {
|
||||
- compound.putBoolean("HasVisualFire", this.hasVisualFire);
|
||||
+ // Paper start - improve visual fire API
|
||||
+ if (this.visualFire.equals(net.kyori.adventure.util.TriState.TRUE)) {
|
||||
+ compound.putBoolean("HasVisualFire", true);
|
||||
}
|
||||
+ compound.putString("Paper.FireOverride", visualFire.name());
|
||||
+ // Paper end
|
||||
|
||||
if (!this.tags.isEmpty()) {
|
||||
compound.store("Tags", TAG_LIST_CODEC, List.copyOf(this.tags));
|
||||
@@ -1860,13 +_,13 @@
|
||||
compound.store("data", CustomData.CODEC, this.customData);
|
||||
}
|
||||
@ -810,6 +840,37 @@
|
||||
return compound;
|
||||
} catch (Throwable var8) {
|
||||
CrashReport crashReport = CrashReport.forThrowable(var8, "Saving entity NBT");
|
||||
@@ -1888,7 +_,7 @@
|
||||
public void load(CompoundTag compound) {
|
||||
try {
|
||||
Vec3 vec3 = compound.read("Pos", Vec3.CODEC).orElse(Vec3.ZERO);
|
||||
- Vec3 vec31 = compound.read("Motion", Vec3.CODEC).orElse(Vec3.ZERO);
|
||||
+ Vec3 vec31 = compound.read("Motion", Vec3.CODEC).orElse(Vec3.ZERO); vec31 = io.papermc.paper.util.MCUtil.sanitizeNanInf(vec31, 0D); // Paper - avoid setting NaN values
|
||||
Vec2 vec2 = compound.read("Rotation", Vec2.CODEC).orElse(Vec2.ZERO);
|
||||
this.setDeltaMovement(Math.abs(vec31.x) > 10.0 ? 0.0 : vec31.x, Math.abs(vec31.y) > 10.0 ? 0.0 : vec31.y, Math.abs(vec31.z) > 10.0 ? 0.0 : vec31.z);
|
||||
this.hasImpulse = true;
|
||||
@@ -1921,7 +_,20 @@
|
||||
this.setNoGravity(compound.getBooleanOr("NoGravity", false));
|
||||
this.setGlowingTag(compound.getBooleanOr("Glowing", false));
|
||||
this.setTicksFrozen(compound.getIntOr("TicksFrozen", 0));
|
||||
- this.hasVisualFire = compound.getBooleanOr("HasVisualFire", false);
|
||||
+ // Paper start - improve visual fire API
|
||||
+ compound.getString("Paper.FireOverride").ifPresentOrElse(
|
||||
+ override -> {
|
||||
+ try {
|
||||
+ this.visualFire = net.kyori.adventure.util.TriState.valueOf(override);
|
||||
+ } catch (final Exception ignored) {
|
||||
+ LOGGER.error("Unknown fire override {} for {}", override, this);
|
||||
+ }
|
||||
+ },
|
||||
+ () -> this.visualFire = compound.getBoolean("HasVisualFire")
|
||||
+ .map(net.kyori.adventure.util.TriState::byBoolean)
|
||||
+ .orElse(net.kyori.adventure.util.TriState.NOT_SET)
|
||||
+ );
|
||||
+ // Paper end
|
||||
this.customData = compound.read("data", CustomData.CODEC).orElse(CustomData.EMPTY);
|
||||
this.tags.clear();
|
||||
compound.read("Tags", TAG_LIST_CODEC).ifPresent(this.tags::addAll);
|
||||
@@ -1932,6 +_,67 @@
|
||||
} else {
|
||||
throw new IllegalStateException("Entity has invalid rotation");
|
||||
|
||||
@ -97,7 +97,7 @@
|
||||
Vec3 vec3 = new Vec3(
|
||||
this.followingPlayer.getX() - this.getX(),
|
||||
this.followingPlayer.getY() + this.followingPlayer.getEyeHeight() / 2.0 - this.getY(),
|
||||
@@ -161,16 +_,27 @@
|
||||
@@ -161,18 +_,29 @@
|
||||
}
|
||||
|
||||
public static void award(ServerLevel level, Vec3 pos, int amount) {
|
||||
@ -124,9 +124,17 @@
|
||||
private static boolean tryMergeToExisting(ServerLevel level, Vec3 pos, int amount) {
|
||||
+ // Paper - TODO some other event for this kind of merge
|
||||
AABB aabb = AABB.ofSize(pos, 1.0, 1.0, 1.0);
|
||||
int randomInt = level.getRandom().nextInt(40);
|
||||
- int randomInt = level.getRandom().nextInt(40);
|
||||
+ int randomInt = level.getRandom().nextInt(io.papermc.paper.configuration.GlobalConfiguration.get().misc.xpOrbGroupsPerArea.or(ORB_GROUPS_PER_AREA)); // Paper - Configure how many orb groups per area
|
||||
List<ExperienceOrb> entities = level.getEntities(EntityTypeTest.forClass(ExperienceOrb.class), aabb, orb -> canMerge(orb, randomInt, amount));
|
||||
@@ -193,9 +_,14 @@
|
||||
if (!entities.isEmpty()) {
|
||||
ExperienceOrb experienceOrb = entities.get(0);
|
||||
@@ -189,13 +_,18 @@
|
||||
}
|
||||
|
||||
private static boolean canMerge(ExperienceOrb orb, int amount, int other) {
|
||||
- return !orb.isRemoved() && (orb.getId() - amount) % 40 == 0 && orb.getValue() == other;
|
||||
+ return !orb.isRemoved() && (orb.getId() - amount) % io.papermc.paper.configuration.GlobalConfiguration.get().misc.xpOrbGroupsPerArea.or(ORB_GROUPS_PER_AREA) == 0 && orb.getValue() == other; // Paper - Configure how many orbs will merge together
|
||||
}
|
||||
|
||||
private void merge(ExperienceOrb orb) {
|
||||
|
||||
@ -198,7 +198,7 @@
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -400,31 +_,34 @@
|
||||
@@ -400,31 +_,42 @@
|
||||
float health = this.getHealth();
|
||||
health -= damageAmount;
|
||||
if (health <= 0.5F) {
|
||||
@ -231,13 +231,24 @@
|
||||
+ // this.dropAllDeathLoot(level, damageSource); // CraftBukkit - moved down
|
||||
|
||||
for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) {
|
||||
ItemStack itemStack = this.equipment.set(equipmentSlot, ItemStack.EMPTY);
|
||||
- ItemStack itemStack = this.equipment.set(equipmentSlot, ItemStack.EMPTY);
|
||||
+ ItemStack itemStack = this.equipment.get(equipmentSlot); // Paper - move equipment removal past event call
|
||||
if (!itemStack.isEmpty()) {
|
||||
- Block.popResource(this.level(), this.blockPosition().above(), itemStack);
|
||||
- }
|
||||
- }
|
||||
+ this.drops.add(new DefaultDrop(itemStack, stack -> Block.popResource(this.level(), this.blockPosition().above(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior; mirror so we can destroy it later - though this call site was safe & spawn drops correctly}
|
||||
}
|
||||
}
|
||||
+ return this.dropAllDeathLoot(level, damageSource); // CraftBukkit - moved from above // Paper
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper start - move equipment removal past event call
|
||||
+ org.bukkit.event.entity.EntityDeathEvent event = this.dropAllDeathLoot(level, damageSource);
|
||||
+ if (!event.isCancelled()) {
|
||||
+ for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) {
|
||||
+ this.equipment.set(equipmentSlot, ItemStack.EMPTY);
|
||||
+ }
|
||||
+ }
|
||||
+ return event;
|
||||
+ // Paper end - move equipment removal past event call
|
||||
}
|
||||
|
||||
private void playBrokenSound() {
|
||||
|
||||
@ -48,7 +48,7 @@
|
||||
double squareRoot = Math.sqrt(d * d + d2 * d2);
|
||||
if (this.level() instanceof ServerLevel serverLevel) {
|
||||
+ // CraftBukkit start
|
||||
+ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, this.getMainHandItem(), arrow.getPickupItem(), arrow, net.minecraft.world.InteractionHand.MAIN_HAND, 0.8F, true); // Paper - improve entity shoot bow event, add arrow stack to event
|
||||
+ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, this.getMainHandItem(), arrow.getPickupItem(), arrow, net.minecraft.world.InteractionHand.MAIN_HAND, distanceFactor, true); // Paper - improve entity shoot bow event, add arrow stack to event
|
||||
+ if (event.isCancelled()) {
|
||||
+ event.getProjectile().remove();
|
||||
+ return;
|
||||
|
||||
@ -56,7 +56,20 @@
|
||||
this.setTarget(null);
|
||||
this.teleport();
|
||||
}
|
||||
@@ -369,11 +_,13 @@
|
||||
@@ -359,21 +_,25 @@
|
||||
AbstractThrownPotion abstractThrownPotion1 = damageSource.getDirectEntity() instanceof AbstractThrownPotion abstractThrownPotion
|
||||
? abstractThrownPotion
|
||||
: null;
|
||||
- if (!damageSource.is(DamageTypeTags.IS_PROJECTILE) && abstractThrownPotion1 == null) {
|
||||
+ if (!damageSource.is(DamageTypeTags.IS_PROJECTILE) && abstractThrownPotion1 == null) { // Paper - EndermanEscapeEvent - diff on change - below logic relies on this path covering non-projectile damage.
|
||||
boolean flag = super.hurtServer(level, damageSource, amount);
|
||||
if (!(damageSource.getEntity() instanceof LivingEntity) && this.random.nextInt(10) != 0) {
|
||||
+ if (this.tryEscape(damageSource.is(net.minecraft.tags.DamageTypeTags.IS_DROWNING) ? com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.DROWN : com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.CRITICAL_HIT)) { // Paper - EndermanEscapeEvent
|
||||
this.teleport();
|
||||
+ } // Paper - EndermanEscapeEvent
|
||||
}
|
||||
|
||||
return flag;
|
||||
} else {
|
||||
boolean flag = abstractThrownPotion1 != null && this.hurtWithCleanWater(level, damageSource, abstractThrownPotion1, amount);
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
double squareRoot = Math.sqrt(d * d + d2 * d2);
|
||||
if (this.level() instanceof ServerLevel serverLevel) {
|
||||
+ // Paper start - EntityShootBowEvent
|
||||
+ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, this.getMainHandItem(), mobArrow.getPickupItem(), mobArrow, target.getUsedItemHand(), 0.8F, true);
|
||||
+ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, this.getMainHandItem(), mobArrow.getPickupItem(), mobArrow, target.getUsedItemHand(), distanceFactor, true);
|
||||
+ if (event.isCancelled()) {
|
||||
+ event.getProjectile().remove();
|
||||
+ return;
|
||||
|
||||
@ -66,7 +66,7 @@
|
||||
+ // CraftBukkit end
|
||||
+ }
|
||||
+ // CraftBukkit start
|
||||
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTransformEvent(this, slimes, org.bukkit.event.entity.EntityTransformEvent.TransformReason.SPLIT).isCancelled()) {
|
||||
+ if (!slimes.isEmpty() && org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTransformEvent(this, slimes, org.bukkit.event.entity.EntityTransformEvent.TransformReason.SPLIT).isCancelled()) { // check for empty converted entities or cancel event
|
||||
+ super.remove(reason, eventCause); // add Bukkit remove cause
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
@ -42,6 +42,29 @@
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -166,12 +_,14 @@
|
||||
if (this.currentState == FishingHook.FishHookState.FLYING) {
|
||||
if (this.hookedIn != null) {
|
||||
this.setDeltaMovement(Vec3.ZERO);
|
||||
+ new io.papermc.paper.event.entity.FishHookStateChangeEvent((org.bukkit.entity.FishHook) getBukkitEntity(), org.bukkit.entity.FishHook.HookState.HOOKED_ENTITY).callEvent(); // Paper - Add FishHookStateChangeEvent. #HOOKED_ENTITY
|
||||
this.currentState = FishingHook.FishHookState.HOOKED_IN_ENTITY;
|
||||
return;
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
this.setDeltaMovement(this.getDeltaMovement().multiply(0.3, 0.2, 0.3));
|
||||
+ new io.papermc.paper.event.entity.FishHookStateChangeEvent((org.bukkit.entity.FishHook) getBukkitEntity(), org.bukkit.entity.FishHook.HookState.BOBBING).callEvent(); // Paper - Add FishHookStateChangeEvent. #BOBBING
|
||||
this.currentState = FishingHook.FishHookState.BOBBING;
|
||||
return;
|
||||
}
|
||||
@@ -184,6 +_,7 @@
|
||||
this.setPos(this.hookedIn.getX(), this.hookedIn.getY(0.8), this.hookedIn.getZ());
|
||||
} else {
|
||||
this.setHookedEntity(null);
|
||||
+ new io.papermc.paper.event.entity.FishHookStateChangeEvent((org.bukkit.entity.FishHook) getBukkitEntity(), org.bukkit.entity.FishHook.HookState.UNHOOKED).callEvent(); // Paper - Add FishHookStateChangeEvent. #UNHOOKED
|
||||
this.currentState = FishingHook.FishHookState.FLYING;
|
||||
}
|
||||
}
|
||||
@@ -247,14 +_,14 @@
|
||||
if (!player.isRemoved() && player.isAlive() && (isFishingRod || isFishingRod1) && !(this.distanceToSqr(player) > 1024.0)) {
|
||||
return false;
|
||||
|
||||
@ -13,11 +13,12 @@
|
||||
public static final SpawnPlacementType RAVAGER_SPAWN_PLACEMENT_TYPE = SpawnPlacements.getPlacementType(EntityType.RAVAGER);
|
||||
public static final MapCodec<Raid> MAP_CODEC = RecordCodecBuilder.mapCodec(
|
||||
instance -> instance.group(
|
||||
@@ -74,6 +_,7 @@
|
||||
@@ -74,6 +_,8 @@
|
||||
Raid.RaidStatus.CODEC.fieldOf("status").forGetter(raid -> raid.status),
|
||||
BlockPos.CODEC.fieldOf("center").forGetter(raid -> raid.center),
|
||||
UUIDUtil.CODEC_SET.fieldOf("heroes_of_the_village").forGetter(raid -> raid.heroesOfTheVillage)
|
||||
+ , org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer.createCodec(PDC_TYPE_REGISTRY).fieldOf(PDC_NBT_KEY).forGetter(raid -> raid.persistentDataContainer)
|
||||
+ , org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer.createCodec(PDC_TYPE_REGISTRY).lenientOptionalFieldOf(PDC_NBT_KEY) // Paper - add persistent data container
|
||||
+ .forGetter(raid -> raid.persistentDataContainer.isEmpty() ? java.util.Optional.empty() : java.util.Optional.of(raid.persistentDataContainer)) // Paper - add persistent data container
|
||||
)
|
||||
.apply(instance, Raid::new)
|
||||
);
|
||||
@ -33,7 +34,7 @@
|
||||
Raid.RaidStatus status,
|
||||
BlockPos center,
|
||||
Set<UUID> heroesOfTheVillage
|
||||
+ , final org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer persistentDataContainer // Paper - add persistent data container
|
||||
+ , final Optional<org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer> persistentDataContainer // Paper - add persistent data container
|
||||
) {
|
||||
this.started = started;
|
||||
this.active = active;
|
||||
@ -41,7 +42,7 @@
|
||||
this.numGroups = numGroups;
|
||||
this.status = status;
|
||||
this.heroesOfTheVillage.addAll(heroesOfTheVillage);
|
||||
+ this.persistentDataContainer = persistentDataContainer; // Paper - add persistent data container
|
||||
+ this.persistentDataContainer = persistentDataContainer.orElseGet(() -> new org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer(PDC_TYPE_REGISTRY)); // Paper - add persistent data container
|
||||
}
|
||||
|
||||
public boolean isOver() {
|
||||
|
||||
@ -1,15 +1,9 @@
|
||||
--- a/net/minecraft/world/inventory/ContainerSynchronizer.java
|
||||
+++ b/net/minecraft/world/inventory/ContainerSynchronizer.java
|
||||
@@ -13,4 +_,12 @@
|
||||
@@ -13,4 +_,6 @@
|
||||
void sendDataChange(AbstractContainerMenu container, int id, int value);
|
||||
|
||||
RemoteSlot createSlot();
|
||||
+
|
||||
+ default void sendOffHandSlotChange() {} // Paper - Sync offhand slot in menus
|
||||
+
|
||||
+ // Paper start - add flag to simplify remote matching logic
|
||||
+ default net.minecraft.server.level.@org.jspecify.annotations.Nullable ServerPlayer player() {
|
||||
+ return null;
|
||||
+ }
|
||||
+ // Paper end - add flag to simplify remote matching logic
|
||||
}
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
--- a/net/minecraft/world/inventory/RemoteSlot.java
|
||||
+++ b/net/minecraft/world/inventory/RemoteSlot.java
|
||||
@@ -29,12 +_,14 @@
|
||||
|
||||
public static class Synchronized implements RemoteSlot {
|
||||
private final HashedPatchMap.HashGenerator hasher;
|
||||
+ private final boolean simplifyMatching; // Paper - add flag to simplify remote matching logic
|
||||
@Nullable
|
||||
private ItemStack remoteStack = null;
|
||||
@Nullable
|
||||
private HashedStack remoteHash = null;
|
||||
|
||||
- public Synchronized(HashedPatchMap.HashGenerator hasher) {
|
||||
+ public Synchronized(HashedPatchMap.HashGenerator hasher, final boolean simplifyMatching) { // Paper - add flag to simplify remote matching logic
|
||||
+ this.simplifyMatching = simplifyMatching; // Paper - add flag to simplify remote matching logic
|
||||
this.hasher = hasher;
|
||||
}
|
||||
|
||||
@@ -54,7 +_,7 @@
|
||||
public boolean matches(ItemStack stack) {
|
||||
if (this.remoteStack != null) {
|
||||
return ItemStack.matches(this.remoteStack, stack);
|
||||
- } else if (this.remoteHash != null && this.remoteHash.matches(stack, this.hasher)) {
|
||||
+ } else if (this.remoteHash != null && this.remoteHash.matches(stack, this.hasher, this.simplifyMatching)) { // Paper - add flag to simplify remote matching logic
|
||||
this.remoteStack = stack.copy();
|
||||
return true;
|
||||
} else {
|
||||
@ -0,0 +1,11 @@
|
||||
--- a/net/minecraft/world/item/BowItem.java
|
||||
+++ b/net/minecraft/world/item/BowItem.java
|
||||
@@ -38,7 +_,7 @@
|
||||
} else {
|
||||
List<ItemStack> list = draw(stack, projectile, player);
|
||||
if (level instanceof ServerLevel serverLevel && !list.isEmpty()) {
|
||||
- this.shoot(serverLevel, player, player.getUsedItemHand(), stack, list, powerForTime * 3.0F, 1.0F, powerForTime == 1.0F, null);
|
||||
+ this.shoot(serverLevel, player, player.getUsedItemHand(), stack, list, powerForTime * 3.0F, 1.0F, powerForTime == 1.0F, null, powerForTime); // Paper - Pass draw strength
|
||||
}
|
||||
|
||||
level.playSound(
|
||||
@ -30,6 +30,15 @@
|
||||
} else {
|
||||
Projectile projectile = super.createProjectile(level, shooter, weapon, ammo, isCrit);
|
||||
if (projectile instanceof AbstractArrow abstractArrow) {
|
||||
@@ -163,7 +_,7 @@
|
||||
if (level instanceof ServerLevel serverLevel) {
|
||||
ChargedProjectiles chargedProjectiles = weapon.set(DataComponents.CHARGED_PROJECTILES, ChargedProjectiles.EMPTY);
|
||||
if (chargedProjectiles != null && !chargedProjectiles.isEmpty()) {
|
||||
- this.shoot(serverLevel, shooter, hand, weapon, chargedProjectiles.getItems(), velocity, inaccuracy, shooter instanceof Player, target);
|
||||
+ this.shoot(serverLevel, shooter, hand, weapon, chargedProjectiles.getItems(), velocity, inaccuracy, shooter instanceof Player, target, 1); // Paper - Pass draw strength
|
||||
if (shooter instanceof ServerPlayer serverPlayer) {
|
||||
CriteriaTriggers.SHOT_CROSSBOW.trigger(serverPlayer, weapon);
|
||||
serverPlayer.awardStat(Stats.ITEM_USED.get(weapon.getItem()));
|
||||
@@ -211,7 +_,14 @@
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
--- a/net/minecraft/world/item/EmptyMapItem.java
|
||||
+++ b/net/minecraft/world/item/EmptyMapItem.java
|
||||
@@ -17,10 +_,16 @@
|
||||
public InteractionResult use(Level level, Player player, InteractionHand hand) {
|
||||
ItemStack itemInHand = player.getItemInHand(hand);
|
||||
if (level instanceof ServerLevel serverLevel) {
|
||||
+ org.bukkit.inventory.ItemStack emptyMap = itemInHand.asBukkitCopy(); // Paper - PlayerMapFilledEvent
|
||||
itemInHand.consume(1, player);
|
||||
player.awardStat(Stats.ITEM_USED.get(this));
|
||||
serverLevel.playSound(null, player, SoundEvents.UI_CARTOGRAPHY_TABLE_TAKE_RESULT, player.getSoundSource(), 1.0F, 1.0F);
|
||||
ItemStack itemStack = MapItem.create(serverLevel, player.getBlockX(), player.getBlockZ(), (byte)0, true, false);
|
||||
+ // Paper start - PlayerMapFilledEvent
|
||||
+ io.papermc.paper.event.player.PlayerMapFilledEvent event = new io.papermc.paper.event.player.PlayerMapFilledEvent((org.bukkit.entity.Player) player.getBukkitEntity(), emptyMap, org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack));
|
||||
+ event.callEvent();
|
||||
+ itemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getCreatedMap());
|
||||
+ // Paper end - PlayerMapFilledEvent
|
||||
if (itemInHand.isEmpty()) {
|
||||
return InteractionResult.SUCCESS.heldItemTransformedTo(itemStack);
|
||||
} else {
|
||||
@ -1,5 +1,13 @@
|
||||
--- a/net/minecraft/world/item/ProjectileWeaponItem.java
|
||||
+++ b/net/minecraft/world/item/ProjectileWeaponItem.java
|
||||
@@ -50,6 +_,7 @@
|
||||
float inaccuracy,
|
||||
boolean isCrit,
|
||||
@Nullable LivingEntity target
|
||||
+ ,float drawStrength // Paper - Pass draw strength
|
||||
) {
|
||||
float f = EnchantmentHelper.processProjectileSpread(level, weapon, shooter, 0.0F);
|
||||
float f1 = projectileItems.size() == 1 ? 0.0F : 2.0F * f / (projectileItems.size() - 1);
|
||||
@@ -62,12 +_,29 @@
|
||||
float f4 = f2 + f3 * ((i + 1) / 2) * f1;
|
||||
f3 = -f3;
|
||||
@ -14,7 +22,7 @@
|
||||
+ Projectile projectile = this.createProjectile(level, shooter, weapon, itemStack, isCrit);
|
||||
+ this.shootProjectile(shooter, projectile, i1, velocity, inaccuracy, f4, target);
|
||||
+
|
||||
+ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(shooter, weapon, itemStack, projectile, hand, velocity, true);
|
||||
+ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(shooter, weapon, itemStack, projectile, hand, drawStrength, true);
|
||||
+ if (event.isCancelled()) {
|
||||
+ event.getProjectile().remove();
|
||||
+ return;
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
Vec3 vec3 = entity.position();
|
||||
- if (entity.randomTeleport(d, d1, d2, true)) {
|
||||
+ // CraftBukkit start - handle canceled status of teleport event
|
||||
+ java.util.Optional<Boolean> status = entity.randomTeleport(d, d1, d2, true, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.CHORUS_FRUIT);
|
||||
+ java.util.Optional<Boolean> status = entity.randomTeleport(d, d1, d2, true, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.CONSUMABLE_EFFECT);
|
||||
+
|
||||
+ // teleport event was canceled, no more tries
|
||||
+ if (status.isEmpty()) break;
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
--- a/net/minecraft/world/item/enchantment/EnchantmentHelper.java
|
||||
+++ b/net/minecraft/world/item/enchantment/EnchantmentHelper.java
|
||||
@@ -52,8 +_,14 @@
|
||||
}
|
||||
|
||||
public static ItemEnchantments updateEnchantments(ItemStack stack, Consumer<ItemEnchantments.Mutable> updater) {
|
||||
+ // Paper start - allowing updating enchantments on items without component
|
||||
+ return updateEnchantments(stack, updater, false);
|
||||
+ }
|
||||
+
|
||||
+ public static ItemEnchantments updateEnchantments(ItemStack stack, Consumer<ItemEnchantments.Mutable> updater, final boolean createComponentIfMissing) {
|
||||
+ // Paper end - allowing updating enchantments on items without component
|
||||
DataComponentType<ItemEnchantments> componentType = getComponentType(stack);
|
||||
- ItemEnchantments itemEnchantments = stack.get(componentType);
|
||||
+ ItemEnchantments itemEnchantments = createComponentIfMissing ? stack.getOrDefault(componentType, ItemEnchantments.EMPTY) : stack.get(componentType); // Paper - allowing updating enchantments on items without component
|
||||
if (itemEnchantments == null) {
|
||||
return ItemEnchantments.EMPTY;
|
||||
} else {
|
||||
@ -24,7 +24,7 @@
|
||||
+ // CraftBukkit start
|
||||
+ private final CraftWorld world;
|
||||
+ public boolean pvpMode;
|
||||
+ public org.bukkit.generator.ChunkGenerator generator;
|
||||
+ public @Nullable org.bukkit.generator.ChunkGenerator generator;
|
||||
+
|
||||
+ public boolean captureBlockStates = false;
|
||||
+ public boolean captureTreeGeneration = false;
|
||||
@ -81,16 +81,16 @@
|
||||
long biomeZoomSeed,
|
||||
- int maxChainedNeighborUpdates
|
||||
+ int maxChainedNeighborUpdates,
|
||||
+ org.bukkit.generator.ChunkGenerator gen, // CraftBukkit
|
||||
+ org.bukkit.generator.BiomeProvider biomeProvider, // CraftBukkit
|
||||
+ org.bukkit.World.Environment env, // CraftBukkit
|
||||
+ @Nullable org.bukkit.generator.ChunkGenerator generator, // Paper
|
||||
+ @Nullable org.bukkit.generator.BiomeProvider biomeProvider, // Paper
|
||||
+ org.bukkit.World.Environment environment, // Paper
|
||||
+ java.util.function.Function<org.spigotmc.SpigotWorldConfig, // Spigot - create per world config
|
||||
+ io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator // Paper - create paper world config
|
||||
) {
|
||||
+ this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName()); // Spigot
|
||||
+ this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config
|
||||
+ this.generator = gen;
|
||||
+ this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env);
|
||||
+ this.generator = generator;
|
||||
+ this.world = new CraftWorld((ServerLevel) this, generator, biomeProvider, environment);
|
||||
+
|
||||
+ for (SpawnCategory spawnCategory : SpawnCategory.values()) {
|
||||
+ if (org.bukkit.craftbukkit.util.CraftSpawnCategory.isValidForLimits(spawnCategory)) {
|
||||
|
||||
@ -1,5 +1,67 @@
|
||||
--- a/net/minecraft/world/level/block/entity/BrushableBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/BrushableBlockEntity.java
|
||||
@@ -65,9 +_,26 @@
|
||||
return false;
|
||||
} else {
|
||||
this.coolDownEndsAtTick = startTick + 10L;
|
||||
+ // Paper start - EntityChangeBlockEvent
|
||||
+ // The vanilla logic here is *so* backwards, we'd be moving basically *all* following calls down.
|
||||
+ // Instead, compute vanilla ourselves up here and just replace the below usages with our computed values for a free diff-on-change.
|
||||
+ final int currentCompletionStage = this.getCompletionState();
|
||||
+ final boolean enoughBrushesToBreak = ++this.brushCount >= REQUIRED_BRUSHES_TO_BREAK;
|
||||
+ final int nextCompletionStage = this.getCompletionState();
|
||||
+ final boolean differentCompletionStages = currentCompletionStage != nextCompletionStage;
|
||||
+ final BlockState nextBrokenBlockState = this.getBlockState().setValue(BlockStateProperties.DUSTED, nextCompletionStage);
|
||||
+ if (enoughBrushesToBreak || differentCompletionStages) {
|
||||
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(
|
||||
+ brusher, this.worldPosition, enoughBrushesToBreak ? computeTurnsTo().defaultBlockState() : nextBrokenBlockState
|
||||
+ )) {
|
||||
+ brushCount--;
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - EntityChangeBlockEvent
|
||||
this.unpackLootTable(level, brusher, stack);
|
||||
- int completionState = this.getCompletionState();
|
||||
- if (++this.brushCount >= 10) {
|
||||
+ int completionState = currentCompletionStage; // Paper - EntityChangeBlockEvent - use precomputed - diff on change
|
||||
+ if (enoughBrushesToBreak) { // Paper - EntityChangeBlockEvent - use precomputed - diff on change
|
||||
this.brushingCompleted(level, brusher, stack);
|
||||
return true;
|
||||
} else {
|
||||
@@ -75,7 +_,7 @@
|
||||
int completionState1 = this.getCompletionState();
|
||||
if (completionState != completionState1) {
|
||||
BlockState blockState = this.getBlockState();
|
||||
- BlockState blockState1 = blockState.setValue(BlockStateProperties.DUSTED, completionState1);
|
||||
+ BlockState blockState1 = nextBrokenBlockState; // Paper - EntityChangeBlockEvent - use precomputed - diff on change
|
||||
level.setBlock(this.getBlockPos(), blockState1, 3);
|
||||
}
|
||||
|
||||
@@ -116,6 +_,11 @@
|
||||
this.dropContent(level, brusher, stack);
|
||||
BlockState blockState = this.getBlockState();
|
||||
level.levelEvent(3008, this.getBlockPos(), Block.getId(blockState));
|
||||
+ // Paper start - EntityChangeEvent - extract result block logic
|
||||
+ this.brushingCompleteUpdateBlock(this.computeTurnsTo());
|
||||
+ }
|
||||
+ private Block computeTurnsTo() {
|
||||
+ // Paper end - EntityChangeEvent - extract result block logic
|
||||
Block turnsInto;
|
||||
if (this.getBlockState().getBlock() instanceof BrushableBlock brushableBlock) {
|
||||
turnsInto = brushableBlock.getTurnsInto();
|
||||
@@ -123,6 +_,11 @@
|
||||
turnsInto = Blocks.AIR;
|
||||
}
|
||||
|
||||
+ // Paper start - EntityChangeEvent - extract result block logic
|
||||
+ return turnsInto;
|
||||
+ }
|
||||
+ public void brushingCompleteUpdateBlock(final Block turnsInto) {
|
||||
+ // Paper end - EntityChangeEvent - extract result block logic
|
||||
level.setBlock(this.worldPosition, turnsInto.defaultBlockState(), 3);
|
||||
}
|
||||
|
||||
@@ -139,7 +_,12 @@
|
||||
double d5 = blockPos.getZ() + 0.5 * d1 + d2;
|
||||
ItemEntity itemEntity = new ItemEntity(level, d3, d4, d5, this.item.split(level.random.nextInt(21) + 10));
|
||||
|
||||
@ -96,6 +96,20 @@
|
||||
}
|
||||
|
||||
public static void addTargetDecoration(ItemStack stack, BlockPos pos, String type, Holder<MapDecorationType> mapDecorationType) {
|
||||
@@ -354,7 +_,12 @@
|
||||
}
|
||||
|
||||
public void setColorsDirty(int x, int z) {
|
||||
- this.setDirty();
|
||||
+ // Paper start - Fix unnecessary map data saves
|
||||
+ this.setColorsDirty(x, z, true);
|
||||
+ }
|
||||
+ public void setColorsDirty(int x, int z, boolean markFileDirty) {
|
||||
+ if (markFileDirty) this.setDirty();
|
||||
+ // Paper end - Fix unnecessary map data saves
|
||||
|
||||
for (MapItemSavedData.HoldingPlayer holdingPlayer : this.carriedBy) {
|
||||
holdingPlayer.markColorsDirty(x, z);
|
||||
@@ -395,7 +_,7 @@
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ public class PaperVersionFetcher implements VersionFetcher {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getVersionMessage(final String serverVersion) {
|
||||
public Component getVersionMessage() {
|
||||
final Component updateMessage;
|
||||
final ServerBuildInfo build = ServerBuildInfo.buildInfo();
|
||||
if (build.buildNumber().isEmpty() && build.gitCommit().isEmpty()) {
|
||||
|
||||
@ -1,10 +1,21 @@
|
||||
package io.papermc.paper;
|
||||
|
||||
import io.papermc.paper.world.damagesource.CombatEntry;
|
||||
import io.papermc.paper.world.damagesource.FallLocationType;
|
||||
import io.papermc.paper.world.damagesource.PaperCombatEntryWrapper;
|
||||
import io.papermc.paper.world.damagesource.PaperCombatTrackerWrapper;
|
||||
import net.minecraft.Optionull;
|
||||
import net.minecraft.world.damagesource.FallLocation;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.craftbukkit.block.CraftBiome;
|
||||
import org.bukkit.craftbukkit.damage.CraftDamageEffect;
|
||||
import org.bukkit.craftbukkit.damage.CraftDamageSource;
|
||||
import org.bukkit.craftbukkit.entity.CraftLivingEntity;
|
||||
import org.bukkit.damage.DamageEffect;
|
||||
import org.bukkit.damage.DamageSource;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@NullMarked
|
||||
public class PaperServerInternalAPIBridge implements InternalAPIBridge {
|
||||
@ -22,4 +33,42 @@ public class PaperServerInternalAPIBridge implements InternalAPIBridge {
|
||||
}
|
||||
return Holder.LEGACY_CUSTOM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CombatEntry createCombatEntry(final LivingEntity entity, final DamageSource damageSource, final float damage) {
|
||||
final net.minecraft.world.entity.LivingEntity mob = ((CraftLivingEntity) entity).getHandle();
|
||||
final FallLocation fallLocation = FallLocation.getCurrentFallLocation(mob);
|
||||
return createCombatEntry(
|
||||
((CraftDamageSource) damageSource).getHandle(),
|
||||
damage,
|
||||
fallLocation,
|
||||
(float) mob.fallDistance
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CombatEntry createCombatEntry(
|
||||
final DamageSource damageSource,
|
||||
final float damage,
|
||||
@Nullable final FallLocationType fallLocationType,
|
||||
final float fallDistance
|
||||
) {
|
||||
return createCombatEntry(
|
||||
((CraftDamageSource) damageSource).getHandle(),
|
||||
damage,
|
||||
Optionull.map(fallLocationType, PaperCombatTrackerWrapper::paperToMinecraft),
|
||||
fallDistance
|
||||
);
|
||||
}
|
||||
|
||||
private CombatEntry createCombatEntry(
|
||||
final net.minecraft.world.damagesource.DamageSource damageSource,
|
||||
final float damage,
|
||||
final net.minecraft.world.damagesource.@Nullable FallLocation fallLocation,
|
||||
final float fallDistance
|
||||
) {
|
||||
return new PaperCombatEntryWrapper(new net.minecraft.world.damagesource.CombatEntry(
|
||||
damageSource, damage, fallLocation, fallDistance
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,15 @@
|
||||
package io.papermc.paper.command;
|
||||
|
||||
import io.papermc.paper.FeatureHooks;
|
||||
import io.papermc.paper.command.subcommands.*;
|
||||
import io.papermc.paper.command.subcommands.DumpItemCommand;
|
||||
import io.papermc.paper.command.subcommands.DumpListenersCommand;
|
||||
import io.papermc.paper.command.subcommands.DumpPluginsCommand;
|
||||
import io.papermc.paper.command.subcommands.EntityCommand;
|
||||
import io.papermc.paper.command.subcommands.HeapDumpCommand;
|
||||
import io.papermc.paper.command.subcommands.MobcapsCommand;
|
||||
import io.papermc.paper.command.subcommands.ReloadCommand;
|
||||
import io.papermc.paper.command.subcommands.SyncLoadInfoCommand;
|
||||
import io.papermc.paper.command.subcommands.VersionCommand;
|
||||
import it.unimi.dsi.fastutil.Pair;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
@ -1,10 +1,15 @@
|
||||
package io.papermc.paper.command;
|
||||
|
||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
import io.papermc.paper.command.brigadier.CommandRegistrationFlag;
|
||||
import io.papermc.paper.command.brigadier.CommandSourceStack;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.bukkit.command.Command;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
|
||||
@ -15,16 +20,32 @@ public final class PaperCommands {
|
||||
}
|
||||
|
||||
private static final Map<String, Command> COMMANDS = new HashMap<>();
|
||||
static {
|
||||
|
||||
public static void registerCommands(final MinecraftServer server) {
|
||||
COMMANDS.put("paper", new PaperCommand("paper"));
|
||||
COMMANDS.put("callback", new CallbackCommand("callback"));
|
||||
COMMANDS.put("mspt", new MSPTCommand("mspt"));
|
||||
}
|
||||
|
||||
public static void registerCommands(final MinecraftServer server) {
|
||||
COMMANDS.forEach((s, command) -> {
|
||||
server.server.getCommandMap().register(s, "Paper", command);
|
||||
});
|
||||
server.server.getCommandMap().register("bukkit", new PaperPluginsCommand());
|
||||
}
|
||||
|
||||
public static void registerCommands() {
|
||||
// Paper commands go here
|
||||
registerInternalCommand(PaperVersionCommand.create(), "bukkit", PaperVersionCommand.DESCRIPTION, List.of("ver", "about"), Set.of());
|
||||
}
|
||||
|
||||
private static void registerInternalCommand(final LiteralCommandNode<CommandSourceStack> node, final String namespace, final String description, final List<String> aliases, final Set<CommandRegistrationFlag> flags) {
|
||||
io.papermc.paper.command.brigadier.PaperCommands.INSTANCE.registerWithFlagsInternal(
|
||||
null,
|
||||
namespace,
|
||||
"Paper",
|
||||
node,
|
||||
description,
|
||||
aliases,
|
||||
flags
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,184 @@
|
||||
package io.papermc.paper.command;
|
||||
|
||||
import com.destroystokyo.paper.PaperVersionFetcher;
|
||||
import com.destroystokyo.paper.util.VersionFetcher;
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
import io.papermc.paper.command.brigadier.CommandSourceStack;
|
||||
import io.papermc.paper.command.brigadier.Commands;
|
||||
import io.papermc.paper.plugin.configuration.PluginMeta;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.util.StringUtil;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@NullMarked
|
||||
public class PaperVersionCommand {
|
||||
public static final String DESCRIPTION = "Gets the version of this server including any plugins in use";
|
||||
|
||||
private static final Component NOT_RUNNING = Component.text()
|
||||
.append(Component.text("This server is not running any plugin by that name."))
|
||||
.appendNewline()
|
||||
.append(Component.text("Use /plugins to get a list of plugins.").clickEvent(ClickEvent.suggestCommand("/plugins")))
|
||||
.build();
|
||||
private static final JoinConfiguration PLAYER_JOIN_CONFIGURATION = JoinConfiguration.separators(
|
||||
Component.text(", ", NamedTextColor.WHITE),
|
||||
Component.text(", and ", NamedTextColor.WHITE)
|
||||
);
|
||||
private static final Component FAILED_TO_FETCH = Component.text("Could not fetch version information!", NamedTextColor.RED);
|
||||
private static final Component FETCHING = Component.text("Checking version, please wait...", NamedTextColor.WHITE, TextDecoration.ITALIC);
|
||||
|
||||
private final VersionFetcher versionFetcher = new PaperVersionFetcher();
|
||||
private CompletableFuture<ComputedVersion> computedVersion = CompletableFuture.completedFuture(new ComputedVersion(Component.empty(), -1)); // Precompute-- someday move that stuff out of bukkit
|
||||
|
||||
public static LiteralCommandNode<CommandSourceStack> create() {
|
||||
final PaperVersionCommand command = new PaperVersionCommand();
|
||||
|
||||
return Commands.literal("version")
|
||||
.requires(source -> source.getSender().hasPermission("bukkit.command.version"))
|
||||
.then(Commands.argument("plugin", StringArgumentType.word())
|
||||
.suggests(command::suggestPlugins)
|
||||
.executes(command::pluginVersion))
|
||||
.executes(command::serverVersion)
|
||||
.build();
|
||||
}
|
||||
|
||||
private int pluginVersion(final CommandContext<CommandSourceStack> context) {
|
||||
final CommandSender sender = context.getSource().getSender();
|
||||
final String pluginName = context.getArgument("plugin", String.class).toLowerCase(Locale.ROOT);
|
||||
|
||||
Plugin plugin = Bukkit.getPluginManager().getPlugin(pluginName);
|
||||
if (plugin == null) {
|
||||
plugin = Arrays.stream(Bukkit.getPluginManager().getPlugins())
|
||||
.filter(checkPlugin -> checkPlugin.getName().toLowerCase(Locale.ROOT).contains(pluginName))
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
if (plugin != null) {
|
||||
this.sendPluginInfo(plugin, sender);
|
||||
} else {
|
||||
sender.sendMessage(NOT_RUNNING);
|
||||
}
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
private CompletableFuture<Suggestions> suggestPlugins(final CommandContext<CommandSourceStack> context, final SuggestionsBuilder builder) {
|
||||
for (final Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
|
||||
final String name = plugin.getName();
|
||||
if (StringUtil.startsWithIgnoreCase(name, builder.getRemainingLowerCase())) {
|
||||
builder.suggest(name);
|
||||
}
|
||||
}
|
||||
|
||||
return CompletableFuture.completedFuture(builder.build());
|
||||
}
|
||||
|
||||
private void sendPluginInfo(final Plugin plugin, final CommandSender sender) {
|
||||
final PluginMeta meta = plugin.getPluginMeta();
|
||||
|
||||
final TextComponent.Builder builder = Component.text()
|
||||
.append(Component.text(meta.getName()))
|
||||
.append(Component.text(" version "))
|
||||
.append(Component.text(meta.getVersion(), NamedTextColor.GREEN)
|
||||
.hoverEvent(Component.translatable("chat.copy.click"))
|
||||
.clickEvent(ClickEvent.copyToClipboard(meta.getVersion()))
|
||||
);
|
||||
|
||||
if (meta.getDescription() != null) {
|
||||
builder
|
||||
.appendNewline()
|
||||
.append(Component.text(meta.getDescription()));
|
||||
}
|
||||
|
||||
if (meta.getWebsite() != null) {
|
||||
Component websiteComponent = Component.text(meta.getWebsite(), NamedTextColor.GREEN).clickEvent(ClickEvent.openUrl(meta.getWebsite()));
|
||||
builder.appendNewline().append(Component.text("Website: ").append(websiteComponent));
|
||||
}
|
||||
|
||||
if (!meta.getAuthors().isEmpty()) {
|
||||
String prefix = meta.getAuthors().size() == 1 ? "Author: " : "Authors: ";
|
||||
builder.appendNewline().append(Component.text(prefix).append(formatNameList(meta.getAuthors())));
|
||||
}
|
||||
|
||||
if (!meta.getContributors().isEmpty()) {
|
||||
builder.appendNewline().append(Component.text("Contributors: ").append(formatNameList(meta.getContributors())));
|
||||
}
|
||||
sender.sendMessage(builder.build());
|
||||
}
|
||||
|
||||
private static Component formatNameList(final List<String> names) {
|
||||
return Component.join(PLAYER_JOIN_CONFIGURATION, names.stream().map(Component::text).toList()).color(NamedTextColor.GREEN);
|
||||
}
|
||||
|
||||
private int serverVersion(CommandContext<CommandSourceStack> context) {
|
||||
sendVersion(context.getSource().getSender());
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
private void sendVersion(final CommandSender sender) {
|
||||
final CompletableFuture<ComputedVersion> version = getVersionOrFetch();
|
||||
if (!version.isDone()) {
|
||||
sender.sendMessage(FETCHING);
|
||||
}
|
||||
|
||||
version.whenComplete((computedVersion, throwable) -> {
|
||||
if (computedVersion != null) {
|
||||
sender.sendMessage(computedVersion.message);
|
||||
} else if (throwable != null) {
|
||||
sender.sendMessage(FAILED_TO_FETCH);
|
||||
MinecraftServer.LOGGER.warn("Could not fetch version information!", throwable);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private CompletableFuture<ComputedVersion> getVersionOrFetch() {
|
||||
if (!this.computedVersion.isDone()) {
|
||||
return this.computedVersion;
|
||||
}
|
||||
|
||||
if (this.computedVersion.isCompletedExceptionally() || System.currentTimeMillis() - this.computedVersion.resultNow().computedTime() > this.versionFetcher.getCacheTime()) {
|
||||
this.computedVersion = this.fetchVersionMessage();
|
||||
}
|
||||
|
||||
return this.computedVersion;
|
||||
}
|
||||
|
||||
private CompletableFuture<ComputedVersion> fetchVersionMessage() {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
final Component message = Component.textOfChildren(
|
||||
Component.text(Bukkit.getVersionMessage(), NamedTextColor.WHITE),
|
||||
Component.newline(),
|
||||
this.versionFetcher.getVersionMessage()
|
||||
);
|
||||
|
||||
return new ComputedVersion(
|
||||
message.hoverEvent(Component.translatable("chat.copy.click", NamedTextColor.WHITE))
|
||||
.clickEvent(ClickEvent.copyToClipboard(PlainTextComponentSerializer.plainText().serialize(message))),
|
||||
System.currentTimeMillis()
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
record ComputedVersion(Component message, long computedTime) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package io.papermc.paper.command.brigadier;
|
||||
|
||||
import io.papermc.paper.plugin.configuration.PluginMeta;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@NullMarked
|
||||
public record APICommandMeta(@Nullable PluginMeta pluginMeta, @Nullable String description, List<String> aliases, @Nullable String helpCommandNamespace, boolean serverSideOnly) {
|
||||
|
||||
public APICommandMeta(final @Nullable PluginMeta pluginMeta, final @Nullable String description) {
|
||||
this(pluginMeta, description, Collections.emptyList(), null, false);
|
||||
}
|
||||
|
||||
public APICommandMeta {
|
||||
aliases = List.copyOf(aliases);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Plugin plugin() {
|
||||
return this.pluginMeta == null ? null : Objects.requireNonNull(Bukkit.getPluginManager().getPlugin(this.pluginMeta.getName()));
|
||||
}
|
||||
|
||||
public APICommandMeta withAliases(List<String> registeredAliases) {
|
||||
return new APICommandMeta(this.pluginMeta, this.description, List.copyOf(registeredAliases), this.helpCommandNamespace, this.serverSideOnly);
|
||||
}
|
||||
}
|
||||
@ -35,8 +35,8 @@ public final class PaperBrigadier {
|
||||
throw new IllegalArgumentException("Unsure how to wrap a " + node);
|
||||
}
|
||||
|
||||
final PluginCommandMeta meta;
|
||||
if ((meta = node.pluginCommandMeta) == null) {
|
||||
final APICommandMeta meta;
|
||||
if ((meta = node.apiCommandMeta) == null) {
|
||||
return new VanillaCommandWrapper(node);
|
||||
}
|
||||
CommandNode<CommandSourceStack> argumentCommandNode = node;
|
||||
@ -46,6 +46,12 @@ public final class PaperBrigadier {
|
||||
|
||||
Map<CommandNode<CommandSourceStack>, String> map = PaperCommands.INSTANCE.getDispatcherInternal().getSmartUsage(argumentCommandNode, DUMMY);
|
||||
String usage = map.isEmpty() ? node.getUsageText() : node.getUsageText() + " " + String.join("\n" + node.getUsageText() + " ", map.values());
|
||||
|
||||
// Internal command
|
||||
if (meta.pluginMeta() == null) {
|
||||
return new VanillaCommandWrapper(node.getName(), meta.description(), usage, meta.aliases(), node, meta.helpCommandNamespace());
|
||||
}
|
||||
|
||||
return new PluginVanillaCommandWrapper(node.getName(), meta.description(), usage, meta.aliases(), node, meta.plugin());
|
||||
}
|
||||
|
||||
|
||||
@ -91,10 +91,13 @@ public class PaperCommands implements Commands, PaperRegistrar<LifecycleEventOwn
|
||||
|
||||
@Override
|
||||
public @Unmodifiable Set<String> registerWithFlags(final PluginMeta pluginMeta, final LiteralCommandNode<CommandSourceStack> node, final @Nullable String description, final Collection<String> aliases, final Set<CommandRegistrationFlag> flags) {
|
||||
final PluginCommandMeta meta = new PluginCommandMeta(pluginMeta, description);
|
||||
final String identifier = pluginMeta.getName().toLowerCase(Locale.ROOT);
|
||||
return registerWithFlagsInternal(pluginMeta, pluginMeta.getName().toLowerCase(Locale.ROOT), null, node, description, aliases, flags);
|
||||
}
|
||||
|
||||
public @Unmodifiable Set<String> registerWithFlagsInternal(final @Nullable PluginMeta pluginMeta, final String namespace, final @Nullable String helpNamespaceOverride, final LiteralCommandNode<CommandSourceStack> node, final @Nullable String description, final Collection<String> aliases, final Set<CommandRegistrationFlag> flags) {
|
||||
final APICommandMeta meta = new APICommandMeta(pluginMeta, description, List.of(), helpNamespaceOverride, flags.contains(CommandRegistrationFlag.SERVER_ONLY));
|
||||
final String literal = node.getLiteral();
|
||||
final LiteralCommandNode<CommandSourceStack> pluginLiteral = PaperBrigadier.copyLiteral(identifier + ":" + literal, node);
|
||||
final LiteralCommandNode<CommandSourceStack> pluginLiteral = PaperBrigadier.copyLiteral(namespace + ":" + literal, node);
|
||||
|
||||
final Set<String> registeredLabels = new HashSet<>(aliases.size() * 2 + 2);
|
||||
|
||||
@ -111,27 +114,27 @@ public class PaperCommands implements Commands, PaperRegistrar<LifecycleEventOwn
|
||||
if (this.registerCopy(alias, pluginLiteral, meta)) {
|
||||
registeredAliases.add(alias);
|
||||
}
|
||||
if (this.registerCopy(identifier + ":" + alias, pluginLiteral, meta)) {
|
||||
registeredAliases.add(identifier + ":" + alias);
|
||||
if (this.registerCopy(namespace + ":" + alias, pluginLiteral, meta)) {
|
||||
registeredAliases.add(namespace + ":" + alias);
|
||||
}
|
||||
}
|
||||
|
||||
pluginLiteral.pluginCommandMeta = new PluginCommandMeta(pluginMeta, description, registeredAliases);
|
||||
node.pluginCommandMeta = pluginLiteral.pluginCommandMeta;
|
||||
pluginLiteral.apiCommandMeta = meta.withAliases(registeredAliases);
|
||||
node.apiCommandMeta = pluginLiteral.apiCommandMeta;
|
||||
|
||||
registeredLabels.addAll(registeredAliases);
|
||||
return registeredLabels.isEmpty() ? Collections.emptySet() : Collections.unmodifiableSet(registeredLabels);
|
||||
}
|
||||
|
||||
private boolean registerCopy(final String aliasLiteral, final LiteralCommandNode<CommandSourceStack> redirectTo, final PluginCommandMeta meta) {
|
||||
private boolean registerCopy(final String aliasLiteral, final LiteralCommandNode<CommandSourceStack> redirectTo, final APICommandMeta meta) {
|
||||
final LiteralCommandNode<CommandSourceStack> node = PaperBrigadier.copyLiteral(aliasLiteral, redirectTo);
|
||||
node.pluginCommandMeta = meta;
|
||||
node.apiCommandMeta = meta;
|
||||
return this.registerIntoDispatcher(node, false);
|
||||
}
|
||||
|
||||
private boolean registerIntoDispatcher(final LiteralCommandNode<CommandSourceStack> node, boolean override) {
|
||||
final CommandNode<CommandSourceStack> existingChild = this.getDispatcher().getRoot().getChild(node.getLiteral());
|
||||
if (existingChild != null && existingChild.pluginCommandMeta == null && !(existingChild instanceof BukkitCommandNode)) {
|
||||
if (existingChild != null && existingChild.apiCommandMeta == null && !(existingChild instanceof BukkitCommandNode)) {
|
||||
override = true; // override vanilla commands
|
||||
}
|
||||
if (existingChild == null || override) { // Avoid merging behavior. Maybe something to look into in the future
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
package io.papermc.paper.command.brigadier;
|
||||
|
||||
import io.papermc.paper.plugin.configuration.PluginMeta;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@NullMarked
|
||||
public record PluginCommandMeta(PluginMeta pluginMeta, @Nullable String description, List<String> aliases) {
|
||||
|
||||
public PluginCommandMeta(final PluginMeta pluginMeta, final @Nullable String description) {
|
||||
this(pluginMeta, description, Collections.emptyList());
|
||||
}
|
||||
|
||||
public PluginCommandMeta {
|
||||
aliases = List.copyOf(aliases);
|
||||
}
|
||||
|
||||
public Plugin plugin() {
|
||||
return Objects.requireNonNull(Bukkit.getPluginManager().getPlugin(this.pluginMeta.getName()));
|
||||
}
|
||||
}
|
||||
@ -17,7 +17,7 @@ public class PluginVanillaCommandWrapper extends VanillaCommandWrapper implement
|
||||
private final List<String> aliases;
|
||||
|
||||
public PluginVanillaCommandWrapper(String name, String description, String usageMessage, List<String> aliases, CommandNode<CommandSourceStack> vanillaCommand, Plugin plugin) {
|
||||
super(name, description, usageMessage, aliases, vanillaCommand);
|
||||
super(name, description, usageMessage, aliases, vanillaCommand, null);
|
||||
this.plugin = plugin;
|
||||
this.aliases = aliases;
|
||||
}
|
||||
|
||||
@ -86,6 +86,7 @@ import org.bukkit.block.structure.Mirror;
|
||||
import org.bukkit.block.structure.StructureRotation;
|
||||
import org.bukkit.craftbukkit.CraftHeightMap;
|
||||
import org.bukkit.craftbukkit.CraftRegistry;
|
||||
import org.bukkit.craftbukkit.block.CraftBlockEntityState;
|
||||
import org.bukkit.craftbukkit.block.CraftBlockStates;
|
||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
import org.bukkit.craftbukkit.scoreboard.CraftCriteria;
|
||||
@ -172,7 +173,11 @@ public class VanillaArgumentProviderImpl implements VanillaArgumentProvider {
|
||||
@Override
|
||||
public ArgumentType<BlockState> blockState() {
|
||||
return this.wrap(BlockStateArgument.block(PaperCommands.INSTANCE.getBuildContext()), (result) -> {
|
||||
return CraftBlockStates.getBlockState(CraftRegistry.getMinecraftRegistry(), BlockPos.ZERO, result.getState(), result.tag);
|
||||
final BlockState snapshot = CraftBlockStates.getBlockState(CraftRegistry.getMinecraftRegistry(), BlockPos.ZERO, result.getState(), null);
|
||||
if (result.tag != null && snapshot instanceof final CraftBlockEntityState<?> blockEntitySnapshot) {
|
||||
blockEntitySnapshot.loadData(result.tag);
|
||||
}
|
||||
return snapshot;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -47,7 +47,7 @@ public class BukkitBrigForwardingMap extends HashMap<String, Command> {
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.size() != 0;
|
||||
return this.size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -10,9 +10,10 @@ import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
import io.papermc.paper.command.brigadier.CommandSourceStack;
|
||||
import java.util.ArrayList;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minecraft.commands.CommandSource;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandException;
|
||||
@ -107,7 +108,7 @@ public class BukkitCommandNode extends LiteralCommandNode<CommandSourceStack> {
|
||||
try {
|
||||
results = this.command.tabComplete(sender, this.literal, args, pos.clone());
|
||||
} catch (CommandException ex) {
|
||||
sender.sendMessage(ChatColor.RED + "An internal error occurred while attempting to tab-complete this command");
|
||||
sender.sendMessage(Component.text("An internal error occurred while attempting to tab-complete this command", NamedTextColor.RED));
|
||||
Bukkit.getServer().getLogger().log(Level.SEVERE, "Exception when " + sender.getName() + " attempted to tab complete " + builder.getRemaining(), ex);
|
||||
}
|
||||
|
||||
|
||||
@ -2,12 +2,13 @@ package io.papermc.paper.command.subcommands;
|
||||
|
||||
import com.destroystokyo.paper.util.SneakyThrow;
|
||||
import io.papermc.paper.command.PaperSubcommand;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
@ -16,6 +17,7 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@ -23,6 +25,7 @@ import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.RegisteredListener;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
|
||||
import static net.kyori.adventure.text.Component.newline;
|
||||
@ -35,6 +38,8 @@ import static net.kyori.adventure.text.format.NamedTextColor.WHITE;
|
||||
|
||||
@DefaultQualifier(NonNull.class)
|
||||
public final class DumpListenersCommand implements PaperSubcommand {
|
||||
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss");
|
||||
private static final String COMMAND_ARGUMENT_TO_FILE = "tofile";
|
||||
private static final MethodHandle EVENT_TYPES_HANDLE;
|
||||
|
||||
static {
|
||||
@ -49,7 +54,7 @@ public final class DumpListenersCommand implements PaperSubcommand {
|
||||
|
||||
@Override
|
||||
public boolean execute(final CommandSender sender, final String subCommand, final String[] args) {
|
||||
if (args.length >= 1 && args[0].equals("tofile")) {
|
||||
if (args.length >= 1 && args[0].equals(COMMAND_ARGUMENT_TO_FILE)) {
|
||||
this.dumpToFile(sender);
|
||||
return true;
|
||||
}
|
||||
@ -58,45 +63,69 @@ public final class DumpListenersCommand implements PaperSubcommand {
|
||||
}
|
||||
|
||||
private void dumpToFile(final CommandSender sender) {
|
||||
final File file = new File("debug/listeners-"
|
||||
+ DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss").format(LocalDateTime.now()) + ".txt");
|
||||
file.getParentFile().mkdirs();
|
||||
try (final PrintWriter writer = new PrintWriter(file)) {
|
||||
for (final String eventClass : eventClassNames()) {
|
||||
final HandlerList handlers;
|
||||
try {
|
||||
handlers = (HandlerList) findClass(eventClass).getMethod("getHandlerList").invoke(null);
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
continue;
|
||||
}
|
||||
if (handlers.getRegisteredListeners().length != 0) {
|
||||
writer.println(eventClass);
|
||||
}
|
||||
for (final RegisteredListener registeredListener : handlers.getRegisteredListeners()) {
|
||||
writer.println(" - " + registeredListener);
|
||||
Path parent = Path.of("debug");
|
||||
Path path = parent.resolve("listeners-" + FORMATTER.format(LocalDateTime.now()) + ".txt");
|
||||
sender.sendMessage(
|
||||
text("Writing listeners into directory", GREEN)
|
||||
.appendSpace()
|
||||
.append(
|
||||
text(parent.toString(), WHITE)
|
||||
.hoverEvent(text("Click to copy the full path of debug directory", WHITE))
|
||||
.clickEvent(ClickEvent.copyToClipboard(parent.toAbsolutePath().toString()))
|
||||
)
|
||||
);
|
||||
try {
|
||||
Files.createDirectories(parent);
|
||||
Files.createFile(path);
|
||||
try (final PrintWriter writer = new PrintWriter(path.toFile())){
|
||||
for (final String eventClass : eventClassNames()) {
|
||||
final HandlerList handlers;
|
||||
try {
|
||||
handlers = (HandlerList) findClass(eventClass).getMethod("getHandlerList").invoke(null);
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
continue;
|
||||
}
|
||||
if (handlers.getRegisteredListeners().length != 0) {
|
||||
writer.println(eventClass);
|
||||
}
|
||||
for (final RegisteredListener registeredListener : handlers.getRegisteredListeners()) {
|
||||
writer.println(" - " + registeredListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
sender.sendMessage(text("Failed to write dumped listener! See the console for more info.", RED));
|
||||
MinecraftServer.LOGGER.warn("Error occurred while dumping listeners", ex);
|
||||
return;
|
||||
}
|
||||
sender.sendMessage(text("Dumped listeners to " + file, GREEN));
|
||||
sender.sendMessage(
|
||||
text("Successfully written listeners into", GREEN)
|
||||
.appendSpace()
|
||||
.append(
|
||||
text(path.toString(), WHITE)
|
||||
.hoverEvent(text("Click to copy the full path of the file", WHITE))
|
||||
.clickEvent(ClickEvent.copyToClipboard(path.toAbsolutePath().toString()))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private void doDumpListeners(final CommandSender sender, final String[] args) {
|
||||
if (args.length == 0) {
|
||||
sender.sendMessage(text("Usage: /paper dumplisteners tofile|<className>", RED));
|
||||
sender.sendMessage(text("Usage: /paper dumplisteners " + COMMAND_ARGUMENT_TO_FILE + "|<className>", RED));
|
||||
return;
|
||||
}
|
||||
|
||||
final String className = args[0];
|
||||
|
||||
try {
|
||||
final HandlerList handlers = (HandlerList) findClass(args[0]).getMethod("getHandlerList").invoke(null);
|
||||
final HandlerList handlers = (HandlerList) findClass(className).getMethod("getHandlerList").invoke(null);
|
||||
|
||||
if (handlers.getRegisteredListeners().length == 0) {
|
||||
sender.sendMessage(text(args[0] + " does not have any registered listeners."));
|
||||
sender.sendMessage(text(className + " does not have any registered listeners."));
|
||||
return;
|
||||
}
|
||||
|
||||
sender.sendMessage(text("Listeners for " + args[0] + ":"));
|
||||
sender.sendMessage(text("Listeners for " + className + ":"));
|
||||
|
||||
for (final RegisteredListener listener : handlers.getRegisteredListeners()) {
|
||||
final Component hoverText = text("Priority: " + listener.getPriority().name() + " (" + listener.getPriority().getSlot() + ")", WHITE)
|
||||
@ -115,12 +144,12 @@ public final class DumpListenersCommand implements PaperSubcommand {
|
||||
sender.sendMessage(text("Total listeners: " + handlers.getRegisteredListeners().length));
|
||||
|
||||
} catch (final ClassNotFoundException e) {
|
||||
sender.sendMessage(text("Unable to find a class named '" + args[0] + "'. Make sure to use the fully qualified name.", RED));
|
||||
sender.sendMessage(text("Unable to find a class named '" + className + "'. Make sure to use the fully qualified name.", RED));
|
||||
} catch (final NoSuchMethodException e) {
|
||||
sender.sendMessage(text("Class '" + args[0] + "' does not have a valid getHandlerList method.", RED));
|
||||
sender.sendMessage(text("Class '" + className + "' does not have a valid getHandlerList method.", RED));
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
sender.sendMessage(text("Something went wrong, see the console for more details.", RED));
|
||||
MinecraftServer.LOGGER.warn("Error occurred while dumping listeners for class " + args[0], e);
|
||||
MinecraftServer.LOGGER.warn("Error occurred while dumping listeners for class {}", className, e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,7 +166,7 @@ public final class DumpListenersCommand implements PaperSubcommand {
|
||||
|
||||
private static List<String> suggestions() {
|
||||
final List<String> ret = new ArrayList<>();
|
||||
ret.add("tofile");
|
||||
ret.add(COMMAND_ARGUMENT_TO_FILE);
|
||||
ret.addAll(eventClassNames());
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.Strictness;
|
||||
import com.google.gson.internal.Streams;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import io.papermc.paper.command.PaperSubcommand;
|
||||
@ -15,7 +16,6 @@ import io.papermc.paper.plugin.entrypoint.classloader.group.PaperPluginClassLoad
|
||||
import io.papermc.paper.plugin.entrypoint.classloader.group.SimpleListPluginClassLoaderGroup;
|
||||
import io.papermc.paper.plugin.entrypoint.classloader.group.SpigotPluginClassLoaderGroup;
|
||||
import io.papermc.paper.plugin.entrypoint.classloader.group.StaticPluginClassLoaderGroup;
|
||||
import io.papermc.paper.plugin.entrypoint.dependency.GraphDependencyContext;
|
||||
import io.papermc.paper.plugin.entrypoint.dependency.SimpleMetaDependencyTree;
|
||||
import io.papermc.paper.plugin.provider.entrypoint.DependencyContext;
|
||||
import io.papermc.paper.plugin.entrypoint.strategy.modern.ModernPluginLoadingStrategy;
|
||||
@ -27,12 +27,14 @@ import io.papermc.paper.plugin.provider.classloader.PaperClassLoaderStorage;
|
||||
import io.papermc.paper.plugin.provider.classloader.PluginClassLoaderGroup;
|
||||
import io.papermc.paper.plugin.storage.ConfiguredProviderStorage;
|
||||
import io.papermc.paper.plugin.storage.ProviderStorage;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@ -47,6 +49,7 @@ import java.util.Map;
|
||||
import static net.kyori.adventure.text.Component.text;
|
||||
import static net.kyori.adventure.text.format.NamedTextColor.GREEN;
|
||||
import static net.kyori.adventure.text.format.NamedTextColor.RED;
|
||||
import static net.kyori.adventure.text.format.NamedTextColor.WHITE;
|
||||
|
||||
@DefaultQualifier(NonNull.class)
|
||||
public final class DumpPluginsCommand implements PaperSubcommand {
|
||||
@ -60,24 +63,40 @@ public final class DumpPluginsCommand implements PaperSubcommand {
|
||||
|
||||
private void dumpPlugins(final CommandSender sender, final String[] args) {
|
||||
Path parent = Path.of("debug");
|
||||
Path path = parent.resolve("plugin-info-" + FORMATTER.format(LocalDateTime.now()) + ".txt");
|
||||
Path path = parent.resolve("plugin-info-" + FORMATTER.format(LocalDateTime.now()) + ".json");
|
||||
try {
|
||||
Files.createDirectories(parent);
|
||||
Files.createFile(path);
|
||||
sender.sendMessage(text("Writing plugin information to " + path, GREEN));
|
||||
sender.sendMessage(
|
||||
text("Writing plugin information into directory", GREEN)
|
||||
.appendSpace()
|
||||
.append(
|
||||
text(parent.toString(), WHITE)
|
||||
.hoverEvent(text("Click to copy the full path of debug directory", WHITE))
|
||||
.clickEvent(ClickEvent.copyToClipboard(parent.toAbsolutePath().toString()))
|
||||
)
|
||||
);
|
||||
|
||||
final JsonObject data = this.writeDebug();
|
||||
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
JsonWriter jsonWriter = new JsonWriter(stringWriter);
|
||||
jsonWriter.setIndent(" ");
|
||||
jsonWriter.setLenient(false);
|
||||
jsonWriter.setStrictness(Strictness.STRICT);
|
||||
Streams.write(data, jsonWriter);
|
||||
|
||||
try (PrintStream out = new PrintStream(Files.newOutputStream(path), false, StandardCharsets.UTF_8)) {
|
||||
out.print(stringWriter);
|
||||
}
|
||||
sender.sendMessage(text("Successfully written plugin debug information!", GREEN));
|
||||
sender.sendMessage(
|
||||
text("Successfully written plugin debug information into", GREEN)
|
||||
.appendSpace()
|
||||
.append(
|
||||
text(path.toString(), WHITE)
|
||||
.hoverEvent(text("Click to copy the full path of the file", WHITE))
|
||||
.clickEvent(ClickEvent.copyToClipboard(path.toAbsolutePath().toString()))
|
||||
)
|
||||
);
|
||||
} catch (Throwable e) {
|
||||
sender.sendMessage(text("Failed to write plugin information! See the console for more info.", RED));
|
||||
MinecraftServer.LOGGER.warn("Error occurred while dumping plugin info", e);
|
||||
@ -97,6 +116,7 @@ public final class DumpPluginsCommand implements PaperSubcommand {
|
||||
return root;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void writeProviders(JsonObject root) {
|
||||
JsonObject rootProviders = new JsonObject();
|
||||
root.add("providers", rootProviders);
|
||||
@ -116,7 +136,6 @@ public final class DumpPluginsCommand implements PaperSubcommand {
|
||||
providerObj.addProperty("soft-dependencies", provider.getMeta().getPluginSoftDependencies().toString());
|
||||
providerObj.addProperty("load-before", provider.getMeta().getLoadBeforePlugins().toString());
|
||||
|
||||
|
||||
providers.add(providerObj);
|
||||
pluginProviders.add((PluginProvider<Object>) provider);
|
||||
}
|
||||
|
||||
@ -62,7 +62,8 @@ public abstract class Configurations<G, W> {
|
||||
protected ObjectMapper.Factory.Builder createObjectMapper() {
|
||||
return ObjectMapper.factoryBuilder()
|
||||
.addConstraint(Constraint.class, new Constraint.Factory())
|
||||
.addConstraint(Constraints.Min.class, Number.class, new Constraints.Min.Factory());
|
||||
.addConstraint(Constraints.Min.class, Number.class, new Constraints.Min.Factory())
|
||||
.addConstraint(Constraints.Max.class, Number.class, new Constraints.Max.Factory());
|
||||
}
|
||||
|
||||
protected YamlConfigurationLoader.Builder createLoaderBuilder() {
|
||||
|
||||
@ -185,8 +185,6 @@ public class GlobalConfiguration extends ConfigurationPart {
|
||||
public CompressionFormat compressionFormat = CompressionFormat.ZLIB;
|
||||
@Comment("This setting controls if equipment should be updated when handling certain player actions.")
|
||||
public boolean updateEquipmentOnPlayerActions = true;
|
||||
@Comment("Only checks an item's amount and type instead of its full data during inventory desync checks.")
|
||||
public boolean simplifyRemoteItemMatching = false;
|
||||
|
||||
public enum CompressionFormat {
|
||||
GZIP,
|
||||
@ -356,6 +354,9 @@ public class GlobalConfiguration extends ConfigurationPart {
|
||||
public IntOr.Default compressionLevel = IntOr.Default.USE_DEFAULT;
|
||||
@Comment("Defines the leniency distance added on the server to the interaction range of a player when validating interact packets.")
|
||||
public DoubleOr.Default clientInteractionLeniencyDistance = DoubleOr.Default.USE_DEFAULT;
|
||||
@Comment("Defines how many orbs groups can exist in an area.")
|
||||
@Constraints.Min(1)
|
||||
public IntOr.Default xpOrbGroupsPerArea = IntOr.Default.USE_DEFAULT;
|
||||
}
|
||||
|
||||
public BlockUpdates blockUpdates;
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
package io.papermc.paper.configuration;
|
||||
|
||||
public class PaperServerConfiguration implements ServerConfiguration {
|
||||
|
||||
@Override
|
||||
public boolean isProxyOnlineMode() {
|
||||
return GlobalConfiguration.get().proxies.isProxyOnlineMode();
|
||||
}
|
||||
}
|
||||
@ -40,4 +40,22 @@ public final class Constraints {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Max {
|
||||
int value();
|
||||
|
||||
final class Factory implements Constraint.Factory<Max, Number> {
|
||||
@Override
|
||||
public Constraint<Number> make(Max data, Type type) {
|
||||
return value -> {
|
||||
if (value != null && value.intValue() > data.value()) {
|
||||
throw new SerializationException(value + " is greater than the max " + data.value());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,8 +2,13 @@ package io.papermc.paper.datacomponent.item;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import io.papermc.paper.datacomponent.item.blocksattacks.DamageReduction;
|
||||
import io.papermc.paper.datacomponent.item.blocksattacks.ItemDamageFunction;
|
||||
import io.papermc.paper.datacomponent.item.blocksattacks.PaperDamageReduction;
|
||||
import io.papermc.paper.datacomponent.item.blocksattacks.PaperItemDamageFunction;
|
||||
import io.papermc.paper.registry.PaperRegistries;
|
||||
import io.papermc.paper.registry.tag.TagKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import net.kyori.adventure.key.Key;
|
||||
@ -30,6 +35,16 @@ public record PaperBlocksAttacks(
|
||||
return this.impl.disableCooldownScale();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DamageReduction> damageReductions() {
|
||||
return this.impl.damageReductions().stream().map(PaperDamageReduction::new).map(paperDamageReduction -> ((DamageReduction) paperDamageReduction)).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDamageFunction itemDamage() {
|
||||
return new PaperItemDamageFunction(this.impl.itemDamage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable TagKey<DamageType> bypassedBy() {
|
||||
final Optional<TagKey<DamageType>> tagKey = this.impl.bypassedBy().map(PaperRegistries::fromNms);
|
||||
@ -50,8 +65,8 @@ public record PaperBlocksAttacks(
|
||||
|
||||
private float blockDelaySeconds;
|
||||
private float disableCooldownScale = 1.0F;
|
||||
//private List<DamageReduction> damageReductions = List.of();
|
||||
//private ItemDamageFunction itemDamage = ItemDamageFunction.DEFAULT;
|
||||
private List<DamageReduction> damageReductions = new ArrayList<>();
|
||||
private ItemDamageFunction itemDamage = new PaperItemDamageFunction(net.minecraft.world.item.component.BlocksAttacks.ItemDamageFunction.DEFAULT);
|
||||
private @Nullable TagKey<DamageType> bypassedBy;
|
||||
private @Nullable Key blockSound;
|
||||
private @Nullable Key disableSound;
|
||||
@ -70,15 +85,18 @@ public record PaperBlocksAttacks(
|
||||
return this;
|
||||
}
|
||||
|
||||
//@Override
|
||||
//public Builder addDamageReduction(final DamageReduction reduction) {
|
||||
// return null;
|
||||
//}
|
||||
@Override
|
||||
public Builder addDamageReduction(final DamageReduction reduction) {
|
||||
Preconditions.checkArgument(reduction.horizontalBlockingAngle() >= 0, "horizontalBlockingAngle must be non-negative, was %s", reduction.horizontalBlockingAngle());
|
||||
this.damageReductions.add(reduction);
|
||||
return this;
|
||||
}
|
||||
|
||||
//@Override
|
||||
//public Builder itemDamage(final ItemDamageFunction function) {
|
||||
// return null;
|
||||
//}
|
||||
@Override
|
||||
public Builder itemDamage(final ItemDamageFunction function) {
|
||||
this.itemDamage = function;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder bypassedBy(@Nullable final TagKey<DamageType> bypassedBy) {
|
||||
@ -98,18 +116,19 @@ public record PaperBlocksAttacks(
|
||||
return this;
|
||||
}
|
||||
|
||||
//@Override
|
||||
//public Builder damageReductions(final List<DamageReduction> reductions) {
|
||||
// return null;
|
||||
//}
|
||||
@Override
|
||||
public Builder damageReductions(final List<DamageReduction> reductions) {
|
||||
this.damageReductions = new ArrayList<>(reductions);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlocksAttacks build() {
|
||||
return new PaperBlocksAttacks(new net.minecraft.world.item.component.BlocksAttacks(
|
||||
this.blockDelaySeconds,
|
||||
this.disableCooldownScale,
|
||||
List.of(), // TODO
|
||||
net.minecraft.world.item.component.BlocksAttacks.ItemDamageFunction.DEFAULT, // TODO
|
||||
this.damageReductions.stream().map(damageReduction -> ((PaperDamageReduction) damageReduction).getHandle()).toList(),
|
||||
((PaperItemDamageFunction) itemDamage).getHandle(),
|
||||
Optional.ofNullable(this.bypassedBy).map(PaperRegistries::toNms),
|
||||
Optional.ofNullable(this.blockSound).map(PaperAdventure::resolveSound),
|
||||
Optional.ofNullable(this.disableSound).map(PaperAdventure::resolveSound)
|
||||
|
||||
@ -5,6 +5,8 @@ import io.papermc.paper.util.MCUtil;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.craftbukkit.potion.CraftPotionType;
|
||||
@ -48,6 +50,19 @@ public record PaperPotionContents(
|
||||
return this.impl.customName().orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Unmodifiable List<PotionEffect> allEffects() {
|
||||
//noinspection SimplifyStreamApiCallChains - explicity want it unmodifiable, as toList() api doesnt guarantee this.
|
||||
return StreamSupport.stream(this.impl.getAllEffects().spliterator(), false)
|
||||
.map(CraftPotionUtil::toBukkit)
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color computeEffectiveColor() {
|
||||
return Color.fromARGB(this.impl.getColor());
|
||||
}
|
||||
|
||||
static final class BuilderImpl implements PotionContents.Builder {
|
||||
|
||||
private final List<MobEffectInstance> customEffects = new ObjectArrayList<>();
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
package io.papermc.paper.datacomponent.item.blocksattacks;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@ApiStatus.Internal
|
||||
@NullMarked
|
||||
public class BlocksAttacksBridgeImpl implements BlocksAttacksBridge {
|
||||
|
||||
@Override
|
||||
public DamageReduction.Builder blocksAttacksDamageReduction() {
|
||||
return new PaperDamageReduction.BuilderImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDamageFunction.Builder blocksAttacksItemDamageFunction() {
|
||||
return new PaperItemDamageFunction.BuilderImpl();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
package io.papermc.paper.datacomponent.item.blocksattacks;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.papermc.paper.registry.RegistryKey;
|
||||
import io.papermc.paper.registry.set.PaperRegistrySets;
|
||||
import io.papermc.paper.registry.set.RegistryKeySet;
|
||||
import net.minecraft.core.HolderSet;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import org.bukkit.craftbukkit.util.Handleable;
|
||||
import org.bukkit.damage.DamageType;
|
||||
import org.checkerframework.checker.index.qual.Positive;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import java.util.Optional;
|
||||
|
||||
public record PaperDamageReduction(
|
||||
net.minecraft.world.item.component.BlocksAttacks.DamageReduction impl
|
||||
) implements DamageReduction, Handleable<net.minecraft.world.item.component.BlocksAttacks.DamageReduction> {
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.item.component.BlocksAttacks.DamageReduction getHandle() {
|
||||
return this.impl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable RegistryKeySet<DamageType> type() {
|
||||
return this.impl.type().map((set) -> PaperRegistrySets.convertToApi(RegistryKey.DAMAGE_TYPE, set)).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Positive float horizontalBlockingAngle() {
|
||||
return this.impl.horizontalBlockingAngle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float base() {
|
||||
return this.impl.base();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float factor() {
|
||||
return this.impl.factor();
|
||||
}
|
||||
|
||||
static final class BuilderImpl implements Builder {
|
||||
|
||||
private Optional<HolderSet<net.minecraft.world.damagesource.DamageType>> type = Optional.empty();
|
||||
private float horizontalBlockingAngle = 90f;
|
||||
private float base = 0;
|
||||
private float factor = 0;
|
||||
|
||||
@Override
|
||||
public Builder type(final @Nullable RegistryKeySet<DamageType> type) {
|
||||
this.type = Optional.ofNullable(type)
|
||||
.map((set) -> PaperRegistrySets.convertToNms(Registries.DAMAGE_TYPE, net.minecraft.server.MinecraftServer.getServer().registryAccess().createSerializationContext(net.minecraft.nbt.NbtOps.INSTANCE).lookupProvider, set));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder horizontalBlockingAngle(@Positive final float horizontalBlockingAngle) {
|
||||
Preconditions.checkArgument(horizontalBlockingAngle > 0, "horizontalBlockingAngle must be positive and not zero, was %s", horizontalBlockingAngle);
|
||||
this.horizontalBlockingAngle = horizontalBlockingAngle;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder base(final float base) {
|
||||
this.base = base;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder factor(final float factor) {
|
||||
this.factor = factor;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DamageReduction build() {
|
||||
return new PaperDamageReduction(new net.minecraft.world.item.component.BlocksAttacks.DamageReduction(
|
||||
this.horizontalBlockingAngle,
|
||||
this.type,
|
||||
this.base,
|
||||
this.factor
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
package io.papermc.paper.datacomponent.item.blocksattacks;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.bukkit.craftbukkit.util.Handleable;
|
||||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
|
||||
public record PaperItemDamageFunction(
|
||||
net.minecraft.world.item.component.BlocksAttacks.ItemDamageFunction impl
|
||||
) implements ItemDamageFunction, Handleable<net.minecraft.world.item.component.BlocksAttacks.ItemDamageFunction> {
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.item.component.BlocksAttacks.ItemDamageFunction getHandle() {
|
||||
return this.impl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNegative float threshold() {
|
||||
return this.impl.threshold();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float base() {
|
||||
return this.impl.base();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float factor() {
|
||||
return this.impl.factor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageToApply(final float damage) {
|
||||
return this.impl.apply(damage);
|
||||
}
|
||||
|
||||
static final class BuilderImpl implements Builder {
|
||||
|
||||
private float threshold;
|
||||
private float base;
|
||||
private float factor;
|
||||
|
||||
@Override
|
||||
public Builder threshold(@NonNegative final float threshold) {
|
||||
Preconditions.checkArgument(threshold >= 0, "threshold must be non-negative, was %s", threshold);
|
||||
this.threshold = threshold;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder base(final float base) {
|
||||
this.base = base;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder factor(final float factor) {
|
||||
this.factor = factor;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDamageFunction build() {
|
||||
return new PaperItemDamageFunction(new net.minecraft.world.item.component.BlocksAttacks.ItemDamageFunction(
|
||||
this.threshold,
|
||||
this.base,
|
||||
this.factor
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Relating to block attacks for components.
|
||||
*/
|
||||
@NullMarked
|
||||
package io.papermc.paper.datacomponent.item.blocksattacks;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
@ -13,7 +13,7 @@ public class PaperSchoolableFish extends CraftFish implements SchoolableFish {
|
||||
|
||||
@Override
|
||||
public AbstractSchoolingFish getHandle() {
|
||||
return (AbstractSchoolingFish) super.getHandle();
|
||||
return (AbstractSchoolingFish) this.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -75,7 +75,11 @@ public final class PluginRemapper {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new PluginRemapper(pluginsDir);
|
||||
try {
|
||||
return new PluginRemapper(pluginsDir);
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException("Failed to create PluginRemapper, try deleting the '" + pluginsDir.resolve(PAPER_REMAPPED) + "' directory", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
|
||||
@ -8,6 +8,7 @@ import io.papermc.paper.util.MappingEnvironment;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@ -52,32 +53,35 @@ class RemappedPluginIndex {
|
||||
try {
|
||||
Files.createDirectories(this.dir);
|
||||
} catch (final IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
this.indexFile = dir.resolve(INDEX_FILE_NAME);
|
||||
if (Files.isRegularFile(this.indexFile)) {
|
||||
try {
|
||||
this.state = this.readIndex();
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
this.state = this.readIndex();
|
||||
} else {
|
||||
this.state = new State();
|
||||
}
|
||||
}
|
||||
|
||||
private State readIndex() throws IOException {
|
||||
private State readIndex() {
|
||||
final State state;
|
||||
try (final BufferedReader reader = Files.newBufferedReader(this.indexFile)) {
|
||||
state = GSON.fromJson(reader, State.class);
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException("Failed to read index file '" + this.indexFile + "'", ex);
|
||||
}
|
||||
|
||||
// If mappings have changed, delete all cached files and create a new index
|
||||
if (!state.mappingsHash.equals(MappingEnvironment.mappingsHash())) {
|
||||
for (final String fileName : state.hashes.values()) {
|
||||
Files.deleteIfExists(this.dir.resolve(fileName));
|
||||
final Path path = this.dir.resolve(fileName);
|
||||
try {
|
||||
Files.deleteIfExists(path);
|
||||
} catch (final IOException ex) {
|
||||
throw new UncheckedIOException("Failed to delete no longer needed file '" + path + "'", ex);
|
||||
}
|
||||
}
|
||||
return new State();
|
||||
}
|
||||
@ -111,10 +115,11 @@ class RemappedPluginIndex {
|
||||
}
|
||||
|
||||
iterator.remove();
|
||||
final Path filePath = this.dir.resolve(fileName);
|
||||
try {
|
||||
Files.deleteIfExists(this.dir.resolve(fileName));
|
||||
Files.deleteIfExists(filePath);
|
||||
} catch (final IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
throw new UncheckedIOException("Failed to delete no longer needed file '" + filePath + "'", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5,10 +5,16 @@ import io.papermc.paper.adventure.PaperAdventure;
|
||||
import io.papermc.paper.datacomponent.DataComponentTypes;
|
||||
import io.papermc.paper.datacomponent.PaperDataComponentType;
|
||||
import io.papermc.paper.registry.data.PaperBannerPatternRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperCatTypeRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperChickenVariantRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperCowVariantRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperDamageTypeRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperEnchantmentRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperFrogVariantRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperGameEventRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperPaintingVariantRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperPigVariantRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperWolfVariantRegistryEntry;
|
||||
import io.papermc.paper.registry.entry.RegistryEntry;
|
||||
import io.papermc.paper.registry.entry.RegistryEntryMeta;
|
||||
import io.papermc.paper.registry.tag.TagKey;
|
||||
@ -111,18 +117,18 @@ public final class PaperRegistries {
|
||||
start(Registries.TRIM_MATERIAL, RegistryKey.TRIM_MATERIAL).craft(TrimMaterial.class, CraftTrimMaterial::new, true).build().delayed(),
|
||||
start(Registries.TRIM_PATTERN, RegistryKey.TRIM_PATTERN).craft(TrimPattern.class, CraftTrimPattern::new, true).build().delayed(),
|
||||
start(Registries.DAMAGE_TYPE, RegistryKey.DAMAGE_TYPE).craft(DamageType.class, CraftDamageType::new).writable(PaperDamageTypeRegistryEntry.PaperBuilder::new).delayed(),
|
||||
start(Registries.WOLF_VARIANT, RegistryKey.WOLF_VARIANT).craft(Wolf.Variant.class, CraftWolf.CraftVariant::new).build().delayed(),
|
||||
start(Registries.WOLF_VARIANT, RegistryKey.WOLF_VARIANT).craft(Wolf.Variant.class, CraftWolf.CraftVariant::new).writable(PaperWolfVariantRegistryEntry.PaperBuilder::new).delayed(),
|
||||
start(Registries.WOLF_SOUND_VARIANT, RegistryKey.WOLF_SOUND_VARIANT).craft(Wolf.SoundVariant.class, CraftWolf.CraftSoundVariant::new).build(),
|
||||
start(Registries.ENCHANTMENT, RegistryKey.ENCHANTMENT).craft(Enchantment.class, CraftEnchantment::new).serializationUpdater(FieldRename.ENCHANTMENT_RENAME).writable(PaperEnchantmentRegistryEntry.PaperBuilder::new).delayed(),
|
||||
start(Registries.JUKEBOX_SONG, RegistryKey.JUKEBOX_SONG).craft(JukeboxSong.class, CraftJukeboxSong::new).build().delayed(),
|
||||
start(Registries.BANNER_PATTERN, RegistryKey.BANNER_PATTERN).craft(PatternType.class, CraftPatternType::new, true).writable(PaperBannerPatternRegistryEntry.PaperBuilder::new).delayed(),
|
||||
start(Registries.PAINTING_VARIANT, RegistryKey.PAINTING_VARIANT).craft(Art.class, CraftArt::new, true).writable(PaperPaintingVariantRegistryEntry.PaperBuilder::new).delayed(),
|
||||
start(Registries.INSTRUMENT, RegistryKey.INSTRUMENT).craft(MusicInstrument.class, CraftMusicInstrument::new, true).build().delayed(),
|
||||
start(Registries.CAT_VARIANT, RegistryKey.CAT_VARIANT).craft(Cat.Type.class, CraftCat.CraftType::new).build().delayed(),
|
||||
start(Registries.FROG_VARIANT, RegistryKey.FROG_VARIANT).craft(Frog.Variant.class, CraftFrog.CraftVariant::new).build().delayed(),
|
||||
start(Registries.CHICKEN_VARIANT, RegistryKey.CHICKEN_VARIANT).craft(Chicken.Variant.class, CraftChicken.CraftVariant::new).build(),
|
||||
start(Registries.COW_VARIANT, RegistryKey.COW_VARIANT).craft(Cow.Variant.class, CraftCow.CraftVariant::new).build(),
|
||||
start(Registries.PIG_VARIANT, RegistryKey.PIG_VARIANT).craft(Pig.Variant.class, CraftPig.CraftVariant::new).build(),
|
||||
start(Registries.CAT_VARIANT, RegistryKey.CAT_VARIANT).craft(Cat.Type.class, CraftCat.CraftType::new).writable(PaperCatTypeRegistryEntry.PaperBuilder::new).delayed(),
|
||||
start(Registries.FROG_VARIANT, RegistryKey.FROG_VARIANT).craft(Frog.Variant.class, CraftFrog.CraftVariant::new).writable(PaperFrogVariantRegistryEntry.PaperBuilder::new).delayed(),
|
||||
start(Registries.CHICKEN_VARIANT, RegistryKey.CHICKEN_VARIANT).craft(Chicken.Variant.class, CraftChicken.CraftVariant::new).writable(PaperChickenVariantRegistryEntry.PaperBuilder::new),
|
||||
start(Registries.COW_VARIANT, RegistryKey.COW_VARIANT).craft(Cow.Variant.class, CraftCow.CraftVariant::new).writable(PaperCowVariantRegistryEntry.PaperBuilder::new),
|
||||
start(Registries.PIG_VARIANT, RegistryKey.PIG_VARIANT).craft(Pig.Variant.class, CraftPig.CraftVariant::new).writable(PaperPigVariantRegistryEntry.PaperBuilder::new),
|
||||
|
||||
// api-only
|
||||
start(Registries.ENTITY_TYPE, RegistryKey.ENTITY_TYPE).apiOnly(PaperSimpleRegistry::entityType),
|
||||
|
||||
@ -0,0 +1,60 @@
|
||||
package io.papermc.paper.registry.data;
|
||||
|
||||
import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
import io.papermc.paper.registry.data.client.ClientTextureAsset;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import net.minecraft.world.entity.animal.CatVariant;
|
||||
import net.minecraft.world.entity.variant.SpawnPrioritySelectors;
|
||||
import org.bukkit.entity.Cat;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import static io.papermc.paper.registry.data.util.Checks.asArgument;
|
||||
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
|
||||
|
||||
public class PaperCatTypeRegistryEntry implements CatTypeRegistryEntry {
|
||||
|
||||
protected net.minecraft.core.@Nullable ClientAsset clientTextureAsset;
|
||||
protected SpawnPrioritySelectors spawnConditions;
|
||||
|
||||
protected final Conversions conversions;
|
||||
|
||||
public PaperCatTypeRegistryEntry(
|
||||
final Conversions conversions,
|
||||
final @Nullable CatVariant internal
|
||||
) {
|
||||
this.conversions = conversions;
|
||||
if (internal == null) {
|
||||
this.spawnConditions = SpawnPrioritySelectors.EMPTY;
|
||||
return;
|
||||
}
|
||||
|
||||
this.clientTextureAsset = internal.assetInfo();
|
||||
this.spawnConditions = internal.spawnConditions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTextureAsset clientTextureAsset() {
|
||||
return this.conversions.asBukkit(asConfigured(this.clientTextureAsset, "clientTextureAsset"));
|
||||
}
|
||||
|
||||
public static final class PaperBuilder extends PaperCatTypeRegistryEntry implements Builder, PaperRegistryBuilder<CatVariant, Cat.Type> {
|
||||
|
||||
public PaperBuilder(final Conversions conversions, final @Nullable CatVariant internal) {
|
||||
super(conversions, internal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder clientTextureAsset(final ClientTextureAsset clientTextureAsset) {
|
||||
this.clientTextureAsset = this.conversions.asVanilla(asArgument(clientTextureAsset, "clientTextureAsset"));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CatVariant build() {
|
||||
return new CatVariant(
|
||||
asConfigured(this.clientTextureAsset, "clientTextureAsset"),
|
||||
asConfigured(this.spawnConditions, "spawnConditions")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
package io.papermc.paper.registry.data;
|
||||
|
||||
import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
import io.papermc.paper.registry.data.client.ClientTextureAsset;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import net.minecraft.world.entity.animal.ChickenVariant;
|
||||
import net.minecraft.world.entity.variant.ModelAndTexture;
|
||||
import net.minecraft.world.entity.variant.SpawnPrioritySelectors;
|
||||
import org.bukkit.entity.Chicken;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import static io.papermc.paper.registry.data.util.Checks.asArgument;
|
||||
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
|
||||
|
||||
public class PaperChickenVariantRegistryEntry implements ChickenVariantRegistryEntry {
|
||||
|
||||
protected ChickenVariant.@Nullable ModelType model;
|
||||
protected net.minecraft.core.@Nullable ClientAsset clientTextureAsset;
|
||||
protected SpawnPrioritySelectors spawnConditions;
|
||||
|
||||
protected final Conversions conversions;
|
||||
|
||||
public PaperChickenVariantRegistryEntry(
|
||||
final Conversions conversions,
|
||||
final @Nullable ChickenVariant internal
|
||||
) {
|
||||
this.conversions = conversions;
|
||||
if (internal == null) {
|
||||
this.spawnConditions = SpawnPrioritySelectors.EMPTY;
|
||||
return;
|
||||
}
|
||||
|
||||
this.clientTextureAsset = internal.modelAndTexture().asset();
|
||||
this.model = internal.modelAndTexture().model();
|
||||
this.spawnConditions = internal.spawnConditions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTextureAsset clientTextureAsset() {
|
||||
return this.conversions.asBukkit(asConfigured(this.clientTextureAsset, "clientTextureAsset"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Model model() {
|
||||
return switch (asConfigured(this.model, "model")) {
|
||||
case NORMAL -> Model.NORMAL;
|
||||
case COLD -> Model.COLD;
|
||||
};
|
||||
}
|
||||
|
||||
public static final class PaperBuilder extends PaperChickenVariantRegistryEntry implements Builder, PaperRegistryBuilder<ChickenVariant, Chicken.Variant> {
|
||||
|
||||
public PaperBuilder(final Conversions conversions, final @Nullable ChickenVariant internal) {
|
||||
super(conversions, internal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder clientTextureAsset(final ClientTextureAsset clientTextureAsset) {
|
||||
this.clientTextureAsset = this.conversions.asVanilla(asArgument(clientTextureAsset, "clientTextureAsset"));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder model(final Model model) {
|
||||
this.model = switch (asArgument(model, "model")) {
|
||||
case NORMAL -> ChickenVariant.ModelType.NORMAL;
|
||||
case COLD -> ChickenVariant.ModelType.COLD;
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChickenVariant build() {
|
||||
return new ChickenVariant(
|
||||
new ModelAndTexture<>(asConfigured(this.model, "model"), asConfigured(this.clientTextureAsset, "clientTextureAsset")),
|
||||
asConfigured(this.spawnConditions, "spawnConditions")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
package io.papermc.paper.registry.data;
|
||||
|
||||
import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
import io.papermc.paper.registry.data.client.ClientTextureAsset;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import net.minecraft.world.entity.animal.CowVariant;
|
||||
import net.minecraft.world.entity.variant.ModelAndTexture;
|
||||
import net.minecraft.world.entity.variant.SpawnPrioritySelectors;
|
||||
import org.bukkit.entity.Cow;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import static io.papermc.paper.registry.data.util.Checks.asArgument;
|
||||
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
|
||||
|
||||
public class PaperCowVariantRegistryEntry implements CowVariantRegistryEntry {
|
||||
|
||||
protected CowVariant.@Nullable ModelType model = null;
|
||||
protected net.minecraft.core.@Nullable ClientAsset clientTextureAsset = null;
|
||||
protected SpawnPrioritySelectors spawnConditions;
|
||||
|
||||
protected final Conversions conversions;
|
||||
|
||||
public PaperCowVariantRegistryEntry(
|
||||
final Conversions conversions,
|
||||
final @Nullable CowVariant internal
|
||||
) {
|
||||
this.conversions = conversions;
|
||||
if (internal == null) {
|
||||
this.spawnConditions = SpawnPrioritySelectors.EMPTY;
|
||||
return;
|
||||
}
|
||||
|
||||
this.clientTextureAsset = internal.modelAndTexture().asset();
|
||||
this.model = internal.modelAndTexture().model();
|
||||
this.spawnConditions = internal.spawnConditions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTextureAsset clientTextureAsset() {
|
||||
return this.conversions.asBukkit(asConfigured(this.clientTextureAsset, "clientTextureAsset"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Model model() {
|
||||
return switch (asConfigured(this.model, "model")) {
|
||||
case NORMAL -> Model.NORMAL;
|
||||
case COLD -> Model.COLD;
|
||||
case WARM -> Model.WARM;
|
||||
};
|
||||
}
|
||||
|
||||
public static final class PaperBuilder extends PaperCowVariantRegistryEntry implements Builder, PaperRegistryBuilder<CowVariant, Cow.Variant> {
|
||||
|
||||
public PaperBuilder(final Conversions conversions, final @Nullable CowVariant internal) {
|
||||
super(conversions, internal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder clientTextureAsset(final ClientTextureAsset clientTextureAsset) {
|
||||
this.clientTextureAsset = this.conversions.asVanilla(asArgument(clientTextureAsset, "clientTextureAsset"));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder model(final Model model) {
|
||||
this.model = switch (asArgument(model, "model")) {
|
||||
case NORMAL -> CowVariant.ModelType.NORMAL;
|
||||
case COLD -> CowVariant.ModelType.COLD;
|
||||
case WARM -> CowVariant.ModelType.WARM;
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CowVariant build() {
|
||||
return new CowVariant(
|
||||
new ModelAndTexture<>(asConfigured(this.model, "model"), asConfigured(this.clientTextureAsset, "clientTextureAsset")),
|
||||
this.spawnConditions
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
package io.papermc.paper.registry.data;
|
||||
|
||||
import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
import io.papermc.paper.registry.data.client.ClientTextureAsset;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import net.minecraft.world.entity.animal.frog.FrogVariant;
|
||||
import net.minecraft.world.entity.variant.SpawnPrioritySelectors;
|
||||
import org.bukkit.entity.Frog;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import static io.papermc.paper.registry.data.util.Checks.asArgument;
|
||||
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
|
||||
|
||||
public class PaperFrogVariantRegistryEntry implements FrogVariantRegistryEntry {
|
||||
|
||||
protected net.minecraft.core.@Nullable ClientAsset clientTextureAsset;
|
||||
protected SpawnPrioritySelectors spawnConditions;
|
||||
|
||||
protected final Conversions conversions;
|
||||
|
||||
public PaperFrogVariantRegistryEntry(
|
||||
final Conversions conversions,
|
||||
final @Nullable FrogVariant internal
|
||||
) {
|
||||
this.conversions = conversions;
|
||||
if (internal == null) {
|
||||
spawnConditions = SpawnPrioritySelectors.EMPTY;
|
||||
return;
|
||||
}
|
||||
|
||||
this.clientTextureAsset = internal.assetInfo();
|
||||
this.spawnConditions = internal.spawnConditions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTextureAsset clientTextureAsset() {
|
||||
return this.conversions.asBukkit(asConfigured(this.clientTextureAsset, "clientTextureAsset"));
|
||||
}
|
||||
|
||||
public static final class PaperBuilder extends PaperFrogVariantRegistryEntry implements Builder, PaperRegistryBuilder<FrogVariant, Frog.Variant> {
|
||||
|
||||
public PaperBuilder(final Conversions conversions, final @Nullable FrogVariant internal) {
|
||||
super(conversions, internal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder clientTextureAsset(final ClientTextureAsset clientTextureAsset) {
|
||||
this.clientTextureAsset = this.conversions.asVanilla(asArgument(clientTextureAsset, "clientTextureAsset"));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FrogVariant build() {
|
||||
return new FrogVariant(
|
||||
asConfigured(this.clientTextureAsset, "clientTextureAsset"),
|
||||
asConfigured(this.spawnConditions, "spawnConditions")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
package io.papermc.paper.registry.data;
|
||||
|
||||
import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
import io.papermc.paper.registry.data.client.ClientTextureAsset;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import net.minecraft.world.entity.animal.PigVariant;
|
||||
import net.minecraft.world.entity.variant.ModelAndTexture;
|
||||
import net.minecraft.world.entity.variant.SpawnPrioritySelectors;
|
||||
import org.bukkit.entity.Pig;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import static io.papermc.paper.registry.data.util.Checks.asArgument;
|
||||
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
|
||||
|
||||
public class PaperPigVariantRegistryEntry implements PigVariantRegistryEntry {
|
||||
|
||||
protected PigVariant.@Nullable ModelType model;
|
||||
protected net.minecraft.core.@Nullable ClientAsset clientTextureAsset;
|
||||
protected SpawnPrioritySelectors spawnConditions;
|
||||
|
||||
protected final Conversions conversions;
|
||||
|
||||
public PaperPigVariantRegistryEntry(
|
||||
final Conversions conversions,
|
||||
final @Nullable PigVariant internal
|
||||
) {
|
||||
this.conversions = conversions;
|
||||
if (internal == null) {
|
||||
spawnConditions = SpawnPrioritySelectors.EMPTY;
|
||||
return;
|
||||
}
|
||||
|
||||
this.clientTextureAsset = internal.modelAndTexture().asset();
|
||||
this.model = internal.modelAndTexture().model();
|
||||
this.spawnConditions = internal.spawnConditions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTextureAsset clientTextureAsset() {
|
||||
return this.conversions.asBukkit(asConfigured(this.clientTextureAsset, "clientTextureAsset"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Model model() {
|
||||
return switch (asConfigured(this.model, "model")) {
|
||||
case NORMAL -> Model.NORMAL;
|
||||
case COLD -> Model.COLD;
|
||||
};
|
||||
}
|
||||
|
||||
public static final class PaperBuilder extends PaperPigVariantRegistryEntry implements Builder, PaperRegistryBuilder<PigVariant, Pig.Variant> {
|
||||
|
||||
public PaperBuilder(final Conversions conversions, final @Nullable PigVariant internal) {
|
||||
super(conversions, internal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder clientTextureAsset(final ClientTextureAsset clientTextureAsset) {
|
||||
this.clientTextureAsset = this.conversions.asVanilla(asArgument(clientTextureAsset, "clientTextureAsset"));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder model(final Model model) {
|
||||
this.model = switch (asArgument(model, "model")) {
|
||||
case NORMAL -> PigVariant.ModelType.NORMAL;
|
||||
case COLD -> PigVariant.ModelType.COLD;
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PigVariant build() {
|
||||
return new PigVariant(
|
||||
new ModelAndTexture<>(asConfigured(this.model, "model"), asConfigured(this.clientTextureAsset, "clientTextureAsset")),
|
||||
asConfigured(this.spawnConditions, "spawnConditions")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,90 @@
|
||||
package io.papermc.paper.registry.data;
|
||||
|
||||
import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
import io.papermc.paper.registry.data.client.ClientTextureAsset;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import net.minecraft.world.entity.animal.wolf.WolfVariant;
|
||||
import net.minecraft.world.entity.variant.SpawnPrioritySelectors;
|
||||
import org.bukkit.entity.Wolf;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import static io.papermc.paper.registry.data.util.Checks.asArgument;
|
||||
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
|
||||
|
||||
public class PaperWolfVariantRegistryEntry implements WolfVariantRegistryEntry {
|
||||
|
||||
protected net.minecraft.core.@Nullable ClientAsset angryClientTextureAsset;
|
||||
protected net.minecraft.core.@Nullable ClientAsset wildClientTextureAsset;
|
||||
protected net.minecraft.core.@Nullable ClientAsset tameClientTextureAsset;
|
||||
protected SpawnPrioritySelectors spawnConditions;
|
||||
|
||||
protected final Conversions conversions;
|
||||
|
||||
public PaperWolfVariantRegistryEntry(
|
||||
final Conversions conversions,
|
||||
final @Nullable WolfVariant internal
|
||||
) {
|
||||
this.conversions = conversions;
|
||||
if (internal == null) {
|
||||
this.spawnConditions = SpawnPrioritySelectors.EMPTY;
|
||||
return;
|
||||
}
|
||||
|
||||
this.angryClientTextureAsset = internal.assetInfo().angry();
|
||||
this.wildClientTextureAsset = internal.assetInfo().wild();
|
||||
this.tameClientTextureAsset = internal.assetInfo().tame();
|
||||
this.spawnConditions = internal.spawnConditions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTextureAsset angryClientTextureAsset() {
|
||||
return this.conversions.asBukkit(asConfigured(this.angryClientTextureAsset, "angryClientTextureAsset"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTextureAsset wildClientTextureAsset() {
|
||||
return this.conversions.asBukkit(asConfigured(this.wildClientTextureAsset, "wildClientTextureAsset"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTextureAsset tameClientTextureAsset() {
|
||||
return this.conversions.asBukkit(asConfigured(this.tameClientTextureAsset, "tameClientTextureAsset"));
|
||||
}
|
||||
|
||||
public static final class PaperBuilder extends PaperWolfVariantRegistryEntry implements Builder, PaperRegistryBuilder<WolfVariant, Wolf.Variant> {
|
||||
|
||||
public PaperBuilder(final Conversions conversions, final @Nullable WolfVariant internal) {
|
||||
super(conversions, internal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder angryClientTextureAsset(final ClientTextureAsset angryClientTextureAsset) {
|
||||
this.angryClientTextureAsset = this.conversions.asVanilla(asArgument(angryClientTextureAsset, "angryClientTextureAsset"));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder wildClientTextureAsset(final ClientTextureAsset wildClientTextureAsset) {
|
||||
this.wildClientTextureAsset = this.conversions.asVanilla(asArgument(wildClientTextureAsset, "wildClientTextureAsset"));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder tameClientTextureAsset(final ClientTextureAsset tameClientTextureAsset) {
|
||||
this.tameClientTextureAsset = this.conversions.asVanilla(asArgument(tameClientTextureAsset, "tameClientTextureAsset"));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WolfVariant build() {
|
||||
return new WolfVariant(
|
||||
new WolfVariant.AssetInfo(
|
||||
asConfigured(this.wildClientTextureAsset, "wildClientTextureAsset"),
|
||||
asConfigured(this.tameClientTextureAsset, "tameClientTextureAsset"),
|
||||
asConfigured(this.angryClientTextureAsset, "angryClientTextureAsset")
|
||||
),
|
||||
asConfigured(this.spawnConditions, "spawnConditions")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,8 +2,10 @@ package io.papermc.paper.registry.data.util;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.mojang.serialization.JavaOps;
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import io.papermc.paper.adventure.WrapperAwareSerializer;
|
||||
import java.util.Optional;
|
||||
import io.papermc.paper.registry.data.client.ClientTextureAsset;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
@ -33,7 +35,6 @@ public class Conversions {
|
||||
return globalInstance;
|
||||
}
|
||||
|
||||
|
||||
private final RegistryOps.RegistryInfoLookup lookup;
|
||||
private final WrapperAwareSerializer serializer;
|
||||
|
||||
@ -55,4 +56,18 @@ public class Conversions {
|
||||
public Component asAdventure(final net.minecraft.network.chat.@Nullable Component vanilla) {
|
||||
return vanilla == null ? Component.empty() : this.serializer.deserialize(vanilla);
|
||||
}
|
||||
|
||||
public ClientTextureAsset asBukkit(final net.minecraft.core.@Nullable ClientAsset clientTextureAsset) {
|
||||
return clientTextureAsset == null ? null : ClientTextureAsset.clientTextureAsset(
|
||||
PaperAdventure.asAdventure(clientTextureAsset.id()),
|
||||
PaperAdventure.asAdventure(clientTextureAsset.texturePath())
|
||||
);
|
||||
}
|
||||
|
||||
public net.minecraft.core.ClientAsset asVanilla(final @Nullable ClientTextureAsset clientTextureAsset) {
|
||||
return clientTextureAsset == null ? null : new net.minecraft.core.ClientAsset(
|
||||
PaperAdventure.asVanilla(clientTextureAsset.identifier()),
|
||||
PaperAdventure.asVanilla(clientTextureAsset.texturePath())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,6 +103,18 @@ public final class MCUtil {
|
||||
run.run();
|
||||
}
|
||||
|
||||
public static double sanitizeNanInf(final double value, final double defaultValue) {
|
||||
return Double.isNaN(value) || Double.isInfinite(value) ? defaultValue : value;
|
||||
}
|
||||
|
||||
public static Vec3 sanitizeNanInf(final Vec3 vec3, final double defaultValue) {
|
||||
return new Vec3(
|
||||
sanitizeNanInf(vec3.x, defaultValue),
|
||||
sanitizeNanInf(vec3.y, defaultValue),
|
||||
sanitizeNanInf(vec3.z, defaultValue)
|
||||
);
|
||||
}
|
||||
|
||||
public static <T> T ensureMain(Supplier<T> run) {
|
||||
return ensureMain(null, run);
|
||||
}
|
||||
@ -140,6 +152,20 @@ public final class MCUtil {
|
||||
return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a NMS World/Vector to Bukkit Location
|
||||
*/
|
||||
public static Location toLocation(Level world, Vec3 pos) {
|
||||
return new Location(world.getWorld(), pos.x(), pos.y(), pos.z());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a NMS World/Vector to Bukkit Location
|
||||
*/
|
||||
public static Location toLocation(Level world, Vec3 pos, float yaw, float pitch) {
|
||||
return new Location(world.getWorld(), pos.x(), pos.y(), pos.z(), yaw, pitch);
|
||||
}
|
||||
|
||||
public static BlockPos toBlockPos(Position pos) {
|
||||
return new BlockPos(pos.blockX(), pos.blockY(), pos.blockZ());
|
||||
}
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
package io.papermc.paper.world.damagesource;
|
||||
|
||||
import net.minecraft.Optionull;
|
||||
import org.bukkit.craftbukkit.damage.CraftDamageSource;
|
||||
import org.bukkit.damage.DamageSource;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@NullMarked
|
||||
public record PaperCombatEntryWrapper(net.minecraft.world.damagesource.CombatEntry handle) implements CombatEntry {
|
||||
|
||||
@Override
|
||||
public DamageSource getDamageSource() {
|
||||
return new CraftDamageSource(this.handle.source());
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getDamage() {
|
||||
return this.handle.damage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable FallLocationType getFallLocationType() {
|
||||
return Optionull.map(this.handle.fallLocation(), PaperCombatTrackerWrapper::minecraftToPaper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFallDistance() {
|
||||
return this.handle.fallDistance();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,111 @@
|
||||
package io.papermc.paper.world.damagesource;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minecraft.Optionull;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.world.damagesource.FallLocation;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@NullMarked
|
||||
public record PaperCombatTrackerWrapper(
|
||||
net.minecraft.world.damagesource.CombatTracker handle
|
||||
) implements CombatTracker {
|
||||
|
||||
@Override
|
||||
public LivingEntity getEntity() {
|
||||
return this.handle.mob.getBukkitLivingEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CombatEntry> getCombatEntries() {
|
||||
final List<CombatEntry> combatEntries = new ArrayList<>(this.handle.entries.size());
|
||||
this.handle.entries.forEach(combatEntry -> combatEntries.add(new PaperCombatEntryWrapper(combatEntry)));
|
||||
return combatEntries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCombatEntries(final List<CombatEntry> combatEntries) {
|
||||
this.handle.entries.clear();
|
||||
combatEntries.forEach(combatEntry -> this.handle.entries.add(((PaperCombatEntryWrapper) combatEntry).handle()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable CombatEntry computeMostSignificantFall() {
|
||||
final net.minecraft.world.damagesource.CombatEntry combatEntry = this.handle.getMostSignificantFall();
|
||||
return combatEntry == null ? null : new PaperCombatEntryWrapper(combatEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInCombat() {
|
||||
return this.handle.inCombat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTakingDamage() {
|
||||
return this.handle.takingDamage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCombatDuration() {
|
||||
return this.handle.getCombatDuration();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCombatEntry(final CombatEntry combatEntry) {
|
||||
final net.minecraft.world.damagesource.CombatEntry entry = ((PaperCombatEntryWrapper) combatEntry).handle();
|
||||
this.handle.recordDamageAndCheckCombatState(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getDeathMessage() {
|
||||
return PaperAdventure.asAdventure(this.handle.getDeathMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetCombatState() {
|
||||
this.handle.resetCombatState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FallLocationType calculateFallLocationType() {
|
||||
final FallLocation fallLocation = FallLocation.getCurrentFallLocation(this.handle().mob);
|
||||
return Optionull.map(fallLocation, PaperCombatTrackerWrapper::minecraftToPaper);
|
||||
}
|
||||
|
||||
private static final BiMap<FallLocation, FallLocationType> FALL_LOCATION_MAPPING = Util.make(() -> {
|
||||
final BiMap<FallLocation, FallLocationType> map = HashBiMap.create(8);
|
||||
map.put(FallLocation.GENERIC, FallLocationType.GENERIC);
|
||||
map.put(FallLocation.LADDER, FallLocationType.LADDER);
|
||||
map.put(FallLocation.VINES, FallLocationType.VINES);
|
||||
map.put(FallLocation.WEEPING_VINES, FallLocationType.WEEPING_VINES);
|
||||
map.put(FallLocation.TWISTING_VINES, FallLocationType.TWISTING_VINES);
|
||||
map.put(FallLocation.SCAFFOLDING, FallLocationType.SCAFFOLDING);
|
||||
map.put(FallLocation.OTHER_CLIMBABLE, FallLocationType.OTHER_CLIMBABLE);
|
||||
map.put(FallLocation.WATER, FallLocationType.WATER);
|
||||
return map;
|
||||
});
|
||||
|
||||
public static FallLocation paperToMinecraft(final FallLocationType fallLocationType) {
|
||||
final FallLocation fallLocation = FALL_LOCATION_MAPPING.inverse().get(fallLocationType);
|
||||
if (fallLocation == null) {
|
||||
throw new IllegalArgumentException("Unknown fall location type: " + fallLocationType.id());
|
||||
}
|
||||
return fallLocation;
|
||||
}
|
||||
|
||||
public static FallLocationType minecraftToPaper(final FallLocation fallLocation) {
|
||||
final FallLocationType fallLocationType = FALL_LOCATION_MAPPING.get(fallLocation);
|
||||
if (fallLocationType == null) {
|
||||
throw new IllegalArgumentException("Unknown fall location: " + fallLocation.id());
|
||||
}
|
||||
return fallLocationType;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,14 +1,16 @@
|
||||
package org.bukkit.craftbukkit;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import io.papermc.paper.registry.RegistryKey;
|
||||
import io.papermc.paper.util.Holderable;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.world.item.Instrument;
|
||||
import org.bukkit.MusicInstrument;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Registry;
|
||||
import org.bukkit.Sound;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class CraftMusicInstrument extends MusicInstrument implements io.papermc.paper.util.Holderable<Instrument> {
|
||||
@ -26,19 +28,19 @@ public class CraftMusicInstrument extends MusicInstrument implements io.papermc.
|
||||
}
|
||||
|
||||
public static Holder<Instrument> bukkitToMinecraftHolder(MusicInstrument bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.INSTRUMENT); // Paper - switch to Holder
|
||||
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.INSTRUMENT);
|
||||
}
|
||||
|
||||
public static Object bukkitToString(MusicInstrument bukkit) { // Paper - switch to Holder
|
||||
public static Object bukkitToString(MusicInstrument bukkit) {
|
||||
Preconditions.checkArgument(bukkit != null);
|
||||
|
||||
return ((CraftMusicInstrument) bukkit).toBukkitSerializationObject(Instrument.DIRECT_CODEC); // Paper - switch to Holder
|
||||
return ((CraftMusicInstrument) bukkit).toBukkitSerializationObject(Instrument.DIRECT_CODEC);
|
||||
}
|
||||
|
||||
public static MusicInstrument stringToBukkit(Object string) { // Paper - switch to Holder
|
||||
public static MusicInstrument stringToBukkit(Object string) {
|
||||
Preconditions.checkArgument(string != null);
|
||||
|
||||
return io.papermc.paper.util.Holderable.fromBukkitSerializationObject(string, Instrument.CODEC, RegistryKey.INSTRUMENT); // Paper - switch to Holder
|
||||
return io.papermc.paper.util.Holderable.fromBukkitSerializationObject(string, Instrument.CODEC, RegistryKey.INSTRUMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -63,8 +65,28 @@ public class CraftMusicInstrument extends MusicInstrument implements io.papermc.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Holder<Instrument> getHolder() { // Paper - switch to Holder
|
||||
return this.holder; // Paper - switch to Holder
|
||||
public Holder<Instrument> getHolder() {
|
||||
return this.holder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getDuration() {
|
||||
return this.getHandle().useDuration();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getRange() {
|
||||
return this.getHandle().range();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component description() {
|
||||
return PaperAdventure.asAdventure(this.getHandle().description());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sound getSound() {
|
||||
return CraftSound.minecraftHolderToBukkit(this.getHandle().soundEvent());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@ -76,7 +98,7 @@ public class CraftMusicInstrument extends MusicInstrument implements io.papermc.
|
||||
@Override
|
||||
public @NotNull String translationKey() {
|
||||
if (!(this.getHandle().description().getContents() instanceof final net.minecraft.network.chat.contents.TranslatableContents translatableContents)) {
|
||||
throw new UnsupportedOperationException("Description isn't translatable!"); // Paper
|
||||
throw new UnsupportedOperationException("Description isn't translatable!");
|
||||
}
|
||||
return translatableContents.getKey();
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@ import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import net.minecraft.core.GlobalPos;
|
||||
@ -33,8 +32,6 @@ import org.bukkit.configuration.serialization.SerializableAs;
|
||||
import org.bukkit.craftbukkit.util.CraftLocation;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.metadata.MetadataValue;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
@SerializableAs("Player")
|
||||
public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializable {
|
||||
@ -362,18 +359,23 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getRespawnLocation() {
|
||||
CompoundTag data = this.getData();
|
||||
public Location getRespawnLocation(final boolean loadLocationAndValidate) {
|
||||
final CompoundTag data = this.getData();
|
||||
if (data == null) return null;
|
||||
|
||||
final ServerPlayer.RespawnConfig respawnConfig = data.read("respawn", ServerPlayer.RespawnConfig.CODEC).orElse(null);
|
||||
if (respawnConfig != null) {
|
||||
final ServerLevel level = this.server.console.getLevel(respawnConfig.dimension());
|
||||
if (level != null) {
|
||||
return CraftLocation.toBukkit(respawnConfig.pos(), level.getWorld(), respawnConfig.angle(), 0);
|
||||
}
|
||||
if (respawnConfig == null) return null;
|
||||
|
||||
final ServerLevel level = this.server.console.getLevel(respawnConfig.dimension());
|
||||
if (level == null) return null;
|
||||
|
||||
if (!loadLocationAndValidate) {
|
||||
return CraftLocation.toBukkit(respawnConfig.pos(), level.getWorld(), respawnConfig.angle(), 0);
|
||||
}
|
||||
return null;
|
||||
|
||||
return ServerPlayer.findRespawnAndUseSpawnBlock(level, respawnConfig, false)
|
||||
.map(resolvedPos -> CraftLocation.toBukkit(resolvedPos.position(), level.getWorld(), resolvedPos.yaw(), 0))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private ServerStatsCounter getStatisticManager() {
|
||||
|
||||
@ -12,6 +12,8 @@ import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.serialization.Dynamic;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import io.papermc.paper.configuration.PaperServerConfiguration;
|
||||
import io.papermc.paper.configuration.ServerConfiguration;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@ -40,6 +42,8 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.imageio.ImageIO;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minecraft.Optionull;
|
||||
import net.minecraft.advancements.AdvancementHolder;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
@ -87,6 +91,7 @@ import net.minecraft.world.inventory.ResultContainer;
|
||||
import net.minecraft.world.inventory.TransientCraftingContainer;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.MapItem;
|
||||
import net.minecraft.world.item.crafting.CraftingInput;
|
||||
import net.minecraft.world.item.crafting.CraftingRecipe;
|
||||
import net.minecraft.world.item.crafting.RecipeHolder;
|
||||
import net.minecraft.world.item.crafting.RecipeType;
|
||||
@ -113,7 +118,6 @@ import net.minecraft.world.level.validation.ContentValidationException;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.bukkit.BanList;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Keyed;
|
||||
import org.bukkit.Location;
|
||||
@ -311,6 +315,7 @@ public final class CraftServer implements Server {
|
||||
private final io.papermc.paper.logging.SysoutCatcher sysoutCatcher = new io.papermc.paper.logging.SysoutCatcher();
|
||||
private final io.papermc.paper.potion.PaperPotionBrewer potionBrewer;
|
||||
public final io.papermc.paper.SparksFly spark;
|
||||
private final ServerConfiguration serverConfig = new PaperServerConfiguration();
|
||||
|
||||
// Paper start - Folia region threading API
|
||||
private final io.papermc.paper.threadedregions.scheduler.FallbackRegionScheduler regionizedScheduler = new io.papermc.paper.threadedregions.scheduler.FallbackRegionScheduler();
|
||||
@ -1717,25 +1722,31 @@ public final class CraftServer implements Server {
|
||||
|
||||
private CraftItemCraftResult createItemCraftResult(Optional<RecipeHolder<CraftingRecipe>> recipe, ItemStack itemStack, CraftingContainer inventoryCrafting) {
|
||||
CraftItemCraftResult craftItemResult = new CraftItemCraftResult(itemStack);
|
||||
recipe.map((holder) -> holder.value().getRemainingItems(inventoryCrafting.asCraftInput())).ifPresent((remainingItems) -> {
|
||||
// tl;dr: this is an API adopted implementation of ResultSlot#onTake
|
||||
final CraftingInput.Positioned positionedCraftInput = inventoryCrafting.asPositionedCraftInput();
|
||||
final CraftingInput craftingInput = positionedCraftInput.input();
|
||||
recipe.map((holder) -> holder.value().getRemainingItems(craftingInput)).ifPresent((remainingItems) -> {
|
||||
// Set the resulting matrix items and overflow items
|
||||
for (int i = 0; i < remainingItems.size(); ++i) {
|
||||
net.minecraft.world.item.ItemStack itemstack1 = inventoryCrafting.getItem(i);
|
||||
net.minecraft.world.item.ItemStack itemstack2 = remainingItems.get(i);
|
||||
for (int height = 0; height < craftingInput.height(); height++) {
|
||||
for (int width = 0; width < craftingInput.width(); width++) {
|
||||
final int inventorySlot = width + positionedCraftInput.left() + (height + positionedCraftInput.top()) * inventoryCrafting.getWidth();
|
||||
net.minecraft.world.item.ItemStack itemInMenu = inventoryCrafting.getItem(inventorySlot);
|
||||
net.minecraft.world.item.ItemStack remainingItem = remainingItems.get(width + height * craftingInput.width());
|
||||
|
||||
if (!itemstack1.isEmpty()) {
|
||||
inventoryCrafting.removeItem(i, 1);
|
||||
itemstack1 = inventoryCrafting.getItem(i);
|
||||
}
|
||||
if (!itemInMenu.isEmpty()) {
|
||||
inventoryCrafting.removeItem(inventorySlot, 1);
|
||||
itemInMenu = inventoryCrafting.getItem(inventorySlot);
|
||||
}
|
||||
|
||||
if (!itemstack2.isEmpty()) {
|
||||
if (itemstack1.isEmpty()) {
|
||||
inventoryCrafting.setItem(i, itemstack2);
|
||||
} else if (net.minecraft.world.item.ItemStack.isSameItemSameComponents(itemstack1, itemstack2)) {
|
||||
itemstack2.grow(itemstack1.getCount());
|
||||
inventoryCrafting.setItem(i, itemstack2);
|
||||
} else {
|
||||
craftItemResult.getOverflowItems().add(CraftItemStack.asBukkitCopy(itemstack2));
|
||||
if (!remainingItem.isEmpty()) {
|
||||
if (itemInMenu.isEmpty()) {
|
||||
inventoryCrafting.setItem(inventorySlot, remainingItem);
|
||||
} else if (net.minecraft.world.item.ItemStack.isSameItemSameComponents(itemInMenu, remainingItem)) {
|
||||
remainingItem.grow(itemInMenu.getCount());
|
||||
inventoryCrafting.setItem(inventorySlot, remainingItem);
|
||||
} else {
|
||||
craftItemResult.getOverflowItems().add(CraftItemStack.asBukkitCopy(remainingItem));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1861,6 +1872,11 @@ public final class CraftServer implements Server {
|
||||
return this.console.usesAuthentication();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ServerConfiguration getServerConfig() {
|
||||
return serverConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getAllowFlight() {
|
||||
return this.console.isFlightAllowed();
|
||||
@ -2537,7 +2553,7 @@ public final class CraftServer implements Server {
|
||||
completions = this.getCommandMap().tabComplete(player, message, CraftLocation.toBukkit(pos, world.getWorld()));
|
||||
}
|
||||
} catch (CommandException ex) {
|
||||
player.sendMessage(ChatColor.RED + "An internal error occurred while attempting to tab-complete this command");
|
||||
player.sendMessage(Component.text("An internal error occurred while attempting to tab-complete this command", NamedTextColor.RED));
|
||||
this.getLogger().log(Level.SEVERE, "Exception when " + player.getName() + " attempted to tab complete " + message, ex);
|
||||
}
|
||||
|
||||
|
||||
@ -14,6 +14,10 @@ public class CraftSound extends OldEnumHolderable<Sound, SoundEvent> implements
|
||||
return CraftRegistry.minecraftToBukkit(minecraft, Registries.SOUND_EVENT);
|
||||
}
|
||||
|
||||
public static Sound minecraftHolderToBukkit(Holder<SoundEvent> minecraft) {
|
||||
return CraftRegistry.minecraftHolderToBukkit(minecraft, Registries.SOUND_EVENT);
|
||||
}
|
||||
|
||||
public static SoundEvent bukkitToMinecraft(Sound bukkit) {
|
||||
return CraftRegistry.bukkitToMinecraft(bukkit);
|
||||
}
|
||||
|
||||
@ -157,8 +157,8 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
private WorldBorder worldBorder;
|
||||
private Environment environment;
|
||||
private final CraftServer server = (CraftServer) Bukkit.getServer();
|
||||
private final ChunkGenerator generator;
|
||||
private final BiomeProvider biomeProvider;
|
||||
private final @Nullable ChunkGenerator generator;
|
||||
private final @Nullable BiomeProvider biomeProvider;
|
||||
private final List<BlockPopulator> populators = new ArrayList<BlockPopulator>();
|
||||
private final BlockMetadataStore blockMetadata = new BlockMetadataStore(this);
|
||||
private final Object2IntOpenHashMap<SpawnCategory> spawnCategoryLimit = new Object2IntOpenHashMap<>();
|
||||
@ -286,12 +286,12 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
|
||||
private static final Random rand = new Random();
|
||||
|
||||
public CraftWorld(ServerLevel world, ChunkGenerator gen, BiomeProvider biomeProvider, Environment env) {
|
||||
public CraftWorld(ServerLevel world, @Nullable ChunkGenerator generator, @Nullable BiomeProvider biomeProvider, Environment environment) {
|
||||
this.world = world;
|
||||
this.generator = gen;
|
||||
this.generator = generator;
|
||||
this.biomeProvider = biomeProvider;
|
||||
|
||||
this.environment = env;
|
||||
this.environment = environment;
|
||||
// Paper start - per world spawn limits
|
||||
for (SpawnCategory spawnCategory : SpawnCategory.values()) {
|
||||
if (CraftSpawnCategory.isValidForLimits(spawnCategory)) {
|
||||
@ -909,7 +909,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Environment getEnvironment() {
|
||||
public @NotNull Environment getEnvironment() {
|
||||
return this.environment;
|
||||
}
|
||||
|
||||
@ -924,12 +924,12 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkGenerator getGenerator() {
|
||||
public @Nullable ChunkGenerator getGenerator() {
|
||||
return this.generator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeProvider getBiomeProvider() {
|
||||
public @Nullable BiomeProvider getBiomeProvider() {
|
||||
return this.biomeProvider;
|
||||
}
|
||||
|
||||
|
||||
@ -26,10 +26,12 @@ import org.bukkit.entity.minecart.CommandMinecart;
|
||||
public class VanillaCommandWrapper extends BukkitCommand { // Paper
|
||||
|
||||
public final CommandNode<CommandSourceStack> vanillaCommand;
|
||||
public final String helpCommandNamespace;
|
||||
|
||||
public VanillaCommandWrapper(String name, String description, String usageMessage, List<String> aliases, CommandNode<CommandSourceStack> vanillaCommand) {
|
||||
public VanillaCommandWrapper(String name, String description, String usageMessage, List<String> aliases, CommandNode<CommandSourceStack> vanillaCommand, String helpCommandNamespace) {
|
||||
super(name, description, usageMessage, aliases);
|
||||
this.vanillaCommand = vanillaCommand;
|
||||
this.helpCommandNamespace = helpCommandNamespace;
|
||||
}
|
||||
|
||||
Commands commands() {
|
||||
@ -40,6 +42,7 @@ public class VanillaCommandWrapper extends BukkitCommand { // Paper
|
||||
super(vanillaCommand.getName(), "A Mojang provided command.", vanillaCommand.getUsageText(), Collections.emptyList());
|
||||
this.vanillaCommand = vanillaCommand;
|
||||
this.setPermission(VanillaCommandWrapper.getPermission(vanillaCommand));
|
||||
this.helpCommandNamespace = "Minecraft";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -9,6 +9,11 @@ public abstract class AbstractProjectile extends CraftEntity implements Projecti
|
||||
super(server, entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.entity.projectile.Projectile getHandle() {
|
||||
return (net.minecraft.world.entity.projectile.Projectile) this.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesBounce() {
|
||||
return false;
|
||||
@ -53,11 +58,6 @@ public abstract class AbstractProjectile extends CraftEntity implements Projecti
|
||||
this.getHandle().preHitTargetOrDeflectSelf(new net.minecraft.world.phys.EntityHitResult(((CraftEntity) entity).getHandle(), new net.minecraft.world.phys.Vec3(vector.getX(), vector.getY(), vector.getZ())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.entity.projectile.Projectile getHandle() {
|
||||
return (net.minecraft.world.entity.projectile.Projectile) entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final org.bukkit.projectiles.ProjectileSource getShooter() {
|
||||
this.getHandle().refreshProjectileSource(true); // Paper - Refresh ProjectileSource for projectiles
|
||||
|
||||
@ -3,6 +3,7 @@ package org.bukkit.craftbukkit.entity;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
import java.util.List;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.BlockCollisions;
|
||||
@ -13,7 +14,6 @@ import org.bukkit.craftbukkit.block.CraftBlock;
|
||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.AbstractArrow;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class CraftAbstractArrow extends AbstractProjectile implements AbstractArrow {
|
||||
|
||||
@ -21,6 +21,11 @@ public abstract class CraftAbstractArrow extends AbstractProjectile implements A
|
||||
super(server, entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.entity.projectile.AbstractArrow getHandle() {
|
||||
return (net.minecraft.world.entity.projectile.AbstractArrow) this.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setKnockbackStrength(int knockbackStrength) {
|
||||
}
|
||||
@ -63,8 +68,6 @@ public abstract class CraftAbstractArrow extends AbstractProjectile implements A
|
||||
this.getHandle().setCritArrow(critical);
|
||||
}
|
||||
|
||||
// Paper - moved to AbstractProjectile
|
||||
|
||||
@Override
|
||||
public boolean isInBlock() {
|
||||
return this.getHandle().isInGround();
|
||||
@ -139,16 +142,6 @@ public abstract class CraftAbstractArrow extends AbstractProjectile implements A
|
||||
this.getHandle().firedFromWeapon = CraftItemStack.asNMSCopy(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.entity.projectile.AbstractArrow getHandle() {
|
||||
return (net.minecraft.world.entity.projectile.AbstractArrow) this.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CraftAbstractArrow";
|
||||
}
|
||||
|
||||
// Paper start
|
||||
@Override
|
||||
public CraftItemStack getItemStack() {
|
||||
|
||||
@ -15,5 +15,4 @@ public abstract class CraftAbstractCow extends CraftAnimals implements AbstractC
|
||||
public net.minecraft.world.entity.animal.AbstractCow getHandle() {
|
||||
return (net.minecraft.world.entity.animal.AbstractCow) this.entity;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -11,13 +11,13 @@ public abstract class CraftAbstractSkeleton extends CraftMonster implements Abst
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkeletonType(Skeleton.SkeletonType type) {
|
||||
throw new UnsupportedOperationException("Not supported.");
|
||||
public net.minecraft.world.entity.monster.AbstractSkeleton getHandle() {
|
||||
return (net.minecraft.world.entity.monster.AbstractSkeleton) this.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.entity.monster.AbstractSkeleton getHandle() {
|
||||
return (net.minecraft.world.entity.monster.AbstractSkeleton) super.getHandle();
|
||||
public void setSkeletonType(Skeleton.SkeletonType type) {
|
||||
throw new UnsupportedOperationException("Not supported.");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -25,11 +25,6 @@ public abstract class CraftAbstractVillager extends CraftAgeable implements Craf
|
||||
return this.getHandle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CraftAbstractVillager";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inventory getInventory() {
|
||||
return new CraftInventory(this.getHandle().getInventory());
|
||||
|
||||
@ -9,19 +9,14 @@ public abstract class CraftAbstractWindCharge extends CraftFireball implements A
|
||||
super(server, entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void explode() {
|
||||
this.getHandle().explode(this.getHandle().position());
|
||||
this.getHandle().discard(EntityRemoveEvent.Cause.EXPLODE); // SPIGOT-7577 - explode doesn't discard the entity, this happens only in tick and onHitBlock
|
||||
}
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.entity.projectile.windcharge.AbstractWindCharge getHandle() {
|
||||
return (net.minecraft.world.entity.projectile.windcharge.AbstractWindCharge) this.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CraftAbstractWindCharge";
|
||||
public void explode() {
|
||||
this.getHandle().explode(this.getHandle().position());
|
||||
this.getHandle().discard(EntityRemoveEvent.Cause.EXPLODE); // SPIGOT-7577 - explode doesn't discard the entity, this happens only in tick and onHitBlock
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,11 @@ public class CraftAgeable extends CraftCreature implements Ageable {
|
||||
super(server, entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AgeableMob getHandle() {
|
||||
return (AgeableMob) this.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAge() {
|
||||
return this.getHandle().getAge();
|
||||
@ -62,14 +67,4 @@ public class CraftAgeable extends CraftCreature implements Ageable {
|
||||
this.setAge(6000);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AgeableMob getHandle() {
|
||||
return (AgeableMob) this.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CraftAgeable";
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,11 +21,6 @@ public class CraftAllay extends CraftCreature implements org.bukkit.entity.Allay
|
||||
return (Allay) this.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CraftAllay";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inventory getInventory() {
|
||||
return new CraftInventory(this.getHandle().getInventory());
|
||||
|
||||
@ -13,9 +13,4 @@ public class CraftAmbient extends CraftMob implements Ambient {
|
||||
public AmbientCreature getHandle() {
|
||||
return (AmbientCreature) this.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CraftAmbient";
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,11 +20,6 @@ public class CraftAnimals extends CraftAgeable implements Animals {
|
||||
return (Animal) this.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CraftAnimals";
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getBreedCause() {
|
||||
return this.getHandle().loveCause;
|
||||
|
||||
@ -30,12 +30,7 @@ public class CraftAreaEffectCloud extends CraftEntity implements AreaEffectCloud
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.entity.AreaEffectCloud getHandle() {
|
||||
return (net.minecraft.world.entity.AreaEffectCloud) super.getHandle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CraftAreaEffectCloud";
|
||||
return (net.minecraft.world.entity.AreaEffectCloud) this.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package org.bukkit.craftbukkit.entity;
|
||||
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
|
||||
import net.minecraft.world.entity.animal.armadillo.Armadillo.ArmadilloState;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.bukkit.entity.Armadillo;
|
||||
|
||||
@ -11,11 +13,46 @@ public class CraftArmadillo extends CraftAnimals implements Armadillo {
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.entity.animal.armadillo.Armadillo getHandle() {
|
||||
return (net.minecraft.world.entity.animal.armadillo.Armadillo) super.getHandle();
|
||||
return (net.minecraft.world.entity.animal.armadillo.Armadillo) this.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CraftArmadillo";
|
||||
public State getState() {
|
||||
return CraftArmadillo.stateToBukkit(this.getHandle().getState());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollUp() {
|
||||
this.getHandle().getBrain().setMemoryWithExpiry(MemoryModuleType.DANGER_DETECTED_RECENTLY, true, net.minecraft.world.entity.animal.armadillo.Armadillo.SCARE_CHECK_INTERVAL);
|
||||
this.getHandle().rollUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollOut() {
|
||||
if (this.getHandle().getBrain().getTimeUntilExpiry(MemoryModuleType.DANGER_DETECTED_RECENTLY) <= ArmadilloState.UNROLLING.animationDuration()) {
|
||||
// already unrolling or unrolled
|
||||
return;
|
||||
}
|
||||
|
||||
this.getHandle().lastHurtByMob = null; // Clear this memory to not have the sensor trigger rollUp instantly for damaged armadillo
|
||||
this.getHandle().getBrain().setMemoryWithExpiry(MemoryModuleType.DANGER_DETECTED_RECENTLY, true, ArmadilloState.UNROLLING.animationDuration());
|
||||
}
|
||||
|
||||
public static State stateToBukkit(ArmadilloState state) {
|
||||
return switch (state) {
|
||||
case IDLE -> State.IDLE;
|
||||
case ROLLING -> State.ROLLING;
|
||||
case SCARED -> State.SCARED;
|
||||
case UNROLLING -> State.UNROLLING;
|
||||
};
|
||||
}
|
||||
|
||||
public static ArmadilloState stateToNMS(State state) {
|
||||
return switch (state) {
|
||||
case State.IDLE -> ArmadilloState.IDLE;
|
||||
case State.ROLLING -> ArmadilloState.ROLLING;
|
||||
case State.SCARED -> ArmadilloState.SCARED;
|
||||
case State.UNROLLING -> ArmadilloState.UNROLLING;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,14 +15,9 @@ public class CraftArmorStand extends CraftLivingEntity implements ArmorStand {
|
||||
super(server, entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CraftArmorStand";
|
||||
}
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.entity.decoration.ArmorStand getHandle() {
|
||||
return (net.minecraft.world.entity.decoration.ArmorStand) super.getHandle();
|
||||
return (net.minecraft.world.entity.decoration.ArmorStand) this.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -29,11 +29,6 @@ public class CraftArrow extends CraftAbstractArrow implements Arrow {
|
||||
return (net.minecraft.world.entity.projectile.Arrow) this.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CraftArrow";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addCustomEffect(PotionEffect effect, boolean override) {
|
||||
if (this.hasCustomEffect(effect.getType())) {
|
||||
|
||||
@ -12,12 +12,7 @@ public class CraftAxolotl extends CraftAnimals implements Axolotl, io.papermc.pa
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.entity.animal.axolotl.Axolotl getHandle() {
|
||||
return (net.minecraft.world.entity.animal.axolotl.Axolotl) super.getHandle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CraftAxolotl";
|
||||
return (net.minecraft.world.entity.animal.axolotl.Axolotl) this.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user