385
This commit is contained in:
parent
ec05cb8b38
commit
0bc9aeef26
122 changed files with 402 additions and 448 deletions
|
@ -7022,7 +7022,7 @@ index aede9b65e799a1f123f71f9390fb05acddda676b..2510589400b3012b827efcab477c6483
|
|||
@Override
|
||||
public void tell(R runnable) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 687c0683ee5b3366d936a178fb4bf9faffc2a556..6041033b3ea201bde1a73ce4e429e8b80e05e2eb 100644
|
||||
index 586acbb52b0fcb09cda195b49b6c737a29a4e35e..b0843917caedc32f800c50cc54706ace9523f64f 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -339,6 +339,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
|
|
@ -1301,7 +1301,7 @@ index 9807c5b2b248a62a476bfe3ae023d57d35811049..62174dae20bd9ff092238f1437f7e2b0
|
|||
|
||||
public UserWhiteList getWhiteList() {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 6041033b3ea201bde1a73ce4e429e8b80e05e2eb..4f321f13352636999c3abc5332e50c747fb45cc9 100644
|
||||
index b0843917caedc32f800c50cc54706ace9523f64f..63f45a77c8511e05954030cf117c5e4cda0a518f 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -140,7 +140,6 @@ import org.bukkit.command.CommandSender;
|
||||
|
|
|
@ -25,7 +25,7 @@ index 9675d91e4e7ed46147c3f7a11dd65122fe998dc2..711318ddc706e72dbd8cea1c541058c8
|
|||
|
||||
public void onTrackingEnd(Entity entity) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 4f321f13352636999c3abc5332e50c747fb45cc9..c355e8d71b4941b2ad43740763209927a3279336 100644
|
||||
index 63f45a77c8511e05954030cf117c5e4cda0a518f..dbe5239b1a1769ef9f2ef66c32b1a68cd684428e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -328,7 +328,27 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
|
|
@ -6,7 +6,7 @@ Subject: [PATCH] Configurable top of nether void damage
|
|||
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index c355e8d71b4941b2ad43740763209927a3279336..fafccc1c98cbc630dc71db623184a62f08618b03 100644
|
||||
index dbe5239b1a1769ef9f2ef66c32b1a68cd684428e..d5f5864b7c1ad4c30f37b360b317b63c129e3a3f 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -706,7 +706,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
|
|
@ -11,7 +11,7 @@ So avoid looking up scoreboards and short circuit to the "not on a team"
|
|||
logic which is most likely to be true.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index fafccc1c98cbc630dc71db623184a62f08618b03..b5c03b3495f5eb5ac6b054d4ca986a6a597c713c 100644
|
||||
index d5f5864b7c1ad4c30f37b360b317b63c129e3a3f..82e57978b79b5275b98a1fa7731c6a23ee861a2f 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -2934,6 +2934,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
|
|
@ -6,7 +6,7 @@ Subject: [PATCH] Use a Shared Random for Entities
|
|||
Reduces memory usage and provides ensures more randomness, Especially since a lot of garbage entity objects get created.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index b5c03b3495f5eb5ac6b054d4ca986a6a597c713c..ea25e9ab6c1d54e834a05951d2369d6e2e3a3fb3 100644
|
||||
index 82e57978b79b5275b98a1fa7731c6a23ee861a2f..bd17157631a74f80e3b5ce50bb1f681abe1dd6a7 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -175,6 +175,79 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
|
|
@ -12,7 +12,7 @@ just as it does in Vanilla, but entity pushing logic will be capped.
|
|||
You can set this to 0 to disable collisions.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index ea25e9ab6c1d54e834a05951d2369d6e2e3a3fb3..78cb145f72efaaf535b6f933b3ca990a3f909608 100644
|
||||
index bd17157631a74f80e3b5ce50bb1f681abe1dd6a7..46a21ed2408a42aafd16647e17e556730e799cbd 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -401,6 +401,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
|
|
@ -5,7 +5,7 @@ Subject: [PATCH] Entity#fromMobSpawner()
|
|||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 78cb145f72efaaf535b6f933b3ca990a3f909608..439e8b4f52ba88456fb8ae5ab960d715f5c0d131 100644
|
||||
index 46a21ed2408a42aafd16647e17e556730e799cbd..946f289e0e681524c6fde696921965dbdedda372 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -402,6 +402,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
|
|
@ -5,7 +5,7 @@ Subject: [PATCH] Add EntityTeleportEndGatewayEvent
|
|||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 439e8b4f52ba88456fb8ae5ab960d715f5c0d131..d790aec175e61bd9dd9c14cbbbd4c3c354bf867a 100644
|
||||
index 946f289e0e681524c6fde696921965dbdedda372..d6017d9d71fb4b3a3df6eaa44da0ebda54c83da4 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -3301,8 +3301,16 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
|
|
@ -11,7 +11,7 @@ Co-authored-by: aerulion <aerulion@gmail.com>
|
|||
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index d790aec175e61bd9dd9c14cbbbd4c3c354bf867a..35edebe672c72849e9f8a9a38f86354f2e987271 100644
|
||||
index d6017d9d71fb4b3a3df6eaa44da0ebda54c83da4..5e7cf17779685355011bb0f684c110807a7736c7 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -1962,6 +1962,21 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
|
|
@ -6,7 +6,7 @@ Subject: [PATCH] add more information to Entity.toString()
|
|||
UUID, ticks lived, valid, dead
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 35edebe672c72849e9f8a9a38f86354f2e987271..0355f2d1deb9fcb85efa015249d5ba81c0f27302 100644
|
||||
index 5e7cf17779685355011bb0f684c110807a7736c7..4ba77d4b109bc33d47130519c1fac704434d393d 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -3280,7 +3280,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
|
|
@ -43,7 +43,7 @@ index ce6be7aed7b392c3e0c851f3f6e1e216bccceaf5..b151506b96a51c74ba408cb555a4d385
|
|||
// WorldServer.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityTypes.getKey(entity.getType())); // CraftBukkit
|
||||
return false;
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 0355f2d1deb9fcb85efa015249d5ba81c0f27302..8368342ea699851f3f2926414a49b9dd3d8be327 100644
|
||||
index 4ba77d4b109bc33d47130519c1fac704434d393d..3830440b913bd2693f2922483e57419c76117315 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -250,6 +250,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
|
|
@ -41,7 +41,7 @@ index 8de0b92285fe2413a4e2fb52fc7bc7a13dad5e90..fcbb0b64feb8d5624de3805d4db6d489
|
|||
Iterator iterator = entityliving.getActiveEffects().iterator();
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 8368342ea699851f3f2926414a49b9dd3d8be327..ab69b0a0c85009e8857aff85a46b1aab9cec14af 100644
|
||||
index 3830440b913bd2693f2922483e57419c76117315..5b3de422b07f680e6639ee84f076bffb3c901d0e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -2706,17 +2706,28 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
|
56
patches/server/0280-Limit-Client-Sign-length-more.patch
Normal file
56
patches/server/0280-Limit-Client-Sign-length-more.patch
Normal file
|
@ -0,0 +1,56 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 27 Feb 2019 22:18:40 -0500
|
||||
Subject: [PATCH] Limit Client Sign length more
|
||||
|
||||
modified clients can send more data from the client
|
||||
to the server and it would get stored on the sign as sent.
|
||||
|
||||
Mojang has a limit of 384 which is much higher than reasonable.
|
||||
|
||||
the client can barely render around 16 characters as-is, but formatting
|
||||
codes can get it to be more than 16 actual length.
|
||||
|
||||
Set a limit of 80 which should give an average of 16 characters 2
|
||||
sets of legacy formatting codes which should be plenty for all uses.
|
||||
|
||||
This does not strip any existing data from the NBT as plugins
|
||||
may use this for storing data out of the rendered area.
|
||||
|
||||
it only impacts data sent from the client.
|
||||
|
||||
Set -DPaper.maxSignLength=XX to change limit or -1 to disable
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 26228dbf1830134c185e884b22487e3e40ccf3aa..528c902b5434875b111812ff3a8099f945404d3c 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -299,6 +299,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
private final MessageSignatureCache messageSignatureCache = MessageSignatureCache.createDefault();
|
||||
private final FutureChain chatMessageChain;
|
||||
private boolean waitingForSwitchToConfig;
|
||||
+ private static final int MAX_SIGN_LINE_LENGTH = Integer.getInteger("Paper.maxSignLength", 80); // Paper - Limit client sign length
|
||||
|
||||
public ServerGamePacketListenerImpl(MinecraftServer server, Connection connection, ServerPlayer player, CommonListenerCookie clientData) {
|
||||
super(server, connection, clientData, player); // CraftBukkit
|
||||
@@ -3151,7 +3152,19 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
|
||||
@Override
|
||||
public void handleSignUpdate(ServerboundSignUpdatePacket packet) {
|
||||
- List<String> list = (List) Stream.of(packet.getLines()).map(ChatFormatting::stripFormatting).collect(Collectors.toList());
|
||||
+ // Paper start - Limit client sign length
|
||||
+ String[] lines = packet.getLines();
|
||||
+ for (int i = 0; i < lines.length; ++i) {
|
||||
+ if (MAX_SIGN_LINE_LENGTH > 0 && lines[i].length() > MAX_SIGN_LINE_LENGTH) {
|
||||
+ // This handles multibyte characters as 1
|
||||
+ int offset = lines[i].codePoints().limit(MAX_SIGN_LINE_LENGTH).map(Character::charCount).sum();
|
||||
+ if (offset < lines[i].length()) {
|
||||
+ lines[i] = lines[i].substring(0, offset); // this will break any filtering, but filtering is NYI as of 1.17
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ List<String> list = (List) Stream.of(lines).map(ChatFormatting::stripFormatting).collect(Collectors.toList());
|
||||
+ // Paper end - Limit client sign length
|
||||
|
||||
this.filterTextPacket(list).thenAcceptAsync((list1) -> {
|
||||
this.updateSignText(packet, list1);
|
|
@ -0,0 +1,18 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Vainomaa <mikroskeem@mikroskeem.eu>
|
||||
Date: Wed, 13 Mar 2019 20:08:09 +0200
|
||||
Subject: [PATCH] Call WhitelistToggleEvent when whitelist is toggled
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 92e81514ce85f32303506d6ffc501946c0320c83..f82728bece2723a8f676ebc5b09885c7833174e4 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -1126,6 +1126,7 @@ public abstract class PlayerList {
|
||||
}
|
||||
|
||||
public void setUsingWhiteList(boolean whitelistEnabled) {
|
||||
+ new com.destroystokyo.paper.event.server.WhitelistToggleEvent(whitelistEnabled).callEvent(); // Paper - WhitelistToggleEvent
|
||||
this.doWhiteList = whitelistEnabled;
|
||||
}
|
||||
|
150
patches/server/0282-Entity-getEntitySpawnReason.patch
Normal file
150
patches/server/0282-Entity-getEntitySpawnReason.patch
Normal file
|
@ -0,0 +1,150 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 24 Mar 2019 00:24:52 -0400
|
||||
Subject: [PATCH] Entity#getEntitySpawnReason
|
||||
|
||||
Allows you to return the SpawnReason for why an Entity Spawned
|
||||
|
||||
Pre existing entities will return NATURAL if it was a non
|
||||
persistenting Living Entity, SPAWNER for spawners,
|
||||
or DEFAULT since data was not stored.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/commands/SummonCommand.java b/src/main/java/net/minecraft/server/commands/SummonCommand.java
|
||||
index bf72cf288ade52ee8cc41ca978f368b3ad575951..798999be50d26be357ef3c6d5b9383ce4d1048c1 100644
|
||||
--- a/src/main/java/net/minecraft/server/commands/SummonCommand.java
|
||||
+++ b/src/main/java/net/minecraft/server/commands/SummonCommand.java
|
||||
@@ -57,6 +57,7 @@ public class SummonCommand {
|
||||
ServerLevel worldserver = source.getLevel();
|
||||
Entity entity = EntityType.loadEntityRecursive(nbttagcompound1, worldserver, (entity1) -> {
|
||||
entity1.moveTo(pos.x, pos.y, pos.z, entity1.getYRot(), entity1.getXRot());
|
||||
+ entity1.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.COMMAND; // Paper - Entity#getEntitySpawnReason
|
||||
return entity1;
|
||||
});
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index b151506b96a51c74ba408cb555a4d38507b2f8c1..bbcee9d8dbf17085b11bb5e38eb37271c51219ba 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1207,6 +1207,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
return true;
|
||||
}
|
||||
// Paper end - extra debug info
|
||||
+ if (entity.spawnReason == null) entity.spawnReason = spawnReason; // Paper - Entity#getEntitySpawnReason
|
||||
if (entity.isRemoved()) {
|
||||
// WorldServer.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityTypes.getKey(entity.getType())); // CraftBukkit
|
||||
return false;
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index f82728bece2723a8f676ebc5b09885c7833174e4..f9794c0eaced71d242cb04b0815bad322ed7165d 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -223,6 +223,11 @@ public abstract class PlayerList {
|
||||
worldserver1 = worldserver;
|
||||
}
|
||||
|
||||
+ // Paper start - Entity#getEntitySpawnReason
|
||||
+ if (optional.isEmpty()) {
|
||||
+ player.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT; // set Player SpawnReason to DEFAULT on first login
|
||||
+ }
|
||||
+ // Paper end - Entity#getEntitySpawnReason
|
||||
player.setServerLevel(worldserver1);
|
||||
String s1 = connection.getLoggableAddress(this.server.logIPs());
|
||||
|
||||
@@ -348,7 +353,7 @@ public abstract class PlayerList {
|
||||
CompoundTag nbttagcompound = ((CompoundTag) optional.get()).getCompound("RootVehicle");
|
||||
ServerLevel finalWorldServer = worldserver1; // CraftBukkit - decompile error
|
||||
Entity entity = EntityType.loadEntityRecursive(nbttagcompound.getCompound("Entity"), worldserver1, (entity1) -> {
|
||||
- return !finalWorldServer.addWithUUID(entity1) ? null : entity1; // CraftBukkit - decompile error
|
||||
+ return !finalWorldServer.addWithUUID(entity1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.MOUNT) ? null : entity1; // CraftBukkit - decompile error // Paper - Entity#getEntitySpawnReason
|
||||
});
|
||||
|
||||
if (entity != null) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 5b3de422b07f680e6639ee84f076bffb3c901d0e..631f2d70b5fd6dabc06062e3c77802d2b61398ae 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -247,6 +247,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
}
|
||||
// Paper end - Share random for entities to make them more random
|
||||
+ public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; // Paper - Entity#getEntitySpawnReason
|
||||
|
||||
private CraftEntity bukkitEntity;
|
||||
|
||||
@@ -2276,6 +2277,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
nbttagcompound.put("Paper.Origin", this.newDoubleList(origin.getX(), origin.getY(), origin.getZ()));
|
||||
}
|
||||
+ if (spawnReason != null) {
|
||||
+ nbttagcompound.putString("Paper.SpawnReason", spawnReason.name());
|
||||
+ }
|
||||
// Save entity's from mob spawner status
|
||||
if (spawnedViaMobSpawner) {
|
||||
nbttagcompound.putBoolean("Paper.FromMobSpawner", true);
|
||||
@@ -2422,6 +2426,26 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
|
||||
spawnedViaMobSpawner = nbt.getBoolean("Paper.FromMobSpawner"); // Restore entity's from mob spawner status
|
||||
+ if (nbt.contains("Paper.SpawnReason")) {
|
||||
+ String spawnReasonName = nbt.getString("Paper.SpawnReason");
|
||||
+ try {
|
||||
+ spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.valueOf(spawnReasonName);
|
||||
+ } catch (Exception ignored) {
|
||||
+ LOGGER.error("Unknown SpawnReason " + spawnReasonName + " for " + this);
|
||||
+ }
|
||||
+ }
|
||||
+ if (spawnReason == null) {
|
||||
+ if (spawnedViaMobSpawner) {
|
||||
+ spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER;
|
||||
+ } else if (this instanceof Mob && (this instanceof net.minecraft.world.entity.animal.Animal || this instanceof net.minecraft.world.entity.animal.AbstractFish) && !((Mob) this).removeWhenFarAway(0.0)) {
|
||||
+ if (!nbt.getBoolean("PersistenceRequired")) {
|
||||
+ spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ if (spawnReason == null) {
|
||||
+ spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT;
|
||||
+ }
|
||||
// Paper end
|
||||
|
||||
} catch (Throwable throwable) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
index ee897b8c9462dbb3d7be9a2994753155065ce205..1d0964a7f544735a0213d5c7832c71f53db139a9 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
@@ -191,6 +191,7 @@ public abstract class BaseSpawner {
|
||||
}
|
||||
|
||||
entity.spawnedViaMobSpawner = true; // Paper
|
||||
+ entity.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER; // Paper - Entity#getEntitySpawnReason
|
||||
flag = true; // Paper
|
||||
// CraftBukkit start
|
||||
if (org.bukkit.craftbukkit.event.CraftEventFactory.callSpawnerSpawnEvent(entity, pos).isCancelled()) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java
|
||||
index dbc0b69603dcffbf3d41d79719aa0f2b7da4a131..dd86f5ec5b2051aeea4e19ff97146362b1e8d019 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java
|
||||
@@ -189,7 +189,7 @@ public class SculkShriekerBlockEntity extends BlockEntity implements GameEventLi
|
||||
|
||||
private boolean trySummonWarden(ServerLevel world) {
|
||||
return this.warningLevel >= 4
|
||||
- && SpawnUtil.trySpawnMob(EntityType.WARDEN, MobSpawnType.TRIGGERED, world, this.getBlockPos(), 20, 5, 6, SpawnUtil.Strategy.ON_TOP_OF_COLLIDER)
|
||||
+ && SpawnUtil.trySpawnMob(EntityType.WARDEN, MobSpawnType.TRIGGERED, world, this.getBlockPos(), 20, 5, 6, SpawnUtil.Strategy.ON_TOP_OF_COLLIDER, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL, null) // Paper - Entity#getEntitySpawnReason
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
index bddf98bdf60473eb1d2e533cf533ed7eee797aaa..ce70c8fddbe63d0af2b1f988ce9a2b40c5d48066 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
@@ -1018,4 +1018,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
return this.getHandle().spawnedViaMobSpawner;
|
||||
}
|
||||
// Paper end - Entity#fromMobSpawner
|
||||
+
|
||||
+ // Paper start - entity spawn reason API
|
||||
+ @Override
|
||||
+ public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason getEntitySpawnReason() {
|
||||
+ return getHandle().spawnReason;
|
||||
+ }
|
||||
+ // Paper end - entity spawn reason API
|
||||
}
|
134
patches/server/0283-Fire-event-on-GS4-query.patch
Normal file
134
patches/server/0283-Fire-event-on-GS4-query.patch
Normal file
|
@ -0,0 +1,134 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Vainomaa <mikroskeem@mikroskeem.eu>
|
||||
Date: Sun, 17 Mar 2019 21:46:56 +0200
|
||||
Subject: [PATCH] Fire event on GS4 query
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java b/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java
|
||||
index f4596e2b82f4bc385b7460f143207c458f1f0162..0e0867d7add9a024bbe9471f8ff92bbb25996a3d 100644
|
||||
--- a/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java
|
||||
+++ b/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java
|
||||
@@ -106,13 +106,32 @@ public class QueryThreadGs4 extends GenericThread {
|
||||
NetworkDataOutputStream networkDataOutputStream = new NetworkDataOutputStream(1460);
|
||||
networkDataOutputStream.write(0);
|
||||
networkDataOutputStream.writeBytes(this.getIdentBytes(packet.getSocketAddress()));
|
||||
- networkDataOutputStream.writeString(this.serverName);
|
||||
+
|
||||
+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType queryType =
|
||||
+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType.BASIC;
|
||||
+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse queryResponse = com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.builder()
|
||||
+ .motd(this.serverName)
|
||||
+ .map(this.worldName)
|
||||
+ .currentPlayers(this.serverInterface.getPlayerCount())
|
||||
+ .maxPlayers(this.maxPlayers)
|
||||
+ .port(this.serverPort)
|
||||
+ .hostname(this.hostIp)
|
||||
+ .gameVersion(this.serverInterface.getServerVersion())
|
||||
+ .serverVersion(org.bukkit.Bukkit.getServer().getName() + " on " + org.bukkit.Bukkit.getServer().getBukkitVersion())
|
||||
+ .build();
|
||||
+ com.destroystokyo.paper.event.server.GS4QueryEvent queryEvent =
|
||||
+ new com.destroystokyo.paper.event.server.GS4QueryEvent(queryType, packet.getAddress(), queryResponse);
|
||||
+ queryEvent.callEvent();
|
||||
+ queryResponse = queryEvent.getResponse();
|
||||
+
|
||||
+ networkDataOutputStream.writeString(queryResponse.getMotd());
|
||||
networkDataOutputStream.writeString("SMP");
|
||||
- networkDataOutputStream.writeString(this.worldName);
|
||||
- networkDataOutputStream.writeString(Integer.toString(this.serverInterface.getPlayerCount()));
|
||||
- networkDataOutputStream.writeString(Integer.toString(this.maxPlayers));
|
||||
- networkDataOutputStream.writeShort((short)this.serverPort);
|
||||
- networkDataOutputStream.writeString(this.hostIp);
|
||||
+ networkDataOutputStream.writeString(queryResponse.getMap());
|
||||
+ networkDataOutputStream.writeString(Integer.toString(queryResponse.getCurrentPlayers()));
|
||||
+ networkDataOutputStream.writeString(Integer.toString(queryResponse.getMaxPlayers()));
|
||||
+ networkDataOutputStream.writeShort((short) queryResponse.getPort());
|
||||
+ networkDataOutputStream.writeString(queryResponse.getHostname());
|
||||
+ // Paper end
|
||||
this.sendTo(networkDataOutputStream.toByteArray(), packet);
|
||||
LOGGER.debug("Status [{}]", socketAddress);
|
||||
}
|
||||
@@ -147,31 +166,75 @@ public class QueryThreadGs4 extends GenericThread {
|
||||
this.rulesResponse.writeString("splitnum");
|
||||
this.rulesResponse.write(128);
|
||||
this.rulesResponse.write(0);
|
||||
+ // Paper start
|
||||
+ // Pack plugins
|
||||
+ java.util.List<com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation> plugins = java.util.Collections.emptyList();
|
||||
+ org.bukkit.plugin.Plugin[] bukkitPlugins;
|
||||
+ if (((net.minecraft.server.dedicated.DedicatedServer) this.serverInterface).server.getQueryPlugins() && (bukkitPlugins = org.bukkit.Bukkit.getPluginManager().getPlugins()).length > 0) {
|
||||
+ plugins = java.util.stream.Stream.of(bukkitPlugins)
|
||||
+ .map(plugin -> com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation.of(plugin.getName(), plugin.getDescription().getVersion()))
|
||||
+ .collect(java.util.stream.Collectors.toList());
|
||||
+ }
|
||||
+
|
||||
+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse queryResponse = com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.builder()
|
||||
+ .motd(this.serverName)
|
||||
+ .map(this.worldName)
|
||||
+ .currentPlayers(this.serverInterface.getPlayerCount())
|
||||
+ .maxPlayers(this.maxPlayers)
|
||||
+ .port(this.serverPort)
|
||||
+ .hostname(this.hostIp)
|
||||
+ .plugins(plugins)
|
||||
+ .players(this.serverInterface.getPlayerNames())
|
||||
+ .gameVersion(this.serverInterface.getServerVersion())
|
||||
+ .serverVersion(org.bukkit.Bukkit.getServer().getName() + " on " + org.bukkit.Bukkit.getServer().getBukkitVersion())
|
||||
+ .build();
|
||||
+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType queryType =
|
||||
+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType.FULL;
|
||||
+ com.destroystokyo.paper.event.server.GS4QueryEvent queryEvent =
|
||||
+ new com.destroystokyo.paper.event.server.GS4QueryEvent(queryType, packet.getAddress(), queryResponse);
|
||||
+ queryEvent.callEvent();
|
||||
+ queryResponse = queryEvent.getResponse();
|
||||
this.rulesResponse.writeString("hostname");
|
||||
- this.rulesResponse.writeString(this.serverName);
|
||||
+ this.rulesResponse.writeString(queryResponse.getMotd());
|
||||
this.rulesResponse.writeString("gametype");
|
||||
this.rulesResponse.writeString("SMP");
|
||||
this.rulesResponse.writeString("game_id");
|
||||
this.rulesResponse.writeString("MINECRAFT");
|
||||
this.rulesResponse.writeString("version");
|
||||
- this.rulesResponse.writeString(this.serverInterface.getServerVersion());
|
||||
+ this.rulesResponse.writeString(queryResponse.getGameVersion());
|
||||
this.rulesResponse.writeString("plugins");
|
||||
- this.rulesResponse.writeString(this.serverInterface.getPluginNames());
|
||||
+ java.lang.StringBuilder pluginsString = new java.lang.StringBuilder();
|
||||
+ pluginsString.append(queryResponse.getServerVersion());
|
||||
+ if (!queryResponse.getPlugins().isEmpty()) {
|
||||
+ pluginsString.append(": ");
|
||||
+ java.util.Iterator<com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation> iter = queryResponse.getPlugins().iterator();
|
||||
+ while (iter.hasNext()) {
|
||||
+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation info = iter.next();
|
||||
+ pluginsString.append(info.getName());
|
||||
+ if (info.getVersion() != null) {
|
||||
+ pluginsString.append(' ').append(info.getVersion().replace(";", ","));
|
||||
+ }
|
||||
+ if (iter.hasNext()) {
|
||||
+ pluginsString.append(';').append(' ');
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ this.rulesResponse.writeString(pluginsString.toString());
|
||||
this.rulesResponse.writeString("map");
|
||||
- this.rulesResponse.writeString(this.worldName);
|
||||
+ this.rulesResponse.writeString(queryResponse.getMap());
|
||||
this.rulesResponse.writeString("numplayers");
|
||||
- this.rulesResponse.writeString(this.serverInterface.getPlayerCount() + "");
|
||||
+ this.rulesResponse.writeString(Integer.toString(queryResponse.getCurrentPlayers()));
|
||||
this.rulesResponse.writeString("maxplayers");
|
||||
- this.rulesResponse.writeString(this.maxPlayers + "");
|
||||
+ this.rulesResponse.writeString(Integer.toString(queryResponse.getMaxPlayers()));
|
||||
this.rulesResponse.writeString("hostport");
|
||||
- this.rulesResponse.writeString(this.serverPort + "");
|
||||
+ this.rulesResponse.writeString(Integer.toString(queryResponse.getPort()));
|
||||
this.rulesResponse.writeString("hostip");
|
||||
- this.rulesResponse.writeString(this.hostIp);
|
||||
+ this.rulesResponse.writeString(queryResponse.getHostname());
|
||||
this.rulesResponse.write(0);
|
||||
this.rulesResponse.write(1);
|
||||
this.rulesResponse.writeString("player_");
|
||||
this.rulesResponse.write(0);
|
||||
- String[] strings = this.serverInterface.getPlayerNames();
|
||||
+ String[] strings = queryResponse.getPlayers().toArray(String[]::new);
|
||||
|
||||
for (String string : strings) {
|
||||
this.rulesResponse.writeString(string);
|
55
patches/server/0284-Add-PlayerPostRespawnEvent.patch
Normal file
55
patches/server/0284-Add-PlayerPostRespawnEvent.patch
Normal file
|
@ -0,0 +1,55 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MisterVector <whizkid3000@hotmail.com>
|
||||
Date: Fri, 26 Oct 2018 21:31:00 -0700
|
||||
Subject: [PATCH] Add PlayerPostRespawnEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index f9794c0eaced71d242cb04b0815bad322ed7165d..7fa13f1fe02a1bdfa93c76e9c2eefc81c9bded50 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -738,6 +738,10 @@ public abstract class PlayerList {
|
||||
|
||||
entityplayer1.addTag(s);
|
||||
}
|
||||
+ // Paper start - Add PlayerPostRespawnEvent
|
||||
+ boolean isBedSpawn = false;
|
||||
+ boolean isRespawn = false;
|
||||
+ // Paper end - Add PlayerPostRespawnEvent
|
||||
|
||||
// CraftBukkit start - fire PlayerRespawnEvent
|
||||
DimensionTransition dimensiontransition;
|
||||
@@ -745,6 +749,7 @@ public abstract class PlayerList {
|
||||
dimensiontransition = entityplayer.findRespawnPositionAndUseSpawnBlock(flag, DimensionTransition.DO_NOTHING, reason);
|
||||
|
||||
if (!flag) entityplayer.reset(); // SPIGOT-4785
|
||||
+ isRespawn = true; // Paper - Add PlayerPostRespawnEvent
|
||||
} else {
|
||||
dimensiontransition = new DimensionTransition(((CraftWorld) location.getWorld()).getHandle(), CraftLocation.toVec3D(location), Vec3.ZERO, location.getYaw(), location.getPitch(), DimensionTransition.DO_NOTHING);
|
||||
}
|
||||
@@ -795,6 +800,11 @@ public abstract class PlayerList {
|
||||
if (iblockdata.is(Blocks.RESPAWN_ANCHOR)) {
|
||||
entityplayer1.connection.send(new ClientboundSoundPacket(SoundEvents.RESPAWN_ANCHOR_DEPLETE, SoundSource.BLOCKS, (double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ(), 1.0F, 1.0F, worldserver.getRandom().nextLong()));
|
||||
}
|
||||
+ // Paper start - Add PlayerPostRespawnEvent
|
||||
+ if (iblockdata.is(net.minecraft.tags.BlockTags.BEDS) && !dimensiontransition.missingRespawnBlock()) {
|
||||
+ isBedSpawn = true;
|
||||
+ }
|
||||
+ // Paper end - Add PlayerPostRespawnEvent
|
||||
}
|
||||
// Added from changeDimension
|
||||
this.sendAllPlayerInfo(entityplayer); // Update health, etc...
|
||||
@@ -816,6 +826,13 @@ public abstract class PlayerList {
|
||||
if (entityplayer.connection.isDisconnected()) {
|
||||
this.save(entityplayer);
|
||||
}
|
||||
+
|
||||
+ // Paper start - Add PlayerPostRespawnEvent
|
||||
+ if (isRespawn) {
|
||||
+ cserver.getPluginManager().callEvent(new com.destroystokyo.paper.event.player.PlayerPostRespawnEvent(entityplayer.getBukkitEntity(), location, isBedSpawn));
|
||||
+ }
|
||||
+ // Paper end - Add PlayerPostRespawnEvent
|
||||
+
|
||||
// CraftBukkit end
|
||||
|
||||
return entityplayer1;
|
|
@ -0,0 +1,27 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 24 Mar 2019 18:09:20 -0400
|
||||
Subject: [PATCH] don't go below 0 for pickupDelay, breaks picking up items
|
||||
|
||||
vanilla checks for == 0
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
index f9dfd6e7b610cfee75524a525ab0e72bed5522da..6dfa43036afeba75a7ecc5a82637f081624d5c69 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
@@ -149,6 +149,7 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
// CraftBukkit start - Use wall time for pickup and despawn timers
|
||||
int elapsedTicks = MinecraftServer.currentTick - this.lastTick;
|
||||
if (this.pickupDelay != 32767) this.pickupDelay -= elapsedTicks;
|
||||
+ this.pickupDelay = Math.max(0, this.pickupDelay); // Paper - don't go below 0
|
||||
if (this.age != -32768) this.age += elapsedTicks;
|
||||
this.lastTick = MinecraftServer.currentTick;
|
||||
// CraftBukkit end
|
||||
@@ -234,6 +235,7 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
// CraftBukkit start - Use wall time for pickup and despawn timers
|
||||
int elapsedTicks = MinecraftServer.currentTick - this.lastTick;
|
||||
if (this.pickupDelay != 32767) this.pickupDelay -= elapsedTicks;
|
||||
+ this.pickupDelay = Math.max(0, this.pickupDelay); // Paper - don't go below 0
|
||||
if (this.age != -32768) this.age += elapsedTicks;
|
||||
this.lastTick = MinecraftServer.currentTick;
|
||||
// CraftBukkit end
|
31
patches/server/0286-Server-Tick-Events.patch
Normal file
31
patches/server/0286-Server-Tick-Events.patch
Normal file
|
@ -0,0 +1,31 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 27 Mar 2019 22:48:45 -0400
|
||||
Subject: [PATCH] Server Tick Events
|
||||
|
||||
Fires event at start and end of a server tick
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 6494b92c6a6444a66ea0e5f8f2890c47f334c938..12f530044d918ddc1ba4b2376419f9ed72283b98 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1435,6 +1435,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
});
|
||||
isOversleep = false;MinecraftTimings.serverOversleep.stopTiming();
|
||||
// Paper end
|
||||
+ new com.destroystokyo.paper.event.server.ServerTickStartEvent(this.tickCount+1).callEvent(); // Paper - Server Tick Events
|
||||
|
||||
++this.tickCount;
|
||||
this.tickRateManager.tick();
|
||||
@@ -1461,6 +1462,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.runAllTasks();
|
||||
}
|
||||
// Paper end
|
||||
+ // Paper start - Server Tick Events
|
||||
+ long endTime = System.nanoTime();
|
||||
+ long remaining = (TICK_TIME - (endTime - lastTick)) - catchupTime;
|
||||
+ new com.destroystokyo.paper.event.server.ServerTickEndEvent(this.tickCount, ((double)(endTime - lastTick) / 1000000D), remaining).callEvent();
|
||||
+ // Paper end - Server Tick Events
|
||||
this.profiler.push("tallying");
|
||||
long j = Util.getNanos() - i;
|
||||
int k = this.tickCount % 100;
|
77
patches/server/0287-PlayerDeathEvent-getItemsToKeep.patch
Normal file
77
patches/server/0287-PlayerDeathEvent-getItemsToKeep.patch
Normal file
|
@ -0,0 +1,77 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 27 Mar 2019 23:01:33 -0400
|
||||
Subject: [PATCH] PlayerDeathEvent#getItemsToKeep
|
||||
|
||||
Exposes a mutable array on items a player should keep on death
|
||||
|
||||
Example Usage: https://gist.github.com/aikar/5bb202de6057a051a950ce1f29feb0b4
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.player.Inventory compartments
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index dfa3542035924ed53a1fafb032334b0bffbe0282..187cbb9e3c39204f1fb53e85788c954059dc7efc 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -899,6 +899,46 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
});
|
||||
}
|
||||
|
||||
+ // Paper start - PlayerDeathEvent#getItemsToKeep
|
||||
+ private static void processKeep(org.bukkit.event.entity.PlayerDeathEvent event, NonNullList<ItemStack> inv) {
|
||||
+ List<org.bukkit.inventory.ItemStack> itemsToKeep = event.getItemsToKeep();
|
||||
+ if (inv == null) {
|
||||
+ // remainder of items left in toKeep - plugin added stuff on death that wasn't in the initial loot?
|
||||
+ if (!itemsToKeep.isEmpty()) {
|
||||
+ for (org.bukkit.inventory.ItemStack itemStack : itemsToKeep) {
|
||||
+ event.getEntity().getInventory().addItem(itemStack);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ for (int i = 0; i < inv.size(); ++i) {
|
||||
+ ItemStack item = inv.get(i);
|
||||
+ if (EnchantmentHelper.hasVanishingCurse(item) || itemsToKeep.isEmpty() || item.isEmpty()) {
|
||||
+ inv.set(i, ItemStack.EMPTY);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ final org.bukkit.inventory.ItemStack bukkitStack = item.getBukkitStack();
|
||||
+ boolean keep = false;
|
||||
+ final Iterator<org.bukkit.inventory.ItemStack> iterator = itemsToKeep.iterator();
|
||||
+ while (iterator.hasNext()) {
|
||||
+ final org.bukkit.inventory.ItemStack itemStack = iterator.next();
|
||||
+ if (bukkitStack.equals(itemStack)) {
|
||||
+ iterator.remove();
|
||||
+ keep = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!keep) {
|
||||
+ inv.set(i, ItemStack.EMPTY);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - PlayerDeathEvent#getItemsToKeep
|
||||
+
|
||||
@Override
|
||||
public void die(DamageSource damageSource) {
|
||||
// this.gameEvent(GameEvent.ENTITY_DIE); // Paper - move below event cancellation check
|
||||
@@ -983,7 +1023,12 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
this.dropExperience(damageSource.getEntity());
|
||||
// we clean the player's inventory after the EntityDeathEvent is called so plugins can get the exact state of the inventory.
|
||||
if (!event.getKeepInventory()) {
|
||||
- this.getInventory().clearContent();
|
||||
+ // Paper start - PlayerDeathEvent#getItemsToKeep
|
||||
+ for (NonNullList<ItemStack> inv : this.getInventory().compartments) {
|
||||
+ processKeep(event, inv);
|
||||
+ }
|
||||
+ processKeep(event, null);
|
||||
+ // Paper end - PlayerDeathEvent#getItemsToKeep
|
||||
}
|
||||
|
||||
this.setCamera(this); // Remove spectated target
|
|
@ -0,0 +1,30 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 6 Apr 2019 10:16:48 -0400
|
||||
Subject: [PATCH] Optimize Captured BlockEntity Lookup
|
||||
|
||||
upstream was doing a containsKey/get pattern, and always doing it at that.
|
||||
that scenario is only even valid if were in the middle of a block place.
|
||||
|
||||
Optimize to check if the captured list even has values in it, and also to
|
||||
just do a get call since the value can never be null.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 8e2acb3c6f815b5b1d3237a2f4e0b5f3683d2c60..5a3a89c568d42a2adbc2b6e2631fd4b70e54f0bf 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -912,9 +912,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
|
||||
@Nullable
|
||||
public BlockEntity getBlockEntity(BlockPos blockposition, boolean validate) {
|
||||
- if (this.capturedTileEntities.containsKey(blockposition)) {
|
||||
- return this.capturedTileEntities.get(blockposition);
|
||||
+ // Paper start - Perf: Optimize capturedTileEntities lookup
|
||||
+ net.minecraft.world.level.block.entity.BlockEntity blockEntity;
|
||||
+ if (!this.capturedTileEntities.isEmpty() && (blockEntity = this.capturedTileEntities.get(blockposition)) != null) {
|
||||
+ return blockEntity;
|
||||
}
|
||||
+ // Paper end - Perf: Optimize capturedTileEntities lookup
|
||||
// CraftBukkit end
|
||||
return this.isOutsideBuildHeight(blockposition) ? null : (!this.isClientSide && Thread.currentThread() != this.thread ? null : this.getChunkAt(blockposition).getBlockEntity(blockposition, LevelChunk.EntityCreationType.IMMEDIATE));
|
||||
}
|
40
patches/server/0289-Add-Heightmap-API.patch
Normal file
40
patches/server/0289-Add-Heightmap-API.patch
Normal file
|
@ -0,0 +1,40 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Tue, 1 Jan 2019 02:22:01 -0800
|
||||
Subject: [PATCH] Add Heightmap API
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index eafb186d158c6cf26b97b1982597bde377396172..deb9685b1279e734e4789ba7a2113b0d71ab1cc6 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -229,6 +229,29 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
return CraftBlock.at(this.world, new BlockPos(x, y, z));
|
||||
}
|
||||
|
||||
+ // Paper start - Implement heightmap api
|
||||
+ @Override
|
||||
+ public int getHighestBlockYAt(final int x, final int z, final com.destroystokyo.paper.HeightmapType heightmap) throws UnsupportedOperationException {
|
||||
+ this.getChunkAt(x >> 4, z >> 4); // heightmap will ret 0 on unloaded areas
|
||||
+
|
||||
+ switch (heightmap) {
|
||||
+ case LIGHT_BLOCKING:
|
||||
+ throw new UnsupportedOperationException(); // TODO
|
||||
+ //return this.world.getHighestBlockY(HeightMap.Type.LIGHT_BLOCKING, x, z);
|
||||
+ case ANY:
|
||||
+ return this.world.getHeight(net.minecraft.world.level.levelgen.Heightmap.Types.WORLD_SURFACE, x, z);
|
||||
+ case SOLID:
|
||||
+ return this.world.getHeight(net.minecraft.world.level.levelgen.Heightmap.Types.OCEAN_FLOOR, x, z);
|
||||
+ case SOLID_OR_LIQUID:
|
||||
+ return this.world.getHeight(net.minecraft.world.level.levelgen.Heightmap.Types.MOTION_BLOCKING, x, z);
|
||||
+ case SOLID_OR_LIQUID_NO_LEAVES:
|
||||
+ return this.world.getHeight(net.minecraft.world.level.levelgen.Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, x, z);
|
||||
+ default:
|
||||
+ throw new UnsupportedOperationException();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public Location getSpawnLocation() {
|
||||
BlockPos spawn = this.world.getSharedSpawnPos();
|
111
patches/server/0290-Mob-Spawner-API-Enhancements.patch
Normal file
111
patches/server/0290-Mob-Spawner-API-Enhancements.patch
Normal file
|
@ -0,0 +1,111 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <blake.galbreath@gmail.com>
|
||||
Date: Fri, 19 Apr 2019 12:41:13 -0500
|
||||
Subject: [PATCH] Mob Spawner API Enhancements
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.level.BaseSpawner isNearPlayer(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;)Z
|
||||
public net.minecraft.world.level.BaseSpawner delay(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;)V
|
||||
public net.minecraft.world.level.BaseSpawner setNextSpawnData(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/SpawnData;)V
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
index 1d0964a7f544735a0213d5c7832c71f53db139a9..b90127f9f805fdb5bb43a4b8ad2b10499b0b6b78 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
@@ -237,7 +237,13 @@ public abstract class BaseSpawner {
|
||||
}
|
||||
|
||||
public void load(@Nullable Level world, BlockPos pos, CompoundTag nbt) {
|
||||
+ // Paper start - use larger int if set
|
||||
+ if (nbt.contains("Paper.Delay")) {
|
||||
+ this.spawnDelay = nbt.getInt("Paper.Delay");
|
||||
+ } else {
|
||||
this.spawnDelay = nbt.getShort("Delay");
|
||||
+ }
|
||||
+ // Paper end
|
||||
boolean flag = nbt.contains("SpawnData", 10);
|
||||
|
||||
if (flag) {
|
||||
@@ -260,9 +266,15 @@ public abstract class BaseSpawner {
|
||||
this.spawnPotentials = SimpleWeightedRandomList.single(this.nextSpawnData != null ? this.nextSpawnData : new SpawnData());
|
||||
}
|
||||
|
||||
+ // Paper start - use ints if set
|
||||
+ if (nbt.contains("Paper.MinSpawnDelay", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) {
|
||||
+ this.minSpawnDelay = nbt.getInt("Paper.MinSpawnDelay");
|
||||
+ this.maxSpawnDelay = nbt.getInt("Paper.MaxSpawnDelay");
|
||||
+ this.spawnCount = nbt.getShort("SpawnCount");
|
||||
+ } else // Paper end
|
||||
if (nbt.contains("MinSpawnDelay", 99)) {
|
||||
- this.minSpawnDelay = nbt.getShort("MinSpawnDelay");
|
||||
- this.maxSpawnDelay = nbt.getShort("MaxSpawnDelay");
|
||||
+ this.minSpawnDelay = nbt.getInt("MinSpawnDelay"); // Paper - short -> int
|
||||
+ this.maxSpawnDelay = nbt.getInt("MaxSpawnDelay"); // Paper - short -> int
|
||||
this.spawnCount = nbt.getShort("SpawnCount");
|
||||
}
|
||||
|
||||
@@ -279,9 +291,20 @@ public abstract class BaseSpawner {
|
||||
}
|
||||
|
||||
public CompoundTag save(CompoundTag nbt) {
|
||||
- nbt.putShort("Delay", (short) this.spawnDelay);
|
||||
- nbt.putShort("MinSpawnDelay", (short) this.minSpawnDelay);
|
||||
- nbt.putShort("MaxSpawnDelay", (short) this.maxSpawnDelay);
|
||||
+ // Paper start
|
||||
+ if (spawnDelay > Short.MAX_VALUE) {
|
||||
+ nbt.putInt("Paper.Delay", this.spawnDelay);
|
||||
+ }
|
||||
+ nbt.putShort("Delay", (short) Math.min(Short.MAX_VALUE, this.spawnDelay));
|
||||
+
|
||||
+ if (minSpawnDelay > Short.MAX_VALUE || maxSpawnDelay > Short.MAX_VALUE) {
|
||||
+ nbt.putInt("Paper.MinSpawnDelay", this.minSpawnDelay);
|
||||
+ nbt.putInt("Paper.MaxSpawnDelay", this.maxSpawnDelay);
|
||||
+ }
|
||||
+
|
||||
+ nbt.putShort("MinSpawnDelay", (short) Math.min(Short.MAX_VALUE, this.minSpawnDelay));
|
||||
+ nbt.putShort("MaxSpawnDelay", (short) Math.min(Short.MAX_VALUE, this.maxSpawnDelay));
|
||||
+ // Paper end
|
||||
nbt.putShort("SpawnCount", (short) this.spawnCount);
|
||||
nbt.putShort("MaxNearbyEntities", (short) this.maxNearbyEntities);
|
||||
nbt.putShort("RequiredPlayerRange", (short) this.requiredPlayerRange);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftCreatureSpawner.java b/src/main/java/org/bukkit/craftbukkit/block/CraftCreatureSpawner.java
|
||||
index 33718f8861b46452ef9977ac0cbd7624a86edb30..4659f11c3aadda2617951f9d98b4858efe1400d7 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftCreatureSpawner.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftCreatureSpawner.java
|
||||
@@ -256,4 +256,36 @@ public class CraftCreatureSpawner extends CraftBlockEntityState<SpawnerBlockEnti
|
||||
new HashMap<>(nms.slotDropChances().entrySet().stream().collect(Collectors.toMap((entry) -> CraftEquipmentSlot.getSlot(entry.getKey()), Map.Entry::getValue)))
|
||||
)).orElse(null);
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public boolean isActivated() {
|
||||
+ this.requirePlaced();
|
||||
+ return this.getSnapshot().getSpawner().isNearPlayer(this.world.getHandle(), this.getPosition());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void resetTimer() {
|
||||
+ this.requirePlaced();
|
||||
+ this.getSnapshot().getSpawner().delay(this.world.getHandle(), this.getPosition());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setSpawnedItem(org.bukkit.inventory.ItemStack itemStack) {
|
||||
+ Preconditions.checkArgument(itemStack != null && !itemStack.getType().isAir(), "spawners cannot spawn air");
|
||||
+ net.minecraft.world.item.ItemStack item = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(itemStack);
|
||||
+ net.minecraft.nbt.CompoundTag entity = new net.minecraft.nbt.CompoundTag();
|
||||
+ entity.putString("id", net.minecraft.core.registries.BuiltInRegistries.ENTITY_TYPE.getKey(net.minecraft.world.entity.EntityType.ITEM).toString());
|
||||
+ entity.put("Item", item.save(this.world.getHandle().registryAccess()));
|
||||
+ this.getSnapshot().getSpawner().setNextSpawnData(
|
||||
+ this.isPlaced() ? this.world.getHandle() : null,
|
||||
+ this.getPosition(),
|
||||
+ new net.minecraft.world.level.SpawnData(
|
||||
+ entity,
|
||||
+ java.util.Optional.empty(),
|
||||
+ Optional.ofNullable(this.getSnapshot().getSpawner().nextSpawnData).flatMap(SpawnData::equipment)
|
||||
+ )
|
||||
+ );
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Fri, 10 May 2019 18:38:19 +0100
|
||||
Subject: [PATCH] Fix CB call to changed postToMainThread method
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
index e2a07d4e006d90132102a6449d57dd9e9642e6af..adf953994d2c7e8f1e15075722ee2b9213e4bf94 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
@@ -366,7 +366,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
|
||||
Objects.requireNonNull(this.connection);
|
||||
// CraftBukkit - Don't wait
|
||||
- minecraftserver.wrapRunnable(networkmanager::handleDisconnection);
|
||||
+ minecraftserver.scheduleOnMain(networkmanager::handleDisconnection); // Paper
|
||||
}
|
||||
|
||||
protected boolean isSingleplayerOwner() {
|
|
@ -0,0 +1,20 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Phoenix616 <mail@moep.tv>
|
||||
Date: Sat, 27 Apr 2019 20:00:43 +0100
|
||||
Subject: [PATCH] Fix sounds when item frames are modified (MC-123450)
|
||||
|
||||
This also fixes the adding sound playing when the item frame direction is changed.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
||||
index 84dcd662981b1eeb03128e7717f6af44c2b9cff6..fdb6898519acfb27baf25d8bbad2013956c1361f 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
||||
@@ -278,7 +278,7 @@ public class ItemFrame extends HangingEntity {
|
||||
|
||||
this.onItemChanged(itemstack);
|
||||
this.getEntityData().set(ItemFrame.DATA_ITEM, itemstack);
|
||||
- if (!itemstack.isEmpty() && playSound) { // CraftBukkit
|
||||
+ if (!itemstack.isEmpty() && flag && playSound) { // CraftBukkit // Paper - only play sound when update flag is set
|
||||
this.playSound(this.getAddItemSound(), 1.0F, 1.0F);
|
||||
}
|
||||
|
72
patches/server/0293-Implement-CraftBlockSoundGroup.patch
Normal file
72
patches/server/0293-Implement-CraftBlockSoundGroup.patch
Normal file
|
@ -0,0 +1,72 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: simpleauthority <jacob@algorithmjunkie.com>
|
||||
Date: Tue, 28 May 2019 03:48:51 -0700
|
||||
Subject: [PATCH] Implement CraftBlockSoundGroup
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/block/CraftBlockSoundGroup.java b/src/main/java/com/destroystokyo/paper/block/CraftBlockSoundGroup.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..3913c407a3bfa7dfa4a5e374a5e792962fcdafe6
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/block/CraftBlockSoundGroup.java
|
||||
@@ -0,0 +1,39 @@
|
||||
+package com.destroystokyo.paper.block;
|
||||
+
|
||||
+import net.minecraft.world.level.block.SoundType;
|
||||
+import org.bukkit.Sound;
|
||||
+import org.bukkit.craftbukkit.CraftSound;
|
||||
+
|
||||
+@Deprecated(forRemoval = true)
|
||||
+public class CraftBlockSoundGroup implements BlockSoundGroup {
|
||||
+ private final SoundType soundEffectType;
|
||||
+
|
||||
+ public CraftBlockSoundGroup(SoundType soundEffectType) {
|
||||
+ this.soundEffectType = soundEffectType;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Sound getBreakSound() {
|
||||
+ return CraftSound.minecraftToBukkit(soundEffectType.getBreakSound());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Sound getStepSound() {
|
||||
+ return CraftSound.minecraftToBukkit(soundEffectType.getStepSound());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Sound getPlaceSound() {
|
||||
+ return CraftSound.minecraftToBukkit(soundEffectType.getPlaceSound());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Sound getHitSound() {
|
||||
+ return CraftSound.minecraftToBukkit(soundEffectType.getHitSound());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Sound getFallSound() {
|
||||
+ return CraftSound.minecraftToBukkit(soundEffectType.getFallSound());
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
index 013298c424025cd88f15d61e50d196f70fa4c58b..d4e14ac1514e2d8b87b4667a91c90eded3ba6636 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
@@ -622,4 +622,16 @@ public class CraftBlock implements Block {
|
||||
public String getTranslationKey() {
|
||||
return this.getNMS().getBlock().getDescriptionId();
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public com.destroystokyo.paper.block.BlockSoundGroup getSoundGroup() {
|
||||
+ return new com.destroystokyo.paper.block.CraftBlockSoundGroup(getNMS().getBlock().defaultBlockState().getSoundType());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public org.bukkit.SoundGroup getBlockSoundGroup() {
|
||||
+ return org.bukkit.craftbukkit.CraftSoundGroup.getSoundGroup(this.getNMS().getSoundType());
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
21
patches/server/0294-Expose-the-internal-current-tick.patch
Normal file
21
patches/server/0294-Expose-the-internal-current-tick.patch
Normal file
|
@ -0,0 +1,21 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <blake.galbreath@gmail.com>
|
||||
Date: Sat, 20 Apr 2019 19:47:34 -0500
|
||||
Subject: [PATCH] Expose the internal current tick
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 006cc9b7817e0413a332c21839549b127ad67cb4..264b5781a472f706f525cb07d4ccebac17d4a5d3 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2910,5 +2910,10 @@ public final class CraftServer implements Server {
|
||||
profile.getGameProfile().getProperties().putAll(((CraftPlayer) player).getHandle().getGameProfile().getProperties());
|
||||
return profile;
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public int getCurrentTick() {
|
||||
+ return net.minecraft.server.MinecraftServer.currentTick;
|
||||
+ }
|
||||
// Paper end
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 15 Jun 2019 10:28:25 -0700
|
||||
Subject: [PATCH] Show blockstate location if we failed to read it
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
||||
index a7bb7d263cb981fcf6dd35a3b32270e89e96945a..92133f16c192f5caf9962a08401ff914550747f8 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
||||
@@ -32,6 +32,7 @@ public class CraftBlockEntityState<T extends BlockEntity> extends CraftBlockStat
|
||||
|
||||
this.tileEntity = tileEntity;
|
||||
|
||||
+ try { // Paper - Show blockstate location if we failed to read it
|
||||
// Paper start
|
||||
this.snapshotDisabled = DISABLE_SNAPSHOT;
|
||||
if (DISABLE_SNAPSHOT) {
|
||||
@@ -44,6 +45,14 @@ public class CraftBlockEntityState<T extends BlockEntity> extends CraftBlockStat
|
||||
this.load(this.snapshot);
|
||||
}
|
||||
// Paper end
|
||||
+ // Paper start - Show blockstate location if we failed to read it
|
||||
+ } catch (Throwable thr) {
|
||||
+ if (thr instanceof ThreadDeath) {
|
||||
+ throw (ThreadDeath)thr;
|
||||
+ }
|
||||
+ throw new RuntimeException("Failed to read BlockState at: world: " + this.getWorld().getName() + " location: (" + this.getX() + ", " + this.getY() + ", " + this.getZ() + ")", thr);
|
||||
+ }
|
||||
+ // Paper end - Show blockstate location if we failed to read it
|
||||
}
|
||||
|
||||
protected CraftBlockEntityState(CraftBlockEntityState<T> state, Location location) {
|
|
@ -0,0 +1,36 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 24 Mar 2019 01:01:32 -0400
|
||||
Subject: [PATCH] Only count Natural Spawned mobs towards natural spawn mob
|
||||
limit
|
||||
|
||||
This resolves the super common complaint about mobs not spawning.
|
||||
|
||||
This was ultimately a flaw in the vanilla count algorithim that allows
|
||||
spawners and other misc mobs to count against the mob limit, which are
|
||||
not bounded, and can prevent the entire world from spawning new.
|
||||
|
||||
I believe Bukkits changes around persistence may of actually made it
|
||||
worse than vanilla.
|
||||
|
||||
This should fully solve all of the issues around it so that only natural
|
||||
influences natural spawns.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
index 41eef8bfd1572aecaf086bfbec300abeae2df794..58ea6a1f95a09c22125a8262b1b221004ebce0e4 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
@@ -83,6 +83,13 @@ public final class NaturalSpawner {
|
||||
MobCategory enumcreaturetype = entity.getType().getCategory();
|
||||
|
||||
if (enumcreaturetype != MobCategory.MISC) {
|
||||
+ // Paper start - Only count natural spawns
|
||||
+ if (!entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
|
||||
+ !(entity.spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL ||
|
||||
+ entity.spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ // Paper end - Only count natural spawns
|
||||
BlockPos blockposition = entity.blockPosition();
|
||||
|
||||
chunkSource.query(ChunkPos.asLong(blockposition), (chunk) -> {
|
|
@ -0,0 +1,39 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Lucavon <lucavonlp@gmail.com>
|
||||
Date: Tue, 23 Jul 2019 20:29:20 -0500
|
||||
Subject: [PATCH] Configurable projectile relative velocity
|
||||
|
||||
This patch adds an option "disable relative projectile velocity", which, when
|
||||
enabled, will cause projectiles to ignore the shooter's current velocity,
|
||||
like they did in Minecraft 1.8 and prior.
|
||||
If a player is falling, for example, their shooting range will be drastically
|
||||
reduced, as a downwards velocity is applied to the projectile. This prevents
|
||||
players from saving themselves from falling off floating islands, for example,
|
||||
as a thrown ender pearl will not make it back to the island, while it would
|
||||
have in 1.8.
|
||||
|
||||
While this could easily be done with plugins, too, there are multiple problems:
|
||||
P1) If multiple plugins cancel the velocity by subtracting the shooter's velocity
|
||||
from the projectile's velocity, the projectile's velocity would be different.
|
||||
As there's no way to detect whether the projectile's velocity has already been
|
||||
adjusted to ignore the player's velocity, plugins can't not do it if it's not
|
||||
necessary.
|
||||
P2) I've noticed some inconsistencies, e.g. weird velocity when shooting while
|
||||
using an elytra. Checking for those inconsistencies is possible, but not as
|
||||
efficient as just not applying the velocity in the first place.
|
||||
P3) Solutions for 1) and especially 2) might not be future-proof, while this
|
||||
server-internal fix makes this change future-proof.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
|
||||
index 30eb86b52f00cfa61af4f93aca50ffc3547c95e8..7863625d49baa13ea87f2ee295b16706071fb960 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
|
||||
@@ -183,7 +183,7 @@ public abstract class Projectile extends Entity implements TraceableEntity {
|
||||
this.shoot((double) f5, (double) f6, (double) f7, speed, divergence);
|
||||
Vec3 vec3d = shooter.getKnownMovement();
|
||||
|
||||
- this.setDeltaMovement(this.getDeltaMovement().add(vec3d.x, shooter.onGround() ? 0.0D : vec3d.y, vec3d.z));
|
||||
+ if (!shooter.level().paperConfig().misc.disableRelativeProjectileVelocity) this.setDeltaMovement(this.getDeltaMovement().add(vec3d.x, shooter.onGround() ? 0.0D : vec3d.y, vec3d.z)); // Paper - allow disabling relative velocity
|
||||
}
|
||||
|
||||
// CraftBukkit start - call projectile hit event
|
19
patches/server/0298-offset-item-frame-ticking.patch
Normal file
19
patches/server/0298-offset-item-frame-ticking.patch
Normal file
|
@ -0,0 +1,19 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kickash32 <kickash32@gmail.com>
|
||||
Date: Tue, 30 Jul 2019 03:17:16 +0500
|
||||
Subject: [PATCH] offset item frame ticking
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/decoration/BlockAttachedEntity.java b/src/main/java/net/minecraft/world/entity/decoration/BlockAttachedEntity.java
|
||||
index e4eece7bbd14514ec60da26a8744672baa8956f9..7bc612890f941177da11da0ce047d5a74d8ebb33 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/decoration/BlockAttachedEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/decoration/BlockAttachedEntity.java
|
||||
@@ -26,7 +26,7 @@ import org.bukkit.event.hanging.HangingBreakEvent;
|
||||
public abstract class BlockAttachedEntity extends Entity {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
- private int checkInterval;
|
||||
+ private int checkInterval; { this.checkInterval = this.getId() % this.level().spigotConfig.hangingTickFrequency; } // Paper - Perf: offset item frame ticking
|
||||
protected BlockPos pos;
|
||||
|
||||
protected BlockAttachedEntity(EntityType<? extends BlockAttachedEntity> type, Level world) {
|
|
@ -0,0 +1,45 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kickash32 <kickash32@gmail.com>
|
||||
Date: Mon, 19 Aug 2019 19:42:35 +0500
|
||||
Subject: [PATCH] Prevent consuming the wrong itemstack
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 6bac6b338302ff0e0e93d5b66d2fd3ea0e666114..3a9c823193e939a6bbf6a43cd440d3fae129a252 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3827,9 +3827,14 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
}
|
||||
|
||||
public void startUsingItem(InteractionHand hand) {
|
||||
+ // Paper start - Prevent consuming the wrong itemstack
|
||||
+ this.startUsingItem(hand, false);
|
||||
+ }
|
||||
+ public void startUsingItem(InteractionHand hand, boolean forceUpdate) {
|
||||
+ // Paper end - Prevent consuming the wrong itemstack
|
||||
ItemStack itemstack = this.getItemInHand(hand);
|
||||
|
||||
- if (!itemstack.isEmpty() && !this.isUsingItem()) {
|
||||
+ if (!itemstack.isEmpty() && !this.isUsingItem() || forceUpdate) { // Paper - Prevent consuming the wrong itemstack
|
||||
this.useItem = itemstack;
|
||||
this.useItemRemaining = itemstack.getUseDuration(this);
|
||||
if (!this.level().isClientSide) {
|
||||
@@ -3914,6 +3919,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
this.releaseUsingItem();
|
||||
} else {
|
||||
if (!this.useItem.isEmpty() && this.isUsingItem()) {
|
||||
+ this.startUsingItem(this.getUsedItemHand(), true); // Paper - Prevent consuming the wrong itemstack
|
||||
this.triggerItemUseEffects(this.useItem, 16);
|
||||
// CraftBukkit start - fire PlayerItemConsumeEvent
|
||||
ItemStack itemstack;
|
||||
@@ -3948,8 +3954,8 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
}
|
||||
|
||||
this.stopUsingItem();
|
||||
- // Paper start - if the replacement is anything but the default, update the client inventory
|
||||
- if (this instanceof ServerPlayer && !com.google.common.base.Objects.equal(defaultReplacement, itemstack)) {
|
||||
+ // Paper start
|
||||
+ if (this instanceof ServerPlayer) {
|
||||
((ServerPlayer) this).getBukkitEntity().updateInventory();
|
||||
}
|
||||
// Paper end
|
18
patches/server/0300-Dont-send-unnecessary-sign-update.patch
Normal file
18
patches/server/0300-Dont-send-unnecessary-sign-update.patch
Normal file
|
@ -0,0 +1,18 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Nassim Jahnke <nassim@njahnke.dev>
|
||||
Date: Sat, 11 Sep 2021 11:56:51 +0200
|
||||
Subject: [PATCH] Dont send unnecessary sign update
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java
|
||||
index 394d0b03f18d55b43f091a9ae1a47e06a6fa4c0d..87e272cfb145c37d26b0bf56f97ec784a9bfd98e 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java
|
||||
@@ -185,6 +185,7 @@ public class SignBlockEntity extends BlockEntity implements CommandSource { // C
|
||||
this.level.sendBlockUpdated(this.getBlockPos(), this.getBlockState(), this.getBlockState(), 3);
|
||||
} else {
|
||||
SignBlockEntity.LOGGER.warn("Player {} just tried to change non-editable sign", player.getName().getString());
|
||||
+ if (player.distanceToSqr(this.getBlockPos().getX(), this.getBlockPos().getY(), this.getBlockPos().getZ()) < 32 * 32) // Paper - Dont send far away sign update
|
||||
((ServerPlayer) player).connection.send(this.getUpdatePacket()); // CraftBukkit
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <blake.galbreath@gmail.com>
|
||||
Date: Wed, 9 Oct 2019 21:46:15 -0500
|
||||
Subject: [PATCH] Add option to disable pillager patrols
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
|
||||
index 7522c40ab352d3b3ce1540f043b4b5f0d411060b..7b5db53d4cf97e41175896de47303526198fb8f6 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
|
||||
@@ -24,6 +24,7 @@ public class PatrolSpawner implements CustomSpawner {
|
||||
|
||||
@Override
|
||||
public int tick(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals) {
|
||||
+ if (world.paperConfig().entities.behavior.pillagerPatrols.disable) return 0; // Paper - Add option to disable pillager patrols
|
||||
if (!spawnMonsters) {
|
||||
return 0;
|
||||
} else if (!world.getGameRules().getBoolean(GameRules.RULE_DO_PATROL_SPAWNING)) {
|
|
@ -0,0 +1,20 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Callahan <mr.callahhh@gmail.com>
|
||||
Date: Mon, 13 Jan 2020 23:47:28 -0600
|
||||
Subject: [PATCH] Prevent sync chunk loads when villagers try to find beds
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/SleepInBed.java b/src/main/java/net/minecraft/world/entity/ai/behavior/SleepInBed.java
|
||||
index 6fe337e8d6db168ea181ed2597674f4829b03c47..e552ae6a7db765301a3d280dbf9348d9dc28b9c2 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/SleepInBed.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/SleepInBed.java
|
||||
@@ -42,7 +42,8 @@ public class SleepInBed extends Behavior<LivingEntity> {
|
||||
}
|
||||
}
|
||||
|
||||
- BlockState blockState = world.getBlockState(globalPos.pos());
|
||||
+ BlockState blockState = world.getBlockStateIfLoaded(globalPos.pos()); // Paper - Prevent sync chunk loads when villagers try to find beds
|
||||
+ if (blockState == null) { return false; } // Paper - Prevent sync chunk loads when villagers try to find beds
|
||||
return globalPos.pos().closerToCenterThan(entity.position(), 2.0) && blockState.is(BlockTags.BEDS) && !blockState.getValue(BedBlock.OCCUPIED);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Wed, 18 Dec 2019 22:21:35 -0600
|
||||
Subject: [PATCH] MC-145656 Fix Follow Range Initial Target
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java
|
||||
index 0dad5be671f990d0edf0a155e2534b3812438902..175ba1184fc997f562f0834b172e17dc1b5b3027 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java
|
||||
@@ -38,6 +38,7 @@ public class NearestAttackableTargetGoal<T extends LivingEntity> extends TargetG
|
||||
this.randomInterval = reducedTickDelay(reciprocalChance);
|
||||
this.setFlags(EnumSet.of(Goal.Flag.TARGET));
|
||||
this.targetConditions = TargetingConditions.forCombat().range(this.getFollowDistance()).selector(targetPredicate);
|
||||
+ if (mob.level().paperConfig().entities.entitiesTargetWithFollowRange) this.targetConditions.useFollowRange(); // Paper - Fix MC-145656
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
|
||||
index bc4b9a46056e83762e29bb04485ad7c754a20336..aecb0ad814586bfc5e56755ee14379a69388b38c 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
|
||||
@@ -77,7 +77,7 @@ public class TargetingConditions {
|
||||
|
||||
if (this.range > 0.0) {
|
||||
double d = this.testInvisible ? targetEntity.getVisibilityPercent(baseEntity) : 1.0;
|
||||
- double e = Math.max(this.range * d, 2.0);
|
||||
+ double e = Math.max((this.useFollowRange ? this.getFollowRange(baseEntity) : this.range) * d, 2.0); // Paper - Fix MC-145656
|
||||
double f = baseEntity.distanceToSqr(targetEntity.getX(), targetEntity.getY(), targetEntity.getZ());
|
||||
if (f > e * e) {
|
||||
return false;
|
||||
@@ -92,4 +92,18 @@ public class TargetingConditions {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // Paper start - Fix MC-145656
|
||||
+ private boolean useFollowRange = false;
|
||||
+
|
||||
+ public TargetingConditions useFollowRange() {
|
||||
+ this.useFollowRange = true;
|
||||
+ return this;
|
||||
+ }
|
||||
+
|
||||
+ private double getFollowRange(LivingEntity entityliving) {
|
||||
+ net.minecraft.world.entity.ai.attributes.AttributeInstance attributeinstance = entityliving.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.FOLLOW_RANGE);
|
||||
+ return attributeinstance == null ? 16.0D : attributeinstance.getValue();
|
||||
+ }
|
||||
+ // Paper end - Fix MC-145656
|
||||
}
|
90
patches/server/0304-Duplicate-UUID-Resolve-Option.patch
Normal file
90
patches/server/0304-Duplicate-UUID-Resolve-Option.patch
Normal file
|
@ -0,0 +1,90 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 21 Jul 2018 14:27:34 -0400
|
||||
Subject: [PATCH] Duplicate UUID Resolve Option
|
||||
|
||||
Due to a bug in https://github.com/PaperMC/Paper/commit/2e29af3df05ec0a383f48be549d1c03200756d24
|
||||
which was added all the way back in March of 2016, it was unknown (potentially not at the time)
|
||||
that an entity might actually change the seed of the random object.
|
||||
|
||||
At some point, EntitySquid did start setting the seed. Due to this shared random, this caused
|
||||
every entity to use a Random object with a predictable seed.
|
||||
|
||||
This has caused entities to potentially generate with the same UUID....
|
||||
|
||||
Over the years, servers have had entities disappear, but no sign of trouble
|
||||
because CraftBukkit removed the log lines indicating that something was wrong.
|
||||
|
||||
We have fixed the root issue causing duplicate UUID's, however we now have chunk
|
||||
files full of entities that have the same UUID as another entity!
|
||||
|
||||
When these chunks load, the 2nd entity will not be added to the world correctly.
|
||||
|
||||
If that chunk loads in a different order in the future, then it will reverse and the
|
||||
missing one is now the one added to the world and not the other. This results in very
|
||||
inconsistent entity behavior.
|
||||
|
||||
This change allows you to recover any duplicate entity by generating a new UUID for it.
|
||||
This also lets you delete them instead if you don't want to risk having new entities added to
|
||||
the world that you previously did not see.
|
||||
|
||||
But for those who are ok with leaving this inconsistent behavior, you may use WARN or NOTHING options.
|
||||
|
||||
It is recommended you regenerate the entities, as these were legit entities, and deserve your love.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java b/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java
|
||||
index e2b72817857a7a203aae4c9de4e01ba1396dc95b..8fa2dec0e4827421d41a9d14e19cf3ac3579bf1c 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java
|
||||
@@ -189,10 +189,51 @@ public class ChunkStatusTasks {
|
||||
entity.discard(null); // CraftBukkit - add Bukkit remove cause
|
||||
needsRemoval = true;
|
||||
}
|
||||
+ checkDupeUUID(world, entity); // Paper - duplicate uuid resolving
|
||||
return !needsRemoval;
|
||||
}));
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
}
|
||||
+
|
||||
+ // Paper start - duplicate uuid resolving
|
||||
+ // rets true if to prevent the entity from being added
|
||||
+ public static boolean checkDupeUUID(ServerLevel level, net.minecraft.world.entity.Entity entity) {
|
||||
+ io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode mode = level.paperConfig().entities.spawning.duplicateUuid.mode;
|
||||
+ if (mode != io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.WARN
|
||||
+ && mode != io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.DELETE
|
||||
+ && mode != io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.SAFE_REGEN) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ net.minecraft.world.entity.Entity other = level.getEntity(entity.getUUID());
|
||||
+
|
||||
+ if (other == null || other == entity) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ if (mode == io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.SAFE_REGEN && other != null && !other.isRemoved()
|
||||
+ && Objects.equals(other.getEncodeId(), entity.getEncodeId())
|
||||
+ && entity.getBukkitEntity().getLocation().distance(other.getBukkitEntity().getLocation()) < level.paperConfig().entities.spawning.duplicateUuid.safeRegenDeleteRange
|
||||
+ ) {
|
||||
+ entity.discard(null);
|
||||
+ return true;
|
||||
+ }
|
||||
+ if (!other.isRemoved()) {
|
||||
+ switch (mode) {
|
||||
+ case SAFE_REGEN: {
|
||||
+ entity.setUUID(java.util.UUID.randomUUID());
|
||||
+ break;
|
||||
+ }
|
||||
+ case DELETE: {
|
||||
+ entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD);
|
||||
+ return true;
|
||||
+ }
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end - duplicate uuid resolving
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Tue, 24 Dec 2019 00:35:42 +0000
|
||||
Subject: [PATCH] PlayerDeathEvent#shouldDropExperience
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 187cbb9e3c39204f1fb53e85788c954059dc7efc..f77edea8a82ef0b77ebe22ec1ee0fc22f94f67a5 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -1020,7 +1020,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
this.tellNeutralMobsThatIDied();
|
||||
}
|
||||
// SPIGOT-5478 must be called manually now
|
||||
- this.dropExperience(damageSource.getEntity());
|
||||
+ if (event.shouldDropExperience()) this.dropExperience(damageSource.getEntity()); // Paper - tie to event
|
||||
// we clean the player's inventory after the EntityDeathEvent is called so plugins can get the exact state of the inventory.
|
||||
if (!event.getKeepInventory()) {
|
||||
// Paper start - PlayerDeathEvent#getItemsToKeep
|
|
@ -0,0 +1,18 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sun, 5 Jan 2020 17:24:34 -0600
|
||||
Subject: [PATCH] Prevent bees loading chunks checking hive position
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
index 048d03c8ef3ef865641b2276477cf84e8d4397a1..58536ee8707c5ad0625cae2f26a58cf03b3f85d7 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
@@ -510,6 +510,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
} else if (this.isTooFarAway(this.hivePos)) {
|
||||
return false;
|
||||
} else {
|
||||
+ if (this.level().getChunkIfLoadedImmediately(this.hivePos.getX() >> 4, this.hivePos.getZ() >> 4) == null) return true; // Paper - just assume the hive is still there, no need to load the chunk(s)
|
||||
BlockEntity tileentity = this.level().getBlockEntity(this.hivePos);
|
||||
|
||||
return tileentity != null && tileentity.getType() == BlockEntityType.BEEHIVE;
|
|
@ -0,0 +1,32 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 3 Nov 2016 20:28:12 -0400
|
||||
Subject: [PATCH] Don't load Chunks from Hoppers and other things
|
||||
|
||||
Hoppers call this to I guess "get the primary side" of a double sided chest.
|
||||
|
||||
If the double sided chest crosses chunk lines, it causes the chunk to load.
|
||||
This will end up causing sync chunk loads, which will unload with Chunk GC,
|
||||
only to be reloaded again the next tick.
|
||||
|
||||
This of course is undesirable, so just return the loaded side as "primary"
|
||||
and treat it as a single chest if the other sides are unloaded
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/DoubleBlockCombiner.java b/src/main/java/net/minecraft/world/level/block/DoubleBlockCombiner.java
|
||||
index 963092cd5a4e756ad6a471379a81d8996cc2b091..20c9921339ec6b5127fbadcedc19577f3906074d 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/DoubleBlockCombiner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/DoubleBlockCombiner.java
|
||||
@@ -34,7 +34,12 @@ public class DoubleBlockCombiner {
|
||||
return new DoubleBlockCombiner.NeighborCombineResult.Single<>(blockEntity);
|
||||
} else {
|
||||
BlockPos blockPos = pos.relative(directionMapper.apply(state));
|
||||
- BlockState blockState = world.getBlockState(blockPos);
|
||||
+ // Paper start - Don't load Chunks from Hoppers and other things
|
||||
+ BlockState blockState = world.getBlockStateIfLoaded(blockPos);
|
||||
+ if (blockState == null) {
|
||||
+ return new DoubleBlockCombiner.NeighborCombineResult.Single<>(blockEntity);
|
||||
+ }
|
||||
+ // Paper end - Don't load Chunks from Hoppers and other things
|
||||
if (blockState.is(state.getBlock())) {
|
||||
DoubleBlockCombiner.BlockType blockType2 = typeMapper.apply(blockState);
|
||||
if (blockType2 != DoubleBlockCombiner.BlockType.SINGLE
|
|
@ -0,0 +1,27 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 11 Jan 2020 21:50:56 -0800
|
||||
Subject: [PATCH] Optimise EntityGetter#getPlayerByUUID
|
||||
|
||||
Use the PlayerList map instead of iterating over all players
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index bbcee9d8dbf17085b11bb5e38eb37271c51219ba..ccb72d13cce7db74a6754498bab41a017a469418 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -330,6 +330,15 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
}
|
||||
// Paper end
|
||||
|
||||
+ // Paper start - optimise getPlayerByUUID
|
||||
+ @Nullable
|
||||
+ @Override
|
||||
+ public Player getPlayerByUUID(UUID uuid) {
|
||||
+ final Player player = this.getServer().getPlayerList().getPlayer(uuid);
|
||||
+ return player != null && player.level() == this ? player : null;
|
||||
+ }
|
||||
+ // Paper end - optimise getPlayerByUUID
|
||||
+
|
||||
// Add env and gen to constructor, IWorldDataServer -> WorldDataServer
|
||||
public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey<Level> resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List<CustomSpawner> list, boolean flag1, @Nullable RandomSequences randomsequences, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) {
|
||||
// IRegistryCustom.Dimension iregistrycustom_dimension = minecraftserver.registryAccess(); // CraftBukkit - decompile error
|
42
patches/server/0309-Fix-items-not-falling-correctly.patch
Normal file
42
patches/server/0309-Fix-items-not-falling-correctly.patch
Normal file
|
@ -0,0 +1,42 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: AJMFactsheets <AJMFactsheets@gmail.com>
|
||||
Date: Fri, 17 Jan 2020 17:17:54 -0600
|
||||
Subject: [PATCH] Fix items not falling correctly
|
||||
|
||||
Since 1.14, Mojang has added an optimization which skips checking if
|
||||
an item should fall every fourth tick.
|
||||
|
||||
However, Spigot's entity activation range class also has an
|
||||
optimization which skips ticking active entities every fourth tick.
|
||||
This can result in a state where an item will never properly fall
|
||||
due to its move method never being called.
|
||||
|
||||
This patch resolves the conflict by offsetting checking Spigot's entity
|
||||
activation range check from an item's move method.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
index 6dfa43036afeba75a7ecc5a82637f081624d5c69..8351e46f667a8f8dd96d97ec15c0165261a2fab4 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
@@ -176,7 +176,7 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
}
|
||||
}
|
||||
|
||||
- if (!this.onGround() || this.getDeltaMovement().horizontalDistanceSqr() > 9.999999747378752E-6D || (this.tickCount + this.getId()) % 4 == 0) {
|
||||
+ if (!this.onGround() || this.getDeltaMovement().horizontalDistanceSqr() > 9.999999747378752E-6D || (this.tickCount + this.getId()) % 4 == 0) { // Paper - Diff on change
|
||||
this.move(MoverType.SELF, this.getDeltaMovement());
|
||||
float f = 0.98F;
|
||||
|
||||
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
|
||||
index 6d51464f6368151e8acc532414ee223714584e96..9fb9fa62c32445ac3c3883a6433759c86dcfc428 100644
|
||||
--- a/src/main/java/org/spigotmc/ActivationRange.java
|
||||
+++ b/src/main/java/org/spigotmc/ActivationRange.java
|
||||
@@ -256,7 +256,7 @@ public class ActivationRange
|
||||
isActive = true;
|
||||
}
|
||||
// Add a little performance juice to active entities. Skip 1/4 if not immune.
|
||||
- } else if ( !entity.defaultActivationState && entity.tickCount % 4 == 0 && !ActivationRange.checkEntityImmunities( entity ) )
|
||||
+ } else if ( !entity.defaultActivationState && (entity.tickCount + entity.getId()) % 4 == 0 && !ActivationRange.checkEntityImmunities( entity ) ) // Paper - Ensure checking item movement is offset from Spigot's entity activation range check
|
||||
{
|
||||
isActive = false;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BrodyBeckwith <brody@beckwith.dev>
|
||||
Date: Tue, 14 Jan 2020 17:49:03 -0500
|
||||
Subject: [PATCH] Optimize call to getFluid for explosions
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
index 512d79b66fed3d1bef645c3ecb59bda032c81d15..1350c8df69b4ffcf9daa73549e496627db8bc6f7 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
@@ -193,7 +193,7 @@ public class Explosion {
|
||||
for (float f1 = 0.3F; f > 0.0F; f -= 0.22500001F) {
|
||||
BlockPos blockposition = BlockPos.containing(d4, d5, d6);
|
||||
BlockState iblockdata = this.level.getBlockState(blockposition);
|
||||
- FluidState fluid = this.level.getFluidState(blockposition);
|
||||
+ FluidState fluid = iblockdata.getFluidState(); // Paper - Perf: Optimize call to getFluid for explosions
|
||||
|
||||
if (!this.level.isInWorldBounds(blockposition)) {
|
||||
break;
|
|
@ -0,0 +1,52 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Fri, 27 Dec 2019 09:42:26 -0800
|
||||
Subject: [PATCH] Guard against serializing mismatching chunk coordinate
|
||||
|
||||
Should help if something dumb happens
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
index 47f5f3d58bb3bf85cf35f9baae77df7fab5c844f..0dd6f1bce4913cb84ba21a20df5573bab3a64645 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
@@ -88,8 +88,21 @@ public class ChunkSerializer {
|
||||
|
||||
public ChunkSerializer() {}
|
||||
|
||||
+ // Paper start - guard against serializing mismatching coordinates
|
||||
+ // TODO Note: This needs to be re-checked each update
|
||||
+ public static ChunkPos getChunkCoordinate(final CompoundTag chunkData) {
|
||||
+ final int dataVersion = ChunkStorage.getVersion(chunkData);
|
||||
+ if (dataVersion < 2842) { // Level tag is removed after this version
|
||||
+ final CompoundTag levelData = chunkData.getCompound("Level");
|
||||
+ return new ChunkPos(levelData.getInt("xPos"), levelData.getInt("zPos"));
|
||||
+ } else {
|
||||
+ return new ChunkPos(chunkData.getInt("xPos"), chunkData.getInt("zPos"));
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - guard against serializing mismatching coordinates
|
||||
+
|
||||
public static ProtoChunk read(ServerLevel world, PoiManager poiStorage, RegionStorageInfo key, ChunkPos chunkPos, CompoundTag nbt) {
|
||||
- ChunkPos chunkcoordintpair1 = new ChunkPos(nbt.getInt("xPos"), nbt.getInt("zPos"));
|
||||
+ ChunkPos chunkcoordintpair1 = new ChunkPos(nbt.getInt("xPos"), nbt.getInt("zPos")); // Paper - guard against serializing mismatching coordinates; diff on change, see ChunkSerializer#getChunkCoordinate
|
||||
|
||||
if (!Objects.equals(chunkPos, chunkcoordintpair1)) {
|
||||
ChunkSerializer.LOGGER.error("Chunk file at {} is in the wrong location; relocating. (Expected {}, got {})", new Object[]{chunkPos, chunkPos, chunkcoordintpair1});
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
|
||||
index 3e194944e50f8395074d68d4abe4c084c3fadcc1..9aa9ab894080a5819fc45698771afd034906d36a 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
|
||||
@@ -172,6 +172,13 @@ public class ChunkStorage implements AutoCloseable {
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> write(ChunkPos chunkPos, CompoundTag nbt) {
|
||||
+ // Paper start - guard against serializing mismatching coordinates
|
||||
+ if (nbt != null && !chunkPos.equals(ChunkSerializer.getChunkCoordinate(nbt))) {
|
||||
+ final String world = (this instanceof net.minecraft.server.level.ChunkMap) ? ((net.minecraft.server.level.ChunkMap) this).level.getWorld().getName() : null;
|
||||
+ throw new IllegalArgumentException("Chunk coordinate and serialized data do not have matching coordinates, trying to serialize coordinate " + chunkPos
|
||||
+ + " but compound says coordinate is " + ChunkSerializer.getChunkCoordinate(nbt) + (world == null ? " for an unknown world" : (" for world: " + world)));
|
||||
+ }
|
||||
+ // Paper end - guard against serializing mismatching coordinates
|
||||
this.handleLegacyStructureIndex(chunkPos);
|
||||
return this.worker.store(chunkPos, nbt);
|
||||
}
|
63
patches/server/0312-Alternative-item-despawn-rate.patch
Normal file
63
patches/server/0312-Alternative-item-despawn-rate.patch
Normal file
|
@ -0,0 +1,63 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kickash32 <kickash32@gmail.com>
|
||||
Date: Mon, 3 Jun 2019 02:02:39 -0400
|
||||
Subject: [PATCH] Alternative item-despawn-rate
|
||||
|
||||
Co-authored-by: Noah van der Aa <ndvdaa@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
index 8351e46f667a8f8dd96d97ec15c0165261a2fab4..2e550c7db6cebc941590c35337fd47416407a5aa 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
@@ -62,6 +62,7 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
public final float bobOffs;
|
||||
private int lastTick = MinecraftServer.currentTick - 1; // CraftBukkit
|
||||
public boolean canMobPickup = true; // Paper - Item#canEntityPickup
|
||||
+ private int despawnRate = -1; // Paper - Alternative item-despawn-rate
|
||||
|
||||
public ItemEntity(EntityType<? extends ItemEntity> type, Level world) {
|
||||
super(type, world);
|
||||
@@ -216,7 +217,7 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
}
|
||||
}
|
||||
|
||||
- if (!this.level().isClientSide && this.age >= this.level().spigotConfig.itemDespawnRate) { // Spigot
|
||||
+ if (!this.level().isClientSide && this.age >= this.despawnRate) { // Spigot // Paper - Alternative item-despawn-rate
|
||||
// CraftBukkit start - fire ItemDespawnEvent
|
||||
if (CraftEventFactory.callItemDespawnEvent(this).isCancelled()) {
|
||||
this.age = 0;
|
||||
@@ -240,7 +241,7 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
this.lastTick = MinecraftServer.currentTick;
|
||||
// CraftBukkit end
|
||||
|
||||
- if (!this.level().isClientSide && this.age >= this.level().spigotConfig.itemDespawnRate) { // Spigot
|
||||
+ if (!this.level().isClientSide && this.age >= this.despawnRate) { // Spigot // Paper - Alternative item-despawn-rate
|
||||
// CraftBukkit start - fire ItemDespawnEvent
|
||||
if (org.bukkit.craftbukkit.event.CraftEventFactory.callItemDespawnEvent(this).isCancelled()) {
|
||||
this.age = 0;
|
||||
@@ -296,7 +297,7 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
private boolean isMergable() {
|
||||
ItemStack itemstack = this.getItem();
|
||||
|
||||
- return this.isAlive() && this.pickupDelay != 32767 && this.age != -32768 && this.age < 6000 && itemstack.getCount() < itemstack.getMaxStackSize();
|
||||
+ return this.isAlive() && this.pickupDelay != 32767 && this.age != -32768 && this.age < this.despawnRate && itemstack.getCount() < itemstack.getMaxStackSize(); // Paper - Alternative item-despawn-rate
|
||||
}
|
||||
|
||||
private void tryToMerge(ItemEntity other) {
|
||||
@@ -544,6 +545,7 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
|
||||
public void setItem(ItemStack stack) {
|
||||
this.getEntityData().set(ItemEntity.DATA_ITEM, stack);
|
||||
+ this.despawnRate = this.level().paperConfig().entities.spawning.altItemDespawnRate.enabled ? this.level().paperConfig().entities.spawning.altItemDespawnRate.items.getOrDefault(stack.getItem(), this.level().spigotConfig.itemDespawnRate) : this.level().spigotConfig.itemDespawnRate; // Paper - Alternative item-despawn-rate
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -598,7 +600,7 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
|
||||
public void makeFakeItem() {
|
||||
this.setNeverPickUp();
|
||||
- this.age = this.level().spigotConfig.itemDespawnRate - 1; // Spigot
|
||||
+ this.age = this.despawnRate - 1; // Spigot // Paper - Alternative item-despawn-rate
|
||||
}
|
||||
|
||||
public float getSpin(float tickDelta) {
|
78
patches/server/0313-Tracking-Range-Improvements.patch
Normal file
78
patches/server/0313-Tracking-Range-Improvements.patch
Normal file
|
@ -0,0 +1,78 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kickash32 <kickash32@gmail.com>
|
||||
Date: Sat, 21 Dec 2019 15:22:09 -0500
|
||||
Subject: [PATCH] Tracking Range Improvements
|
||||
|
||||
Sets tracking range of watermobs to animals instead of misc and simplifies code
|
||||
|
||||
Also ignores Enderdragon, defaulting it to Mojang's setting
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index e2f176d34443f0d1b00649efa45c65138042a015..3784fbe3548727ab5ad8cfefef2d8d594a76123f 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1613,6 +1613,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
while (iterator.hasNext()) {
|
||||
Entity entity = (Entity) iterator.next();
|
||||
int j = entity.getType().clientTrackingRange() * 16;
|
||||
+ j = org.spigotmc.TrackingRange.getEntityTrackingRange(entity, j); // Paper
|
||||
|
||||
if (j > i) {
|
||||
i = j;
|
||||
diff --git a/src/main/java/org/spigotmc/TrackingRange.java b/src/main/java/org/spigotmc/TrackingRange.java
|
||||
index 73f9563551632a5369ba55e8fe9211afc325e869..bb06f89a29f30144e7e2113e088a503db006a83c 100644
|
||||
--- a/src/main/java/org/spigotmc/TrackingRange.java
|
||||
+++ b/src/main/java/org/spigotmc/TrackingRange.java
|
||||
@@ -7,7 +7,6 @@ import net.minecraft.world.entity.ExperienceOrb;
|
||||
import net.minecraft.world.entity.decoration.ItemFrame;
|
||||
import net.minecraft.world.entity.decoration.Painting;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
-import net.minecraft.world.entity.monster.Ghast;
|
||||
|
||||
public class TrackingRange
|
||||
{
|
||||
@@ -30,22 +29,21 @@ public class TrackingRange
|
||||
if ( entity instanceof ServerPlayer )
|
||||
{
|
||||
return config.playerTrackingRange;
|
||||
- } else if ( entity.activationType == ActivationRange.ActivationType.MONSTER || entity.activationType == ActivationRange.ActivationType.RAIDER )
|
||||
- {
|
||||
- return config.monsterTrackingRange;
|
||||
- } else if ( entity instanceof Ghast )
|
||||
- {
|
||||
- if ( config.monsterTrackingRange > config.monsterActivationRange )
|
||||
- {
|
||||
+ // Paper start - Simplify and set water mobs to animal tracking range
|
||||
+ }
|
||||
+ switch (entity.activationType) {
|
||||
+ case RAIDER:
|
||||
+ case MONSTER:
|
||||
+ case FLYING_MONSTER:
|
||||
return config.monsterTrackingRange;
|
||||
- } else
|
||||
- {
|
||||
- return config.monsterActivationRange;
|
||||
- }
|
||||
- } else if ( entity.activationType == ActivationRange.ActivationType.ANIMAL )
|
||||
- {
|
||||
- return config.animalTrackingRange;
|
||||
- } else if ( entity instanceof ItemFrame || entity instanceof Painting || entity instanceof ItemEntity || entity instanceof ExperienceOrb )
|
||||
+ case WATER:
|
||||
+ case VILLAGER:
|
||||
+ case ANIMAL:
|
||||
+ return config.animalTrackingRange;
|
||||
+ case MISC:
|
||||
+ }
|
||||
+ if ( entity instanceof ItemFrame || entity instanceof Painting || entity instanceof ItemEntity || entity instanceof ExperienceOrb )
|
||||
+ // Paper end
|
||||
{
|
||||
return config.miscTrackingRange;
|
||||
} else if ( entity instanceof Display )
|
||||
@@ -53,6 +51,7 @@ public class TrackingRange
|
||||
return config.displayTrackingRange;
|
||||
} else
|
||||
{
|
||||
+ if (entity instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon) return ((net.minecraft.server.level.ServerLevel)(entity.getCommandSenderWorld())).getChunkSource().chunkMap.serverViewDistance; // Paper - enderdragon is exempt
|
||||
return config.otherTrackingRange;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sun, 26 Jan 2020 16:30:19 -0600
|
||||
Subject: [PATCH] Bees get gravity in void. Fixes MC-167279
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
index 58536ee8707c5ad0625cae2f26a58cf03b3f85d7..4134ee48909110f8c338f5d553d4cc1e9e31aaba 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
@@ -144,7 +144,22 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
public Bee(EntityType<? extends Bee> type, Level world) {
|
||||
super(type, world);
|
||||
this.remainingCooldownBeforeLocatingNewFlower = Mth.nextInt(this.random, 20, 60);
|
||||
- this.moveControl = new FlyingMoveControl(this, 20, true);
|
||||
+ // Paper start - Fix MC-167279
|
||||
+ class BeeFlyingMoveControl extends FlyingMoveControl {
|
||||
+ public BeeFlyingMoveControl(final Mob entity, final int maxPitchChange, final boolean noGravity) {
|
||||
+ super(entity, maxPitchChange, noGravity);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void tick() {
|
||||
+ if (this.mob.getY() <= Bee.this.level().getMinBuildHeight()) {
|
||||
+ this.mob.setNoGravity(false);
|
||||
+ }
|
||||
+ super.tick();
|
||||
+ }
|
||||
+ }
|
||||
+ this.moveControl = new BeeFlyingMoveControl(this, 20, true);
|
||||
+ // Paper end - Fix MC-167279
|
||||
this.lookControl = new Bee.BeeLookControl(this);
|
||||
this.setPathfindingMalus(PathType.DANGER_FIRE, -1.0F);
|
||||
this.setPathfindingMalus(PathType.WATER, -1.0F);
|
95
patches/server/0315-Improve-Block-breakNaturally-API.patch
Normal file
95
patches/server/0315-Improve-Block-breakNaturally-API.patch
Normal file
|
@ -0,0 +1,95 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Thu, 2 Jan 2020 12:25:07 -0600
|
||||
Subject: [PATCH] Improve Block#breakNaturally API
|
||||
|
||||
Adds bool parameter to play world effect on block break
|
||||
|
||||
Adds bool parameter to drop xp from blocks
|
||||
|
||||
Fixes fluid-logged blocks not leaving fluid behind if
|
||||
broken
|
||||
|
||||
Handles special cases for ice and turtle eggs
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.level.block.TurtleEggBlock decreaseEggs(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)V
|
||||
|
||||
Co-authored-by: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/IceBlock.java b/src/main/java/net/minecraft/world/level/block/IceBlock.java
|
||||
index 363dd6ab9c7b650913795ef350374d5c4e7e4925..e862814c1e54776f11050623b52476accc2f1f79 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/IceBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/IceBlock.java
|
||||
@@ -35,6 +35,11 @@ public class IceBlock extends HalfTransparentBlock {
|
||||
@Override
|
||||
public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) {
|
||||
super.playerDestroy(world, player, pos, state, blockEntity, tool);
|
||||
+ // Paper start - Improve Block#breakNaturally API
|
||||
+ this.afterDestroy(world, pos, tool);
|
||||
+ }
|
||||
+ public void afterDestroy(Level world, BlockPos pos, ItemStack tool) {
|
||||
+ // Paper end - Improve Block#breakNaturally API
|
||||
if (!EnchantmentHelper.hasTag(tool, EnchantmentTags.PREVENTS_ICE_MELTING)) {
|
||||
if (world.dimensionType().ultraWarm()) {
|
||||
world.removeBlock(pos, false);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
index d4e14ac1514e2d8b87b4667a91c90eded3ba6636..f041b5d80bff9c022b007e04ef1558e9116acc6b 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
@@ -452,6 +452,18 @@ public class CraftBlock implements Block {
|
||||
|
||||
@Override
|
||||
public boolean breakNaturally(ItemStack item) {
|
||||
+ // Paper start
|
||||
+ return this.breakNaturally(item, false);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean breakNaturally(boolean triggerEffect, boolean dropExperience) {
|
||||
+ return this.breakNaturally(null, triggerEffect, dropExperience);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean breakNaturally(ItemStack item, boolean triggerEffect, boolean dropExperience) {
|
||||
+ // Paper end
|
||||
// Order matters here, need to drop before setting to air so skulls can get their data
|
||||
net.minecraft.world.level.block.state.BlockState iblockdata = this.getNMS();
|
||||
net.minecraft.world.level.block.Block block = iblockdata.getBlock();
|
||||
@@ -461,11 +473,35 @@ public class CraftBlock implements Block {
|
||||
// Modelled off EntityHuman#hasBlock
|
||||
if (block != Blocks.AIR && (item == null || !iblockdata.requiresCorrectToolForDrops() || nmsItem.isCorrectToolForDrops(iblockdata))) {
|
||||
net.minecraft.world.level.block.Block.dropResources(iblockdata, this.world.getMinecraftWorld(), this.position, this.world.getBlockEntity(this.position), null, nmsItem);
|
||||
+ // Paper start - improve Block#breanNaturally
|
||||
+ if (triggerEffect) {
|
||||
+ if (iblockdata.getBlock() instanceof net.minecraft.world.level.block.BaseFireBlock) {
|
||||
+ this.world.levelEvent(net.minecraft.world.level.block.LevelEvent.SOUND_EXTINGUISH_FIRE, this.position, 0);
|
||||
+ } else {
|
||||
+ this.world.levelEvent(net.minecraft.world.level.block.LevelEvent.PARTICLES_DESTROY_BLOCK, this.position, net.minecraft.world.level.block.Block.getId(iblockdata));
|
||||
+ }
|
||||
+ }
|
||||
+ if (dropExperience) block.popExperience(this.world.getMinecraftWorld(), this.position, block.getExpDrop(iblockdata, this.world.getMinecraftWorld(), this.position, nmsItem, true));
|
||||
+ // Paper end
|
||||
result = true;
|
||||
}
|
||||
|
||||
// SPIGOT-6778: Directly call setBlock instead of setTypeAndData, so that the tile entiy is not removed and custom remove logic is run.
|
||||
- return this.world.setBlock(this.position, Blocks.AIR.defaultBlockState(), 3) && result;
|
||||
+ // Paper start - improve breakNaturally
|
||||
+ boolean destroyed = this.world.removeBlock(this.position, false);
|
||||
+ if (destroyed) {
|
||||
+ block.destroy(this.world, this.position, iblockdata);
|
||||
+ }
|
||||
+ if (result) {
|
||||
+ // special cases
|
||||
+ if (block instanceof net.minecraft.world.level.block.IceBlock iceBlock) {
|
||||
+ iceBlock.afterDestroy(this.world.getMinecraftWorld(), this.position, nmsItem);
|
||||
+ } else if (block instanceof net.minecraft.world.level.block.TurtleEggBlock turtleEggBlock) {
|
||||
+ turtleEggBlock.decreaseEggs(this.world.getMinecraftWorld(), this.position, iblockdata);
|
||||
+ }
|
||||
+ }
|
||||
+ return destroyed && result;
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
|
@ -0,0 +1,60 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 25 Jan 2020 17:04:35 -0800
|
||||
Subject: [PATCH] Optimise getChunkAt calls for loaded chunks
|
||||
|
||||
bypass the need to get a player chunk, then get the either,
|
||||
then unwrap it...
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 6032cdc1b169c8ed0890091bce5066fbbb73ae30..86453364a0433a0196099a8cd271fa2bc7924fbb 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -253,6 +253,12 @@ public class ServerChunkCache extends ChunkSource {
|
||||
return this.getChunk(x, z, leastStatus, create);
|
||||
}, this.mainThreadProcessor).join();
|
||||
} else {
|
||||
+ // Paper start - Perf: Optimise getChunkAt calls for loaded chunks
|
||||
+ LevelChunk ifLoaded = this.getChunkAtIfLoadedMainThread(x, z);
|
||||
+ if (ifLoaded != null) {
|
||||
+ return ifLoaded;
|
||||
+ }
|
||||
+ // Paper end - Perf: Optimise getChunkAt calls for loaded chunks
|
||||
ProfilerFiller gameprofilerfiller = this.level.getProfiler();
|
||||
|
||||
gameprofilerfiller.incrementCounter("getChunk");
|
||||
@@ -296,33 +302,7 @@ public class ServerChunkCache extends ChunkSource {
|
||||
if (Thread.currentThread() != this.mainThread) {
|
||||
return null;
|
||||
} else {
|
||||
- this.level.getProfiler().incrementCounter("getChunkNow");
|
||||
- long k = ChunkPos.asLong(chunkX, chunkZ);
|
||||
-
|
||||
- ChunkAccess ichunkaccess;
|
||||
-
|
||||
- for (int l = 0; l < 4; ++l) {
|
||||
- if (k == this.lastChunkPos[l] && this.lastChunkStatus[l] == ChunkStatus.FULL) {
|
||||
- ichunkaccess = this.lastChunk[l];
|
||||
- return ichunkaccess instanceof LevelChunk ? (LevelChunk) ichunkaccess : null;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- ChunkHolder playerchunk = this.getVisibleChunkIfPresent(k);
|
||||
-
|
||||
- if (playerchunk == null) {
|
||||
- return null;
|
||||
- } else {
|
||||
- ichunkaccess = playerchunk.getChunkIfPresent(ChunkStatus.FULL);
|
||||
- if (ichunkaccess != null) {
|
||||
- this.storeInCache(k, ichunkaccess, ChunkStatus.FULL);
|
||||
- if (ichunkaccess instanceof LevelChunk) {
|
||||
- return (LevelChunk) ichunkaccess;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return null;
|
||||
- }
|
||||
+ return this.getChunkAtIfLoadedMainThread(chunkX, chunkZ); // Paper - Perf: Optimise getChunkAt calls for loaded chunks
|
||||
}
|
||||
}
|
||||
|
331
patches/server/0317-Add-debug-for-sync-chunk-loads.patch
Normal file
331
patches/server/0317-Add-debug-for-sync-chunk-loads.patch
Normal file
|
@ -0,0 +1,331 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Fri, 19 Jul 2019 03:29:14 -0700
|
||||
Subject: [PATCH] Add debug for sync chunk loads
|
||||
|
||||
This patch adds a tool to find calls to getChunkAt which would load
|
||||
chunks, however it must be enabled by setting the startup flag
|
||||
-Dpaper.debug-sync-loads=true
|
||||
|
||||
- To get a debug log for sync loads, the command is
|
||||
/paper syncloadinfo
|
||||
- To clear clear the currently stored sync load info, use
|
||||
/paper syncloadinfo clear
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java b/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..404a8fd128043527d23f22ee26f7c8c739f09089
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java
|
||||
@@ -0,0 +1,175 @@
|
||||
+package com.destroystokyo.paper.io;
|
||||
+
|
||||
+import com.google.gson.JsonArray;
|
||||
+import com.google.gson.JsonObject;
|
||||
+import com.mojang.datafixers.util.Pair;
|
||||
+import it.unimi.dsi.fastutil.longs.Long2IntMap;
|
||||
+import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
+
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.List;
|
||||
+import java.util.Map;
|
||||
+import java.util.WeakHashMap;
|
||||
+import net.minecraft.world.level.Level;
|
||||
+
|
||||
+public class SyncLoadFinder {
|
||||
+
|
||||
+ public static final boolean ENABLED = Boolean.getBoolean("paper.debug-sync-loads");
|
||||
+
|
||||
+ private static final WeakHashMap<Level, Object2ObjectOpenHashMap<ThrowableWithEquals, SyncLoadInformation>> SYNC_LOADS = new WeakHashMap<>();
|
||||
+
|
||||
+ private static final class SyncLoadInformation {
|
||||
+
|
||||
+ public int times;
|
||||
+
|
||||
+ public final Long2IntOpenHashMap coordinateTimes = new Long2IntOpenHashMap();
|
||||
+ }
|
||||
+
|
||||
+ public static void clear() {
|
||||
+ SYNC_LOADS.clear();
|
||||
+ }
|
||||
+
|
||||
+ public static void logSyncLoad(final Level world, final int chunkX, final int chunkZ) {
|
||||
+ if (!ENABLED) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ final ThrowableWithEquals stacktrace = new ThrowableWithEquals(Thread.currentThread().getStackTrace());
|
||||
+
|
||||
+ SYNC_LOADS.compute(world, (final Level keyInMap, Object2ObjectOpenHashMap<ThrowableWithEquals, SyncLoadInformation> map) -> {
|
||||
+ if (map == null) {
|
||||
+ map = new Object2ObjectOpenHashMap<>();
|
||||
+ }
|
||||
+
|
||||
+ map.compute(stacktrace, (ThrowableWithEquals keyInMap0, SyncLoadInformation valueInMap) -> {
|
||||
+ if (valueInMap == null) {
|
||||
+ valueInMap = new SyncLoadInformation();
|
||||
+ }
|
||||
+
|
||||
+ ++valueInMap.times;
|
||||
+
|
||||
+ valueInMap.coordinateTimes.compute(io.papermc.paper.util.MCUtil.getCoordinateKey(chunkX, chunkZ), (Long keyInMap1, Integer valueInMap1) -> {
|
||||
+ return valueInMap1 == null ? Integer.valueOf(1) : Integer.valueOf(valueInMap1.intValue() + 1);
|
||||
+ });
|
||||
+
|
||||
+ return valueInMap;
|
||||
+ });
|
||||
+
|
||||
+ return map;
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ public static JsonObject serialize() {
|
||||
+ final JsonObject ret = new JsonObject();
|
||||
+
|
||||
+ final JsonArray worldsData = new JsonArray();
|
||||
+
|
||||
+ for (final Map.Entry<Level, Object2ObjectOpenHashMap<ThrowableWithEquals, SyncLoadInformation>> entry : SYNC_LOADS.entrySet()) {
|
||||
+ final Level world = entry.getKey();
|
||||
+
|
||||
+ final JsonObject worldData = new JsonObject();
|
||||
+
|
||||
+ worldData.addProperty("name", world.getWorld().getName());
|
||||
+
|
||||
+ final List<Pair<ThrowableWithEquals, SyncLoadInformation>> data = new ArrayList<>();
|
||||
+
|
||||
+ entry.getValue().forEach((ThrowableWithEquals stacktrace, SyncLoadInformation times) -> {
|
||||
+ data.add(new Pair<>(stacktrace, times));
|
||||
+ });
|
||||
+
|
||||
+ data.sort((Pair<ThrowableWithEquals, SyncLoadInformation> pair1, Pair<ThrowableWithEquals, SyncLoadInformation> pair2) -> {
|
||||
+ return Integer.compare(pair2.getSecond().times, pair1.getSecond().times); // reverse order
|
||||
+ });
|
||||
+
|
||||
+ final JsonArray stacktraces = new JsonArray();
|
||||
+
|
||||
+ for (Pair<ThrowableWithEquals, SyncLoadInformation> pair : data) {
|
||||
+ final JsonObject stacktrace = new JsonObject();
|
||||
+
|
||||
+ stacktrace.addProperty("times", pair.getSecond().times);
|
||||
+
|
||||
+ final JsonArray traces = new JsonArray();
|
||||
+
|
||||
+ for (StackTraceElement element : pair.getFirst().stacktrace) {
|
||||
+ traces.add(String.valueOf(element));
|
||||
+ }
|
||||
+
|
||||
+ stacktrace.add("stacktrace", traces);
|
||||
+
|
||||
+ final JsonArray coordinates = new JsonArray();
|
||||
+
|
||||
+ for (Long2IntMap.Entry coordinate : pair.getSecond().coordinateTimes.long2IntEntrySet()) {
|
||||
+ final long key = coordinate.getLongKey();
|
||||
+ final int times = coordinate.getIntValue();
|
||||
+ coordinates.add("(" + io.papermc.paper.util.MCUtil.getCoordinateX(key) + "," + io.papermc.paper.util.MCUtil.getCoordinateZ(key) + "): " + times);
|
||||
+ }
|
||||
+
|
||||
+ stacktrace.add("coordinates", coordinates);
|
||||
+
|
||||
+ stacktraces.add(stacktrace);
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ worldData.add("stacktraces", stacktraces);
|
||||
+ worldsData.add(worldData);
|
||||
+ }
|
||||
+
|
||||
+ ret.add("worlds", worldsData);
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ static final class ThrowableWithEquals {
|
||||
+
|
||||
+ private final StackTraceElement[] stacktrace;
|
||||
+ private final int hash;
|
||||
+
|
||||
+ public ThrowableWithEquals(final StackTraceElement[] stacktrace) {
|
||||
+ this.stacktrace = stacktrace;
|
||||
+ this.hash = ThrowableWithEquals.hash(stacktrace);
|
||||
+ }
|
||||
+
|
||||
+ public static int hash(final StackTraceElement[] stacktrace) {
|
||||
+ int hash = 0;
|
||||
+
|
||||
+ for (int i = 0; i < stacktrace.length; ++i) {
|
||||
+ hash *= 31;
|
||||
+ hash += stacktrace[i].hashCode();
|
||||
+ }
|
||||
+
|
||||
+ return hash;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int hashCode() {
|
||||
+ return this.hash;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean equals(final Object obj) {
|
||||
+ if (obj == null || obj.getClass() != this.getClass()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ final ThrowableWithEquals other = (ThrowableWithEquals)obj;
|
||||
+ final StackTraceElement[] otherStackTrace = other.stacktrace;
|
||||
+
|
||||
+ if (this.stacktrace.length != otherStackTrace.length || this.hash != other.hash) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ if (this == obj) {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ for (int i = 0; i < this.stacktrace.length; ++i) {
|
||||
+ if (!this.stacktrace[i].equals(otherStackTrace[i])) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/command/PaperCommand.java b/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
index e1820a339452cd3388dd7cbb928c5f58779a77b6..3010d57efcc97fb409bfe43b1fc9af198c099a67 100644
|
||||
--- a/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
+++ b/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
@@ -38,6 +38,7 @@ public final class PaperCommand extends Command {
|
||||
commands.put(Set.of("reload"), new ReloadCommand());
|
||||
commands.put(Set.of("version"), new VersionCommand());
|
||||
commands.put(Set.of("dumpplugins"), new DumpPluginsCommand());
|
||||
+ commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand());
|
||||
|
||||
return commands.entrySet().stream()
|
||||
.flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue())))
|
||||
diff --git a/src/main/java/io/papermc/paper/command/subcommands/SyncLoadInfoCommand.java b/src/main/java/io/papermc/paper/command/subcommands/SyncLoadInfoCommand.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..95d6022c9cfb2e36ec5a71be6e34354027c2ec08
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/command/subcommands/SyncLoadInfoCommand.java
|
||||
@@ -0,0 +1,88 @@
|
||||
+package io.papermc.paper.command.subcommands;
|
||||
+
|
||||
+import com.destroystokyo.paper.io.SyncLoadFinder;
|
||||
+import com.google.gson.JsonObject;
|
||||
+import com.google.gson.internal.Streams;
|
||||
+import com.google.gson.stream.JsonWriter;
|
||||
+import io.papermc.paper.command.CommandUtil;
|
||||
+import io.papermc.paper.command.PaperSubcommand;
|
||||
+import java.io.File;
|
||||
+import java.io.FileOutputStream;
|
||||
+import java.io.PrintStream;
|
||||
+import java.io.StringWriter;
|
||||
+import java.nio.charset.StandardCharsets;
|
||||
+import java.time.LocalDateTime;
|
||||
+import java.time.format.DateTimeFormatter;
|
||||
+import java.util.List;
|
||||
+
|
||||
+import net.kyori.adventure.text.event.ClickEvent;
|
||||
+import net.kyori.adventure.text.event.HoverEvent;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+import org.bukkit.command.CommandSender;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+import static net.kyori.adventure.text.Component.text;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.GRAY;
|
||||
+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 SyncLoadInfoCommand implements PaperSubcommand {
|
||||
+ @Override
|
||||
+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) {
|
||||
+ this.doSyncLoadInfo(sender, args);
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public List<String> tabComplete(final CommandSender sender, final String subCommand, final String[] args) {
|
||||
+ return CommandUtil.getListMatchingLast(sender, args, "clear");
|
||||
+ }
|
||||
+
|
||||
+ private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss");
|
||||
+
|
||||
+ private void doSyncLoadInfo(final CommandSender sender, final String[] args) {
|
||||
+ if (!SyncLoadFinder.ENABLED) {
|
||||
+ String systemFlag = "-Dpaper.debug-sync-loads=true";
|
||||
+ sender.sendMessage(text().color(RED).append(text("This command requires the server startup flag '")).append(
|
||||
+ text(systemFlag, WHITE).clickEvent(ClickEvent.copyToClipboard(systemFlag))
|
||||
+ .hoverEvent(HoverEvent.showText(text("Click to copy the system flag")))).append(
|
||||
+ text("' to be set.")));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (args.length > 0 && args[0].equals("clear")) {
|
||||
+ SyncLoadFinder.clear();
|
||||
+ sender.sendMessage(text("Sync load data cleared.", GRAY));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ File file = new File(new File(new File("."), "debug"),
|
||||
+ "sync-load-info-" + FORMATTER.format(LocalDateTime.now()) + ".txt");
|
||||
+ file.getParentFile().mkdirs();
|
||||
+ sender.sendMessage(text("Writing sync load info to " + file, GREEN));
|
||||
+
|
||||
+
|
||||
+ try {
|
||||
+ final JsonObject data = SyncLoadFinder.serialize();
|
||||
+
|
||||
+ StringWriter stringWriter = new StringWriter();
|
||||
+ JsonWriter jsonWriter = new JsonWriter(stringWriter);
|
||||
+ jsonWriter.setIndent(" ");
|
||||
+ jsonWriter.setLenient(false);
|
||||
+ Streams.write(data, jsonWriter);
|
||||
+
|
||||
+ try (
|
||||
+ PrintStream out = new PrintStream(new FileOutputStream(file), false, StandardCharsets.UTF_8)
|
||||
+ ) {
|
||||
+ out.print(stringWriter);
|
||||
+ }
|
||||
+ sender.sendMessage(text("Successfully written sync load information!", GREEN));
|
||||
+ } catch (Throwable thr) {
|
||||
+ sender.sendMessage(text("Failed to write sync load information! See the console for more info.", RED));
|
||||
+ MinecraftServer.LOGGER.warn("Error occurred while dumping sync chunk load info", thr);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 86453364a0433a0196099a8cd271fa2bc7924fbb..7b85cf6aba07cb64f58b913dda5da9124146bddd 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -280,6 +280,7 @@ public class ServerChunkCache extends ChunkSource {
|
||||
|
||||
Objects.requireNonNull(completablefuture);
|
||||
if (!completablefuture.isDone()) { // Paper
|
||||
+ com.destroystokyo.paper.io.SyncLoadFinder.logSyncLoad(this.level, x, z); // Paper - Add debug for sync chunk loads
|
||||
this.level.timings.syncChunkLoad.startTiming(); // Paper
|
||||
chunkproviderserver_b.managedBlock(completablefuture::isDone);
|
||||
this.level.timings.syncChunkLoad.stopTiming(); // Paper
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index ccb72d13cce7db74a6754498bab41a017a469418..33cb58e7298e7900dbcd37dbdb21de83bfca6a26 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -422,6 +422,13 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public boolean hasChunk(int chunkX, int chunkZ) {
|
||||
+ return this.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ) != null;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
/** @deprecated */
|
||||
@Deprecated
|
||||
@VisibleForTesting
|
47
patches/server/0318-Improve-java-version-check.patch
Normal file
47
patches/server/0318-Improve-java-version-check.patch
Normal file
|
@ -0,0 +1,47 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Nassim Jahnke <nassim@njahnke.dev>
|
||||
Date: Wed, 16 Mar 2022 13:58:16 +0100
|
||||
Subject: [PATCH] Improve java version check
|
||||
|
||||
Co-Authored-By: MiniDigger <admin@benndorf.dev>
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
index faa228698c7dd60bde0f3767cc27957ece04b8be..f3bce016e729d553aaa6185470bbf4317f94352b 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
@@ -203,23 +203,27 @@ public class Main {
|
||||
return;
|
||||
}
|
||||
|
||||
+ // Paper start - Improve java version check
|
||||
+ boolean skip = Boolean.getBoolean("Paper.IgnoreJavaVersion");
|
||||
float javaVersion = Float.parseFloat(System.getProperty("java.class.version"));
|
||||
- if (javaVersion < 61.0) {
|
||||
- System.err.println("Unsupported Java detected (" + javaVersion + "). This version of Minecraft requires at least Java 17. Check your Java version with the command 'java -version'.");
|
||||
- return;
|
||||
- }
|
||||
- if (javaVersion > 66.0) {
|
||||
- System.err.println("Unsupported Java detected (" + javaVersion + "). Only up to Java 22 is supported.");
|
||||
+ boolean isOldVersion = javaVersion < 61.0;
|
||||
+ if (!skip && isOldVersion) {
|
||||
+ System.err.println("Unsupported Java detected (" + javaVersion + "). This version of Minecraft requires at least Java 21. Check your Java version with the command 'java -version'. For more info see https://docs.papermc.io/misc/java-install");
|
||||
return;
|
||||
}
|
||||
String javaVersionName = System.getProperty("java.version");
|
||||
// J2SE SDK/JRE Version String Naming Convention
|
||||
boolean isPreRelease = javaVersionName.contains("-");
|
||||
- if (isPreRelease && javaVersion == 61.0) {
|
||||
- System.err.println("Unsupported Java detected (" + javaVersionName + "). You are running an outdated, pre-release version. Only general availability versions of Java are supported. Please update your Java version.");
|
||||
+ if (!skip && isPreRelease) {
|
||||
+ System.err.println("Unsupported Java detected (" + javaVersionName + "). You are running an unsupported, non official, version. Only general availability versions of Java are supported. Please update your Java version. See https://docs.papermc.io/paper/faq#unsupported-java-detected-what-do-i-do for more information.");
|
||||
return;
|
||||
}
|
||||
|
||||
+ if (skip && (isOldVersion || isPreRelease)) {
|
||||
+ System.err.println("Unsupported Java detected ("+ javaVersionName + "), but the check was skipped. Proceed with caution! ");
|
||||
+ }
|
||||
+ // Paper end - Improve java version check
|
||||
+
|
||||
try {
|
||||
// Paper start - Handled by TerminalConsoleAppender
|
||||
/*
|
26
patches/server/0319-Add-ThrownEggHatchEvent.patch
Normal file
26
patches/server/0319-Add-ThrownEggHatchEvent.patch
Normal file
|
@ -0,0 +1,26 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <blake.galbreath@gmail.com>
|
||||
Date: Sun, 9 Feb 2020 00:19:05 -0600
|
||||
Subject: [PATCH] Add ThrownEggHatchEvent
|
||||
|
||||
Adds a new event similar to PlayerEggThrowEvent, but without the Player requirement
|
||||
(dispensers can throw eggs to hatch them, too).
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java
|
||||
index 62850e899955732afdd255ea1e55fc84b7c6c96b..dbd60cc8c39f5d2d4c77e2de4f2567e7fa456cd2 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java
|
||||
@@ -86,6 +86,13 @@ public class ThrownEgg extends ThrowableItemProjectile {
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ // Paper start - Add ThrownEggHatchEvent
|
||||
+ com.destroystokyo.paper.event.entity.ThrownEggHatchEvent event = new com.destroystokyo.paper.event.entity.ThrownEggHatchEvent((org.bukkit.entity.Egg) getBukkitEntity(), hatching, b0, hatchingType);
|
||||
+ event.callEvent();
|
||||
+ hatching = event.isHatching();
|
||||
+ b0 = hatching ? event.getNumHatches() : 0; // If hatching is set to false, ensure child count is 0
|
||||
+ hatchingType = event.getHatchingType();
|
||||
+ // Paper end - Add ThrownEggHatchEvent
|
||||
|
||||
for (int i = 0; i < b0; ++i) {
|
||||
Entity entitychicken = this.level().getWorld().makeEntity(new org.bukkit.Location(this.level().getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), 0.0F), hatchingType.getEntityClass()); // CraftBukkit
|
76
patches/server/0320-Entity-Jump-API.patch
Normal file
76
patches/server/0320-Entity-Jump-API.patch
Normal file
|
@ -0,0 +1,76 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sat, 8 Feb 2020 23:26:11 -0600
|
||||
Subject: [PATCH] Entity Jump API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.LivingEntity jumping
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 3a9c823193e939a6bbf6a43cd440d3fae129a252..191ec36c917f377246e3379c410c9aa2d930cebc 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3405,8 +3405,10 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
} else if (this.isInLava() && (!this.onGround() || d3 > d4)) {
|
||||
this.jumpInLiquid(FluidTags.LAVA);
|
||||
} else if ((this.onGround() || flag && d3 <= d4) && this.noJumpDelay == 0) {
|
||||
+ if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper - Entity Jump API
|
||||
this.jumpFromGround();
|
||||
this.noJumpDelay = 10;
|
||||
+ } else { this.setJumping(false); } // Paper - Entity Jump API; setJumping(false) stops a potential loop
|
||||
}
|
||||
} else {
|
||||
this.noJumpDelay = 0;
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/animal/Panda.java b/src/main/java/net/minecraft/world/entity/animal/Panda.java
|
||||
index 228cfb77e12ed5979e422dc5dbb5e8dcf363b509..8df42121aa22ec9f95a1b8627b64b0ff71e36314 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Panda.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Panda.java
|
||||
@@ -541,7 +541,9 @@ public class Panda extends Animal {
|
||||
Panda entitypanda = (Panda) iterator.next();
|
||||
|
||||
if (!entitypanda.isBaby() && entitypanda.onGround() && !entitypanda.isInWater() && entitypanda.canPerformAction()) {
|
||||
+ if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper - Entity Jump API
|
||||
entitypanda.jumpFromGround();
|
||||
+ } else { this.setJumping(false); } // Paper - Entity Jump API; setJumping(false) stops a potential loop
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/Ravager.java b/src/main/java/net/minecraft/world/entity/monster/Ravager.java
|
||||
index 4d91bc4b90a208fec789325dbcec8cc56d1a2a8b..aa4111eef22546f8aa630228c51ef5761c9b373b 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Ravager.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Ravager.java
|
||||
@@ -160,7 +160,9 @@ public class Ravager extends Raider {
|
||||
}
|
||||
|
||||
if (!flag && this.onGround()) {
|
||||
+ if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper - Entity Jump API
|
||||
this.jumpFromGround();
|
||||
+ } else { this.setJumping(false); } // Paper - Entity Jump API; setJumping(false) stops a potential loop
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
index 5de2da8f473b6ee59be1b49c5002a0161981136c..ccb779066fb5f3ebf9e4bdabdffc9c18c1a75cbb 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
@@ -963,4 +963,20 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
|
||||
return org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(this.getHandle().getUsedItemHand());
|
||||
}
|
||||
// Paper end - active item API
|
||||
+
|
||||
+ // Paper start - entity jump API
|
||||
+ @Override
|
||||
+ public boolean isJumping() {
|
||||
+ return getHandle().jumping;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setJumping(boolean jumping) {
|
||||
+ getHandle().setJumping(jumping);
|
||||
+ if (jumping && getHandle() instanceof Mob) {
|
||||
+ // this is needed to actually make a mob jump
|
||||
+ ((Mob) getHandle()).getJumpControl().jump();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - entity jump API
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Fri, 7 Feb 2020 14:36:56 -0600
|
||||
Subject: [PATCH] Add option to nerf pigmen from nether portals
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 631f2d70b5fd6dabc06062e3c77802d2b61398ae..d890331b9bd8c7b29efb21454af34a0b246b1674 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -404,6 +404,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
public void inactiveTick() { }
|
||||
// Spigot end
|
||||
protected int numCollisions = 0; // Paper - Cap entity collisions
|
||||
+ public boolean fromNetherPortal; // Paper - Add option to nerf pigmen from nether portals
|
||||
public boolean spawnedViaMobSpawner; // Paper - Yes this name is similar to above, upstream took the better one
|
||||
// Paper start - Entity origin API
|
||||
@javax.annotation.Nullable
|
||||
@@ -2284,6 +2285,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
if (spawnedViaMobSpawner) {
|
||||
nbttagcompound.putBoolean("Paper.FromMobSpawner", true);
|
||||
}
|
||||
+ if (fromNetherPortal) {
|
||||
+ nbttagcompound.putBoolean("Paper.FromNetherPortal", true);
|
||||
+ }
|
||||
// Paper end
|
||||
return nbttagcompound;
|
||||
} catch (Throwable throwable) {
|
||||
@@ -2426,6 +2430,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
|
||||
spawnedViaMobSpawner = nbt.getBoolean("Paper.FromMobSpawner"); // Restore entity's from mob spawner status
|
||||
+ fromNetherPortal = nbt.getBoolean("Paper.FromNetherPortal");
|
||||
if (nbt.contains("Paper.SpawnReason")) {
|
||||
String spawnReasonName = nbt.getString("Paper.SpawnReason");
|
||||
try {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
|
||||
index 19c813ab9e71eed150ae569f903287e9283d9292..ab1cbcf5ef1ebffd39373bacb2b0983d2c8fa15a 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
|
||||
@@ -88,6 +88,8 @@ public class NetherPortalBlock extends Block implements Portal {
|
||||
|
||||
if (entity != null) {
|
||||
entity.setPortalCooldown();
|
||||
+ entity.fromNetherPortal = true; // Paper - Add option to nerf pigmen from nether portals
|
||||
+ if (world.paperConfig().entities.behavior.nerfPigmenFromNetherPortals) ((net.minecraft.world.entity.Mob) entity).aware = false; // Paper - Add option to nerf pigmen from nether portals
|
||||
}
|
||||
}
|
||||
}
|
399
patches/server/0322-Make-the-GUI-graph-fancier.patch
Normal file
399
patches/server/0322-Make-the-GUI-graph-fancier.patch
Normal file
|
@ -0,0 +1,399 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sun, 2 Feb 2020 04:00:40 -0600
|
||||
Subject: [PATCH] Make the GUI graph fancier
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/gui/GraphColor.java b/src/main/java/com/destroystokyo/paper/gui/GraphColor.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..a4e641fdcccd3efcd1a2865dc6dc28d50671b995
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/gui/GraphColor.java
|
||||
@@ -0,0 +1,44 @@
|
||||
+package com.destroystokyo.paper.gui;
|
||||
+
|
||||
+import java.awt.Color;
|
||||
+
|
||||
+public class GraphColor {
|
||||
+ private static final Color[] colorLine = new Color[101];
|
||||
+ private static final Color[] colorFill = new Color[101];
|
||||
+
|
||||
+ static {
|
||||
+ for (int i = 0; i < 101; i++) {
|
||||
+ Color color = createColor(i);
|
||||
+ colorLine[i] = new Color(color.getRed() / 2, color.getGreen() / 2, color.getBlue() / 2, 255);
|
||||
+ colorFill[i] = new Color(colorLine[i].getRed(), colorLine[i].getGreen(), colorLine[i].getBlue(), 125);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static Color getLineColor(int percent) {
|
||||
+ return colorLine[percent];
|
||||
+ }
|
||||
+
|
||||
+ public static Color getFillColor(int percent) {
|
||||
+ return colorFill[percent];
|
||||
+ }
|
||||
+
|
||||
+ private static Color createColor(int percent) {
|
||||
+ if (percent <= 50) {
|
||||
+ return new Color(0X00FF00);
|
||||
+ }
|
||||
+
|
||||
+ int value = 510 - (int) (Math.min(Math.max(0, ((percent - 50) / 50F)), 1) * 510);
|
||||
+
|
||||
+ int red, green;
|
||||
+ if (value < 255) {
|
||||
+ red = 255;
|
||||
+ green = (int) (Math.sqrt(value) * 16);
|
||||
+ } else {
|
||||
+ green = 255;
|
||||
+ value = value - 255;
|
||||
+ red = 255 - (value * value / 255);
|
||||
+ }
|
||||
+
|
||||
+ return new Color(red, green, 0);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/gui/GraphData.java b/src/main/java/com/destroystokyo/paper/gui/GraphData.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..186fc722965e403f76b1480e1c2381fc34e29049
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/gui/GraphData.java
|
||||
@@ -0,0 +1,47 @@
|
||||
+package com.destroystokyo.paper.gui;
|
||||
+
|
||||
+import java.awt.Color;
|
||||
+
|
||||
+public class GraphData {
|
||||
+ private long total;
|
||||
+ private long free;
|
||||
+ private long max;
|
||||
+ private long usedMem;
|
||||
+ private int usedPercent;
|
||||
+
|
||||
+ public GraphData(long total, long free, long max) {
|
||||
+ this.total = total;
|
||||
+ this.free = free;
|
||||
+ this.max = max;
|
||||
+ this.usedMem = total - free;
|
||||
+ this.usedPercent = usedMem == 0 ? 0 : (int) (usedMem * 100L / max);
|
||||
+ }
|
||||
+
|
||||
+ public long getTotal() {
|
||||
+ return total;
|
||||
+ }
|
||||
+
|
||||
+ public long getFree() {
|
||||
+ return free;
|
||||
+ }
|
||||
+
|
||||
+ public long getMax() {
|
||||
+ return max;
|
||||
+ }
|
||||
+
|
||||
+ public long getUsedMem() {
|
||||
+ return usedMem;
|
||||
+ }
|
||||
+
|
||||
+ public int getUsedPercent() {
|
||||
+ return usedPercent;
|
||||
+ }
|
||||
+
|
||||
+ public Color getFillColor() {
|
||||
+ return GraphColor.getFillColor(usedPercent);
|
||||
+ }
|
||||
+
|
||||
+ public Color getLineColor() {
|
||||
+ return GraphColor.getLineColor(usedPercent);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/gui/GuiStatsComponent.java b/src/main/java/com/destroystokyo/paper/gui/GuiStatsComponent.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..537bc6213545e8ff1b7b51bc4b27fd5b2a740883
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/gui/GuiStatsComponent.java
|
||||
@@ -0,0 +1,41 @@
|
||||
+package com.destroystokyo.paper.gui;
|
||||
+
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+
|
||||
+import javax.swing.JPanel;
|
||||
+import javax.swing.Timer;
|
||||
+import java.awt.BorderLayout;
|
||||
+import java.awt.Dimension;
|
||||
+
|
||||
+public class GuiStatsComponent extends JPanel {
|
||||
+ private final Timer timer;
|
||||
+ private final RAMGraph ramGraph;
|
||||
+
|
||||
+ public GuiStatsComponent(MinecraftServer server) {
|
||||
+ super(new BorderLayout());
|
||||
+
|
||||
+ setOpaque(false);
|
||||
+
|
||||
+ ramGraph = new RAMGraph();
|
||||
+ RAMDetails ramDetails = new RAMDetails(server);
|
||||
+
|
||||
+ add(ramGraph, "North");
|
||||
+ add(ramDetails, "Center");
|
||||
+
|
||||
+ timer = new Timer(500, (event) -> {
|
||||
+ ramGraph.update();
|
||||
+ ramDetails.update();
|
||||
+ });
|
||||
+ timer.start();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Dimension getPreferredSize() {
|
||||
+ return new Dimension(350, 200);
|
||||
+ }
|
||||
+
|
||||
+ public void close() {
|
||||
+ timer.stop();
|
||||
+ ramGraph.stop();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..f93373d28d741e1f8a53e07b4e328ce9c4e1657f
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java
|
||||
@@ -0,0 +1,74 @@
|
||||
+package com.destroystokyo.paper.gui;
|
||||
+
|
||||
+import net.minecraft.Util;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+import net.minecraft.util.TimeUtil;
|
||||
+
|
||||
+import javax.swing.DefaultListCellRenderer;
|
||||
+import javax.swing.DefaultListSelectionModel;
|
||||
+import javax.swing.JList;
|
||||
+import javax.swing.border.EmptyBorder;
|
||||
+import java.awt.Dimension;
|
||||
+import java.text.DecimalFormat;
|
||||
+import java.text.DecimalFormatSymbols;
|
||||
+import java.util.Locale;
|
||||
+import java.util.Vector;
|
||||
+
|
||||
+public class RAMDetails extends JList<String> {
|
||||
+ public static final DecimalFormat DECIMAL_FORMAT = Util.make(new DecimalFormat("########0.000"), (format)
|
||||
+ -> format.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ROOT)));
|
||||
+
|
||||
+ private final MinecraftServer server;
|
||||
+
|
||||
+ public RAMDetails(MinecraftServer server) {
|
||||
+ this.server = server;
|
||||
+
|
||||
+ setBorder(new EmptyBorder(0, 10, 0, 0));
|
||||
+ setFixedCellHeight(20);
|
||||
+ setOpaque(false);
|
||||
+
|
||||
+ DefaultListCellRenderer renderer = new DefaultListCellRenderer();
|
||||
+ renderer.setOpaque(false);
|
||||
+ setCellRenderer(renderer);
|
||||
+
|
||||
+ setSelectionModel(new DefaultListSelectionModel() {
|
||||
+ @Override
|
||||
+ public void setAnchorSelectionIndex(final int anchorIndex) {
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setLeadAnchorNotificationEnabled(final boolean flag) {
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setLeadSelectionIndex(final int leadIndex) {
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setSelectionInterval(final int index0, final int index1) {
|
||||
+ }
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Dimension getPreferredSize() {
|
||||
+ return new Dimension(350, 100);
|
||||
+ }
|
||||
+
|
||||
+ public void update() {
|
||||
+ GraphData data = RAMGraph.DATA.peekLast();
|
||||
+ Vector<String> vector = new Vector<>();
|
||||
+ vector.add("Memory use: " + (data.getUsedMem() / 1024L / 1024L) + " mb (" + (data.getFree() * 100L / data.getMax()) + "% free)");
|
||||
+ vector.add("Heap: " + (data.getTotal() / 1024L / 1024L) + " / " + (data.getMax() / 1024L / 1024L) + " mb");
|
||||
+ vector.add("Avg tick: " + DECIMAL_FORMAT.format((double)this.server.getAverageTickTimeNanos() / (double) TimeUtil.NANOSECONDS_PER_MILLISECOND) + " ms");
|
||||
+ setListData(vector);
|
||||
+ }
|
||||
+
|
||||
+ public double getAverage(long[] tickTimes) {
|
||||
+ long total = 0L;
|
||||
+ for (long value : tickTimes) {
|
||||
+ total += value * 1000;
|
||||
+ }
|
||||
+ return ((double) total / (double) tickTimes.length) * 1.0E-6D;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/gui/RAMGraph.java b/src/main/java/com/destroystokyo/paper/gui/RAMGraph.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..c3e54da4ab6440811aab2f9dd1e218802ac13285
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/gui/RAMGraph.java
|
||||
@@ -0,0 +1,144 @@
|
||||
+package com.destroystokyo.paper.gui;
|
||||
+
|
||||
+import javax.swing.JComponent;
|
||||
+import javax.swing.SwingUtilities;
|
||||
+import javax.swing.Timer;
|
||||
+import javax.swing.ToolTipManager;
|
||||
+import java.awt.Color;
|
||||
+import java.awt.Dimension;
|
||||
+import java.awt.Graphics;
|
||||
+import java.awt.MouseInfo;
|
||||
+import java.awt.Point;
|
||||
+import java.awt.PointerInfo;
|
||||
+import java.awt.event.MouseAdapter;
|
||||
+import java.awt.event.MouseEvent;
|
||||
+import java.text.SimpleDateFormat;
|
||||
+import java.util.Date;
|
||||
+import java.util.LinkedList;
|
||||
+import java.util.concurrent.TimeUnit;
|
||||
+
|
||||
+public class RAMGraph extends JComponent {
|
||||
+ public static final LinkedList<GraphData> DATA = new LinkedList<GraphData>() {
|
||||
+ @Override
|
||||
+ public boolean add(GraphData data) {
|
||||
+ if (size() >= 348) {
|
||||
+ remove();
|
||||
+ }
|
||||
+ return super.add(data);
|
||||
+ }
|
||||
+ };
|
||||
+
|
||||
+ static {
|
||||
+ GraphData empty = new GraphData(0, 0, 0);
|
||||
+ for (int i = 0; i < 350; i++) {
|
||||
+ DATA.add(empty);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private final Timer timer;
|
||||
+ private final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss");
|
||||
+
|
||||
+ private int currentTick;
|
||||
+
|
||||
+ public RAMGraph() {
|
||||
+ ToolTipManager.sharedInstance().setInitialDelay(0);
|
||||
+
|
||||
+ addMouseListener(new MouseAdapter() {
|
||||
+ final int defaultDismissTimeout = ToolTipManager.sharedInstance().getDismissDelay();
|
||||
+ final int dismissDelayMinutes = (int) TimeUnit.MINUTES.toMillis(10);
|
||||
+
|
||||
+ @Override
|
||||
+ public void mouseEntered(MouseEvent me) {
|
||||
+ ToolTipManager.sharedInstance().setDismissDelay(dismissDelayMinutes);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void mouseExited(MouseEvent me) {
|
||||
+ ToolTipManager.sharedInstance().setDismissDelay(defaultDismissTimeout);
|
||||
+ }
|
||||
+ });
|
||||
+
|
||||
+ timer = new Timer(50, (event) -> repaint());
|
||||
+ timer.start();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Dimension getPreferredSize() {
|
||||
+ return new Dimension(350, 110);
|
||||
+ }
|
||||
+
|
||||
+ public void update() {
|
||||
+ Runtime jvm = Runtime.getRuntime();
|
||||
+ DATA.add(new GraphData(jvm.totalMemory(), jvm.freeMemory(), jvm.maxMemory()));
|
||||
+
|
||||
+ PointerInfo pointerInfo = MouseInfo.getPointerInfo();
|
||||
+ if (pointerInfo != null) {
|
||||
+ Point point = pointerInfo.getLocation();
|
||||
+ if (point != null) {
|
||||
+ Point loc = new Point(point);
|
||||
+ SwingUtilities.convertPointFromScreen(loc, this);
|
||||
+ if (this.contains(loc)) {
|
||||
+ ToolTipManager.sharedInstance().mouseMoved(
|
||||
+ new MouseEvent(this, -1, System.currentTimeMillis(), 0, loc.x, loc.y,
|
||||
+ point.x, point.y, 0, false, 0));
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ currentTick++;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void paint(Graphics graphics) {
|
||||
+ graphics.setColor(new Color(0xFFFFFFFF));
|
||||
+ graphics.fillRect(0, 0, 350, 100);
|
||||
+
|
||||
+ graphics.setColor(new Color(0x888888));
|
||||
+ graphics.drawLine(1, 25, 348, 25);
|
||||
+ graphics.drawLine(1, 50, 348, 50);
|
||||
+ graphics.drawLine(1, 75, 348, 75);
|
||||
+
|
||||
+ int i = 0;
|
||||
+ for (GraphData data : DATA) {
|
||||
+ i++;
|
||||
+ if ((i + currentTick) % 120 == 0) {
|
||||
+ graphics.setColor(new Color(0x888888));
|
||||
+ graphics.drawLine(i, 1, i, 99);
|
||||
+ }
|
||||
+ int used = data.getUsedPercent();
|
||||
+ if (used > 0) {
|
||||
+ Color color = data.getLineColor();
|
||||
+ graphics.setColor(data.getFillColor());
|
||||
+ graphics.fillRect(i, 100 - used, 1, used);
|
||||
+ graphics.setColor(color);
|
||||
+ graphics.fillRect(i, 100 - used, 1, 1);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ graphics.setColor(new Color(0xFF000000));
|
||||
+ graphics.drawRect(0, 0, 348, 100);
|
||||
+
|
||||
+ Point m = getMousePosition();
|
||||
+ if (m != null && m.x > 0 && m.x < 348 && m.y > 0 && m.y < 100) {
|
||||
+ GraphData data = DATA.get(m.x);
|
||||
+ int used = data.getUsedPercent();
|
||||
+ graphics.setColor(new Color(0x000000));
|
||||
+ graphics.drawLine(m.x, 1, m.x, 99);
|
||||
+ graphics.drawOval(m.x - 2, 100 - used - 2, 5, 5);
|
||||
+ graphics.setColor(data.getLineColor());
|
||||
+ graphics.fillOval(m.x - 2, 100 - used - 2, 5, 5);
|
||||
+ setToolTipText(String.format("<html><body>Used: %s mb (%s%%)<br/>%s</body></html>",
|
||||
+ Math.round(data.getUsedMem() / 1024F / 1024F),
|
||||
+ used, getTime(m.x)));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public String getTime(int halfSeconds) {
|
||||
+ int millis = (348 - halfSeconds) / 2 * 1000;
|
||||
+ return TIME_FORMAT.format(new Date((System.currentTimeMillis() - millis)));
|
||||
+ }
|
||||
+
|
||||
+ public void stop() {
|
||||
+ timer.stop();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
|
||||
index 84a2c6c397604279ba821286f5c3c855e6041400..8b570b0c3967a22c085f390110cb29cbd9c8feff 100644
|
||||
--- a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
|
||||
+++ b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
|
||||
@@ -95,7 +95,7 @@ public class MinecraftServerGui extends JComponent {
|
||||
|
||||
private JComponent buildInfoPanel() {
|
||||
JPanel jpanel = new JPanel(new BorderLayout());
|
||||
- StatsComponent guistatscomponent = new StatsComponent(this.server);
|
||||
+ com.destroystokyo.paper.gui.GuiStatsComponent guistatscomponent = new com.destroystokyo.paper.gui.GuiStatsComponent(this.server); // Paper - Make GUI graph fancier
|
||||
Collection<Runnable> collection = this.finalizers; // CraftBukkit - decompile error
|
||||
|
||||
Objects.requireNonNull(guistatscomponent);
|
30
patches/server/0323-add-hand-to-BlockMultiPlaceEvent.patch
Normal file
30
patches/server/0323-add-hand-to-BlockMultiPlaceEvent.patch
Normal file
|
@ -0,0 +1,30 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Trigary <trigary0@gmail.com>
|
||||
Date: Sun, 1 Mar 2020 22:43:24 +0100
|
||||
Subject: [PATCH] add hand to BlockMultiPlaceEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
index 3405d27c360cde4e735aef1d5a01a53bbd00b0e0..a073dd7a0d8440aa00f0f02dc02187b4ff48bc7f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -402,13 +402,18 @@ public class CraftEventFactory {
|
||||
}
|
||||
|
||||
org.bukkit.inventory.ItemStack item;
|
||||
+ // Paper start - add hand to BlockMultiPlaceEvent
|
||||
+ EquipmentSlot equipmentSlot;
|
||||
if (hand == InteractionHand.MAIN_HAND) {
|
||||
item = player.getInventory().getItemInMainHand();
|
||||
+ equipmentSlot = EquipmentSlot.HAND;
|
||||
} else {
|
||||
item = player.getInventory().getItemInOffHand();
|
||||
+ equipmentSlot = EquipmentSlot.OFF_HAND;
|
||||
}
|
||||
|
||||
- BlockMultiPlaceEvent event = new BlockMultiPlaceEvent(blockStates, blockClicked, item, player, canBuild);
|
||||
+ BlockMultiPlaceEvent event = new BlockMultiPlaceEvent(blockStates, blockClicked, item, player, canBuild, equipmentSlot);
|
||||
+ // Paper end
|
||||
craftServer.getPluginManager().callEvent(event);
|
||||
|
||||
return event;
|
|
@ -0,0 +1,18 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Sat, 7 Mar 2020 00:07:51 +0000
|
||||
Subject: [PATCH] Validate tripwire hook placement before update
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
|
||||
index bc4d324f086d815c139408629a561ea4d94c839b..8614fad5b3df7a6030384b108b1689bf6b9f1209 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
|
||||
@@ -189,6 +189,7 @@ public class TripWireHookBlock extends Block {
|
||||
|
||||
TripWireHookBlock.emitState(world, pos, flag4, flag5, flag2, flag3);
|
||||
if (!flag) {
|
||||
+ if (world.getBlockState(pos).getBlock() == Blocks.TRIPWIRE_HOOK) // Paper - Validate tripwire hook placement before update
|
||||
world.setBlock(pos, (BlockState) iblockdata3.setValue(TripWireHookBlock.FACING, enumdirection), 3);
|
||||
if (flag1) {
|
||||
TripWireHookBlock.notifyNeighbors(block, world, pos, enumdirection);
|
|
@ -0,0 +1,19 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <blake.galbreath@gmail.com>
|
||||
Date: Sat, 13 Apr 2019 16:50:58 -0500
|
||||
Subject: [PATCH] Add option to allow iron golems to spawn in air
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java
|
||||
index 615be0b85fb3d28a044c6bae6a0fe93ec4fca061..1807da10d07d1f6e4ddbc0fa1b8da34a688d67c3 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java
|
||||
@@ -325,7 +325,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob {
|
||||
BlockPos blockposition1 = blockposition.below();
|
||||
BlockState iblockdata = world.getBlockState(blockposition1);
|
||||
|
||||
- if (!iblockdata.entityCanStandOn(world, blockposition1, this)) {
|
||||
+ if (!iblockdata.entityCanStandOn(world, blockposition1, this) && !this.level().paperConfig().entities.spawning.ironGolemsCanSpawnInAir) { // Paper - Add option to allow iron golems to spawn in air
|
||||
return false;
|
||||
} else {
|
||||
for (int i = 1; i < 3; ++i) {
|
|
@ -0,0 +1,26 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zero <zero@cock.li>
|
||||
Date: Sat, 22 Feb 2020 16:10:31 -0500
|
||||
Subject: [PATCH] Configurable chance of villager zombie infection
|
||||
|
||||
This allows you to solve an issue in vanilla behavior where:
|
||||
* On easy difficulty your villagers will NEVER get infected, meaning they will always die.
|
||||
* On normal difficulty they will have a 50% of getting infected or dying.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
index d981f8679149669f6ca4ea950d744149974532b2..e2a3978899497b6622829d6577cfaa723092da9d 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
@@ -454,10 +454,8 @@ public class Zombie extends Monster {
|
||||
public boolean killedEntity(ServerLevel world, LivingEntity other) {
|
||||
boolean flag = super.killedEntity(world, other);
|
||||
|
||||
- if ((world.getDifficulty() == Difficulty.NORMAL || world.getDifficulty() == Difficulty.HARD) && other instanceof Villager entityvillager) {
|
||||
- if (world.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) {
|
||||
- return flag;
|
||||
- }
|
||||
+ final double fallbackChance = world.getDifficulty() == Difficulty.HARD ? 100d : world.getDifficulty() == Difficulty.NORMAL ? 50d : 0d; // Paper - Configurable chance of villager zombie infection
|
||||
+ if (this.random.nextDouble() * 100 < world.paperConfig().entities.behavior.zombieVillagerInfectionChance.or(fallbackChance) && other instanceof Villager entityvillager) { // Paper - Configurable chance of villager zombie infection
|
||||
// CraftBukkit start
|
||||
flag = Zombie.zombifyVillager(world, entityvillager, this.blockPosition(), this.isSilent(), CreatureSpawnEvent.SpawnReason.INFECTION) == null;
|
||||
}
|
61
patches/server/0327-Optimise-Chunk-getFluid.patch
Normal file
61
patches/server/0327-Optimise-Chunk-getFluid.patch
Normal file
|
@ -0,0 +1,61 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Tue, 14 Jan 2020 14:59:08 -0800
|
||||
Subject: [PATCH] Optimise Chunk#getFluid
|
||||
|
||||
Removing the try catch and generally reducing ops should make it
|
||||
faster on its own, however removing the try catch makes it
|
||||
easier to inline due to code size
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 00f6ef5ffe33d6d45b5356e215324cbe0eadfda4..cda4413901fb465a855396e42356adaadefd4195 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -369,18 +369,20 @@ public class LevelChunk extends ChunkAccess {
|
||||
}
|
||||
|
||||
public FluidState getFluidState(int x, int y, int z) {
|
||||
- try {
|
||||
- int l = this.getSectionIndex(y);
|
||||
-
|
||||
- if (l >= 0 && l < this.sections.length) {
|
||||
- LevelChunkSection chunksection = this.sections[l];
|
||||
+ // Paper start - Perf: Optimise Chunk#getFluid
|
||||
+ // try { // Remove try catch
|
||||
+ int index = this.getSectionIndex(y);
|
||||
+ if (index >= 0 && index < this.sections.length) {
|
||||
+ LevelChunkSection chunksection = this.sections[index];
|
||||
|
||||
if (!chunksection.hasOnlyAir()) {
|
||||
- return chunksection.getFluidState(x & 15, y & 15, z & 15);
|
||||
+ return chunksection.states.get((y & 15) << 8 | (z & 15) << 4 | x & 15).getFluidState();
|
||||
+ // Paper end - Perf: Optimise Chunk#getFluid
|
||||
}
|
||||
}
|
||||
|
||||
return Fluids.EMPTY.defaultFluidState();
|
||||
+ /* // Paper - Perf: Optimise Chunk#getFluid
|
||||
} catch (Throwable throwable) {
|
||||
CrashReport crashreport = CrashReport.forThrowable(throwable, "Getting fluid state");
|
||||
CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Block being got");
|
||||
@@ -390,6 +392,7 @@ public class LevelChunk extends ChunkAccess {
|
||||
});
|
||||
throw new ReportedException(crashreport);
|
||||
}
|
||||
+ */ // Paper - Perf: Optimise Chunk#getFluid
|
||||
}
|
||||
|
||||
// CraftBukkit start
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
index 2c153af611399e884752f8256bee4fe32de5c572..90d1c3e23e753c29660f7d993b3c90ac022941c3 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
@@ -43,7 +43,7 @@ public class LevelChunkSection {
|
||||
}
|
||||
|
||||
public FluidState getFluidState(int x, int y, int z) {
|
||||
- return ((BlockState) this.states.get(x, y, z)).getFluidState();
|
||||
+ return this.states.get(x, y, z).getFluidState(); // Paper - Perf: Optimise Chunk#getFluid; diff on change - we expect this to be effectively just getType(x, y, z).getFluid(). If this changes we need to check other patches that use IBlockData#getFluid.
|
||||
}
|
||||
|
||||
public void acquire() {
|
|
@ -0,0 +1,19 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Wed, 2 Dec 2020 20:17:54 -0800
|
||||
Subject: [PATCH] Set spigots verbose world setting to false by def
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java
|
||||
index da91101f250a828a88b0511f7fd34879956db8dd..c15c60fb88c9d6e370e2100c57ccb59d5441c96f 100644
|
||||
--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java
|
||||
+++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java
|
||||
@@ -20,7 +20,7 @@ public class SpigotWorldConfig
|
||||
|
||||
public void init()
|
||||
{
|
||||
- this.verbose = this.getBoolean( "verbose", true );
|
||||
+ this.verbose = this.getBoolean( "verbose", false ); // Paper
|
||||
|
||||
this.log( "-------- World Settings For [" + this.worldName + "] --------" );
|
||||
SpigotConfig.readConfig( SpigotWorldConfig.class, this );
|
206
patches/server/0329-Add-tick-times-API-and-mspt-command.patch
Normal file
206
patches/server/0329-Add-tick-times-API-and-mspt-command.patch
Normal file
|
@ -0,0 +1,206 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sun, 5 Apr 2020 22:23:14 -0500
|
||||
Subject: [PATCH] Add tick times API and /mspt command
|
||||
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/command/MSPTCommand.java b/src/main/java/io/papermc/paper/command/MSPTCommand.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..8b5293b0c696ef21d0101493ffa41b60bf0bc86b
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/command/MSPTCommand.java
|
||||
@@ -0,0 +1,102 @@
|
||||
+package io.papermc.paper.command;
|
||||
+
|
||||
+import net.kyori.adventure.text.Component;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+import org.bukkit.Location;
|
||||
+import org.bukkit.command.Command;
|
||||
+import org.bukkit.command.CommandSender;
|
||||
+
|
||||
+import java.text.DecimalFormat;
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.Arrays;
|
||||
+import java.util.Collections;
|
||||
+import java.util.List;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+import static net.kyori.adventure.text.Component.text;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.GOLD;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.GRAY;
|
||||
+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.YELLOW;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public final class MSPTCommand extends Command {
|
||||
+ private static final DecimalFormat DF = new DecimalFormat("########0.0");
|
||||
+ private static final Component SLASH = text("/");
|
||||
+
|
||||
+ public MSPTCommand(final String name) {
|
||||
+ super(name);
|
||||
+ this.description = "View server tick times";
|
||||
+ this.usageMessage = "/mspt";
|
||||
+ this.setPermission("bukkit.command.mspt");
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException {
|
||||
+ return Collections.emptyList();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean execute(CommandSender sender, String commandLabel, String[] args) {
|
||||
+ if (!testPermission(sender)) return true;
|
||||
+
|
||||
+ MinecraftServer server = MinecraftServer.getServer();
|
||||
+
|
||||
+ List<Component> times = new ArrayList<>();
|
||||
+ times.addAll(eval(server.tickTimes5s.getTimes()));
|
||||
+ times.addAll(eval(server.tickTimes10s.getTimes()));
|
||||
+ times.addAll(eval(server.tickTimes60s.getTimes()));
|
||||
+
|
||||
+ sender.sendMessage(text().content("Server tick times ").color(GOLD)
|
||||
+ .append(text().color(YELLOW)
|
||||
+ .append(
|
||||
+ text("("),
|
||||
+ text("avg", GRAY),
|
||||
+ text("/"),
|
||||
+ text("min", GRAY),
|
||||
+ text("/"),
|
||||
+ text("max", GRAY),
|
||||
+ text(")")
|
||||
+ )
|
||||
+ ).append(
|
||||
+ text(" from last 5s"),
|
||||
+ text(",", GRAY),
|
||||
+ text(" 10s"),
|
||||
+ text(",", GRAY),
|
||||
+ text(" 1m"),
|
||||
+ text(":", YELLOW)
|
||||
+ )
|
||||
+ );
|
||||
+ sender.sendMessage(text().content("◴ ").color(GOLD)
|
||||
+ .append(text().color(GRAY)
|
||||
+ .append(
|
||||
+ times.get(0), SLASH, times.get(1), SLASH, times.get(2), text(", ", YELLOW),
|
||||
+ times.get(3), SLASH, times.get(4), SLASH, times.get(5), text(", ", YELLOW),
|
||||
+ times.get(6), SLASH, times.get(7), SLASH, times.get(8)
|
||||
+ )
|
||||
+ )
|
||||
+ );
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ private static List<Component> eval(long[] times) {
|
||||
+ long min = Integer.MAX_VALUE;
|
||||
+ long max = 0L;
|
||||
+ long total = 0L;
|
||||
+ for (long value : times) {
|
||||
+ if (value > 0L && value < min) min = value;
|
||||
+ if (value > max) max = value;
|
||||
+ total += value;
|
||||
+ }
|
||||
+ double avgD = ((double) total / (double) times.length) * 1.0E-6D;
|
||||
+ double minD = ((double) min) * 1.0E-6D;
|
||||
+ double maxD = ((double) max) * 1.0E-6D;
|
||||
+ return Arrays.asList(getColor(avgD), getColor(minD), getColor(maxD));
|
||||
+ }
|
||||
+
|
||||
+ private static Component getColor(double avg) {
|
||||
+ return text(DF.format(avg), avg >= 50 ? RED : avg >= 40 ? YELLOW : GREEN);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/command/PaperCommands.java b/src/main/java/io/papermc/paper/command/PaperCommands.java
|
||||
index 72f2e81b9905a0d57ed8e2a88578f62d5235c456..7b58b2d6297800c2dcdbf7539e5ab8e7703f39f1 100644
|
||||
--- a/src/main/java/io/papermc/paper/command/PaperCommands.java
|
||||
+++ b/src/main/java/io/papermc/paper/command/PaperCommands.java
|
||||
@@ -18,6 +18,7 @@ public final class PaperCommands {
|
||||
static {
|
||||
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) {
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 12f530044d918ddc1ba4b2376419f9ed72283b98..2a2b5205692573c9886a2696f376958809b899ac 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -258,6 +258,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
private int playerIdleTimeout;
|
||||
private final long[] tickTimesNanos;
|
||||
private long aggregatedTickTimesNanos;
|
||||
+ // Paper start - Add tick times API and /mspt command
|
||||
+ public final TickTimes tickTimes5s = new TickTimes(100);
|
||||
+ public final TickTimes tickTimes10s = new TickTimes(200);
|
||||
+ public final TickTimes tickTimes60s = new TickTimes(1200);
|
||||
+ // Paper end - Add tick times API and /mspt command
|
||||
@Nullable
|
||||
private KeyPair keyPair;
|
||||
@Nullable
|
||||
@@ -1475,6 +1480,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.aggregatedTickTimesNanos += j;
|
||||
this.tickTimesNanos[k] = j;
|
||||
this.smoothedTickTimeMillis = this.smoothedTickTimeMillis * 0.8F + (float) j / (float) TimeUtil.NANOSECONDS_PER_MILLISECOND * 0.19999999F;
|
||||
+ // Paper start - Add tick times API and /mspt command
|
||||
+ this.tickTimes5s.add(this.tickCount, j);
|
||||
+ this.tickTimes10s.add(this.tickCount, j);
|
||||
+ this.tickTimes60s.add(this.tickCount, j);
|
||||
+ // Paper end - Add tick times API and /mspt command
|
||||
this.logTickMethodTime(i);
|
||||
this.profiler.pop();
|
||||
org.spigotmc.WatchdogThread.tick(); // Spigot
|
||||
@@ -2863,4 +2873,30 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
public static record ServerResourcePackInfo(UUID id, String url, String hash, boolean isRequired, @Nullable Component prompt) {
|
||||
|
||||
}
|
||||
+
|
||||
+ // Paper start - Add tick times API and /mspt command
|
||||
+ public static class TickTimes {
|
||||
+ private final long[] times;
|
||||
+
|
||||
+ public TickTimes(int length) {
|
||||
+ times = new long[length];
|
||||
+ }
|
||||
+
|
||||
+ void add(int index, long time) {
|
||||
+ times[index % times.length] = time;
|
||||
+ }
|
||||
+
|
||||
+ public long[] getTimes() {
|
||||
+ return times.clone();
|
||||
+ }
|
||||
+
|
||||
+ public double getAverage() {
|
||||
+ long total = 0L;
|
||||
+ for (long value : times) {
|
||||
+ total += value;
|
||||
+ }
|
||||
+ return ((double) total / (double) times.length) * 1.0E-6D;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Add tick times API and /mspt command
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 264b5781a472f706f525cb07d4ccebac17d4a5d3..edf6921ed70ea3281cf870dfb779e908ea3d1905 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2681,6 +2681,16 @@ public final class CraftServer implements Server {
|
||||
return CraftMagicNumbers.INSTANCE;
|
||||
}
|
||||
|
||||
+ @Override
|
||||
+ public long[] getTickTimes() {
|
||||
+ return this.getServer().tickTimes5s.getTimes();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public double getAverageTickTime() {
|
||||
+ return this.getServer().tickTimes5s.getAverage();
|
||||
+ }
|
||||
+
|
||||
// Spigot start
|
||||
private final org.bukkit.Server.Spigot spigot = new org.bukkit.Server.Spigot()
|
||||
{
|
22
patches/server/0330-Expose-MinecraftServer-isRunning.patch
Normal file
22
patches/server/0330-Expose-MinecraftServer-isRunning.patch
Normal file
|
@ -0,0 +1,22 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: JRoy <joshroy126@gmail.com>
|
||||
Date: Fri, 10 Apr 2020 21:24:12 -0400
|
||||
Subject: [PATCH] Expose MinecraftServer#isRunning
|
||||
|
||||
This allows for plugins to detect if the server is actually turning off in onDisable rather than just plugins reloading.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index edf6921ed70ea3281cf870dfb779e908ea3d1905..cb6f6762b41ca78ff7c13a65690ce0be1bdac292 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2925,5 +2925,10 @@ public final class CraftServer implements Server {
|
||||
public int getCurrentTick() {
|
||||
return net.minecraft.server.MinecraftServer.currentTick;
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isStopping() {
|
||||
+ return net.minecraft.server.MinecraftServer.getServer().hasStopped();
|
||||
+ }
|
||||
// Paper end
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mariell Hoversholm <proximyst@proximyst.com>
|
||||
Date: Thu, 30 Apr 2020 16:56:54 +0200
|
||||
Subject: [PATCH] Add Raw Byte ItemStack Serialization
|
||||
|
||||
Serializes using NBT which is safer for server data migrations than bukkits format.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
index 7800e0a5aa381181d6a19d55f90490154de05c04..890beb473c240c084c4dd12c5dd792895117358e 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
@@ -483,6 +483,53 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
public com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() {
|
||||
return new com.destroystokyo.paper.PaperVersionFetcher();
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public byte[] serializeItem(ItemStack item) {
|
||||
+ Preconditions.checkNotNull(item, "null cannot be serialized");
|
||||
+ Preconditions.checkArgument(item.getType() != Material.AIR, "air cannot be serialized");
|
||||
+
|
||||
+ return serializeNbtToBytes((net.minecraft.nbt.CompoundTag) (item instanceof CraftItemStack ? ((CraftItemStack) item).handle : CraftItemStack.asNMSCopy(item)).save(MinecraftServer.getServer().registryAccess()));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ItemStack deserializeItem(byte[] data) {
|
||||
+ Preconditions.checkNotNull(data, "null cannot be deserialized");
|
||||
+ Preconditions.checkArgument(data.length > 0, "cannot deserialize nothing");
|
||||
+
|
||||
+ net.minecraft.nbt.CompoundTag compound = deserializeNbtFromBytes(data);
|
||||
+ final int dataVersion = compound.getInt("DataVersion");
|
||||
+ compound = (net.minecraft.nbt.CompoundTag) MinecraftServer.getServer().fixerUpper.update(References.ITEM_STACK, new Dynamic<>(NbtOps.INSTANCE, compound), dataVersion, this.getDataVersion()).getValue();
|
||||
+ return CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.parse(MinecraftServer.getServer().registryAccess(), compound).orElseThrow());
|
||||
+ }
|
||||
+
|
||||
+ private byte[] serializeNbtToBytes(CompoundTag compound) {
|
||||
+ compound.putInt("DataVersion", getDataVersion());
|
||||
+ java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream();
|
||||
+ try {
|
||||
+ net.minecraft.nbt.NbtIo.writeCompressed(
|
||||
+ compound,
|
||||
+ outputStream
|
||||
+ );
|
||||
+ } catch (IOException ex) {
|
||||
+ throw new RuntimeException(ex);
|
||||
+ }
|
||||
+ return outputStream.toByteArray();
|
||||
+ }
|
||||
+
|
||||
+ private net.minecraft.nbt.CompoundTag deserializeNbtFromBytes(byte[] data) {
|
||||
+ net.minecraft.nbt.CompoundTag compound;
|
||||
+ try {
|
||||
+ compound = net.minecraft.nbt.NbtIo.readCompressed(
|
||||
+ new java.io.ByteArrayInputStream(data), net.minecraft.nbt.NbtAccounter.unlimitedHeap()
|
||||
+ );
|
||||
+ } catch (IOException ex) {
|
||||
+ throw new RuntimeException(ex);
|
||||
+ }
|
||||
+ int dataVersion = compound.getInt("DataVersion");
|
||||
+ Preconditions.checkArgument(dataVersion <= getDataVersion(), "Newer version! Server downgrades are not supported!");
|
||||
+ return compound;
|
||||
+ }
|
||||
// Paper end
|
||||
|
||||
@Override
|
|
@ -0,0 +1,96 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Phoenix616 <mail@moep.tv>
|
||||
Date: Sat, 1 Feb 2020 16:50:39 +0100
|
||||
Subject: [PATCH] Pillager patrol spawn settings and per player options
|
||||
|
||||
This adds config options for defining the spawn chance, spawn delay and
|
||||
spawn start day as well as toggles for handling the spawn delay and
|
||||
start day per player. (Based on the time played statistic)
|
||||
When not per player it will use the Vanilla mechanic of one delay per
|
||||
world and the world age for the start day.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index f77edea8a82ef0b77ebe22ec1ee0fc22f94f67a5..f47f95f44252a1be48efbbec284a8dbcd494c760 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -269,6 +269,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
public boolean wonGame;
|
||||
private int containerUpdateDelay; // Paper - Configurable container update tick rate
|
||||
public long loginTime; // Paper - Replace OfflinePlayer#getLastPlayed
|
||||
+ public int patrolSpawnDelay; // Paper - Pillager patrol spawn settings and per player options
|
||||
// Paper start - cancellable death event
|
||||
public boolean queueHealthUpdatePacket;
|
||||
public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
|
||||
index 7b5db53d4cf97e41175896de47303526198fb8f6..1741360aa3f2409b1a8ddf1d4602ffe57651a586 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
|
||||
@@ -24,7 +24,7 @@ public class PatrolSpawner implements CustomSpawner {
|
||||
|
||||
@Override
|
||||
public int tick(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals) {
|
||||
- if (world.paperConfig().entities.behavior.pillagerPatrols.disable) return 0; // Paper - Add option to disable pillager patrols
|
||||
+ if (world.paperConfig().entities.behavior.pillagerPatrols.disable || world.paperConfig().entities.behavior.pillagerPatrols.spawnChance == 0) return 0; // Paper - Add option to disable pillager patrols & Pillager patrol spawn settings and per player options
|
||||
if (!spawnMonsters) {
|
||||
return 0;
|
||||
} else if (!world.getGameRules().getBoolean(GameRules.RULE_DO_PATROL_SPAWNING)) {
|
||||
@@ -32,23 +32,51 @@ public class PatrolSpawner implements CustomSpawner {
|
||||
} else {
|
||||
RandomSource randomsource = world.random;
|
||||
|
||||
- --this.nextTick;
|
||||
- if (this.nextTick > 0) {
|
||||
+ // Paper start - Pillager patrol spawn settings and per player options
|
||||
+ // Random player selection moved up for per player spawning and configuration
|
||||
+ int j = world.players().size();
|
||||
+ if (j < 1) {
|
||||
return 0;
|
||||
+ }
|
||||
+
|
||||
+ net.minecraft.server.level.ServerPlayer entityhuman = world.players().get(randomsource.nextInt(j));
|
||||
+ if (entityhuman.isSpectator()) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ int patrolSpawnDelay;
|
||||
+ if (world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.perPlayer) {
|
||||
+ --entityhuman.patrolSpawnDelay;
|
||||
+ patrolSpawnDelay = entityhuman.patrolSpawnDelay;
|
||||
} else {
|
||||
- this.nextTick += 12000 + randomsource.nextInt(1200);
|
||||
- long i = world.getDayTime() / 24000L;
|
||||
+ this.nextTick--;
|
||||
+ patrolSpawnDelay = this.nextTick;
|
||||
+ }
|
||||
+
|
||||
+ if (patrolSpawnDelay > 0) {
|
||||
+ return 0;
|
||||
+ } else {
|
||||
+ long days;
|
||||
+ if (world.paperConfig().entities.behavior.pillagerPatrols.start.perPlayer) {
|
||||
+ days = entityhuman.getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.PLAY_TIME)) / 24000L; // PLAY_ONE_MINUTE is actually counting in ticks, a misnomer by Mojang
|
||||
+ } else {
|
||||
+ days = world.getDayTime() / 24000L;
|
||||
+ }
|
||||
+ if (world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.perPlayer) {
|
||||
+ entityhuman.patrolSpawnDelay += world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.ticks + randomsource.nextInt(1200);
|
||||
+ } else {
|
||||
+ this.nextTick += world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.ticks + randomsource.nextInt(1200);
|
||||
+ }
|
||||
|
||||
- if (i >= 5L && world.isDay()) {
|
||||
- if (randomsource.nextInt(5) != 0) {
|
||||
+ if (days >= world.paperConfig().entities.behavior.pillagerPatrols.start.day && world.isDay()) {
|
||||
+ if (randomsource.nextDouble() >= world.paperConfig().entities.behavior.pillagerPatrols.spawnChance) {
|
||||
+ // Paper end - Pillager patrol spawn settings and per player options
|
||||
return 0;
|
||||
} else {
|
||||
- int j = world.players().size();
|
||||
|
||||
if (j < 1) {
|
||||
return 0;
|
||||
} else {
|
||||
- Player entityhuman = (Player) world.players().get(randomsource.nextInt(j));
|
||||
|
||||
if (entityhuman.isSpectator()) {
|
||||
return 0;
|
|
@ -0,0 +1,44 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 31 Mar 2020 03:50:42 -0400
|
||||
Subject: [PATCH] Remote Connections shouldn't hold up shutdown
|
||||
|
||||
Bugs in the connection logic appears to leave stale connections even, preventing shutdown
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index b15cee6f21ff300b596922a8eed35a5f8a89fe22..d6dc8c983d26ce89f17a990be4284fdc78ad164b 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -416,11 +416,11 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
}
|
||||
|
||||
if (this.rconThread != null) {
|
||||
- this.rconThread.stop();
|
||||
+ this.rconThread.stopNonBlocking(); // Paper - don't wait for remote connections
|
||||
}
|
||||
|
||||
if (this.queryThreadGs4 != null) {
|
||||
- this.queryThreadGs4.stop();
|
||||
+ // this.remoteStatusListener.stop(); // Paper - don't wait for remote connections
|
||||
}
|
||||
|
||||
System.exit(0); // CraftBukkit
|
||||
diff --git a/src/main/java/net/minecraft/server/rcon/thread/RconThread.java b/src/main/java/net/minecraft/server/rcon/thread/RconThread.java
|
||||
index 594fbb033b63b8c9fb8752b1fcc78f8e9f7a2a83..c12d7db2b048a327c0e8f398848cd3a9bce0ebce 100644
|
||||
--- a/src/main/java/net/minecraft/server/rcon/thread/RconThread.java
|
||||
+++ b/src/main/java/net/minecraft/server/rcon/thread/RconThread.java
|
||||
@@ -104,6 +104,14 @@ public class RconThread extends GenericThread {
|
||||
|
||||
this.clients.clear();
|
||||
}
|
||||
+ // Paper start - don't wait for remote connections
|
||||
+ public void stopNonBlocking() {
|
||||
+ this.running = false;
|
||||
+ for (RconClient client : this.clients) {
|
||||
+ client.running = false;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - don't wait for remote connections
|
||||
|
||||
private void closeSocket(ServerSocket socket) {
|
||||
LOGGER.debug("closeSocket: {}", socket);
|
|
@ -0,0 +1,58 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: chickeneer <emcchickeneer@gmail.com>
|
||||
Date: Tue, 17 Mar 2020 14:18:50 -0500
|
||||
Subject: [PATCH] Do not allow bees to load chunks for beehives
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
index 4134ee48909110f8c338f5d553d4cc1e9e31aaba..615b57fac9def18d9dcaefcfe397c74c11cac627 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
@@ -421,6 +421,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
if (this.hivePos == null) {
|
||||
return false;
|
||||
} else {
|
||||
+ if (!this.level().isLoadedAndInBounds(this.hivePos)) return false; // Paper - Do not allow bees to load chunks for beehives
|
||||
BlockEntity tileentity = this.level().getBlockEntity(this.hivePos);
|
||||
|
||||
return tileentity instanceof BeehiveBlockEntity && ((BeehiveBlockEntity) tileentity).isFireNearby();
|
||||
@@ -454,6 +455,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
}
|
||||
|
||||
private boolean doesHiveHaveSpace(BlockPos pos) {
|
||||
+ if (!this.level().isLoadedAndInBounds(pos)) return false; // Paper - Do not allow bees to load chunks for beehives
|
||||
BlockEntity tileentity = this.level().getBlockEntity(pos);
|
||||
|
||||
return tileentity instanceof BeehiveBlockEntity ? !((BeehiveBlockEntity) tileentity).isFull() : false;
|
||||
@@ -924,6 +926,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
@Override
|
||||
public boolean canBeeUse() {
|
||||
if (Bee.this.hasHive() && Bee.this.wantsToEnterHive() && Bee.this.hivePos.closerToCenterThan(Bee.this.position(), 2.0D)) {
|
||||
+ if (!Bee.this.level().isLoadedAndInBounds(Bee.this.hivePos)) return false; // Paper - Do not allow bees to load chunks for beehives
|
||||
BlockEntity tileentity = Bee.this.level().getBlockEntity(Bee.this.hivePos);
|
||||
|
||||
if (tileentity instanceof BeehiveBlockEntity) {
|
||||
@@ -947,6 +950,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
+ if (!Bee.this.level().isLoadedAndInBounds(Bee.this.hivePos)) return; // Paper - Do not allow bees to load chunks for beehives
|
||||
BlockEntity tileentity = Bee.this.level().getBlockEntity(Bee.this.hivePos);
|
||||
|
||||
if (tileentity instanceof BeehiveBlockEntity tileentitybeehive) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/Vex.java b/src/main/java/net/minecraft/world/entity/monster/Vex.java
|
||||
index d6f73c719d58970c6d13340f78c3303916b46546..2985296a9a034e535157f55e322fc8c107827752 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Vex.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Vex.java
|
||||
@@ -356,7 +356,10 @@ public class Vex extends Monster implements TraceableEntity {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
BlockPos blockposition1 = blockposition.offset(Vex.this.random.nextInt(15) - 7, Vex.this.random.nextInt(11) - 5, Vex.this.random.nextInt(15) - 7);
|
||||
|
||||
- if (Vex.this.level().isEmptyBlock(blockposition1)) {
|
||||
+ // Paper start - Don't load chunks
|
||||
+ final net.minecraft.world.level.block.state.BlockState blockState = Vex.this.level().getBlockStateIfLoaded(blockposition1);
|
||||
+ if (blockState != null && blockState.isAir()) {
|
||||
+ // Paper end - Don't load chunks
|
||||
Vex.this.moveControl.setWantedPosition((double) blockposition1.getX() + 0.5D, (double) blockposition1.getY() + 0.5D, (double) blockposition1.getZ() + 0.5D, 0.25D);
|
||||
if (Vex.this.getTarget() == null) {
|
||||
Vex.this.getLookControl().setLookAt((double) blockposition1.getX() + 0.5D, (double) blockposition1.getY() + 0.5D, (double) blockposition1.getZ() + 0.5D, 180.0F, 20.0F);
|
|
@ -0,0 +1,47 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 2 Apr 2020 01:42:39 -0400
|
||||
Subject: [PATCH] Prevent Double PlayerChunkMap adds crashing server
|
||||
|
||||
Suspected case would be around the technique used in .stopRiding
|
||||
Stack will identify any causer of this and warn instead of crashing.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 3784fbe3548727ab5ad8cfefef2d8d594a76123f..5732aded2e4dbeea84dbe6ebac71c2ad5ce4729a 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1308,6 +1308,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
public void addEntity(Entity entity) {
|
||||
org.spigotmc.AsyncCatcher.catchOp("entity track"); // Spigot
|
||||
+ // Paper start - ignore and warn about illegal addEntity calls instead of crashing server
|
||||
+ if (!entity.valid || entity.level() != this.level || this.entityMap.containsKey(entity.getId())) {
|
||||
+ LOGGER.error("Illegal ChunkMap::addEntity for world " + this.level.getWorld().getName()
|
||||
+ + ": " + entity + (this.entityMap.containsKey(entity.getId()) ? " ALREADY CONTAINED (This would have crashed your server)" : ""), new Throwable());
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - ignore and warn about illegal addEntity calls instead of crashing server
|
||||
if (!(entity instanceof EnderDragonPart)) {
|
||||
EntityType<?> entitytypes = entity.getType();
|
||||
int i = entitytypes.clientTrackingRange() * 16;
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 33cb58e7298e7900dbcd37dbdb21de83bfca6a26..a87782c3cb0a751f532feda0b827d7c7eac163e1 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -2149,7 +2149,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
|
||||
public void onTrackingStart(Entity entity) {
|
||||
org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot
|
||||
- ServerLevel.this.getChunkSource().addEntity(entity);
|
||||
+ // ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server; moved down below valid=true
|
||||
if (entity instanceof ServerPlayer entityplayer) {
|
||||
ServerLevel.this.players.add(entityplayer);
|
||||
ServerLevel.this.updateSleepingPlayerList();
|
||||
@@ -2179,6 +2179,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
entity.updateDynamicGameEventListener(DynamicGameEventListener::add);
|
||||
entity.inWorld = true; // CraftBukkit - Mark entity as in world
|
||||
entity.valid = true; // CraftBukkit
|
||||
+ ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server
|
||||
// Paper start - Entity origin API
|
||||
if (entity.getOriginVector() == null) {
|
||||
entity.setOrigin(entity.getBukkitEntity().getLocation());
|
21
patches/server/0336-Don-t-tick-dead-players.patch
Normal file
21
patches/server/0336-Don-t-tick-dead-players.patch
Normal file
|
@ -0,0 +1,21 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 2 Apr 2020 17:16:48 -0400
|
||||
Subject: [PATCH] Don't tick dead players
|
||||
|
||||
Causes sync chunk loads and who knows what all else.
|
||||
This is safe because Spectators are skipped in unloaded chunks too in vanilla.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index f47f95f44252a1be48efbbec284a8dbcd494c760..d2f5ff035d4d496c035b8ae0c04c67e3de78fd4b 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -767,7 +767,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
|
||||
public void doTick() {
|
||||
try {
|
||||
- if (!this.isSpectator() || !this.touchingUnloadedChunk()) {
|
||||
+ if (valid && !this.isSpectator() || !this.touchingUnloadedChunk()) { // Paper - don't tick dead players that are not in the world currently (pending respawn)
|
||||
super.tick();
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 2 Apr 2020 19:31:16 -0400
|
||||
Subject: [PATCH] Dead Player's shouldn't be able to move
|
||||
|
||||
This fixes a lot of game state issues where packets were delayed for processing
|
||||
due to 1.15's new queue but processed while dead.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
index e8fb36582430332e511c2d7ac1e604763f4052e3..1d8aa3b3c3deba7d04dd115d1f0b70b078111f1e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
@@ -1172,7 +1172,7 @@ public abstract class Player extends LivingEntity {
|
||||
|
||||
@Override
|
||||
protected boolean isImmobile() {
|
||||
- return super.isImmobile() || this.isSleeping();
|
||||
+ return super.isImmobile() || this.isSleeping() || this.isRemoved() || !valid; // Paper - player's who are dead or not in a world shouldn't move...
|
||||
}
|
||||
|
||||
@Override
|
|
@ -0,0 +1,48 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 9 Apr 2020 21:20:33 -0400
|
||||
Subject: [PATCH] Don't move existing players to world spawn
|
||||
|
||||
This can cause a nasty server lag the spawn chunks are not kept loaded
|
||||
or they aren't finished loading yet, or if the world spawn radius is
|
||||
larger than the keep loaded range.
|
||||
|
||||
By skipping this, we avoid potential for a large spike on server start.
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.server.level.ServerPlayer fudgeSpawnLocation(Lnet/minecraft/server/level/ServerLevel;)V
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index d2f5ff035d4d496c035b8ae0c04c67e3de78fd4b..142bdd74f930a1a2a004c8b6d9435318d1a07b71 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -358,7 +358,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
this.server = server;
|
||||
this.stats = server.getPlayerList().getPlayerStats(this);
|
||||
this.advancements = server.getPlayerList().getPlayerAdvancements(this);
|
||||
- this.moveTo(this.adjustSpawnLocation(world, world.getSharedSpawnPos()).getBottomCenter(), 0.0F, 0.0F);
|
||||
+ // this.moveTo(this.adjustSpawnLocation(world, world.getSharedSpawnPos()).getBottomCenter(), 0.0F, 0.0F); // Paper - Don't move existing players to world spawn
|
||||
this.updateOptions(clientOptions);
|
||||
this.object = null;
|
||||
|
||||
@@ -630,7 +630,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
position = Vec3.atCenterOf(world.getSharedSpawnPos());
|
||||
}
|
||||
this.setLevel(world);
|
||||
- this.setPos(position);
|
||||
+ this.setPosRaw(position.x(), position.y(), position.z()); // Paper - don't register to chunks yet
|
||||
}
|
||||
this.gameMode.setLevel((ServerLevel) world);
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 7fa13f1fe02a1bdfa93c76e9c2eefc81c9bded50..5cc92a5f55a9492928c4ba140d4e45dcf75b5431 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -226,6 +226,7 @@ public abstract class PlayerList {
|
||||
// Paper start - Entity#getEntitySpawnReason
|
||||
if (optional.isEmpty()) {
|
||||
player.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT; // set Player SpawnReason to DEFAULT on first login
|
||||
+ player.moveTo(player.adjustSpawnLocation(worldserver1, worldserver1.getSharedSpawnPos()).getBottomCenter(), 0.0F, 0.0F);
|
||||
}
|
||||
// Paper end - Entity#getEntitySpawnReason
|
||||
player.setServerLevel(worldserver1);
|
47
patches/server/0339-Optimize-Pathfinding.patch
Normal file
47
patches/server/0339-Optimize-Pathfinding.patch
Normal file
|
@ -0,0 +1,47 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 3 Mar 2016 02:02:07 -0600
|
||||
Subject: [PATCH] Optimize Pathfinding
|
||||
|
||||
Prevents pathfinding from spamming failures for things such as
|
||||
arrow attacks.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
||||
index 188904c9f0f81db1d63eec953d6746f2dc23dc81..2e9991e6b3c05584002744a2ee2579b1dba218b2 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
||||
@@ -192,13 +192,33 @@ public abstract class PathNavigation {
|
||||
return this.moveTo(this.createPath(x, y, z, 1), speed);
|
||||
}
|
||||
|
||||
+ // Paper start - Perf: Optimise pathfinding
|
||||
+ private int lastFailure = 0;
|
||||
+ private int pathfindFailures = 0;
|
||||
+ // Paper end - Perf: Optimise pathfinding
|
||||
+
|
||||
public boolean moveTo(double x, double y, double z, int distance, double speed) {
|
||||
return this.moveTo(this.createPath(x, y, z, distance), speed);
|
||||
}
|
||||
|
||||
public boolean moveTo(Entity entity, double speed) {
|
||||
+ // Paper start - Perf: Optimise pathfinding
|
||||
+ if (this.pathfindFailures > 10 && this.path == null && net.minecraft.server.MinecraftServer.currentTick < this.lastFailure + 40) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end - Perf: Optimise pathfinding
|
||||
Path path = this.createPath(entity, 1);
|
||||
- return path != null && this.moveTo(path, speed);
|
||||
+ // Paper start - Perf: Optimise pathfinding
|
||||
+ if (path != null && this.moveTo(path, speed)) {
|
||||
+ this.lastFailure = 0;
|
||||
+ this.pathfindFailures = 0;
|
||||
+ return true;
|
||||
+ } else {
|
||||
+ this.pathfindFailures++;
|
||||
+ this.lastFailure = net.minecraft.server.MinecraftServer.currentTick;
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end - Perf: Optimise pathfinding
|
||||
}
|
||||
|
||||
public boolean moveTo(@Nullable Path path, double speed) {
|
48
patches/server/0340-Reduce-Either-Optional-allocation.patch
Normal file
48
patches/server/0340-Reduce-Either-Optional-allocation.patch
Normal file
|
@ -0,0 +1,48 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 6 Apr 2020 18:35:09 -0700
|
||||
Subject: [PATCH] Reduce Either Optional allocation
|
||||
|
||||
In order to get chunk values, we shouldn't need to create
|
||||
an optional each time.
|
||||
|
||||
diff --git a/src/main/java/com/mojang/datafixers/util/Either.java b/src/main/java/com/mojang/datafixers/util/Either.java
|
||||
index 698ff6caf5924ce5c731254acd466c381c55c9b3..d54e617fc583ae7a045ebba8fde6bc5a486d73d5 100644
|
||||
--- a/src/main/java/com/mojang/datafixers/util/Either.java
|
||||
+++ b/src/main/java/com/mojang/datafixers/util/Either.java
|
||||
@@ -22,7 +22,7 @@ public abstract class Either<L, R> implements App<Either.Mu<R>, L> {
|
||||
}
|
||||
|
||||
private static final class Left<L, R> extends Either<L, R> {
|
||||
- private final L value;
|
||||
+ private final L value; private Optional<L> valueOptional; // Paper - Perf: Reduce Either Optional allocation
|
||||
|
||||
public Left(final L value) {
|
||||
this.value = value;
|
||||
@@ -51,7 +51,7 @@ public abstract class Either<L, R> implements App<Either.Mu<R>, L> {
|
||||
|
||||
@Override
|
||||
public Optional<L> left() {
|
||||
- return Optional.of(value);
|
||||
+ return this.valueOptional == null ? this.valueOptional = Optional.of(this.value) : this.valueOptional; // Paper - Perf: Reduce Either Optional allocation
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -83,7 +83,7 @@ public abstract class Either<L, R> implements App<Either.Mu<R>, L> {
|
||||
}
|
||||
|
||||
private static final class Right<L, R> extends Either<L, R> {
|
||||
- private final R value;
|
||||
+ private final R value; private Optional<R> valueOptional; // Paper - Perf: Reduce Either Optional allocation
|
||||
|
||||
public Right(final R value) {
|
||||
this.value = value;
|
||||
@@ -117,7 +117,7 @@ public abstract class Either<L, R> implements App<Either.Mu<R>, L> {
|
||||
|
||||
@Override
|
||||
public Optional<R> right() {
|
||||
- return Optional.of(value);
|
||||
+ return this.valueOptional == null ? this.valueOptional = Optional.of(this.value) : this.valueOptional; // Paper - Perf: Reduce Either Optional allocation
|
||||
}
|
||||
|
||||
@Override
|
|
@ -0,0 +1,50 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 6 Apr 2020 17:39:25 -0700
|
||||
Subject: [PATCH] Reduce memory footprint of CompoundTag
|
||||
|
||||
Fastutil maps are going to have a lower memory footprint - which
|
||||
is important because we clone chunk data after reading it for safety.
|
||||
So, reduce the impact of the clone on GC.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/nbt/CompoundTag.java b/src/main/java/net/minecraft/nbt/CompoundTag.java
|
||||
index 1cbc42c44911b71dfadebc2d60e0e5cb9b6cafe6..df246d69591e1a5822a0109c99b0f67996da71fa 100644
|
||||
--- a/src/main/java/net/minecraft/nbt/CompoundTag.java
|
||||
+++ b/src/main/java/net/minecraft/nbt/CompoundTag.java
|
||||
@@ -49,7 +49,7 @@ public class CompoundTag implements Tag {
|
||||
|
||||
private static CompoundTag loadCompound(DataInput input, NbtAccounter tracker) throws IOException {
|
||||
tracker.accountBytes(48L);
|
||||
- Map<String, Tag> map = Maps.newHashMap();
|
||||
+ it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<String, Tag> map = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(8, 0.8f); // Paper - Reduce memory footprint of CompoundTag
|
||||
|
||||
byte b;
|
||||
while ((b = input.readByte()) != 0) {
|
||||
@@ -166,7 +166,7 @@ public class CompoundTag implements Tag {
|
||||
}
|
||||
|
||||
public CompoundTag() {
|
||||
- this(Maps.newHashMap());
|
||||
+ this(new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(8, 0.8f)); // Paper - Reduce memory footprint of CompoundTag
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -481,8 +481,16 @@ public class CompoundTag implements Tag {
|
||||
|
||||
@Override
|
||||
public CompoundTag copy() {
|
||||
- Map<String, Tag> map = Maps.newHashMap(Maps.transformValues(this.tags, Tag::copy));
|
||||
- return new CompoundTag(map);
|
||||
+ // Paper start - Reduce memory footprint of CompoundTag
|
||||
+ it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<String, Tag> ret = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(this.tags.size(), 0.8f);
|
||||
+ java.util.Iterator<java.util.Map.Entry<String, Tag>> iterator = (this.tags instanceof it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap) ? ((it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap)this.tags).object2ObjectEntrySet().fastIterator() : this.tags.entrySet().iterator();
|
||||
+ while (iterator.hasNext()) {
|
||||
+ Map.Entry<String, Tag> entry = iterator.next();
|
||||
+ ret.put(entry.getKey(), entry.getValue().copy());
|
||||
+ }
|
||||
+
|
||||
+ return new CompoundTag(ret);
|
||||
+ // Paper end - Reduce memory footprint of CompoundTag
|
||||
}
|
||||
|
||||
@Override
|
|
@ -0,0 +1,50 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Mon, 13 Apr 2020 07:31:44 +0100
|
||||
Subject: [PATCH] Prevent opening inventories when frozen
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 142bdd74f930a1a2a004c8b6d9435318d1a07b71..9bb7eafb72d5264a5c53a2f53dc60d94ec976431 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -712,7 +712,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
containerUpdateDelay = this.level().paperConfig().tickRates.containerUpdate;
|
||||
}
|
||||
// Paper end - Configurable container update tick rate
|
||||
- if (!this.level().isClientSide && !this.containerMenu.stillValid(this)) {
|
||||
+ if (!this.level().isClientSide && this.containerMenu != this.inventoryMenu && (this.isImmobile() || !this.containerMenu.stillValid(this))) { // Paper - Prevent opening inventories when frozen
|
||||
this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.CANT_USE); // Paper - Inventory close reason
|
||||
this.containerMenu = this.inventoryMenu;
|
||||
}
|
||||
@@ -1637,7 +1637,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
} else {
|
||||
// CraftBukkit start
|
||||
this.containerMenu = container;
|
||||
- this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle()));
|
||||
+ if (!this.isImmobile()) this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle())); // Paper - Prevent opening inventories when frozen
|
||||
// CraftBukkit end
|
||||
this.initMenu(container);
|
||||
return OptionalInt.of(this.containerCounter);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
index c79607a2f45b7a487a95cf98b9b0eb6b36501410..eb2d39d408e7f46a8f047a2b0d76981f24e1320a 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
@@ -326,7 +326,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
|
||||
if (adventure$title == null) adventure$title = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(container.getBukkitView().getTitle()); // Paper
|
||||
|
||||
//player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); // Paper - comment
|
||||
- player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper
|
||||
+ if (!player.isImmobile()) player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper - Prevent opening inventories when frozen
|
||||
player.containerMenu = container;
|
||||
player.initMenu(container);
|
||||
}
|
||||
@@ -400,7 +400,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
|
||||
net.kyori.adventure.text.Component adventure$title = inventory.title(); // Paper
|
||||
if (adventure$title == null) adventure$title = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(inventory.getTitle()); // Paper
|
||||
//player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); // Paper - comment
|
||||
- player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper
|
||||
+ if (!player.isImmobile()) player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper - Prevent opening inventories when frozen
|
||||
player.containerMenu = container;
|
||||
player.initMenu(container);
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Wed, 15 Apr 2020 17:56:07 -0700
|
||||
Subject: [PATCH] Don't run entity collision code if not needed
|
||||
|
||||
Will not run if:
|
||||
Max entity cramming is disabled and the max collisions per entity is less than or equal to 0.
|
||||
Entity#isPushable() returns false, meaning all entities will not be able to collide with this
|
||||
entity anyways.
|
||||
The entity's current team collision rule causes them to NEVER collide.
|
||||
|
||||
Co-authored-by: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 191ec36c917f377246e3379c410c9aa2d930cebc..c5721045681bcd2db99eec42a1c1455515868af1 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3516,10 +3516,24 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
if (this.level().isClientSide()) {
|
||||
this.level().getEntities(EntityTypeTest.forClass(net.minecraft.world.entity.player.Player.class), this.getBoundingBox(), EntitySelector.pushableBy(this)).forEach(this::doPush);
|
||||
} else {
|
||||
+ // Paper start - don't run getEntities if we're not going to use its result
|
||||
+ if (!this.isPushable()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ net.minecraft.world.scores.Team team = this.getTeam();
|
||||
+ if (team != null && team.getCollisionRule() == net.minecraft.world.scores.Team.CollisionRule.NEVER) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ int i = this.level().getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING);
|
||||
+ if (i <= 0 && this.level().paperConfig().collisions.maxEntityCollisions <= 0) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - don't run getEntities if we're not going to use its result
|
||||
List<Entity> list = this.level().getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushableBy(this));
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
- int i = this.level().getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING);
|
||||
+ // Paper - don't run getEntities if we're not going to use its result; moved up
|
||||
|
||||
if (i > 0 && list.size() > i - 1 && this.random.nextInt(4) == 0) {
|
||||
int j = 0;
|
194
patches/server/0344-Implement-Player-Client-Options-API.patch
Normal file
194
patches/server/0344-Implement-Player-Client-Options-API.patch
Normal file
|
@ -0,0 +1,194 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MiniDigger <admin@benndorf.dev>
|
||||
Date: Mon, 20 Jan 2020 21:38:15 +0100
|
||||
Subject: [PATCH] Implement Player Client Options API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.player.Player DATA_PLAYER_MODE_CUSTOMISATION
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperSkinParts.java b/src/main/java/com/destroystokyo/paper/PaperSkinParts.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..b6f4400df3d8ec7e06a996de54f8cabba57885e1
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperSkinParts.java
|
||||
@@ -0,0 +1,74 @@
|
||||
+package com.destroystokyo.paper;
|
||||
+
|
||||
+import com.google.common.base.Objects;
|
||||
+
|
||||
+import java.util.StringJoiner;
|
||||
+
|
||||
+public class PaperSkinParts implements SkinParts {
|
||||
+
|
||||
+ private final int raw;
|
||||
+
|
||||
+ public PaperSkinParts(int raw) {
|
||||
+ this.raw = raw;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasCapeEnabled() {
|
||||
+ return (raw & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasJacketEnabled() {
|
||||
+ return (raw >> 1 & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasLeftSleeveEnabled() {
|
||||
+ return (raw >> 2 & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasRightSleeveEnabled() {
|
||||
+ return (raw >> 3 & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasLeftPantsEnabled() {
|
||||
+ return (raw >> 4 & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasRightPantsEnabled() {
|
||||
+ return (raw >> 5 & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasHatsEnabled() {
|
||||
+ return (raw >> 6 & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getRaw() {
|
||||
+ return raw;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean equals(Object o) {
|
||||
+ if (this == o) return true;
|
||||
+ if (o == null || getClass() != o.getClass()) return false;
|
||||
+ PaperSkinParts that = (PaperSkinParts) o;
|
||||
+ return raw == that.raw;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int hashCode() {
|
||||
+ return Objects.hashCode(raw);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String toString() {
|
||||
+ return new StringJoiner(", ", PaperSkinParts.class.getSimpleName() + "[", "]")
|
||||
+ .add("raw=" + raw)
|
||||
+ .add("cape=" + hasCapeEnabled())
|
||||
+ .add("jacket=" + hasJacketEnabled())
|
||||
+ .add("leftSleeve=" + hasLeftSleeveEnabled())
|
||||
+ .add("rightSleeve=" + hasRightSleeveEnabled())
|
||||
+ .add("leftPants=" + hasLeftPantsEnabled())
|
||||
+ .add("rightPants=" + hasRightPantsEnabled())
|
||||
+ .add("hats=" + hasHatsEnabled())
|
||||
+ .toString();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 9bb7eafb72d5264a5c53a2f53dc60d94ec976431..df6fb7dd6015ce6e558a97598c822243dcc1c284 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -359,7 +359,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
this.stats = server.getPlayerList().getPlayerStats(this);
|
||||
this.advancements = server.getPlayerList().getPlayerAdvancements(this);
|
||||
// this.moveTo(this.adjustSpawnLocation(world, world.getSharedSpawnPos()).getBottomCenter(), 0.0F, 0.0F); // Paper - Don't move existing players to world spawn
|
||||
- this.updateOptions(clientOptions);
|
||||
+ this.updateOptionsNoEvents(clientOptions); // Paper - don't call options events on login
|
||||
this.object = null;
|
||||
|
||||
this.cachedSingleHashSet = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<>(this); // Paper
|
||||
@@ -2149,7 +2149,23 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - Client option API
|
||||
+ private java.util.Map<com.destroystokyo.paper.ClientOption<?>, ?> getClientOptionMap(String locale, int viewDistance, com.destroystokyo.paper.ClientOption.ChatVisibility chatVisibility, boolean chatColors, com.destroystokyo.paper.PaperSkinParts skinParts, org.bukkit.inventory.MainHand mainHand, boolean allowsServerListing, boolean textFilteringEnabled) {
|
||||
+ java.util.Map<com.destroystokyo.paper.ClientOption<?>, Object> map = new java.util.HashMap<>();
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.LOCALE, locale);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.VIEW_DISTANCE, viewDistance);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.CHAT_VISIBILITY, chatVisibility);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.CHAT_COLORS_ENABLED, chatColors);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.SKIN_PARTS, skinParts);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.MAIN_HAND, mainHand);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.ALLOW_SERVER_LISTINGS, allowsServerListing);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.TEXT_FILTERING_ENABLED, textFilteringEnabled);
|
||||
+ return map;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public void updateOptions(ClientInformation clientOptions) {
|
||||
+ new com.destroystokyo.paper.event.player.PlayerClientOptionsChangeEvent(getBukkitEntity(), getClientOptionMap(clientOptions.language(), clientOptions.viewDistance(), com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(clientOptions.chatVisibility().name()), clientOptions.chatColors(), new com.destroystokyo.paper.PaperSkinParts(clientOptions.modelCustomisation()), clientOptions.mainHand() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT, clientOptions.allowsListing(), clientOptions.textFilteringEnabled())).callEvent(); // Paper - settings event
|
||||
// CraftBukkit start
|
||||
if (this.getMainArm() != clientOptions.mainHand()) {
|
||||
PlayerChangedMainHandEvent event = new PlayerChangedMainHandEvent(this.getBukkitEntity(), this.getMainArm() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT);
|
||||
@@ -2161,6 +2177,11 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
this.server.server.getPluginManager().callEvent(new com.destroystokyo.paper.event.player.PlayerLocaleChangeEvent(this.getBukkitEntity(), this.language, clientOptions.language())); // Paper
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ // Paper start - don't call options events on login
|
||||
+ this.updateOptionsNoEvents(clientOptions);
|
||||
+ }
|
||||
+ public void updateOptionsNoEvents(ClientInformation clientOptions) {
|
||||
+ // Paper end
|
||||
this.language = clientOptions.language();
|
||||
this.adventure$locale = java.util.Objects.requireNonNullElse(net.kyori.adventure.translation.Translator.parseLocale(this.language), java.util.Locale.US); // Paper
|
||||
this.requestedViewDistance = clientOptions.viewDistance();
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index b03813ebc9aa665f670767be9c37cbb84756838e..e837939d35ee168f5640b28fae07675817492cb9 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -653,6 +653,28 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
connection.disconnect(message == null ? net.kyori.adventure.text.Component.empty() : message);
|
||||
}
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public <T> T getClientOption(com.destroystokyo.paper.ClientOption<T> type) {
|
||||
+ if (com.destroystokyo.paper.ClientOption.SKIN_PARTS == type) {
|
||||
+ return type.getType().cast(new com.destroystokyo.paper.PaperSkinParts(getHandle().getEntityData().get(net.minecraft.world.entity.player.Player.DATA_PLAYER_MODE_CUSTOMISATION)));
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.CHAT_COLORS_ENABLED == type) {
|
||||
+ return type.getType().cast(getHandle().canChatInColor());
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.CHAT_VISIBILITY == type) {
|
||||
+ return type.getType().cast(getHandle().getChatVisibility() == null ? com.destroystokyo.paper.ClientOption.ChatVisibility.UNKNOWN : com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(getHandle().getChatVisibility().name()));
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.LOCALE == type) {
|
||||
+ return type.getType().cast(getLocale());
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.MAIN_HAND == type) {
|
||||
+ return type.getType().cast(getMainHand());
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.VIEW_DISTANCE == type) {
|
||||
+ return type.getType().cast(getClientViewDistance());
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.ALLOW_SERVER_LISTINGS == type) {
|
||||
+ return type.getType().cast(getHandle().allowsListing());
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.TEXT_FILTERING_ENABLED == type) {
|
||||
+ return type.getType().cast(getHandle().isTextFilteringEnabled());
|
||||
+ }
|
||||
+ throw new RuntimeException("Unknown settings type");
|
||||
+ }
|
||||
// Paper end
|
||||
|
||||
@Override
|
||||
diff --git a/src/test/java/io/papermc/paper/world/TranslationKeyTest.java b/src/test/java/io/papermc/paper/world/TranslationKeyTest.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..7f8b6462d2a1bbd39a870d2543bebc135f7eb45b
|
||||
--- /dev/null
|
||||
+++ b/src/test/java/io/papermc/paper/world/TranslationKeyTest.java
|
||||
@@ -0,0 +1,18 @@
|
||||
+package io.papermc.paper.world;
|
||||
+
|
||||
+import com.destroystokyo.paper.ClientOption;
|
||||
+import net.minecraft.world.entity.player.ChatVisiblity;
|
||||
+import org.bukkit.Difficulty;
|
||||
+import org.junit.jupiter.api.Assertions;
|
||||
+import org.junit.jupiter.api.Test;
|
||||
+
|
||||
+public class TranslationKeyTest {
|
||||
+
|
||||
+ @Test
|
||||
+ public void testChatVisibilityKeys() {
|
||||
+ for (ClientOption.ChatVisibility chatVisibility : ClientOption.ChatVisibility.values()) {
|
||||
+ if (chatVisibility == ClientOption.ChatVisibility.UNKNOWN) continue;
|
||||
+ Assertions.assertEquals(ChatVisiblity.valueOf(chatVisibility.name()).getKey(), chatVisibility.translationKey(), chatVisibility + "'s translation key doesn't match");
|
||||
+ }
|
||||
+ }
|
||||
+}
|
|
@ -0,0 +1,23 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 18 Apr 2020 15:59:41 -0400
|
||||
Subject: [PATCH] Don't crash if player is attempted to be removed from
|
||||
untracked chunk.
|
||||
|
||||
I suspect it deals with teleporting as it uses players current x/y/z
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
index 27065ffc5473c518acee3a3096b83fac61eb7860..cbabbfbb9967ddf9a56f3be24a88e0fcd4415aa2 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
@@ -272,8 +272,8 @@ public abstract class DistanceManager {
|
||||
ObjectSet<ServerPlayer> objectset = (ObjectSet) this.playersPerChunk.get(i);
|
||||
if (objectset == null) return; // CraftBukkit - SPIGOT-6208
|
||||
|
||||
- objectset.remove(player);
|
||||
- if (objectset.isEmpty()) {
|
||||
+ if (objectset != null) objectset.remove(player); // Paper - some state corruption happens here, don't crash, clean up gracefully
|
||||
+ if (objectset == null || objectset.isEmpty()) { // Paper
|
||||
this.playersPerChunk.remove(i);
|
||||
this.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false);
|
||||
this.playerTicketManager.update(i, Integer.MAX_VALUE, false);
|
|
@ -0,0 +1,105 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 19 Apr 2020 00:05:46 -0400
|
||||
Subject: [PATCH] Fire PlayerJoinEvent when Player is actually ready
|
||||
|
||||
For years, plugin developers have had to delay many things they do
|
||||
inside of the PlayerJoinEvent by 1 tick to make it actually work.
|
||||
|
||||
This all boiled down to 1 reason why: The event fired before the
|
||||
player was fully ready and joined to the world!
|
||||
|
||||
Additionally, if that player logged out on a vehicle, the event
|
||||
fired before the vehicle was even loaded, so that plugins had no
|
||||
access to the vehicle during this event either.
|
||||
|
||||
This change finally fixes this issue, fully preparing the player
|
||||
into the world as a fully ready entity, vehicle included.
|
||||
|
||||
There should be no plugins that break because of this change, but might
|
||||
improve consistency with other plugins instead.
|
||||
|
||||
For example, if 2 plugins listens to this event, and the first one
|
||||
teleported the player in the event, then the 2nd plugin actually
|
||||
would be getting a valid player!
|
||||
|
||||
This was very non deterministic. This change will ensure every plugin
|
||||
receives a deterministic result, and should no longer require 1 tick
|
||||
delays anymore.
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.server.level.ChunkMap addEntity(Lnet/minecraft/world/entity/Entity;)V
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 5732aded2e4dbeea84dbe6ebac71c2ad5ce4729a..d1247df5c51b0d377a27ea7cc5b5a2d1f1bf9b32 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1315,6 +1315,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
return;
|
||||
}
|
||||
// Paper end - ignore and warn about illegal addEntity calls instead of crashing server
|
||||
+ if (entity instanceof ServerPlayer && ((ServerPlayer) entity).supressTrackerForLogin) return; // Paper - Fire PlayerJoinEvent when Player is actually ready; Delay adding to tracker until after list packets
|
||||
if (!(entity instanceof EnderDragonPart)) {
|
||||
EntityType<?> entitytypes = entity.getType();
|
||||
int i = entitytypes.clientTrackingRange() * 16;
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index df6fb7dd6015ce6e558a97598c822243dcc1c284..b808d9c710d6cd59ac34ea537f603fd4002073d0 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -288,6 +288,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
public double maxHealthCache;
|
||||
public boolean joining = true;
|
||||
public boolean sentListPacket = false;
|
||||
+ public boolean supressTrackerForLogin = false; // Paper - Fire PlayerJoinEvent when Player is actually ready
|
||||
public String kickLeaveMessage = null; // SPIGOT-3034: Forward leave message to PlayerQuitEvent
|
||||
// CraftBukkit end
|
||||
public boolean isRealPlayer; // Paper
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 5cc92a5f55a9492928c4ba140d4e45dcf75b5431..47392be43dffcb983c29683263227780a3ddee24 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -297,6 +297,12 @@ public abstract class PlayerList {
|
||||
this.playersByUUID.put(player.getUUID(), player);
|
||||
// this.broadcastAll(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityplayer))); // CraftBukkit - replaced with loop below
|
||||
|
||||
+ // Paper start - Fire PlayerJoinEvent when Player is actually ready; correctly register player BEFORE PlayerJoinEvent, so the entity is valid and doesn't require tick delay hacks
|
||||
+ player.supressTrackerForLogin = true;
|
||||
+ worldserver1.addNewPlayer(player);
|
||||
+ this.server.getCustomBossEvents().onPlayerConnect(player); // see commented out section below worldserver.addPlayerJoin(entityplayer);
|
||||
+ this.mountSavedVehicle(player, worldserver1, optional);
|
||||
+ // Paper end - Fire PlayerJoinEvent when Player is actually ready
|
||||
// CraftBukkit start
|
||||
CraftPlayer bukkitPlayer = player.getBukkitEntity();
|
||||
|
||||
@@ -335,6 +341,8 @@ public abstract class PlayerList {
|
||||
player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityplayer1)));
|
||||
}
|
||||
player.sentListPacket = true;
|
||||
+ player.supressTrackerForLogin = false; // Paper - Fire PlayerJoinEvent when Player is actually ready
|
||||
+ ((ServerLevel)player.level()).getChunkSource().chunkMap.addEntity(player); // Paper - Fire PlayerJoinEvent when Player is actually ready; track entity now
|
||||
// CraftBukkit end
|
||||
|
||||
player.refreshEntityData(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn
|
||||
@@ -350,6 +358,11 @@ public abstract class PlayerList {
|
||||
worldserver1 = player.serverLevel(); // CraftBukkit - Update in case join event changed it
|
||||
// CraftBukkit end
|
||||
this.sendActivePlayerEffects(player);
|
||||
+ // Paper start - Fire PlayerJoinEvent when Player is actually ready; move vehicle into method so it can be called above - short circuit around that code
|
||||
+ this.onPlayerJoinFinish(player, worldserver1, s1);
|
||||
+ }
|
||||
+ private void mountSavedVehicle(ServerPlayer player, ServerLevel worldserver1, Optional<CompoundTag> optional) {
|
||||
+ // Paper end - Fire PlayerJoinEvent when Player is actually ready
|
||||
if (optional.isPresent() && ((CompoundTag) optional.get()).contains("RootVehicle", 10)) {
|
||||
CompoundTag nbttagcompound = ((CompoundTag) optional.get()).getCompound("RootVehicle");
|
||||
ServerLevel finalWorldServer = worldserver1; // CraftBukkit - decompile error
|
||||
@@ -396,6 +409,10 @@ public abstract class PlayerList {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - Fire PlayerJoinEvent when Player is actually ready
|
||||
+ }
|
||||
+ public void onPlayerJoinFinish(ServerPlayer player, ServerLevel worldserver1, String s1) {
|
||||
+ // Paper end - Fire PlayerJoinEvent when Player is actually ready
|
||||
player.initInventoryMenu();
|
||||
// CraftBukkit - Moved from above, added world
|
||||
// Paper start - Configurable player collision; Add to collideRule team if needed
|
|
@ -0,0 +1,119 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: 2277 <38501234+2277@users.noreply.github.com>
|
||||
Date: Tue, 31 Mar 2020 10:33:55 +0100
|
||||
Subject: [PATCH] Move player to spawn point if spawn in unloaded world
|
||||
|
||||
If the playerdata contains an invalid world (missing, unloaded, invalid,
|
||||
etc.), spawn the player at the spawn point of the main world.
|
||||
|
||||
Co-authored-by: Wyatt Childers <wchilders@nearce.com>
|
||||
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 47392be43dffcb983c29683263227780a3ddee24..fa35bc76575a3ffe6435ff24db0c7ad78b53e309 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -197,6 +197,7 @@ public abstract class PlayerList {
|
||||
}
|
||||
|
||||
Optional<CompoundTag> optional = this.load(player); // CraftBukkit - decompile error
|
||||
+ ResourceKey<Level> resourcekey = null; // Paper
|
||||
// CraftBukkit start - Better rename detection
|
||||
if (optional.isPresent()) {
|
||||
CompoundTag nbttagcompound = optional.get();
|
||||
@@ -206,19 +207,47 @@ public abstract class PlayerList {
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
- ResourceKey<Level> resourcekey = (ResourceKey) optional.flatMap((nbttagcompound) -> {
|
||||
+ // Paper start - move logic in Entity to here, to use bukkit supplied world UUID & reset to main world spawn if no valid world is found
|
||||
+ boolean[] invalidPlayerWorld = {false};
|
||||
+ bukkitData: if (optional.isPresent()) {
|
||||
+ // The main way for bukkit worlds to store the world is the world UUID despite mojang adding custom worlds
|
||||
+ final org.bukkit.World bWorld;
|
||||
+ if (optional.get().contains("WorldUUIDMost") && optional.get().contains("WorldUUIDLeast")) {
|
||||
+ bWorld = org.bukkit.Bukkit.getServer().getWorld(new UUID(optional.get().getLong("WorldUUIDMost"), optional.get().getLong("WorldUUIDLeast")));
|
||||
+ } else if (optional.get().contains("world", net.minecraft.nbt.Tag.TAG_STRING)) { // Paper - legacy bukkit world name
|
||||
+ bWorld = org.bukkit.Bukkit.getServer().getWorld(optional.get().getString("world"));
|
||||
+ } else {
|
||||
+ break bukkitData; // if neither of the bukkit data points exist, proceed to the vanilla migration section
|
||||
+ }
|
||||
+ if (bWorld != null) {
|
||||
+ resourcekey = ((CraftWorld) bWorld).getHandle().dimension();
|
||||
+ } else {
|
||||
+ resourcekey = Level.OVERWORLD;
|
||||
+ invalidPlayerWorld[0] = true;
|
||||
+ }
|
||||
+ }
|
||||
+ if (resourcekey == null) { // only run the vanilla logic if we haven't found a world from the bukkit data
|
||||
+ // Below is the vanilla way of getting the dimension, this is for migration from vanilla servers
|
||||
+ resourcekey = optional.flatMap((nbttagcompound) -> {
|
||||
+ // Paper end
|
||||
DataResult<ResourceKey<Level>> dataresult = DimensionType.parseLegacy(new Dynamic(NbtOps.INSTANCE, nbttagcompound.get("Dimension"))); // CraftBukkit - decompile error
|
||||
Logger logger = PlayerList.LOGGER;
|
||||
|
||||
Objects.requireNonNull(logger);
|
||||
- return dataresult.resultOrPartial(logger::error);
|
||||
- }).orElse(player.serverLevel().dimension()); // CraftBukkit - SPIGOT-7507: If no dimension, fall back to existing dimension loaded from "WorldUUID", which in turn defaults to World.OVERWORLD
|
||||
+ // Paper start - reset to main world spawn if no valid world is found
|
||||
+ final Optional<ResourceKey<Level>> result = dataresult.resultOrPartial(logger::error);
|
||||
+ invalidPlayerWorld[0] = result.isEmpty();
|
||||
+ return result;
|
||||
+ }).orElse(Level.OVERWORLD); // Paper - revert to vanilla default main world, this isn't an "invalid world" since no player data existed
|
||||
+ }
|
||||
+ // Paper end
|
||||
ServerLevel worldserver = this.server.getLevel(resourcekey);
|
||||
ServerLevel worldserver1;
|
||||
|
||||
if (worldserver == null) {
|
||||
PlayerList.LOGGER.warn("Unknown respawn dimension {}, defaulting to overworld", resourcekey);
|
||||
worldserver1 = this.server.overworld();
|
||||
+ invalidPlayerWorld[0] = true; // Paper - reset to main world if no world with parsed value is found
|
||||
} else {
|
||||
worldserver1 = worldserver;
|
||||
}
|
||||
@@ -226,6 +255,10 @@ public abstract class PlayerList {
|
||||
// Paper start - Entity#getEntitySpawnReason
|
||||
if (optional.isEmpty()) {
|
||||
player.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT; // set Player SpawnReason to DEFAULT on first login
|
||||
+ // Paper start - reset to main world spawn if first spawn or invalid world
|
||||
+ }
|
||||
+ if (optional.isEmpty() || invalidPlayerWorld[0]) {
|
||||
+ // Paper end - reset to main world spawn if first spawn or invalid world
|
||||
player.moveTo(player.adjustSpawnLocation(worldserver1, worldserver1.getSharedSpawnPos()).getBottomCenter(), 0.0F, 0.0F);
|
||||
}
|
||||
// Paper end - Entity#getEntitySpawnReason
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index d890331b9bd8c7b29efb21454af34a0b246b1674..2ce2926f4e3a79a1a329cdd684852970f6f104f2 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -2387,27 +2387,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
- // CraftBukkit start - Reset world
|
||||
- if (this instanceof ServerPlayer) {
|
||||
- Server server = Bukkit.getServer();
|
||||
- org.bukkit.World bworld = null;
|
||||
-
|
||||
- // TODO: Remove World related checks, replaced with WorldUID
|
||||
- String worldName = nbt.getString("world");
|
||||
-
|
||||
- if (nbt.contains("WorldUUIDMost") && nbt.contains("WorldUUIDLeast")) {
|
||||
- UUID uid = new UUID(nbt.getLong("WorldUUIDMost"), nbt.getLong("WorldUUIDLeast"));
|
||||
- bworld = server.getWorld(uid);
|
||||
- } else {
|
||||
- bworld = server.getWorld(worldName);
|
||||
- }
|
||||
-
|
||||
- if (bworld == null) {
|
||||
- bworld = ((org.bukkit.craftbukkit.CraftServer) server).getServer().getLevel(Level.OVERWORLD).getWorld();
|
||||
- }
|
||||
-
|
||||
- ((ServerPlayer) this).setLevel(bworld == null ? null : ((CraftWorld) bworld).getHandle());
|
||||
- }
|
||||
+ // CraftBukkit start
|
||||
+ // Paper - move world parsing/loading to PlayerList#placeNewPlayer
|
||||
this.getBukkitEntity().readBukkitValues(nbt);
|
||||
if (nbt.contains("Bukkit.invisible")) {
|
||||
boolean bukkitInvisible = nbt.getBoolean("Bukkit.invisible");
|
|
@ -0,0 +1,28 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: nossr50 <nossr50@gmail.com>
|
||||
Date: Thu, 26 Mar 2020 19:44:50 -0700
|
||||
Subject: [PATCH] Add PlayerAttackEntityCooldownResetEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index c5721045681bcd2db99eec42a1c1455515868af1..1886cebc32ded9c4e0c7409a4db6f78fcdf847ea 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -2248,7 +2248,16 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
|
||||
EntityDamageEvent event = CraftEventFactory.handleLivingEntityDamageEvent(this, damagesource, originalDamage, hardHatModifier, blockingModifier, armorModifier, resistanceModifier, magicModifier, absorptionModifier, hardHat, blocking, armor, resistance, magic, absorption);
|
||||
if (damagesource.getEntity() instanceof net.minecraft.world.entity.player.Player) {
|
||||
- ((net.minecraft.world.entity.player.Player) damagesource.getEntity()).resetAttackStrengthTicker(); // Moved from EntityHuman in order to make the cooldown reset get called after the damage event is fired
|
||||
+ // Paper start - PlayerAttackEntityCooldownResetEvent
|
||||
+ if (damagesource.getEntity() instanceof ServerPlayer) {
|
||||
+ ServerPlayer player = (ServerPlayer) damagesource.getEntity();
|
||||
+ if (new com.destroystokyo.paper.event.player.PlayerAttackEntityCooldownResetEvent(player.getBukkitEntity(), this.getBukkitEntity(), player.getAttackStrengthScale(0F)).callEvent()) {
|
||||
+ player.resetAttackStrengthTicker();
|
||||
+ }
|
||||
+ } else {
|
||||
+ ((net.minecraft.world.entity.player.Player) damagesource.getEntity()).resetAttackStrengthTicker();
|
||||
+ }
|
||||
+ // Paper end - PlayerAttackEntityCooldownResetEvent
|
||||
}
|
||||
if (event.isCancelled()) {
|
||||
return false;
|
|
@ -0,0 +1,27 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 23 Apr 2020 01:36:39 -0400
|
||||
Subject: [PATCH] Don't fire BlockFade on worldgen threads
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/FireBlock.java b/src/main/java/net/minecraft/world/level/block/FireBlock.java
|
||||
index 886b8d2284e3ae85184c842b24869029b9ee4ebe..ceaa2a7048afc4955d3695af5291e83a79d83c5d 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/FireBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/FireBlock.java
|
||||
@@ -108,6 +108,7 @@ public class FireBlock extends BaseFireBlock {
|
||||
@Override
|
||||
protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
|
||||
// CraftBukkit start
|
||||
+ if (!(world instanceof ServerLevel)) return this.canSurvive(state, world, pos) ? (BlockState) this.getStateWithAge(world, pos, (Integer) state.getValue(FireBlock.AGE)) : Blocks.AIR.defaultBlockState(); // Paper - don't fire events in world generation
|
||||
if (!this.canSurvive(state, world, pos)) {
|
||||
// Suppress during worldgen
|
||||
if (!(world instanceof Level)) {
|
||||
@@ -123,7 +124,7 @@ public class FireBlock extends BaseFireBlock {
|
||||
return blockState.getHandle();
|
||||
}
|
||||
}
|
||||
- return this.getStateWithAge(world, pos, (Integer) state.getValue(FireBlock.AGE));
|
||||
+ return this.getStateWithAge(world, pos, (Integer) state.getValue(FireBlock.AGE)); // Paper - don't fire events in world generation; diff on change, see "don't fire events in world generation"
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sat, 25 Apr 2020 15:13:41 -0500
|
||||
Subject: [PATCH] Add phantom creative and insomniac controls
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||
index 3207166061bf9c4d7bf3f38e5a9f7aff23ccd5c1..ee4495b67c46cf1282cdd6ad15b224b0b7b10bfb 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||
@@ -28,6 +28,7 @@ public final class EntitySelector {
|
||||
return !entity.isSpectator();
|
||||
};
|
||||
public static final Predicate<Entity> CAN_BE_COLLIDED_WITH = EntitySelector.NO_SPECTATORS.and(Entity::canBeCollidedWith);
|
||||
+ public static Predicate<Player> IS_INSOMNIAC = (player) -> net.minecraft.util.Mth.clamp(((net.minecraft.server.level.ServerPlayer) player).getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= 72000; // Paper - Add phantom creative and insomniac controls
|
||||
|
||||
private EntitySelector() {}
|
||||
// Paper start - Affects Spawning API
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java
|
||||
index 3c3f70d05fb51b530b792adf84c324840bd03c14..4b3bec32921feb1dcf71abf5e8d34fcbbc59baf5 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java
|
||||
@@ -549,6 +549,7 @@ public class Phantom extends FlyingMob implements Enemy {
|
||||
Player entityhuman = (Player) iterator.next();
|
||||
|
||||
if (Phantom.this.canAttack(entityhuman, TargetingConditions.DEFAULT)) {
|
||||
+ if (!level().paperConfig().entities.behavior.phantomsOnlyAttackInsomniacs || EntitySelector.IS_INSOMNIAC.test(entityhuman)) // Paper - Add phantom creative and insomniac controls
|
||||
Phantom.this.setTarget(entityhuman, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER, true); // CraftBukkit - reason
|
||||
return true;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java
|
||||
index bb7f2d3ff7fc6f5cadb4ab24efb5a3a2f5bdc33f..f74d41e57570a40cd5ce4da3076f3210b6594a63 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java
|
||||
@@ -48,7 +48,7 @@ public class PhantomSpawner implements CustomSpawner {
|
||||
while (iterator.hasNext()) {
|
||||
ServerPlayer entityplayer = (ServerPlayer) iterator.next();
|
||||
|
||||
- if (!entityplayer.isSpectator()) {
|
||||
+ if (!entityplayer.isSpectator() && (!world.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !entityplayer.isCreative())) { // Paper - Add phantom creative and insomniac controls
|
||||
BlockPos blockposition = entityplayer.blockPosition();
|
||||
|
||||
if (!world.dimensionType().hasSkyLight() || blockposition.getY() >= world.getSeaLevel() && world.canSeeSky(blockposition)) {
|
|
@ -0,0 +1,156 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 25 Apr 2020 06:46:35 -0400
|
||||
Subject: [PATCH] Fix item duplication and teleport issues
|
||||
|
||||
This notably fixes the newest "Donkey Dupe", but also fixes a lot
|
||||
of dupe bugs in general around nether portals and entity world transfer
|
||||
|
||||
We also fix item duplication generically by anytime we clone an item
|
||||
to drop it on the ground, destroy the source item.
|
||||
|
||||
This avoid an itemstack ever existing twice in the world state pre
|
||||
clean up stage.
|
||||
|
||||
So even if something NEW comes up, it would be impossible to drop the
|
||||
same item twice because the source was destroyed.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 2ce2926f4e3a79a1a329cdd684852970f6f104f2..b1d870b9a3b414ed49b4674afc2c6088d457ebc1 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -2517,11 +2517,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
} else {
|
||||
// CraftBukkit start - Capture drops for death event
|
||||
if (this instanceof net.minecraft.world.entity.LivingEntity && !((net.minecraft.world.entity.LivingEntity) this).forceDrops) {
|
||||
- ((net.minecraft.world.entity.LivingEntity) this).drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(stack));
|
||||
+ ((net.minecraft.world.entity.LivingEntity) this).drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack)); // Paper - mirror so we can destroy it later
|
||||
return null;
|
||||
}
|
||||
// CraftBukkit end
|
||||
- ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY() + (double) yOffset, this.getZ(), stack);
|
||||
+ ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY() + (double) yOffset, this.getZ(), stack.copy()); // Paper - copy so we can destroy original
|
||||
+ stack.setCount(0); // Paper - destroy this item - if this ever leaks due to game bugs, ensure it doesn't dupe
|
||||
|
||||
entityitem.setDefaultPickUpDelay();
|
||||
// CraftBukkit start
|
||||
@@ -3337,6 +3338,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
public Entity changeDimension(DimensionTransition teleportTarget) {
|
||||
Level world = this.level();
|
||||
|
||||
+ // Paper start - Fix item duplication and teleport issues
|
||||
+ if (!this.isAlive() || !this.valid) {
|
||||
+ LOGGER.warn("Illegal Entity Teleport " + this + " to " + teleportTarget.newLevel() + ":" + teleportTarget.pos(), new Throwable());
|
||||
+ return null;
|
||||
+ }
|
||||
+ // Paper end - Fix item duplication and teleport issues
|
||||
if (world instanceof ServerLevel worldserver) {
|
||||
if (!this.isRemoved()) {
|
||||
// CraftBukkit start
|
||||
@@ -3379,6 +3386,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
||||
if (entity2 != null) {
|
||||
if (this != entity2) {
|
||||
+ // Paper start - Fix item duplication and teleport issues
|
||||
+ if (this instanceof Mob) {
|
||||
+ ((Mob) this).dropLeash(true, true); // Paper drop lead
|
||||
+ }
|
||||
+ // Paper end - Fix item duplication and teleport issues
|
||||
entity2.restoreFrom(this);
|
||||
this.removeAfterChangingDimensions();
|
||||
// CraftBukkit start - Forward the CraftEntity to the new entity
|
||||
@@ -3454,7 +3466,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
|
||||
public boolean canChangeDimensions(Level from, Level to) {
|
||||
- return true;
|
||||
+ return this.isAlive() && this.valid; // Paper - Fix item duplication and teleport issues
|
||||
}
|
||||
|
||||
public float getBlockExplosionResistance(Explosion explosion, BlockGetter world, BlockPos pos, BlockState blockState, FluidState fluidState, float max) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 1886cebc32ded9c4e0c7409a4db6f78fcdf847ea..94c0de0a50e2a076e5aed86a673fe03d9698ba36 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -1717,9 +1717,9 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
// Paper start
|
||||
org.bukkit.event.entity.EntityDeathEvent deathEvent = this.dropAllDeathLoot(worldserver, damageSource);
|
||||
if (deathEvent == null || !deathEvent.isCancelled()) {
|
||||
- if (this.deathScore >= 0 && entityliving != null) {
|
||||
- entityliving.awardKillScore(this, this.deathScore, damageSource);
|
||||
- }
|
||||
+ // if (this.deathScore >= 0 && entityliving != null) { // Paper - Fix item duplication and teleport issues; moved to be run earlier in #dropAllDeathLoot before destroying the drop items in CraftEventFactory#callEntityDeathEvent
|
||||
+ // entityliving.awardKillScore(this, this.deathScore, damageSource);
|
||||
+ // }
|
||||
// Paper start - clear equipment if event is not cancelled
|
||||
if (this instanceof Mob) {
|
||||
for (EquipmentSlot slot : this.clearedEquipmentSlots) {
|
||||
@@ -1811,8 +1811,13 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
this.dropCustomDeathLoot(world, damageSource, flag);
|
||||
this.clearEquipmentSlots = prev; // Paper
|
||||
}
|
||||
- // CraftBukkit start - Call death event
|
||||
- org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, damageSource, this.drops); // Paper
|
||||
+ // CraftBukkit start - Call death event // Paper start - call advancement triggers with correct entity equipment
|
||||
+ org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, damageSource, this.drops, () -> {
|
||||
+ final LivingEntity entityliving = this.getKillCredit();
|
||||
+ if (this.deathScore >= 0 && entityliving != null) {
|
||||
+ entityliving.awardKillScore(this, this.deathScore, damageSource);
|
||||
+ }
|
||||
+ }); // Paper end
|
||||
this.postDeathDropItems(deathEvent); // Paper
|
||||
this.drops = new ArrayList<>();
|
||||
// CraftBukkit end
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
index 92bb0c63330ad3a4cb13b2dc655020714e9b1ffd..cc1189c2d7dc57ba8f29aad4ba5d2a07362bcd5b 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
@@ -635,7 +635,7 @@ public class ArmorStand extends LivingEntity {
|
||||
for (i = 0; i < this.handItems.size(); ++i) {
|
||||
itemstack = (ItemStack) this.handItems.get(i);
|
||||
if (!itemstack.isEmpty()) {
|
||||
- this.drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack)); // CraftBukkit - add to drops
|
||||
+ this.drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)); // CraftBukkit - add to drops // Paper - mirror so we can destroy it later - though this call site was safe
|
||||
this.handItems.set(i, ItemStack.EMPTY);
|
||||
}
|
||||
}
|
||||
@@ -643,7 +643,7 @@ public class ArmorStand extends LivingEntity {
|
||||
for (i = 0; i < this.armorItems.size(); ++i) {
|
||||
itemstack = (ItemStack) this.armorItems.get(i);
|
||||
if (!itemstack.isEmpty()) {
|
||||
- this.drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack)); // CraftBukkit - add to drops
|
||||
+ this.drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)); // CraftBukkit - add to drops // Paper - mirror so we can destroy it later - though this call site was safe
|
||||
this.armorItems.set(i, ItemStack.EMPTY);
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
index a073dd7a0d8440aa00f0f02dc02187b4ff48bc7f..4552a77e84d3c957431a918ca78dcf2e06f2e74c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -895,6 +895,11 @@ public class CraftEventFactory {
|
||||
}
|
||||
|
||||
public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, DamageSource damageSource, List<org.bukkit.inventory.ItemStack> drops) {
|
||||
+ // Paper start
|
||||
+ return CraftEventFactory.callEntityDeathEvent(victim, damageSource, drops, com.google.common.util.concurrent.Runnables.doNothing());
|
||||
+ }
|
||||
+ public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, DamageSource damageSource, List<org.bukkit.inventory.ItemStack> drops, Runnable lootCheck) {
|
||||
+ // Paper end
|
||||
CraftLivingEntity entity = (CraftLivingEntity) victim.getBukkitEntity();
|
||||
CraftDamageSource bukkitDamageSource = new CraftDamageSource(damageSource);
|
||||
EntityDeathEvent event = new EntityDeathEvent(entity, bukkitDamageSource, drops, victim.getExpReward(damageSource.getEntity()));
|
||||
@@ -909,11 +914,13 @@ public class CraftEventFactory {
|
||||
playDeathSound(victim, event);
|
||||
// Paper end
|
||||
victim.expToDrop = event.getDroppedExp();
|
||||
+ lootCheck.run(); // Paper - advancement triggers before destroying items
|
||||
|
||||
for (org.bukkit.inventory.ItemStack stack : event.getDrops()) {
|
||||
if (stack == null || stack.getType() == Material.AIR || stack.getAmount() == 0) continue;
|
||||
|
||||
- world.dropItem(entity.getLocation(), stack);
|
||||
+ world.dropItem(entity.getLocation(), stack); // Paper - note: dropItem already clones due to this being bukkit -> NMS
|
||||
+ if (stack instanceof CraftItemStack) stack.setAmount(0); // Paper - destroy this item - if this ever leaks due to game bugs, ensure it doesn't dupe, but don't nuke bukkit stacks of manually added items
|
||||
}
|
||||
|
||||
return event;
|
31
patches/server/0352-Villager-Restocks-API.patch
Normal file
31
patches/server/0352-Villager-Restocks-API.patch
Normal file
|
@ -0,0 +1,31 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: zbk <zbk@projectsolaris.net>
|
||||
Date: Sun, 26 Apr 2020 23:49:01 -0400
|
||||
Subject: [PATCH] Villager Restocks API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.npc.Villager numberOfRestocksToday
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
index 3b765b9f3b449ef8ff9c82967e4e730a090d4e5d..423f6fcaf49252553d2285308633f13e2427b607 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
@@ -87,6 +87,18 @@ public class CraftVillager extends CraftAbstractVillager implements Villager {
|
||||
this.getHandle().setVillagerXp(experience);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public int getRestocksToday() {
|
||||
+ return getHandle().numberOfRestocksToday;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setRestocksToday(int restocksToday) {
|
||||
+ getHandle().numberOfRestocksToday = restocksToday;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public boolean sleep(Location location) {
|
||||
Preconditions.checkArgument(location != null, "Location cannot be null");
|
|
@ -0,0 +1,26 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 2 May 2020 03:09:46 -0400
|
||||
Subject: [PATCH] Validate PickItem Packet and kick for invalid
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 528c902b5434875b111812ff3a8099f945404d3c..0e89021e44a5d9d3fd0169199839dbcc33e283d5 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -895,7 +895,14 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
@Override
|
||||
public void handlePickItem(ServerboundPickItemPacket packet) {
|
||||
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
|
||||
- this.player.getInventory().pickSlot(packet.getSlot());
|
||||
+ // Paper start - validate pick item position
|
||||
+ if (!(packet.getSlot() >= 0 && packet.getSlot() < this.player.getInventory().items.size())) {
|
||||
+ ServerGamePacketListenerImpl.LOGGER.warn("{} tried to set an invalid carried item", this.player.getName().getString());
|
||||
+ this.disconnect("Invalid hotbar selection (Hacking?)");
|
||||
+ return;
|
||||
+ }
|
||||
+ this.player.getInventory().pickSlot(packet.getSlot()); // Paper - Diff above if changed
|
||||
+ // Paper end - validate pick item position
|
||||
this.player.connection.send(new ClientboundContainerSetSlotPacket(-2, 0, this.player.getInventory().selected, this.player.getInventory().getItem(this.player.getInventory().selected)));
|
||||
this.player.connection.send(new ClientboundContainerSetSlotPacket(-2, 0, packet.getSlot(), this.player.getInventory().getItem(packet.getSlot())));
|
||||
this.player.connection.send(new ClientboundSetCarriedItemPacket(this.player.getInventory().selected));
|
|
@ -0,0 +1,30 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Mon, 4 May 2020 01:08:56 -0400
|
||||
Subject: [PATCH] Set cap on JDK per-thread native byte buffer cache
|
||||
|
||||
See: https://www.evanjones.ca/java-bytebuffer-leak.html
|
||||
|
||||
This is potentially a source of lots of native memory usage.
|
||||
|
||||
We are clearly seeing native usage upwards to 1-4GB which doesn't make sense.
|
||||
|
||||
Region File usage fixed in previous patch should of tecnically only been somewhat
|
||||
temporary until GC finally gets it some time later, but between all the various
|
||||
plugins doing IO on various threads, this hidden detail of the JDK could be
|
||||
keeping long lived large direct buffers in cache.
|
||||
|
||||
Set system properly at server startup if not set already to help protect from this.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
index f3bce016e729d553aaa6185470bbf4317f94352b..02243b69cca7255588b43dab57e1c9ca4c3ca87f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
@@ -27,6 +27,7 @@ public class Main {
|
||||
}
|
||||
// Paper end
|
||||
// Todo: Installation script
|
||||
+ if (System.getProperty("jdk.nio.maxCachedBufferSize") == null) System.setProperty("jdk.nio.maxCachedBufferSize", "262144"); // Paper - cap per-thread NIO cache size; https://www.evanjones.ca/java-bytebuffer-leak.html
|
||||
OptionParser parser = new OptionParser() {
|
||||
{
|
||||
this.acceptsAll(Main.asList("?", "help"), "Show the help");
|
118
patches/server/0355-misc-debugging-dumps.patch
Normal file
118
patches/server/0355-misc-debugging-dumps.patch
Normal file
|
@ -0,0 +1,118 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Thu, 18 Feb 2021 20:23:28 +0000
|
||||
Subject: [PATCH] misc debugging dumps
|
||||
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/util/TraceUtil.java b/src/main/java/io/papermc/paper/util/TraceUtil.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..479bb92d159f33c54c2d9c39d8a63aa9e74d95b9
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/util/TraceUtil.java
|
||||
@@ -0,0 +1,25 @@
|
||||
+package io.papermc.paper.util;
|
||||
+
|
||||
+import org.bukkit.Bukkit;
|
||||
+
|
||||
+public final class TraceUtil {
|
||||
+
|
||||
+ public static void dumpTraceForThread(Thread thread, String reason) {
|
||||
+ Bukkit.getLogger().warning(thread.getName() + ": " + reason);
|
||||
+ StackTraceElement[] trace = StacktraceDeobfuscator.INSTANCE.deobfuscateStacktrace(thread.getStackTrace());
|
||||
+ for (StackTraceElement traceElement : trace) {
|
||||
+ Bukkit.getLogger().warning("\tat " + traceElement);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static void dumpTraceForThread(String reason) {
|
||||
+ final Throwable thr = new Throwable(reason);
|
||||
+ StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(thr);
|
||||
+ thr.printStackTrace();
|
||||
+ }
|
||||
+
|
||||
+ public static void printStackTrace(Throwable thr) {
|
||||
+ StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(thr);
|
||||
+ thr.printStackTrace();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
|
||||
index 2b5235aea933462ca711abb5b59b6715a9af5ecb..52818e877c797ed82f7eecc8e1e1716168422b29 100644
|
||||
--- a/src/main/java/net/minecraft/commands/Commands.java
|
||||
+++ b/src/main/java/net/minecraft/commands/Commands.java
|
||||
@@ -340,7 +340,7 @@ public class Commands {
|
||||
} catch (Exception exception) {
|
||||
MutableComponent ichatmutablecomponent = Component.literal(exception.getMessage() == null ? exception.getClass().getName() : exception.getMessage());
|
||||
|
||||
- if (Commands.LOGGER.isDebugEnabled()) {
|
||||
+ if (commandlistenerwrapper.getServer().isDebugging() || Commands.LOGGER.isDebugEnabled()) { // Paper - Debugging
|
||||
Commands.LOGGER.error("Command exception: /{}", s, exception);
|
||||
StackTraceElement[] astacktraceelement = exception.getStackTrace();
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 2a2b5205692573c9886a2696f376958809b899ac..15938074ad20133f5ccdab0c8566556d7b807d8f 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -916,6 +916,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
// CraftBukkit start
|
||||
private boolean hasStopped = false;
|
||||
+ private boolean hasLoggedStop = false; // Paper - Debugging
|
||||
private final Object stopLock = new Object();
|
||||
public final boolean hasStopped() {
|
||||
synchronized (this.stopLock) {
|
||||
@@ -930,6 +931,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
if (this.hasStopped) return;
|
||||
this.hasStopped = true;
|
||||
}
|
||||
+ if (!hasLoggedStop && isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging
|
||||
// CraftBukkit end
|
||||
if (this.metricsRecorder.isRecording()) {
|
||||
this.cancelRecordingMetrics();
|
||||
@@ -1034,6 +1036,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
public void safeShutdown(boolean waitForShutdown, boolean isRestarting) {
|
||||
this.isRestarting = isRestarting;
|
||||
+ this.hasLoggedStop = true; // Paper - Debugging
|
||||
+ if (isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging
|
||||
// Paper end
|
||||
this.running = false;
|
||||
if (waitForShutdown) {
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
index 5457358bc76889153036818fdfd70a043ec4e40f..f0701ff9be510e6bed7767f154832eb80797b565 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
@@ -70,6 +70,10 @@ public class ServerConfigurationPacketListenerImpl extends ServerCommonPacketLis
|
||||
|
||||
@Override
|
||||
public void onDisconnect(DisconnectionDetails info) {
|
||||
+ // Paper start - Debugging
|
||||
+ if (net.minecraft.server.MinecraftServer.getServer().isDebugging()) {
|
||||
+ ServerConfigurationPacketListenerImpl.LOGGER.info("{} lost connection: {}, while in configuration phase {}", this.gameProfile, reason.getString(), currentTask != null ? currentTask.type().id() : "null");
|
||||
+ } else // Paper end
|
||||
ServerConfigurationPacketListenerImpl.LOGGER.info("{} lost connection: {}", this.gameProfile, info.reason().getString());
|
||||
super.onDisconnect(info);
|
||||
}
|
||||
@@ -169,6 +173,11 @@ public class ServerConfigurationPacketListenerImpl extends ServerCommonPacketLis
|
||||
playerlist.placeNewPlayer(this.connection, entityplayer, this.createCookie(this.clientInformation));
|
||||
} catch (Exception exception) {
|
||||
ServerConfigurationPacketListenerImpl.LOGGER.error("Couldn't place player in world", exception);
|
||||
+ // Paper start - Debugging
|
||||
+ if (MinecraftServer.getServer().isDebugging()) {
|
||||
+ exception.printStackTrace();
|
||||
+ }
|
||||
+ // Paper end - Debugging
|
||||
this.connection.send(new ClientboundDisconnectPacket(ServerConfigurationPacketListenerImpl.DISCONNECT_REASON_INVALID_DATA));
|
||||
this.connection.disconnect(ServerConfigurationPacketListenerImpl.DISCONNECT_REASON_INVALID_DATA);
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index cb6f6762b41ca78ff7c13a65690ce0be1bdac292..093c2159eb9d9603b5e3f0d420769d6b9d872be8 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -1039,6 +1039,7 @@ public final class CraftServer implements Server {
|
||||
plugin.getDescription().getFullName(),
|
||||
"This plugin is not properly shutting down its async tasks when it is being reloaded. This may cause conflicts with the newly loaded version of the plugin"
|
||||
));
|
||||
+ if (console.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread(worker.getThread(), "still running"); // Paper - Debugging
|
||||
}
|
||||
io.papermc.paper.plugin.PluginInitializerManager.reload(this.console); // Paper
|
||||
this.loadPlugins();
|
24
patches/server/0356-Prevent-teleporting-dead-entities.patch
Normal file
24
patches/server/0356-Prevent-teleporting-dead-entities.patch
Normal file
|
@ -0,0 +1,24 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Tue, 3 Mar 2020 05:26:40 +0000
|
||||
Subject: [PATCH] Prevent teleporting dead entities
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 0e89021e44a5d9d3fd0169199839dbcc33e283d5..05033408070a08c7b982a675dc3acb79db392229 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1553,6 +1553,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
}
|
||||
|
||||
public void internalTeleport(double d0, double d1, double d2, float f, float f1, Set<RelativeMovement> set) { // Paper
|
||||
+ // Paper start - Prevent teleporting dead entities
|
||||
+ if (player.isRemoved()) {
|
||||
+ LOGGER.info("Attempt to teleport removed player {} restricted", player.getScoreboardName());
|
||||
+ if (server.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Attempt to teleport removed player");
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Prevent teleporting dead entities
|
||||
// CraftBukkit start
|
||||
if (Float.isNaN(f)) {
|
||||
f = 0;
|
798
patches/server/0357-Implement-Mob-Goal-API.patch
Normal file
798
patches/server/0357-Implement-Mob-Goal-API.patch
Normal file
|
@ -0,0 +1,798 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MiniDigger <admin@benndorf.dev>
|
||||
Date: Fri, 3 Jan 2020 16:26:19 +0100
|
||||
Subject: [PATCH] Implement Mob Goal API
|
||||
|
||||
|
||||
diff --git a/build.gradle.kts b/build.gradle.kts
|
||||
index 7b002d28932e21878dbab248abf85066a8a80a9c..2bcb4eacd06c76f2c950b424b2a2c4d53497c538 100644
|
||||
--- a/build.gradle.kts
|
||||
+++ b/build.gradle.kts
|
||||
@@ -41,6 +41,7 @@ dependencies {
|
||||
runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18")
|
||||
runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18")
|
||||
|
||||
+ testImplementation("io.github.classgraph:classgraph:4.8.47") // Paper - mob goal test
|
||||
testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")
|
||||
testImplementation("org.hamcrest:hamcrest:2.2")
|
||||
testImplementation("org.mockito:mockito-core:5.11.0")
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..3f8cca8027051694cb0440373e75f418f73edf87
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java
|
||||
@@ -0,0 +1,378 @@
|
||||
+package com.destroystokyo.paper.entity.ai;
|
||||
+
|
||||
+import com.destroystokyo.paper.entity.RangedEntity;
|
||||
+import com.destroystokyo.paper.util.set.OptimizedSmallEnumSet;
|
||||
+import com.google.common.collect.BiMap;
|
||||
+import com.google.common.collect.HashBiMap;
|
||||
+import io.papermc.paper.util.ObfHelper;
|
||||
+import java.lang.reflect.Constructor;
|
||||
+import java.util.EnumSet;
|
||||
+import java.util.HashMap;
|
||||
+import java.util.HashSet;
|
||||
+import java.util.Map;
|
||||
+import java.util.Set;
|
||||
+import net.minecraft.world.entity.FlyingMob;
|
||||
+import net.minecraft.world.entity.PathfinderMob;
|
||||
+import net.minecraft.world.entity.TamableAnimal;
|
||||
+import net.minecraft.world.entity.ai.goal.Goal;
|
||||
+import net.minecraft.world.entity.ambient.AmbientCreature;
|
||||
+import net.minecraft.world.entity.animal.AbstractFish;
|
||||
+import net.minecraft.world.entity.animal.AbstractGolem;
|
||||
+import net.minecraft.world.entity.animal.AbstractSchoolingFish;
|
||||
+import net.minecraft.world.entity.animal.Animal;
|
||||
+import net.minecraft.world.entity.animal.Pufferfish;
|
||||
+import net.minecraft.world.entity.animal.ShoulderRidingEntity;
|
||||
+import net.minecraft.world.entity.animal.SnowGolem;
|
||||
+import net.minecraft.world.entity.animal.WaterAnimal;
|
||||
+import net.minecraft.world.entity.animal.camel.Camel;
|
||||
+import net.minecraft.world.entity.animal.horse.AbstractChestedHorse;
|
||||
+import net.minecraft.world.entity.boss.wither.WitherBoss;
|
||||
+import net.minecraft.world.entity.monster.AbstractIllager;
|
||||
+import net.minecraft.world.entity.monster.EnderMan;
|
||||
+import net.minecraft.world.entity.monster.PatrollingMonster;
|
||||
+import net.minecraft.world.entity.monster.RangedAttackMob;
|
||||
+import net.minecraft.world.entity.monster.SpellcasterIllager;
|
||||
+import net.minecraft.world.entity.monster.ZombifiedPiglin;
|
||||
+import net.minecraft.world.entity.monster.breeze.Breeze;
|
||||
+import net.minecraft.world.entity.monster.piglin.AbstractPiglin;
|
||||
+import org.bukkit.NamespacedKey;
|
||||
+import org.bukkit.entity.AbstractHorse;
|
||||
+import org.bukkit.entity.AbstractSkeleton;
|
||||
+import org.bukkit.entity.AbstractVillager;
|
||||
+import org.bukkit.entity.Ageable;
|
||||
+import org.bukkit.entity.Ambient;
|
||||
+import org.bukkit.entity.Animals;
|
||||
+import org.bukkit.entity.Bat;
|
||||
+import org.bukkit.entity.Bee;
|
||||
+import org.bukkit.entity.Blaze;
|
||||
+import org.bukkit.entity.Cat;
|
||||
+import org.bukkit.entity.CaveSpider;
|
||||
+import org.bukkit.entity.ChestedHorse;
|
||||
+import org.bukkit.entity.Chicken;
|
||||
+import org.bukkit.entity.Cod;
|
||||
+import org.bukkit.entity.Cow;
|
||||
+import org.bukkit.entity.Creature;
|
||||
+import org.bukkit.entity.Creeper;
|
||||
+import org.bukkit.entity.Dolphin;
|
||||
+import org.bukkit.entity.Donkey;
|
||||
+import org.bukkit.entity.Drowned;
|
||||
+import org.bukkit.entity.ElderGuardian;
|
||||
+import org.bukkit.entity.EnderDragon;
|
||||
+import org.bukkit.entity.Enderman;
|
||||
+import org.bukkit.entity.Endermite;
|
||||
+import org.bukkit.entity.Evoker;
|
||||
+import org.bukkit.entity.Fish;
|
||||
+import org.bukkit.entity.Flying;
|
||||
+import org.bukkit.entity.Fox;
|
||||
+import org.bukkit.entity.Ghast;
|
||||
+import org.bukkit.entity.Giant;
|
||||
+import org.bukkit.entity.Golem;
|
||||
+import org.bukkit.entity.Guardian;
|
||||
+import org.bukkit.entity.Hoglin;
|
||||
+import org.bukkit.entity.Horse;
|
||||
+import org.bukkit.entity.Husk;
|
||||
+import org.bukkit.entity.Illager;
|
||||
+import org.bukkit.entity.Illusioner;
|
||||
+import org.bukkit.entity.IronGolem;
|
||||
+import org.bukkit.entity.Llama;
|
||||
+import org.bukkit.entity.MagmaCube;
|
||||
+import org.bukkit.entity.Mob;
|
||||
+import org.bukkit.entity.Monster;
|
||||
+import org.bukkit.entity.Mule;
|
||||
+import org.bukkit.entity.MushroomCow;
|
||||
+import org.bukkit.entity.Ocelot;
|
||||
+import org.bukkit.entity.Panda;
|
||||
+import org.bukkit.entity.Parrot;
|
||||
+import org.bukkit.entity.Phantom;
|
||||
+import org.bukkit.entity.Pig;
|
||||
+import org.bukkit.entity.PigZombie;
|
||||
+import org.bukkit.entity.Piglin;
|
||||
+import org.bukkit.entity.PiglinAbstract;
|
||||
+import org.bukkit.entity.PiglinBrute;
|
||||
+import org.bukkit.entity.Pillager;
|
||||
+import org.bukkit.entity.PolarBear;
|
||||
+import org.bukkit.entity.PufferFish;
|
||||
+import org.bukkit.entity.Rabbit;
|
||||
+import org.bukkit.entity.Raider;
|
||||
+import org.bukkit.entity.Ravager;
|
||||
+import org.bukkit.entity.Salmon;
|
||||
+import org.bukkit.entity.Sheep;
|
||||
+import org.bukkit.entity.Shulker;
|
||||
+import org.bukkit.entity.Silverfish;
|
||||
+import org.bukkit.entity.Skeleton;
|
||||
+import org.bukkit.entity.SkeletonHorse;
|
||||
+import org.bukkit.entity.Slime;
|
||||
+import org.bukkit.entity.Snowman;
|
||||
+import org.bukkit.entity.Spellcaster;
|
||||
+import org.bukkit.entity.Spider;
|
||||
+import org.bukkit.entity.Squid;
|
||||
+import org.bukkit.entity.Stray;
|
||||
+import org.bukkit.entity.Strider;
|
||||
+import org.bukkit.entity.Tameable;
|
||||
+import org.bukkit.entity.TraderLlama;
|
||||
+import org.bukkit.entity.TropicalFish;
|
||||
+import org.bukkit.entity.Turtle;
|
||||
+import org.bukkit.entity.Vex;
|
||||
+import org.bukkit.entity.Villager;
|
||||
+import org.bukkit.entity.Vindicator;
|
||||
+import org.bukkit.entity.WanderingTrader;
|
||||
+import org.bukkit.entity.WaterMob;
|
||||
+import org.bukkit.entity.Witch;
|
||||
+import org.bukkit.entity.Wither;
|
||||
+import org.bukkit.entity.WitherSkeleton;
|
||||
+import org.bukkit.entity.Wolf;
|
||||
+import org.bukkit.entity.Zoglin;
|
||||
+import org.bukkit.entity.Zombie;
|
||||
+import org.bukkit.entity.ZombieHorse;
|
||||
+import org.bukkit.entity.ZombieVillager;
|
||||
+
|
||||
+public class MobGoalHelper {
|
||||
+
|
||||
+ private static final BiMap<String, String> deobfuscationMap = HashBiMap.create();
|
||||
+ private static final Map<Class<? extends Goal>, Class<? extends Mob>> entityClassCache = new HashMap<>();
|
||||
+ private static final Map<Class<? extends net.minecraft.world.entity.Mob>, Class<? extends Mob>> bukkitMap = new HashMap<>();
|
||||
+
|
||||
+ static final Set<String> ignored = new HashSet<>();
|
||||
+
|
||||
+ static {
|
||||
+ // TODO these kinda should be checked on each release, in case obfuscation changes
|
||||
+ deobfuscationMap.put("abstract_skeleton_1", "abstract_skeleton_melee");
|
||||
+
|
||||
+ ignored.add("goal_selector_1");
|
||||
+ ignored.add("goal_selector_2");
|
||||
+ ignored.add("selector_1");
|
||||
+ ignored.add("selector_2");
|
||||
+ ignored.add("wrapped");
|
||||
+
|
||||
+ bukkitMap.put(net.minecraft.world.entity.Mob.class, Mob.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.AgeableMob.class, Ageable.class);
|
||||
+ bukkitMap.put(AmbientCreature.class, Ambient.class);
|
||||
+ bukkitMap.put(Animal.class, Animals.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.ambient.Bat.class, Bat.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Bee.class, Bee.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Blaze.class, Blaze.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Cat.class, Cat.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.CaveSpider.class, CaveSpider.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Chicken.class, Chicken.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Cod.class, Cod.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Cow.class, Cow.class);
|
||||
+ bukkitMap.put(PathfinderMob.class, Creature.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Creeper.class, Creeper.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Dolphin.class, Dolphin.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Drowned.class, Drowned.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.boss.enderdragon.EnderDragon.class, EnderDragon.class);
|
||||
+ bukkitMap.put(EnderMan.class, Enderman.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Endermite.class, Endermite.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Evoker.class, Evoker.class);
|
||||
+ bukkitMap.put(AbstractFish.class, Fish.class);
|
||||
+ bukkitMap.put(AbstractSchoolingFish.class, Fish.class); // close enough
|
||||
+ bukkitMap.put(FlyingMob.class, Flying.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Fox.class, Fox.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Ghast.class, Ghast.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Giant.class, Giant.class);
|
||||
+ bukkitMap.put(AbstractGolem.class, Golem.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Guardian.class, Guardian.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.ElderGuardian.class, ElderGuardian.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.horse.Horse.class, Horse.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.horse.AbstractHorse.class, AbstractHorse.class);
|
||||
+ bukkitMap.put(AbstractChestedHorse.class, ChestedHorse.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.horse.Donkey.class, Donkey.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.horse.Mule.class, Mule.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.horse.SkeletonHorse.class, SkeletonHorse.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.horse.ZombieHorse.class, ZombieHorse.class);
|
||||
+ bukkitMap.put(Camel.class, org.bukkit.entity.Camel.class);
|
||||
+ bukkitMap.put(AbstractIllager.class, Illager.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Illusioner.class, Illusioner.class);
|
||||
+ bukkitMap.put(SpellcasterIllager.class, Spellcaster.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.IronGolem.class, IronGolem.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.horse.Llama.class, Llama.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.horse.TraderLlama.class, TraderLlama.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.MagmaCube.class, MagmaCube.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Monster.class, Monster.class);
|
||||
+ bukkitMap.put(PatrollingMonster.class, Raider.class); // close enough
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.MushroomCow.class, MushroomCow.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Ocelot.class, Ocelot.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Panda.class, Panda.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Parrot.class, Parrot.class);
|
||||
+ bukkitMap.put(ShoulderRidingEntity.class, Parrot.class); // close enough
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Phantom.class, Phantom.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Pig.class, Pig.class);
|
||||
+ bukkitMap.put(ZombifiedPiglin.class, PigZombie.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Pillager.class, Pillager.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.PolarBear.class, PolarBear.class);
|
||||
+ bukkitMap.put(Pufferfish.class, PufferFish.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Rabbit.class, Rabbit.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.raid.Raider.class, Raider.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Ravager.class, Ravager.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Salmon.class, Salmon.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Sheep.class, Sheep.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Shulker.class, Shulker.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Silverfish.class, Silverfish.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Skeleton.class, Skeleton.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.AbstractSkeleton.class, AbstractSkeleton.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Stray.class, Stray.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.WitherSkeleton.class, WitherSkeleton.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Slime.class, Slime.class);
|
||||
+ bukkitMap.put(SnowGolem.class, Snowman.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Spider.class, Spider.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Squid.class, Squid.class);
|
||||
+ bukkitMap.put(TamableAnimal.class, Tameable.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.TropicalFish.class, TropicalFish.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Turtle.class, Turtle.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Vex.class, Vex.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.npc.Villager.class, Villager.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.npc.AbstractVillager.class, AbstractVillager.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.npc.WanderingTrader.class, WanderingTrader.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Vindicator.class, Vindicator.class);
|
||||
+ bukkitMap.put(WaterAnimal.class, WaterMob.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Witch.class, Witch.class);
|
||||
+ bukkitMap.put(WitherBoss.class, Wither.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Wolf.class, Wolf.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Zombie.class, Zombie.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Husk.class, Husk.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.ZombieVillager.class, ZombieVillager.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.hoglin.Hoglin.class, Hoglin.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.piglin.Piglin.class, Piglin.class);
|
||||
+ bukkitMap.put(AbstractPiglin.class, PiglinAbstract.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.piglin.PiglinBrute.class, PiglinBrute.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Strider.class, Strider.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Zoglin.class, Zoglin.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.GlowSquid.class, org.bukkit.entity.GlowSquid.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.axolotl.Axolotl.class, org.bukkit.entity.Axolotl.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.goat.Goat.class, org.bukkit.entity.Goat.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.frog.Frog.class, org.bukkit.entity.Frog.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.frog.Tadpole.class, org.bukkit.entity.Tadpole.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.warden.Warden.class, org.bukkit.entity.Warden.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.allay.Allay.class, org.bukkit.entity.Allay.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.sniffer.Sniffer.class, org.bukkit.entity.Sniffer.class);
|
||||
+ bukkitMap.put(Breeze.class, org.bukkit.entity.Breeze.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.armadillo.Armadillo.class, org.bukkit.entity.Armadillo.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Bogged.class, org.bukkit.entity.Bogged.class);
|
||||
+ }
|
||||
+
|
||||
+ public static String getUsableName(Class<?> clazz) {
|
||||
+ String name = io.papermc.paper.util.MappingEnvironment.reobf() ? ObfHelper.INSTANCE.deobfClassName(clazz.getName()) : clazz.getName();
|
||||
+ name = name.substring(name.lastIndexOf(".") + 1);
|
||||
+ boolean flag = false;
|
||||
+ // inner classes
|
||||
+ if (name.contains("$")) {
|
||||
+ String cut = name.substring(name.indexOf("$") + 1);
|
||||
+ if (cut.length() <= 2) {
|
||||
+ name = name.replace("Entity", "");
|
||||
+ name = name.replace("$", "_");
|
||||
+ flag = true;
|
||||
+ } else {
|
||||
+ // mapped, wooo
|
||||
+ name = cut;
|
||||
+ }
|
||||
+ }
|
||||
+ name = name.replace("PathfinderGoal", "");
|
||||
+ name = name.replace("TargetGoal", "");
|
||||
+ name = name.replace("Goal", "");
|
||||
+ StringBuilder sb = new StringBuilder();
|
||||
+ for (char c : name.toCharArray()) {
|
||||
+ if (c >= 'A' && c <= 'Z') {
|
||||
+ sb.append("_");
|
||||
+ sb.append(Character.toLowerCase(c));
|
||||
+ } else {
|
||||
+ sb.append(c);
|
||||
+ }
|
||||
+ }
|
||||
+ name = sb.toString();
|
||||
+ name = name.replaceFirst("_", "");
|
||||
+
|
||||
+ if (flag && !deobfuscationMap.containsKey(name.toLowerCase(java.util.Locale.ROOT)) && !ignored.contains(name)) {
|
||||
+ System.out.println("need to map " + clazz.getName() + " (" + name.toLowerCase(java.util.Locale.ROOT) + ")");
|
||||
+ }
|
||||
+
|
||||
+ // did we rename this key?
|
||||
+ return deobfuscationMap.getOrDefault(name, name);
|
||||
+ }
|
||||
+
|
||||
+ public static EnumSet<GoalType> vanillaToPaper(Goal goal) {
|
||||
+ EnumSet<GoalType> goals = EnumSet.noneOf(GoalType.class);
|
||||
+ for (GoalType type : GoalType.values()) {
|
||||
+ if (goal.getFlags().contains(paperToVanilla(type))) {
|
||||
+ goals.add(type);
|
||||
+ }
|
||||
+ }
|
||||
+ return goals;
|
||||
+ }
|
||||
+
|
||||
+ public static GoalType vanillaToPaper(Goal.Flag type) {
|
||||
+ switch (type) {
|
||||
+ case MOVE:
|
||||
+ return GoalType.MOVE;
|
||||
+ case LOOK:
|
||||
+ return GoalType.LOOK;
|
||||
+ case JUMP:
|
||||
+ return GoalType.JUMP;
|
||||
+ case UNKNOWN_BEHAVIOR:
|
||||
+ return GoalType.UNKNOWN_BEHAVIOR;
|
||||
+ case TARGET:
|
||||
+ return GoalType.TARGET;
|
||||
+ default:
|
||||
+ throw new IllegalArgumentException("Unknown vanilla mob goal type " + type.name());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static EnumSet<Goal.Flag> paperToVanilla(EnumSet<GoalType> types) {
|
||||
+ EnumSet<Goal.Flag> goals = EnumSet.noneOf(Goal.Flag.class);
|
||||
+ for (GoalType type : types) {
|
||||
+ goals.add(paperToVanilla(type));
|
||||
+ }
|
||||
+ return goals;
|
||||
+ }
|
||||
+
|
||||
+ public static Goal.Flag paperToVanilla(GoalType type) {
|
||||
+ switch (type) {
|
||||
+ case MOVE:
|
||||
+ return Goal.Flag.MOVE;
|
||||
+ case LOOK:
|
||||
+ return Goal.Flag.LOOK;
|
||||
+ case JUMP:
|
||||
+ return Goal.Flag.JUMP;
|
||||
+ case UNKNOWN_BEHAVIOR:
|
||||
+ return Goal.Flag.UNKNOWN_BEHAVIOR;
|
||||
+ case TARGET:
|
||||
+ return Goal.Flag.TARGET;
|
||||
+ default:
|
||||
+ throw new IllegalArgumentException("Unknown paper mob goal type " + type.name());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static <T extends Mob> GoalKey<T> getKey(Class<? extends Goal> goalClass) {
|
||||
+ String name = getUsableName(goalClass);
|
||||
+ if (ignored.contains(name)) {
|
||||
+ //noinspection unchecked
|
||||
+ return (GoalKey<T>) GoalKey.of(Mob.class, NamespacedKey.minecraft(name));
|
||||
+ }
|
||||
+ return GoalKey.of(getEntity(goalClass), NamespacedKey.minecraft(name));
|
||||
+ }
|
||||
+
|
||||
+ public static <T extends Mob> Class<T> getEntity(Class<? extends Goal> goalClass) {
|
||||
+ //noinspection unchecked
|
||||
+ return (Class<T>) entityClassCache.computeIfAbsent(goalClass, key -> {
|
||||
+ for (Constructor<?> ctor : key.getDeclaredConstructors()) {
|
||||
+ for (int i = 0; i < ctor.getParameterCount(); i++) {
|
||||
+ Class<?> param = ctor.getParameterTypes()[i];
|
||||
+ if (net.minecraft.world.entity.Mob.class.isAssignableFrom(param)) {
|
||||
+ //noinspection unchecked
|
||||
+ return toBukkitClass((Class<? extends net.minecraft.world.entity.Mob>) param);
|
||||
+ } else if (RangedAttackMob.class.isAssignableFrom(param)) {
|
||||
+ return RangedEntity.class;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ throw new RuntimeException("Can't figure out applicable entity for mob goal " + goalClass); // maybe just return EntityInsentient?
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ public static Class<? extends Mob> toBukkitClass(Class<? extends net.minecraft.world.entity.Mob> nmsClass) {
|
||||
+ Class<? extends Mob> bukkitClass = bukkitMap.get(nmsClass);
|
||||
+ if (bukkitClass == null) {
|
||||
+ throw new RuntimeException("Can't figure out applicable bukkit entity for nms entity " + nmsClass); // maybe just return Mob?
|
||||
+ }
|
||||
+ return bukkitClass;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/PaperCustomGoal.java b/src/main/java/com/destroystokyo/paper/entity/ai/PaperCustomGoal.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..b5f75ad725f5933db8f0688b2c0b27d620919241
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/PaperCustomGoal.java
|
||||
@@ -0,0 +1,53 @@
|
||||
+package com.destroystokyo.paper.entity.ai;
|
||||
+
|
||||
+import org.bukkit.entity.Mob;
|
||||
+
|
||||
+/**
|
||||
+ * Wraps api in vanilla
|
||||
+ */
|
||||
+public class PaperCustomGoal<T extends Mob> extends net.minecraft.world.entity.ai.goal.Goal {
|
||||
+
|
||||
+ private final Goal<T> handle;
|
||||
+
|
||||
+ public PaperCustomGoal(Goal<T> handle) {
|
||||
+ this.handle = handle;
|
||||
+
|
||||
+ this.setFlags(MobGoalHelper.paperToVanilla(handle.getTypes()));
|
||||
+ if (this.getFlags().size() == 0) {
|
||||
+ this.getFlags().add(Flag.UNKNOWN_BEHAVIOR);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean canUse() {
|
||||
+ return handle.shouldActivate();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean canContinueToUse() {
|
||||
+ return handle.shouldStayActive();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void start() {
|
||||
+ handle.start();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void stop() {
|
||||
+ handle.stop();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void tick() {
|
||||
+ handle.tick();
|
||||
+ }
|
||||
+
|
||||
+ public Goal<T> getHandle() {
|
||||
+ return handle;
|
||||
+ }
|
||||
+
|
||||
+ public GoalKey<T> getKey() {
|
||||
+ return handle.getKey();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/PaperMobGoals.java b/src/main/java/com/destroystokyo/paper/entity/ai/PaperMobGoals.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..30ed9ffd6a65914d7545636150a09327aba047c3
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/PaperMobGoals.java
|
||||
@@ -0,0 +1,224 @@
|
||||
+package com.destroystokyo.paper.entity.ai;
|
||||
+
|
||||
+import java.util.Collection;
|
||||
+import java.util.EnumSet;
|
||||
+import java.util.HashSet;
|
||||
+import java.util.LinkedList;
|
||||
+import java.util.List;
|
||||
+import java.util.Set;
|
||||
+import net.minecraft.world.entity.ai.goal.GoalSelector;
|
||||
+import net.minecraft.world.entity.ai.goal.WrappedGoal;
|
||||
+import org.bukkit.craftbukkit.entity.CraftMob;
|
||||
+import org.bukkit.entity.Mob;
|
||||
+
|
||||
+public class PaperMobGoals implements MobGoals {
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> void addGoal(T mob, int priority, Goal<T> goal) {
|
||||
+ CraftMob craftMob = (CraftMob) mob;
|
||||
+ net.minecraft.world.entity.ai.goal.Goal mojangGoal;
|
||||
+
|
||||
+ if (goal instanceof PaperVanillaGoal vanillaGoal) {
|
||||
+ mojangGoal = vanillaGoal.getHandle();
|
||||
+ } else {
|
||||
+ mojangGoal = new PaperCustomGoal<>(goal);
|
||||
+ }
|
||||
+
|
||||
+ getHandle(craftMob, goal.getTypes()).addGoal(priority, mojangGoal);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> void removeGoal(T mob, Goal<T> goal) {
|
||||
+ CraftMob craftMob = (CraftMob) mob;
|
||||
+ if (goal instanceof PaperCustomGoal) {
|
||||
+ getHandle(craftMob, goal.getTypes()).removeGoal((net.minecraft.world.entity.ai.goal.Goal) goal);
|
||||
+ } else if (goal instanceof PaperVanillaGoal) {
|
||||
+ getHandle(craftMob, goal.getTypes()).removeGoal(((PaperVanillaGoal<?>) goal).getHandle());
|
||||
+ } else {
|
||||
+ List<net.minecraft.world.entity.ai.goal.Goal> toRemove = new LinkedList<>();
|
||||
+ for (WrappedGoal item : getHandle(craftMob, goal.getTypes()).getAvailableGoals()) {
|
||||
+ if (item.getGoal() instanceof PaperCustomGoal) {
|
||||
+ //noinspection unchecked
|
||||
+ if (((PaperCustomGoal<T>) item.getGoal()).getHandle() == goal) {
|
||||
+ toRemove.add(item.getGoal());
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ for (net.minecraft.world.entity.ai.goal.Goal g : toRemove) {
|
||||
+ getHandle(craftMob, goal.getTypes()).removeGoal(g);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> void removeAllGoals(T mob) {
|
||||
+ for (GoalType type : GoalType.values()) {
|
||||
+ removeAllGoals(mob, type);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> void removeAllGoals(T mob, GoalType type) {
|
||||
+ for (Goal<T> goal : getAllGoals(mob, type)) {
|
||||
+ removeGoal(mob, goal);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> void removeGoal(T mob, GoalKey<T> key) {
|
||||
+ for (Goal<T> goal : getGoals(mob, key)) {
|
||||
+ removeGoal(mob, goal);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> boolean hasGoal(T mob, GoalKey<T> key) {
|
||||
+ for (Goal<T> g : getAllGoals(mob)) {
|
||||
+ if (g.getKey().equals(key)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> Goal<T> getGoal(T mob, GoalKey<T> key) {
|
||||
+ for (Goal<T> g : getAllGoals(mob)) {
|
||||
+ if (g.getKey().equals(key)) {
|
||||
+ return g;
|
||||
+ }
|
||||
+ }
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> Collection<Goal<T>> getGoals(T mob, GoalKey<T> key) {
|
||||
+ Set<Goal<T>> goals = new HashSet<>();
|
||||
+ for (Goal<T> g : getAllGoals(mob)) {
|
||||
+ if (g.getKey().equals(key)) {
|
||||
+ goals.add(g);
|
||||
+ }
|
||||
+ }
|
||||
+ return goals;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> Collection<Goal<T>> getAllGoals(T mob) {
|
||||
+ Set<Goal<T>> goals = new HashSet<>();
|
||||
+ for (GoalType type : GoalType.values()) {
|
||||
+ goals.addAll(getAllGoals(mob, type));
|
||||
+ }
|
||||
+ return goals;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> Collection<Goal<T>> getAllGoals(T mob, GoalType type) {
|
||||
+ CraftMob craftMob = (CraftMob) mob;
|
||||
+ Set<Goal<T>> goals = new HashSet<>();
|
||||
+ for (WrappedGoal item : getHandle(craftMob, type).getAvailableGoals()) {
|
||||
+ if (!item.getGoal().getFlags().contains(MobGoalHelper.paperToVanilla(type))) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (item.getGoal() instanceof PaperCustomGoal) {
|
||||
+ //noinspection unchecked
|
||||
+ goals.add(((PaperCustomGoal<T>) item.getGoal()).getHandle());
|
||||
+ } else {
|
||||
+ goals.add(item.getGoal().asPaperVanillaGoal());
|
||||
+ }
|
||||
+ }
|
||||
+ return goals;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> Collection<Goal<T>> getAllGoalsWithout(T mob, GoalType type) {
|
||||
+ CraftMob craftMob = (CraftMob) mob;
|
||||
+ Set<Goal<T>> goals = new HashSet<>();
|
||||
+ for (GoalType internalType : GoalType.values()) {
|
||||
+ if (internalType == type) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ for (WrappedGoal item : getHandle(craftMob, internalType).getAvailableGoals()) {
|
||||
+ if (item.getGoal().getFlags().contains(MobGoalHelper.paperToVanilla(type))) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (item.getGoal() instanceof PaperCustomGoal) {
|
||||
+ //noinspection unchecked
|
||||
+ goals.add(((PaperCustomGoal<T>) item.getGoal()).getHandle());
|
||||
+ } else {
|
||||
+ goals.add(item.getGoal().asPaperVanillaGoal());
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return goals;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> Collection<Goal<T>> getRunningGoals(T mob) {
|
||||
+ Set<Goal<T>> goals = new HashSet<>();
|
||||
+ for (GoalType type : GoalType.values()) {
|
||||
+ goals.addAll(getRunningGoals(mob, type));
|
||||
+ }
|
||||
+ return goals;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> Collection<Goal<T>> getRunningGoals(T mob, GoalType type) {
|
||||
+ CraftMob craftMob = (CraftMob) mob;
|
||||
+ Set<Goal<T>> goals = new HashSet<>();
|
||||
+ getHandle(craftMob, type).getAvailableGoals()
|
||||
+ .stream().filter(WrappedGoal::isRunning)
|
||||
+ .filter(item -> item.getGoal().getFlags().contains(MobGoalHelper.paperToVanilla(type)))
|
||||
+ .forEach(item -> {
|
||||
+ if (item.getGoal() instanceof PaperCustomGoal) {
|
||||
+ //noinspection unchecked
|
||||
+ goals.add(((PaperCustomGoal<T>) item.getGoal()).getHandle());
|
||||
+ } else {
|
||||
+ goals.add(item.getGoal().asPaperVanillaGoal());
|
||||
+ }
|
||||
+ });
|
||||
+ return goals;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> Collection<Goal<T>> getRunningGoalsWithout(T mob, GoalType type) {
|
||||
+ CraftMob craftMob = (CraftMob) mob;
|
||||
+ Set<Goal<T>> goals = new HashSet<>();
|
||||
+ for (GoalType internalType : GoalType.values()) {
|
||||
+ if (internalType == type) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ getHandle(craftMob, internalType).getAvailableGoals()
|
||||
+ .stream()
|
||||
+ .filter(WrappedGoal::isRunning)
|
||||
+ .filter(item -> !item.getGoal().getFlags().contains(MobGoalHelper.paperToVanilla(type)))
|
||||
+ .forEach(item -> {
|
||||
+ if (item.getGoal() instanceof PaperCustomGoal) {
|
||||
+ //noinspection unchecked
|
||||
+ goals.add(((PaperCustomGoal<T>) item.getGoal()).getHandle());
|
||||
+ } else {
|
||||
+ goals.add(item.getGoal().asPaperVanillaGoal());
|
||||
+ }
|
||||
+ });
|
||||
+ }
|
||||
+ return goals;
|
||||
+ }
|
||||
+
|
||||
+ private GoalSelector getHandle(CraftMob mob, EnumSet<GoalType> types) {
|
||||
+ if (types.contains(GoalType.TARGET)) {
|
||||
+ return mob.getHandle().targetSelector;
|
||||
+ } else {
|
||||
+ return mob.getHandle().goalSelector;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private GoalSelector getHandle(CraftMob mob, GoalType type) {
|
||||
+ if (type == GoalType.TARGET) {
|
||||
+ return mob.getHandle().targetSelector;
|
||||
+ } else {
|
||||
+ return mob.getHandle().goalSelector;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/PaperVanillaGoal.java b/src/main/java/com/destroystokyo/paper/entity/ai/PaperVanillaGoal.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..b5c594a5499556ad452d9939c75e150af8252e90
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/PaperVanillaGoal.java
|
||||
@@ -0,0 +1,61 @@
|
||||
+package com.destroystokyo.paper.entity.ai;
|
||||
+
|
||||
+import java.util.EnumSet;
|
||||
+import net.minecraft.world.entity.ai.goal.Goal;
|
||||
+import org.bukkit.entity.Mob;
|
||||
+
|
||||
+/**
|
||||
+ * Wraps vanilla in api
|
||||
+ */
|
||||
+public class PaperVanillaGoal<T extends Mob> implements VanillaGoal<T> {
|
||||
+
|
||||
+ private final Goal handle;
|
||||
+ private final GoalKey<T> key;
|
||||
+
|
||||
+ private final EnumSet<GoalType> types;
|
||||
+
|
||||
+ public PaperVanillaGoal(Goal handle) {
|
||||
+ this.handle = handle;
|
||||
+ this.key = MobGoalHelper.getKey(handle.getClass());
|
||||
+ this.types = MobGoalHelper.vanillaToPaper(handle);
|
||||
+ }
|
||||
+
|
||||
+ public Goal getHandle() {
|
||||
+ return handle;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean shouldActivate() {
|
||||
+ return handle.canUse();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean shouldStayActive() {
|
||||
+ return handle.canContinueToUse();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void start() {
|
||||
+ handle.start();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void stop() {
|
||||
+ handle.stop();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void tick() {
|
||||
+ handle.tick();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public GoalKey<T> getKey() {
|
||||
+ return key;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public EnumSet<GoalType> getTypes() {
|
||||
+ return types;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java b/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
|
||||
index 6667ecc4b7eded4e20a415cef1e1b1179e6710b8..16f9a98b8a939e5ca7e2dc04f87134a7ed66736b 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
|
||||
@@ -51,7 +51,19 @@ public abstract class Goal {
|
||||
return Mth.positiveCeilDiv(serverTicks, 2);
|
||||
}
|
||||
|
||||
+ // Paper start - Mob goal api
|
||||
+ private com.destroystokyo.paper.entity.ai.PaperVanillaGoal<?> vanillaGoal;
|
||||
+ public <T extends org.bukkit.entity.Mob> com.destroystokyo.paper.entity.ai.Goal<T> asPaperVanillaGoal() {
|
||||
+ if(this.vanillaGoal == null) {
|
||||
+ this.vanillaGoal = new com.destroystokyo.paper.entity.ai.PaperVanillaGoal<>(this);
|
||||
+ }
|
||||
+ //noinspection unchecked
|
||||
+ return (com.destroystokyo.paper.entity.ai.Goal<T>) this.vanillaGoal;
|
||||
+ }
|
||||
+ // Paper end - Mob goal api
|
||||
+
|
||||
public static enum Flag {
|
||||
+ UNKNOWN_BEHAVIOR, // Paper - add UNKNOWN_BEHAVIOR
|
||||
MOVE,
|
||||
LOOK,
|
||||
JUMP,
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 093c2159eb9d9603b5e3f0d420769d6b9d872be8..7eaf0f56cbf0695132a029b0a208f283f43e47b5 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2931,5 +2931,11 @@ public final class CraftServer implements Server {
|
||||
public boolean isStopping() {
|
||||
return net.minecraft.server.MinecraftServer.getServer().hasStopped();
|
||||
}
|
||||
+
|
||||
+ private com.destroystokyo.paper.entity.ai.MobGoals mobGoals = new com.destroystokyo.paper.entity.ai.PaperMobGoals();
|
||||
+ @Override
|
||||
+ public com.destroystokyo.paper.entity.ai.MobGoals getMobGoals() {
|
||||
+ return mobGoals;
|
||||
+ }
|
||||
// Paper end
|
||||
}
|
122
patches/server/0358-Add-villager-reputation-API.patch
Normal file
122
patches/server/0358-Add-villager-reputation-API.patch
Normal file
|
@ -0,0 +1,122 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mariell Hoversholm <proximyst@proximyst.com>
|
||||
Date: Wed, 22 Apr 2020 23:29:20 +0200
|
||||
Subject: [PATCH] Add villager reputation API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.ai.gossip.GossipContainer$EntityGossips
|
||||
public net.minecraft.world.entity.ai.gossip.GossipContainer$EntityGossips <init>()V
|
||||
public net.minecraft.world.entity.ai.gossip.GossipContainer gossips
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
index f06a5f0d9c5c877ddf963254d3124f5fe2d67282..aa32804bc9affe9a615d3ffaa513f6f09aab3f32 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
@@ -216,6 +216,43 @@ public class GossipContainer {
|
||||
public void remove(GossipType gossipType) {
|
||||
this.entries.removeInt(gossipType);
|
||||
}
|
||||
+
|
||||
+ // Paper start - Add villager reputation API
|
||||
+ private static final GossipType[] TYPES = GossipType.values();
|
||||
+ public com.destroystokyo.paper.entity.villager.Reputation getPaperReputation() {
|
||||
+ Map<com.destroystokyo.paper.entity.villager.ReputationType, Integer> map = new java.util.EnumMap<>(com.destroystokyo.paper.entity.villager.ReputationType.class);
|
||||
+ for (Object2IntMap.Entry<GossipType> type : this.entries.object2IntEntrySet()) {
|
||||
+ map.put(toApi(type.getKey()), type.getIntValue());
|
||||
+ }
|
||||
+
|
||||
+ return new com.destroystokyo.paper.entity.villager.Reputation(map);
|
||||
+ }
|
||||
+
|
||||
+ public void assignFromPaperReputation(com.destroystokyo.paper.entity.villager.Reputation rep) {
|
||||
+ for (GossipType type : TYPES) {
|
||||
+ com.destroystokyo.paper.entity.villager.ReputationType api = toApi(type);
|
||||
+
|
||||
+ if (rep.hasReputationSet(api)) {
|
||||
+ int reputation = rep.getReputation(api);
|
||||
+ if (reputation == 0) {
|
||||
+ this.entries.removeInt(type);
|
||||
+ } else {
|
||||
+ this.entries.put(type, reputation);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static com.destroystokyo.paper.entity.villager.ReputationType toApi(GossipType type) {
|
||||
+ return switch (type) {
|
||||
+ case MAJOR_NEGATIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MAJOR_NEGATIVE;
|
||||
+ case MINOR_NEGATIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MINOR_NEGATIVE;
|
||||
+ case MINOR_POSITIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MINOR_POSITIVE;
|
||||
+ case MAJOR_POSITIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MAJOR_POSITIVE;
|
||||
+ case TRADING -> com.destroystokyo.paper.entity.villager.ReputationType.TRADING;
|
||||
+ };
|
||||
+ }
|
||||
+ // Paper end - Add villager reputation API
|
||||
}
|
||||
|
||||
static record GossipEntry(UUID target, GossipType type, int value) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
index 423f6fcaf49252553d2285308633f13e2427b607..00fb708bce2c79817cd9fccadec72f07f0d26317 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
@@ -18,6 +18,13 @@ import org.bukkit.entity.Villager;
|
||||
import org.bukkit.entity.ZombieVillager;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
|
||||
+// Paper start
|
||||
+import com.destroystokyo.paper.entity.villager.Reputation;
|
||||
+import com.google.common.collect.Maps;
|
||||
+import java.util.Map;
|
||||
+import java.util.UUID;
|
||||
+// Paper end
|
||||
+
|
||||
public class CraftVillager extends CraftAbstractVillager implements Villager {
|
||||
|
||||
public CraftVillager(CraftServer server, net.minecraft.world.entity.npc.Villager entity) {
|
||||
@@ -176,4 +183,45 @@ public class CraftVillager extends CraftAbstractVillager implements Villager {
|
||||
.getOptional(CraftNamespacedKey.toMinecraft(bukkit.getKey())).orElseThrow();
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // Paper start - Add villager reputation API
|
||||
+ @Override
|
||||
+ public Reputation getReputation(UUID uniqueId) {
|
||||
+ net.minecraft.world.entity.ai.gossip.GossipContainer.EntityGossips rep = getHandle().getGossips().gossips.get(uniqueId);
|
||||
+ if (rep == null) {
|
||||
+ return new Reputation(new java.util.EnumMap<>(com.destroystokyo.paper.entity.villager.ReputationType.class));
|
||||
+ }
|
||||
+
|
||||
+ return rep.getPaperReputation();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Map<UUID, Reputation> getReputations() {
|
||||
+ return getHandle().getGossips().gossips.entrySet()
|
||||
+ .stream()
|
||||
+ .collect(java.util.stream.Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getPaperReputation()));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setReputation(UUID uniqueId, Reputation reputation) {
|
||||
+ net.minecraft.world.entity.ai.gossip.GossipContainer.EntityGossips nmsReputation =
|
||||
+ getHandle().getGossips().gossips.computeIfAbsent(
|
||||
+ uniqueId,
|
||||
+ key -> new net.minecraft.world.entity.ai.gossip.GossipContainer.EntityGossips()
|
||||
+ );
|
||||
+ nmsReputation.assignFromPaperReputation(reputation);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setReputations(Map<UUID, Reputation> reputations) {
|
||||
+ for (Map.Entry<UUID, Reputation> entry : reputations.entrySet()) {
|
||||
+ setReputation(entry.getKey(), entry.getValue());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void clearReputations() {
|
||||
+ getHandle().getGossips().gossips.clear();
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Fri, 10 Nov 2017 23:03:12 -0500
|
||||
Subject: [PATCH] ExperienceOrb merging/stacking API and fixes
|
||||
|
||||
Adds an option for maximum exp value when merging orbs
|
||||
|
||||
Adds ExperienceOrbMergeEvent
|
||||
Fired when the server is about to merge 2 experience orbs
|
||||
as entities. Plugins can cancel it if they want to ensure experience orbs do not lose important
|
||||
metadata such as spawn reason, or conditionally move data from source to target.
|
||||
|
||||
Fixes an issue where the stacked count was not taking into account
|
||||
for mending repairs and when merging with spigot's merge-on-spawn
|
||||
logic
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.ExperienceOrb count
|
||||
|
||||
Co-authored-by: Aikar <aikar@aikar.co>
|
||||
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
|
||||
index 0916e24271d07ad5db51c5bc68791722b0f69c2b..a758b2456acac23095fe4619ae10300a034cb460 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
|
||||
@@ -244,6 +244,7 @@ public class ExperienceOrb extends Entity {
|
||||
}
|
||||
|
||||
private static boolean tryMergeToExisting(ServerLevel world, Vec3 pos, int amount) {
|
||||
+ // Paper - TODO some other event for this kind of merge
|
||||
AABB axisalignedbb = AABB.ofSize(pos, 1.0D, 1.0D, 1.0D);
|
||||
int j = world.getRandom().nextInt(40);
|
||||
List<ExperienceOrb> list = world.getEntities(EntityTypeTest.forClass(ExperienceOrb.class), axisalignedbb, (entityexperienceorb) -> {
|
||||
@@ -270,6 +271,11 @@ public class ExperienceOrb extends Entity {
|
||||
}
|
||||
|
||||
private void merge(ExperienceOrb other) {
|
||||
+ // Paper start - call orb merge event
|
||||
+ if (!new com.destroystokyo.paper.event.entity.ExperienceOrbMergeEvent((org.bukkit.entity.ExperienceOrb) this.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) other.getBukkitEntity()).callEvent()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - call orb merge event
|
||||
this.count += other.count;
|
||||
this.age = Math.min(this.age, other.age);
|
||||
other.discard(EntityRemoveEvent.Cause.MERGE); // CraftBukkit - add Bukkit remove cause
|
||||
@@ -360,7 +366,7 @@ public class ExperienceOrb extends Entity {
|
||||
int l = amount - k * amount / j;
|
||||
|
||||
if (l > 0) {
|
||||
- this.value = l; // CraftBukkit - update exp value of orb for PlayerItemMendEvent calls
|
||||
+ // this.value = l; // CraftBukkit - update exp value of orb for PlayerItemMendEvent calls // Paper - the value field should not be mutated here because it doesn't take "count" into account
|
||||
return this.repairPlayerItems(player, l);
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java
|
||||
index 5a7d314ec0562e472f5dc45924a7b24841cff126..650e4a01cecc4cc08e7ff9ebcc4c367084351f21 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java
|
||||
@@ -18,6 +18,18 @@ public class CraftExperienceOrb extends CraftEntity implements ExperienceOrb {
|
||||
this.getHandle().value = value;
|
||||
}
|
||||
|
||||
+ // Paper start - expose count
|
||||
+ @Override
|
||||
+ public int getCount() {
|
||||
+ return this.getHandle().count;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setCount(final int count) {
|
||||
+ this.getHandle().count = count;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
// Paper start
|
||||
public java.util.UUID getTriggerEntityId() {
|
||||
return getHandle().triggerEntityId;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
index 4552a77e84d3c957431a918ca78dcf2e06f2e74c..805aec84b57f0a426c1337445dfdd084cb0a0507 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -704,15 +704,29 @@ public class CraftEventFactory {
|
||||
if (entity instanceof net.minecraft.world.entity.ExperienceOrb xp) {
|
||||
double radius = world.spigotConfig.expMerge;
|
||||
if (radius > 0) {
|
||||
+ // Paper start - Maximum exp value when merging; Whole section has been tweaked, see comments for specifics
|
||||
+ final long maxValue = world.paperConfig().entities.behavior.experienceMergeMaxValue;
|
||||
+ final boolean mergeUnconditionally = maxValue <= 0;
|
||||
+ if (mergeUnconditionally || xp.value < maxValue) { // Paper - Skip iteration if unnecessary
|
||||
+
|
||||
List<Entity> entities = world.getEntities(entity, entity.getBoundingBox().inflate(radius, radius, radius));
|
||||
for (Entity e : entities) {
|
||||
if (e instanceof net.minecraft.world.entity.ExperienceOrb loopItem) {
|
||||
- if (!loopItem.isRemoved()) {
|
||||
+ // Paper start
|
||||
+ if (!loopItem.isRemoved() && xp.count == loopItem.count && (mergeUnconditionally || loopItem.value < maxValue) && new com.destroystokyo.paper.event.entity.ExperienceOrbMergeEvent((org.bukkit.entity.ExperienceOrb) entity.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) loopItem.getBukkitEntity()).callEvent()) { // Paper - ExperienceOrbMergeEvent
|
||||
+ long newTotal = (long)xp.value + (long)loopItem.value;
|
||||
+ if ((int) newTotal < 0) continue; // Overflow
|
||||
+ if (!mergeUnconditionally && newTotal > maxValue) {
|
||||
+ loopItem.value = (int) (newTotal - maxValue);
|
||||
+ xp.value = (int) maxValue;
|
||||
+ } else {
|
||||
xp.value += loopItem.value;
|
||||
loopItem.discard(null); // Add Bukkit remove cause
|
||||
+ } // Paper end - Maximum exp value when merging
|
||||
}
|
||||
}
|
||||
}
|
||||
+ } // Paper end - End iteration skip check - All tweaking ends here
|
||||
}
|
||||
}
|
||||
// Spigot end
|
60
patches/server/0360-Fix-PotionEffect-ignores-icon-flag.patch
Normal file
60
patches/server/0360-Fix-PotionEffect-ignores-icon-flag.patch
Normal file
|
@ -0,0 +1,60 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kickash32 <kickash32@gmail.com>
|
||||
Date: Fri, 8 May 2020 00:49:18 -0400
|
||||
Subject: [PATCH] Fix PotionEffect ignores icon flag
|
||||
|
||||
Co-authored-by: Tamion <70228790+notTamion@users.noreply.github.com>
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
index ccb779066fb5f3ebf9e4bdabdffc9c18c1a75cbb..1544242abfbd0f9accf5fe515a95d9ac0db50d4f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
@@ -484,7 +484,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
|
||||
|
||||
@Override
|
||||
public boolean addPotionEffect(PotionEffect effect, boolean force) {
|
||||
- this.getHandle().addEffect(new MobEffectInstance(CraftPotionEffectType.bukkitToMinecraftHolder(effect.getType()), effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles()), EntityPotionEffectEvent.Cause.PLUGIN);
|
||||
+ this.getHandle().addEffect(org.bukkit.craftbukkit.potion.CraftPotionUtil.fromBukkit(effect), EntityPotionEffectEvent.Cause.PLUGIN); // Paper - Don't ignore icon
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -505,7 +505,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
|
||||
@Override
|
||||
public PotionEffect getPotionEffect(PotionEffectType type) {
|
||||
MobEffectInstance handle = this.getHandle().getEffect(CraftPotionEffectType.bukkitToMinecraftHolder(type));
|
||||
- return (handle == null) ? null : new PotionEffect(CraftPotionEffectType.minecraftHolderToBukkit(handle.getEffect()), handle.getDuration(), handle.getAmplifier(), handle.isAmbient(), handle.isVisible());
|
||||
+ return (handle == null) ? null : org.bukkit.craftbukkit.potion.CraftPotionUtil.toBukkit(handle); // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -517,7 +517,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
|
||||
public Collection<PotionEffect> getActivePotionEffects() {
|
||||
List<PotionEffect> effects = new ArrayList<PotionEffect>();
|
||||
for (MobEffectInstance handle : this.getHandle().activeEffects.values()) {
|
||||
- effects.add(new PotionEffect(CraftPotionEffectType.minecraftHolderToBukkit(handle.getEffect()), handle.getDuration(), handle.getAmplifier(), handle.isAmbient(), handle.isVisible()));
|
||||
+ effects.add(org.bukkit.craftbukkit.potion.CraftPotionUtil.toBukkit(handle)); // Paper
|
||||
}
|
||||
return effects;
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java
|
||||
index b7525f6ddc8f315ec9830b6b8f225d4839d306ad..01af4db5d0f17ea2943e5c464d4122a358503bc1 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java
|
||||
@@ -78,7 +78,7 @@ public class CraftPotionUtil {
|
||||
|
||||
public static MobEffectInstance fromBukkit(PotionEffect effect) {
|
||||
Holder<MobEffect> type = CraftPotionEffectType.bukkitToMinecraftHolder(effect.getType());
|
||||
- return new MobEffectInstance(type, effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles());
|
||||
+ return new MobEffectInstance(type, effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles(), effect.hasIcon()); // Paper
|
||||
}
|
||||
|
||||
public static PotionEffect toBukkit(MobEffectInstance effect) {
|
||||
@@ -87,7 +87,7 @@ public class CraftPotionUtil {
|
||||
int duration = effect.getDuration();
|
||||
boolean ambient = effect.isAmbient();
|
||||
boolean particles = effect.isVisible();
|
||||
- return new PotionEffect(type, duration, amp, ambient, particles);
|
||||
+ return new PotionEffect(type, duration, amp, ambient, particles, effect.showIcon()); // Paper
|
||||
}
|
||||
|
||||
public static boolean equals(Holder<MobEffect> mobEffect, PotionEffectType type) {
|
44
patches/server/0361-Potential-bed-API.patch
Normal file
44
patches/server/0361-Potential-bed-API.patch
Normal file
|
@ -0,0 +1,44 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: JRoy <joshroy126@gmail.com>
|
||||
Date: Sun, 10 May 2020 23:06:30 -0400
|
||||
Subject: [PATCH] Potential bed API
|
||||
|
||||
Adds a new method to fetch the location of a player's bed without generating any sync loads.
|
||||
|
||||
getPotentialBedLocation - Gets the last known location of a player's bed. This does not preform any check if the bed is still valid and does not load any chunks.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
index eb2d39d408e7f46a8f047a2b0d76981f24e1320a..bbd3f0981eb95348ef12c9af8fa1712c022ed869 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
@@ -12,6 +12,7 @@ import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket;
|
||||
import net.minecraft.network.protocol.game.ServerboundContainerClosePacket;
|
||||
+import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.MenuProvider;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
@@ -129,6 +130,22 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
|
||||
return this.getHandle().sleepCounter;
|
||||
}
|
||||
|
||||
+ // Paper start - Potential bed api
|
||||
+ @Override
|
||||
+ public Location getPotentialBedLocation() {
|
||||
+ ServerPlayer handle = (ServerPlayer) getHandle();
|
||||
+ BlockPos bed = handle.getRespawnPosition();
|
||||
+ if (bed == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ ServerLevel worldServer = handle.server.getLevel(handle.getRespawnDimension());
|
||||
+ if (worldServer == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ return new Location(worldServer.getWorld(), bed.getX(), bed.getY(), bed.getZ());
|
||||
+ }
|
||||
+ // Paper end
|
||||
@Override
|
||||
public boolean sleep(Location location, boolean force) {
|
||||
Preconditions.checkArgument(location != null, "Location cannot be null");
|
|
@ -0,0 +1,60 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 10 May 2020 22:16:17 -0400
|
||||
Subject: [PATCH] Wait for Async Tasks during shutdown
|
||||
|
||||
Server.reload() had this logic to give time for tasks to shutdown,
|
||||
however shutdown did not...
|
||||
|
||||
Adds a 5 second grace period for any async tasks to finish and warns
|
||||
if any are still running after that delay just as reload does.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 15938074ad20133f5ccdab0c8566556d7b807d8f..095215a5cbf1abeb7836a6ccc87c195019a7f019 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -943,6 +943,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
// CraftBukkit start
|
||||
if (this.server != null) {
|
||||
this.server.disablePlugins();
|
||||
+ this.server.waitForAsyncTasksShutdown(); // Paper - Wait for Async Tasks during shutdown
|
||||
}
|
||||
// CraftBukkit end
|
||||
if (io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper != null) io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper.shutdown(); // Paper - Plugin remapping
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 7eaf0f56cbf0695132a029b0a208f283f43e47b5..118708bd917518333359ce1407e1e26e4ec6a180 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -1050,6 +1050,32 @@ public final class CraftServer implements Server {
|
||||
org.spigotmc.WatchdogThread.hasStarted = true; // Paper - Disable watchdog early timeout on reload
|
||||
}
|
||||
|
||||
+ // Paper start - Wait for Async Tasks during shutdown
|
||||
+ public void waitForAsyncTasksShutdown() {
|
||||
+ int pollCount = 0;
|
||||
+
|
||||
+ // Wait for at most 5 seconds for plugins to close their threads
|
||||
+ while (pollCount < 10*5 && getScheduler().getActiveWorkers().size() > 0) {
|
||||
+ try {
|
||||
+ Thread.sleep(100);
|
||||
+ } catch (InterruptedException e) {}
|
||||
+ pollCount++;
|
||||
+ }
|
||||
+
|
||||
+ List<BukkitWorker> overdueWorkers = getScheduler().getActiveWorkers();
|
||||
+ for (BukkitWorker worker : overdueWorkers) {
|
||||
+ Plugin plugin = worker.getOwner();
|
||||
+ getLogger().log(Level.SEVERE, String.format(
|
||||
+ "Nag author(s): '%s' of '%s' about the following: %s",
|
||||
+ plugin.getPluginMeta().getAuthors(),
|
||||
+ plugin.getPluginMeta().getDisplayName(),
|
||||
+ "This plugin is not properly shutting down its async tasks when it is being shut down. This task may throw errors during the final shutdown logs and might not complete before process dies."
|
||||
+ ));
|
||||
+ if (console.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread(worker.getThread(), "still running"); // Paper - Debugging
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Wait for Async Tasks during shutdown
|
||||
+
|
||||
@Override
|
||||
public void reloadData() {
|
||||
ReloadCommand.reload(this.console);
|
|
@ -0,0 +1,19 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kickash32 <kickash32@gmail.com>
|
||||
Date: Sat, 9 May 2020 02:01:48 -0400
|
||||
Subject: [PATCH] Ensure EntityRaider respects game and entity rules for
|
||||
picking up items
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/raid/Raider.java b/src/main/java/net/minecraft/world/entity/raid/Raider.java
|
||||
index 6fb56c826f0eaf76ab7896f784084b4fb1b3d105..e5dff812dc979ecf71939a85b2213965d15e7954 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/raid/Raider.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/raid/Raider.java
|
||||
@@ -292,6 +292,7 @@ public abstract class Raider extends PatrollingMonster {
|
||||
|
||||
@Override
|
||||
public boolean canUse() {
|
||||
+ if (!this.mob.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) || !this.mob.canPickUpLoot()) return false; // Paper - respect game and entity rules for picking up items
|
||||
Raid raid = this.mob.getCurrentRaid();
|
||||
|
||||
if (this.mob.hasActiveRaid() && !this.mob.getCurrentRaid().isOver() && this.mob.canBeLeader() && !ItemStack.matches(this.mob.getItemBySlot(EquipmentSlot.HEAD), Raid.getLeaderBannerInstance(this.mob.registryAccess().lookupOrThrow(Registries.BANNER_PATTERN)))) {
|
|
@ -0,0 +1,47 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mariell Hoversholm <proximyst@proximyst.com>
|
||||
Date: Sat, 16 May 2020 10:12:15 +0200
|
||||
Subject: [PATCH] Add option for console having all permissions
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java b/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java
|
||||
index 324e6d1a4fadd3e557e4ba05f04e6a5891cc54df..4e56018b64d11f76c8da43fd8f85c6de72204e36 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java
|
||||
@@ -93,5 +93,15 @@ public class CraftConsoleCommandSender extends ServerCommandSender implements Co
|
||||
public void sendMessage(final net.kyori.adventure.identity.Identity identity, final net.kyori.adventure.text.Component message, final net.kyori.adventure.audience.MessageType type) {
|
||||
this.sendRawMessage(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(message));
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasPermission(String name) {
|
||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().console.hasAllPermissions || super.hasPermission(name);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasPermission(org.bukkit.permissions.Permission perm) {
|
||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().console.hasAllPermissions || super.hasPermission(perm);
|
||||
+ }
|
||||
// Paper end
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/command/CraftRemoteConsoleCommandSender.java b/src/main/java/org/bukkit/craftbukkit/command/CraftRemoteConsoleCommandSender.java
|
||||
index 5b7d230103f421fb939072e1526854f715430e51..b5e325a7b2d3f49299b35e233ed6539b5bfc3465 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/command/CraftRemoteConsoleCommandSender.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/command/CraftRemoteConsoleCommandSender.java
|
||||
@@ -55,4 +55,16 @@ public class CraftRemoteConsoleCommandSender extends ServerCommandSender impleme
|
||||
public void setOp(boolean value) {
|
||||
throw new UnsupportedOperationException("Cannot change operator status of remote controller.");
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public boolean hasPermission(String name) {
|
||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().console.hasAllPermissions || super.hasPermission(name);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasPermission(org.bukkit.permissions.Permission perm) {
|
||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().console.hasAllPermissions || super.hasPermission(perm);
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: chickeneer <emcchickeneer@gmail.com>
|
||||
Date: Fri, 5 Jun 2020 20:02:04 -0500
|
||||
Subject: [PATCH] Fix villager trading demand - MC-163962
|
||||
|
||||
Prevent demand from going negative and tending to negative infinity
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java
|
||||
index 44808589939afe50d8294269b7da12019acd2690..89982d25f60c8b60ba91e559ef88278f338fe215 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java
|
||||
@@ -124,7 +124,7 @@ public class MerchantOffer {
|
||||
}
|
||||
|
||||
public void updateDemand() {
|
||||
- this.demand = this.demand + this.uses - (this.maxUses - this.uses);
|
||||
+ this.demand = Math.max(0, this.demand + this.uses - (this.maxUses - this.uses)); // Paper - Fix MC-163962
|
||||
}
|
||||
|
||||
public ItemStack assemble() {
|
31
patches/server/0366-Maps-shouldn-t-load-chunks.patch
Normal file
31
patches/server/0366-Maps-shouldn-t-load-chunks.patch
Normal file
|
@ -0,0 +1,31 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Phoenix616 <mail@moep.tv>
|
||||
Date: Sun, 7 Jun 2020 21:43:42 +0100
|
||||
Subject: [PATCH] Maps shouldn't load chunks
|
||||
|
||||
Previously maps would load all chunks in a certain radius depending on
|
||||
their scale when trying to update their content. This would result in
|
||||
main thread chunk loads when they weren't really necessary, especially
|
||||
on low view distances or "slow" async chunk loads after teleports or
|
||||
other prioritisation.
|
||||
|
||||
This changes it to only try to render already loaded chunks based on
|
||||
the assumption that the chunks around the player will get loaded
|
||||
eventually anyways and that maps will get checked for update every
|
||||
five ticks that movement occur in anyways.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/item/MapItem.java b/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
index 4e6d42051de14a1a62184fbb586ea38fb31261b3..36de7c63370c529579d31ba1d77ec12b754ef313 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
@@ -98,8 +98,8 @@ public class MapItem extends ComplexItem {
|
||||
int r = (j / i + o - 64) * i;
|
||||
int s = (k / i + p - 64) * i;
|
||||
Multiset<MapColor> multiset = LinkedHashMultiset.create();
|
||||
- LevelChunk levelChunk = world.getChunk(SectionPos.blockToSectionCoord(r), SectionPos.blockToSectionCoord(s));
|
||||
- if (!levelChunk.isEmpty()) {
|
||||
+ LevelChunk levelChunk = world.getChunkIfLoaded(SectionPos.blockToSectionCoord(r), SectionPos.blockToSectionCoord(s)); // Paper - Maps shouldn't load chunks
|
||||
+ if (levelChunk != null && !levelChunk.isEmpty()) { // Paper - Maps shouldn't load chunks
|
||||
int t = 0;
|
||||
double e = 0.0;
|
||||
if (world.dimensionType().hasCeiling()) {
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue