385
This commit is contained in:
parent
ec05cb8b38
commit
0bc9aeef26
122 changed files with 402 additions and 448 deletions
|
@ -1,56 +0,0 @@
|
|||
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 04a9c48b9a9895ffe6ec0721bdfafb1b524bf386..e728b9f317d12c3c452db70ba7d1e930c84e345d 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
|
||||
@@ -3134,7 +3135,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);
|
|
@ -1,18 +0,0 @@
|
|||
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 f472d6eb337de1274424dabe39d4e8a094710165..f91e145a748dc524e1e95ee3afe00aa74a1aee9a 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -1157,6 +1157,7 @@ public abstract class PlayerList {
|
||||
}
|
||||
|
||||
public void setUsingWhiteList(boolean whitelistEnabled) {
|
||||
+ new com.destroystokyo.paper.event.server.WhitelistToggleEvent(whitelistEnabled).callEvent(); // Paper - WhitelistToggleEvent
|
||||
this.doWhiteList = whitelistEnabled;
|
||||
}
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
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 42dd9ab70c07e92258da70ad29b51c7780401a5d..2b524c41daa4fe1605a40c151a90de101d96e8af 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1209,6 +1209,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 f91e145a748dc524e1e95ee3afe00aa74a1aee9a..e3ce13685499e2adea5b776ec4abbdd978b6af58 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());
|
||||
|
||||
@@ -355,7 +360,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 ea8abc813809360b51cd67072d12efa03f4b4f20..7544a013111a830618371b9b929c950d8f791bd8 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -241,6 +241,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;
|
||||
|
||||
@@ -2205,6 +2206,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);
|
||||
@@ -2351,6 +2355,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 570957f00ad4817d5631c72060e85f85af634619..baa876db3a58a3c756a72ef1ad081964b358f58e 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
|
||||
@@ -183,7 +183,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 621970006f21d219784dc58d7aa8d6062c4620f1..571b8352de4070622cdc47a50643beada0b16c36 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
@@ -1001,4 +1001,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
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
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);
|
|
@ -1,48 +0,0 @@
|
|||
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 e3ce13685499e2adea5b776ec4abbdd978b6af58..8ce2826b1ded161a8220273d1fc5260ed3b6772f 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -751,9 +751,14 @@ public abstract class PlayerList {
|
||||
|
||||
boolean flag2 = false;
|
||||
|
||||
+ // Paper start - Add PlayerPostRespawnEvent
|
||||
+ boolean isBedSpawn = false;
|
||||
+ boolean isRespawn = false;
|
||||
+ // Paper end - Add PlayerPostRespawnEvent
|
||||
+
|
||||
// CraftBukkit start - fire PlayerRespawnEvent
|
||||
if (location == null) {
|
||||
- boolean isBedSpawn = false;
|
||||
+ // boolean isBedSpawn = false; // Paper - Add PlayerPostRespawnEvent; moved up
|
||||
ServerLevel worldserver1 = this.server.getLevel(entityplayer.getRespawnDimension());
|
||||
if (worldserver1 != null) {
|
||||
Optional optional;
|
||||
@@ -805,6 +810,7 @@ public abstract class PlayerList {
|
||||
|
||||
location = respawnEvent.getRespawnLocation();
|
||||
if (!flag) entityplayer.reset(); // SPIGOT-4785
|
||||
+ isRespawn = true; // Paper - Add PlayerPostRespawnEvent
|
||||
} else {
|
||||
location.setWorld(worldserver.getWorld());
|
||||
}
|
||||
@@ -863,6 +869,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;
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
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 d97e12a2dca072ae102b029fb67472dacc2c5b40..f0e6375236d61f32235ed23c3bae49db1545d1a2 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
@@ -148,6 +148,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
|
||||
@@ -233,6 +234,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
|
|
@ -1,31 +0,0 @@
|
|||
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 8cf548656f7ec76c1663cd16b83d94bf3582d020..3b6517cb569a6c702dabb60e8f98cd5f9c367e5b 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1407,6 +1407,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();
|
||||
@@ -1433,6 +1434,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;
|
|
@ -1,77 +0,0 @@
|
|||
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 3354c929142b56a992348ff1a6f262b36d24d3a5..d15fed8770c672b1d387f6cd3b11577ba54ebedb 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -890,6 +890,46 @@ public class ServerPlayer extends 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
|
||||
@@ -974,7 +1014,12 @@ public class ServerPlayer extends Player {
|
||||
this.dropExperience();
|
||||
// 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
|
|
@ -1,30 +0,0 @@
|
|||
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 30ceb1e2765217e284abcb786b2c1f7b60f9c3dc..895c263570acf0f8ac2e8d680a6187bc189a205e 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -907,9 +907,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));
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
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 f3d52650e9dd338396d325c9fb7a46e3927d3b36..77395861f528b0443db84bf882351c7f5ccfd3ba 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();
|
|
@ -1,111 +0,0 @@
|
|||
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
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
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 a0dc17702fb6c8c96f262bc917624a46a40920fa..289a74e35836717bd20c777e9fc8c17722e90411 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() {
|
|
@ -1,20 +0,0 @@
|
|||
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 d4f498789ae1d93533f058b0ce4981eed1ce8ea2..5a0658932cc45c49c9285b1419d574dd83041732 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
||||
@@ -313,7 +313,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);
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
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
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
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 eb1b151560ef77cd8208f44880c860626caf8d3b..10b638183a06702ce97159e634b18a9c8b55d049 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2902,5 +2902,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
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
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) {
|
|
@ -1,36 +0,0 @@
|
|||
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) -> {
|
|
@ -1,39 +0,0 @@
|
|||
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 516999dc425d23c570dabfe4f3c829650a6d205d..40348e45b02be9a0b397a883940a476fb6738ef4 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
|
||||
@@ -176,7 +176,7 @@ public abstract class Projectile extends Entity implements TraceableEntity {
|
||||
this.shoot((double) f5, (double) f6, (double) f7, speed, divergence);
|
||||
Vec3 vec3d = shooter.getDeltaMovement();
|
||||
|
||||
- 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
|
|
@ -1,19 +0,0 @@
|
|||
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/HangingEntity.java b/src/main/java/net/minecraft/world/entity/decoration/HangingEntity.java
|
||||
index 47a62680279f15ac93eb521f7ec93c3b8d52c602..0ffff5329fa2c7833f9ec71528cb7f951cf78109 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/decoration/HangingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/decoration/HangingEntity.java
|
||||
@@ -40,7 +40,7 @@ public abstract class HangingEntity extends Entity {
|
||||
protected static final Predicate<Entity> HANGING_ENTITY = (entity) -> {
|
||||
return entity instanceof HangingEntity;
|
||||
};
|
||||
- private int checkInterval;
|
||||
+ private int checkInterval; { this.checkInterval = this.getId() % this.level().spigotConfig.hangingTickFrequency; } // Paper - Perf: offset item frame ticking
|
||||
public BlockPos pos;
|
||||
protected Direction direction;
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
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 7a9e6671ac38a3473d5562b0eb1de9eecc95c6c5..73738ef71f2698a6116cd5371f80c26a97c0a77c 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3805,9 +3805,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();
|
||||
if (!this.level().isClientSide) {
|
||||
@@ -3887,6 +3892,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;
|
||||
@@ -3921,8 +3927,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
|
|
@ -1,18 +0,0 @@
|
|||
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
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
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)) {
|
|
@ -1,20 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
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
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
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/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 1c508d1f122d287cd8dc0a905de96436c343327a..6fa52a83d343ff151667cd9ade0ec60f026ce66d 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -906,6 +906,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
entity.discard(null); // CraftBukkit - add Bukkit remove cause
|
||||
needsRemoval = true;
|
||||
}
|
||||
+ checkDupeUUID(world, entity); // Paper - duplicate uuid resolving
|
||||
return !needsRemoval;
|
||||
}));
|
||||
// CraftBukkit end
|
||||
@@ -948,6 +949,46 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
});
|
||||
}
|
||||
|
||||
+ // Paper start - duplicate uuid resolving
|
||||
+ // rets true if to prevent the entity from being added
|
||||
+ public static boolean checkDupeUUID(ServerLevel level, 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;
|
||||
+ }
|
||||
+ 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
|
||||
+
|
||||
public CompletableFuture<ChunkResult<LevelChunk>> prepareTickingChunk(ChunkHolder holder) {
|
||||
CompletableFuture<ChunkResult<List<ChunkAccess>>> completablefuture = this.getChunkRangeFuture(holder, 1, (i) -> {
|
||||
return ChunkStatus.FULL;
|
|
@ -1,19 +0,0 @@
|
|||
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 d15fed8770c672b1d387f6cd3b11577ba54ebedb..932b68089c55c8f1b84a15272378d4322a0a5a91 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -1011,7 +1011,7 @@ public class ServerPlayer extends Player {
|
||||
this.tellNeutralMobsThatIDied();
|
||||
}
|
||||
// SPIGOT-5478 must be called manually now
|
||||
- this.dropExperience();
|
||||
+ if (event.shouldDropExperience()) this.dropExperience(); // 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
|
|
@ -1,18 +0,0 @@
|
|||
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 8b0d13513656752a0b40e25c5041d41491b9eef0..5ecf8a87a31a0243c281e2a69823f5f79be69ca5 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
@@ -499,6 +499,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;
|
|
@ -1,32 +0,0 @@
|
|||
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
|
|
@ -1,27 +0,0 @@
|
|||
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 2b524c41daa4fe1605a40c151a90de101d96e8af..51644c24900600d95c3f6df073769b68be702b2d 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -329,6 +329,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
|
|
@ -1,42 +0,0 @@
|
|||
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 f0e6375236d61f32235ed23c3bae49db1545d1a2..5782033cbe408f60340833ddb49dbca3623aaa83 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
@@ -175,7 +175,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;
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
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 d15f216193613504c456d63a1c358973afad3ed1..03c25fec51562f652a8060cde4aabfe9e8bbcfe0 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
@@ -192,7 +192,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;
|
|
@ -1,51 +0,0 @@
|
|||
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 b0518725a2e145d29bd5bc0aa7e6998a47dcb511..b3f8df13e97cbde7dd914b42004d186f90b78646 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,20 @@ 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, 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 5ed1b824978c3805e91aeed8e172206ada9fb720..09a73383867d1ffadababd24428ee7a61ab98959 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
|
||||
@@ -168,6 +168,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);
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
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 5782033cbe408f60340833ddb49dbca3623aaa83..a6dc7c7aab40a9b21c7debd0f9a1619238cff94c 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
@@ -61,6 +61,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);
|
||||
@@ -215,7 +216,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;
|
||||
@@ -239,7 +240,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;
|
||||
@@ -295,7 +296,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) {
|
||||
@@ -543,6 +544,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
|
||||
@@ -597,7 +599,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) {
|
|
@ -1,78 +0,0 @@
|
|||
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 6fa52a83d343ff151667cd9ade0ec60f026ce66d..f13f8119cf43711b96b4dc5834fceaa0282d632d 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1774,6 +1774,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;
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
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 5ecf8a87a31a0243c281e2a69823f5f79be69ca5..210e65919082205ea9227520e9cccc064cd94369 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
@@ -143,7 +143,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);
|
|
@ -1,95 +0,0 @@
|
|||
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 46ee66d06c727a3ad6638f09ac97cd0f07676a7b..4bfe53e3a231a7bec461759e78c7a6cbcb8bb625 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.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, tool) == 0) {
|
||||
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
|
|
@ -1,66 +0,0 @@
|
|||
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 fe0521ad6f0601ebdf7a616c0500479ecb34cabb..fa2df210b05529d228c5ee208f125dcf5288dfec 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -252,6 +252,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");
|
||||
@@ -295,39 +301,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);
|
||||
-
|
||||
- for (int l = 0; l < 4; ++l) {
|
||||
- if (k == this.lastChunkPos[l] && this.lastChunkStatus[l] == ChunkStatus.FULL) {
|
||||
- ChunkAccess ichunkaccess = this.lastChunk[l];
|
||||
-
|
||||
- return ichunkaccess instanceof LevelChunk ? (LevelChunk) ichunkaccess : null;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- ChunkHolder playerchunk = this.getVisibleChunkIfPresent(k);
|
||||
-
|
||||
- if (playerchunk == null) {
|
||||
- return null;
|
||||
- } else {
|
||||
- ChunkResult<ChunkAccess> chunkresult = (ChunkResult) playerchunk.getFutureIfPresent(ChunkStatus.FULL).getNow(null); // CraftBukkit - decompile error
|
||||
-
|
||||
- if (chunkresult == null) {
|
||||
- return null;
|
||||
- } else {
|
||||
- ChunkAccess ichunkaccess1 = (ChunkAccess) chunkresult.orElse(null); // CraftBukkit - decompile error
|
||||
-
|
||||
- if (ichunkaccess1 != null) {
|
||||
- this.storeInCache(k, ichunkaccess1, ChunkStatus.FULL);
|
||||
- if (ichunkaccess1 instanceof LevelChunk) {
|
||||
- return (LevelChunk) ichunkaccess1;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return null;
|
||||
- }
|
||||
- }
|
||||
+ return this.getChunkAtIfLoadedMainThread(chunkX, chunkZ); // Paper - Perf: Optimise getChunkAt calls for loaded chunks
|
||||
}
|
||||
}
|
||||
|
|
@ -1,331 +0,0 @@
|
|||
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 fa2df210b05529d228c5ee208f125dcf5288dfec..0e89cf0742b9443f5256081987242554de24d893 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -279,6 +279,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 51644c24900600d95c3f6df073769b68be702b2d..1170a0031368ede2e45d24720506f6519cbd55da 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -421,6 +421,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
|
|
@ -1,47 +0,0 @@
|
|||
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 1f62158072d7503f0148a9af4e9fbebab30e6fd7..6048e80241246cabf0390e11d217cd8c291d31b6 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
|
||||
/*
|
|
@ -1,26 +0,0 @@
|
|||
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 02da4d1ff3c72e8adad2f4cee449ad21dec34e02..82bb8004635865f5202578d5a6f520048e7269d5 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java
|
||||
@@ -83,6 +83,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
|
|
@ -1,76 +0,0 @@
|
|||
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 73738ef71f2698a6116cd5371f80c26a97c0a77c..639357aa6335b96da3723973a754db763ecbc0f8 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3385,8 +3385,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 4a1b25bb8a3d342400cb657781e9eab68decd479..fb4c7220c4edad54813036d62db7e3eefeda92a3 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Panda.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Panda.java
|
||||
@@ -536,7 +536,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 1264fb03d2dcab088fc4a7c2788c9f9df53cba5d..cec801ba14bed8b043b2375f1bf9e7811a63e995 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Ravager.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Ravager.java
|
||||
@@ -159,7 +159,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 b2172a8c70ab77ba7c98b6b2b27595765d7eba11..539280a0265a4746ebc9ede6667df3699dfb8125 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
@@ -961,4 +961,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
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
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 7544a013111a830618371b9b929c950d8f791bd8..102f32c0724b6042412c010cffa02e5b454ab757 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -398,6 +398,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
|
||||
@@ -2213,6 +2214,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) {
|
||||
@@ -2355,6 +2359,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 f0d4c16fffe7af7e913f4bb300c72f7bdf91e0e8..d3f2c0e3107a781b462a2b67c10cd1e5f05feefb 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
|
||||
@@ -71,6 +71,8 @@ public class NetherPortalBlock extends Block {
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,399 +0,0 @@
|
|||
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);
|
|
@ -1,30 +0,0 @@
|
|||
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 3d8c4cc4d1bdd8c5ceea65fc2189070098410849..c0f0627d3c303e625be584c6eba5865f5622490f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -401,13 +401,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;
|
|
@ -1,18 +0,0 @@
|
|||
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);
|
|
@ -1,19 +0,0 @@
|
|||
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 3a51d3722ef8dba0e4b3ebcff0de8cede3bf3371..932fae98c551052cadba4c6fc6e575fc30a25d58 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java
|
||||
@@ -317,7 +317,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) {
|
|
@ -1,26 +0,0 @@
|
|||
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 2d6cf6ea1717b28871c40de69120336c59a4d347..66fa70762ba3387aa200caa4d8a4e557498cfff1 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
@@ -443,10 +443,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;
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
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 963d86e7505e4d9c3854d35d9b59aed3369e8a57..744db9eec4f7bdeb32f83300960a7fce63b393d8 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -370,18 +370,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");
|
||||
@@ -391,6 +393,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() {
|
|
@ -1,19 +0,0 @@
|
|||
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 );
|
|
@ -1,206 +0,0 @@
|
|||
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 3b6517cb569a6c702dabb60e8f98cd5f9c367e5b..6e31678d1b49584208b7c0ed1f6cfd394f597362 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -252,6 +252,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
|
||||
@@ -1447,6 +1452,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
|
||||
@@ -2787,4 +2797,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 10b638183a06702ce97159e634b18a9c8b55d049..428a2738008c14f7e0179c15026494eda44fa14f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2673,6 +2673,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()
|
||||
{
|
|
@ -1,22 +0,0 @@
|
|||
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 428a2738008c14f7e0179c15026494eda44fa14f..af99292c4461819c4c7d304134f3f3ffb88c175d 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2917,5 +2917,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
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
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 9730a3fe6b1e2734d897936dc8bff7c06edb3687..3fc189cd1e54f91c1713315214da9b6af2923074 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
|
|
@ -1,96 +0,0 @@
|
|||
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 932b68089c55c8f1b84a15272378d4322a0a5a91..10369280138e3baf563cd1099af5eb878cd2a39b 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -265,6 +265,7 @@ public class ServerPlayer extends 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;
|
|
@ -1,44 +0,0 @@
|
|||
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 3736fdd1dba4fc86012c687c5525a52cb8094f47..539a8ddfcf660bf824325516c88cf91f4a32a746 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -412,11 +412,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);
|
|
@ -1,58 +0,0 @@
|
|||
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 210e65919082205ea9227520e9cccc064cd94369..d4389172c3c006ebec5d9cd8213cdd499ab39b68 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
@@ -410,6 +410,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();
|
||||
@@ -443,6 +444,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;
|
||||
@@ -913,6 +915,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) {
|
||||
@@ -936,6 +939,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 970cd8e02464c69087756f9d1deee197c9c092af..fd3b37dde54623ba38186efb2a64d364c86b81d2 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);
|
|
@ -1,47 +0,0 @@
|
|||
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 f13f8119cf43711b96b4dc5834fceaa0282d632d..66936834a80ef6b645ab44f3439defcb90237bfa 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1469,6 +1469,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 1170a0031368ede2e45d24720506f6519cbd55da..df623f10def1ecf071971119f449a773063b3ce1 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -2181,7 +2181,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();
|
||||
@@ -2211,6 +2211,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());
|
|
@ -1,21 +0,0 @@
|
|||
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 10369280138e3baf563cd1099af5eb878cd2a39b..5d42a20c2b908858c3b61a8100addec5100b33a0 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -758,7 +758,7 @@ public class ServerPlayer extends 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();
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
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 e60385c2b84ca0807ed5fc710017a1de09aa3c4e..37190eb2d7a8f81989908f58aa13de1ba964e43a 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
@@ -1162,7 +1162,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
|
|
@ -1,48 +0,0 @@
|
|||
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 5d42a20c2b908858c3b61a8100addec5100b33a0..1856f0692f1894614a9366378b3209a87a1253ec 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -353,7 +353,7 @@ public class ServerPlayer extends Player {
|
||||
this.server = server;
|
||||
this.stats = server.getPlayerList().getPlayerStats(this);
|
||||
this.advancements = server.getPlayerList().getPlayerAdvancements(this);
|
||||
- this.fudgeSpawnLocation(world);
|
||||
+ // this.fudgeSpawnLocation(world); // Paper - Don't move existing players to world spawn
|
||||
this.updateOptions(clientOptions);
|
||||
this.object = null;
|
||||
|
||||
@@ -621,7 +621,7 @@ public class ServerPlayer extends 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 8ce2826b1ded161a8220273d1fc5260ed3b6772f..d2f94afe667627a14cff896b463c2b9b51bf6e29 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.fudgeSpawnLocation(worldserver1); // Paper - Don't move existing players to world spawn
|
||||
}
|
||||
// Paper end - Entity#getEntitySpawnReason
|
||||
player.setServerLevel(worldserver1);
|
|
@ -1,47 +0,0 @@
|
|||
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) {
|
|
@ -1,48 +0,0 @@
|
|||
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
|
|
@ -1,50 +0,0 @@
|
|||
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
|
|
@ -1,50 +0,0 @@
|
|||
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 1856f0692f1894614a9366378b3209a87a1253ec..2720fee3f0e8d1c9a3e2a13c86bf2d60fa9de26c 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -703,7 +703,7 @@ public class ServerPlayer extends 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;
|
||||
}
|
||||
@@ -1602,7 +1602,7 @@ public class ServerPlayer extends 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);
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
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 639357aa6335b96da3723973a754db763ecbc0f8..2b38a9d88b459674b1b8d667c4e02b93ad7290b4 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3496,10 +3496,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;
|
|
@ -1,194 +0,0 @@
|
|||
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 2720fee3f0e8d1c9a3e2a13c86bf2d60fa9de26c..f9b2bbda1cbd16f8635d6fff05bb5c0e26a5e6f1 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -354,7 +354,7 @@ public class ServerPlayer extends Player {
|
||||
this.stats = server.getPlayerList().getPlayerStats(this);
|
||||
this.advancements = server.getPlayerList().getPlayerAdvancements(this);
|
||||
// this.fudgeSpawnLocation(world); // 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
|
||||
@@ -2096,7 +2096,23 @@ public class ServerPlayer extends 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);
|
||||
@@ -2108,6 +2124,11 @@ public class ServerPlayer extends 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
|
||||
+ 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 332f916a5063aa3048675eb906bb3ff5050b37bb..61b9dabaa74ee9e2b357316382ecbdf6c822b916 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -651,6 +651,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");
|
||||
+ }
|
||||
+ }
|
||||
+}
|
|
@ -1,23 +0,0 @@
|
|||
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 e8640bcbc1d4e2965049974385585f5060cb6a44..c473cb1888e9ab0e91ba44f1439b81742758304e 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
@@ -284,8 +284,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);
|
|
@ -1,106 +0,0 @@
|
|||
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 66936834a80ef6b645ab44f3439defcb90237bfa..406c78dcb97d954f16f05d379d4dbf74c61c8fd1 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1476,6 +1476,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 f9b2bbda1cbd16f8635d6fff05bb5c0e26a5e6f1..bf6c81300d29c445a1012d1159866547c202d135 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -284,6 +284,7 @@ public class ServerPlayer extends 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 d2f94afe667627a14cff896b463c2b9b51bf6e29..a4db0bcefc92091ff26b146a2ce914c1d36a3c23 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
|
||||
@@ -356,7 +364,11 @@ public abstract class PlayerList {
|
||||
|
||||
playerconnection.send(new ClientboundUpdateMobEffectPacket(player.getId(), mobeffect, false));
|
||||
}
|
||||
-
|
||||
+ // 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
|
||||
@@ -403,6 +415,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
|
|
@ -1,119 +0,0 @@
|
|||
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 a4db0bcefc92091ff26b146a2ce914c1d36a3c23..935061ed5c22b48e43d27fe0840cc69fb60d5344 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.fudgeSpawnLocation(worldserver1); // Paper - Don't move existing players to world spawn
|
||||
}
|
||||
// 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 102f32c0724b6042412c010cffa02e5b454ab757..33329cb73324ea3e005d59ee3f9ea1225ada7055 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -2316,27 +2316,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");
|
|
@ -1,28 +0,0 @@
|
|||
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 2b38a9d88b459674b1b8d667c4e02b93ad7290b4..accb574f961114f225596a633b36a91e3009ed87 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;
|
|
@ -1,27 +0,0 @@
|
|||
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
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
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 4292a0fbab588a8cd58db36bc279f2991231aeec..ac119e2efff7ba3c32425783ffcf4b3c44156f27 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)) {
|
|
@ -1,167 +0,0 @@
|
|||
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 33329cb73324ea3e005d59ee3f9ea1225ada7055..fcdfe37d2135190e44527190976a718b2f9359c5 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -2446,11 +2446,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
|
||||
@@ -3243,6 +3244,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
@Nullable
|
||||
public Entity teleportTo(ServerLevel worldserver, Vec3 location) {
|
||||
// CraftBukkit end
|
||||
+ // Paper start - Fix item duplication and teleport issues
|
||||
+ if (!this.isAlive() || !this.valid) {
|
||||
+ LOGGER.warn("Illegal Entity Teleport " + this + " to " + worldserver + ":" + location, new Throwable());
|
||||
+ return null;
|
||||
+ }
|
||||
+ // Paper end - Fix item duplication and teleport issues
|
||||
if (this.level() instanceof ServerLevel && !this.isRemoved()) {
|
||||
this.level().getProfiler().push("changeDimension");
|
||||
// CraftBukkit start
|
||||
@@ -3269,6 +3276,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
// CraftBukkit end
|
||||
|
||||
this.level().getProfiler().popPush("reloading");
|
||||
+ // 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
|
||||
Entity entity = this.getType().create(worldserver);
|
||||
|
||||
if (entity != null) {
|
||||
@@ -3286,10 +3298,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
// CraftBukkit start - Forward the CraftEntity to the new entity
|
||||
this.getBukkitEntity().setHandle(entity);
|
||||
entity.bukkitEntity = this.getBukkitEntity();
|
||||
-
|
||||
- if (this instanceof Mob) {
|
||||
- ((Mob) this).dropLeash(true, false); // Unleash to prevent duping of leads.
|
||||
- }
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
@@ -3410,7 +3418,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
|
||||
public boolean canChangeDimensions() {
|
||||
- return !this.isPassenger() && !this.isVehicle();
|
||||
+ return !this.isPassenger() && !this.isVehicle() && isAlive() && 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 accb574f961114f225596a633b36a91e3009ed87..a4d5e0ffbdade4e1b15d30de6e60feddda697c24 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -1734,9 +1734,9 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
// Paper start
|
||||
org.bukkit.event.entity.EntityDeathEvent deathEvent = this.dropAllDeathLoot(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) {
|
||||
@@ -1837,8 +1837,13 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
this.dropCustomDeathLoot(source, i, flag);
|
||||
this.clearEquipmentSlots = prev; // Paper
|
||||
}
|
||||
- // CraftBukkit start - Call death event
|
||||
- org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, source, 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, source, this.drops, () -> {
|
||||
+ final LivingEntity entityliving = this.getKillCredit();
|
||||
+ if (this.deathScore >= 0 && entityliving != null) {
|
||||
+ entityliving.awardKillScore(this, this.deathScore, source);
|
||||
+ }
|
||||
+ }); // 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 029d5756f424dba57b4a974b09453c2f0cf0e8e2..e1f6853c450a2e6a0d7607f1faec7bc5c82d9621 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
@@ -628,7 +628,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);
|
||||
}
|
||||
}
|
||||
@@ -636,7 +636,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 c0f0627d3c303e625be584c6eba5865f5622490f..18d1e2ff18cae10ec6f1b7adf480bd6bfe738584 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -894,6 +894,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());
|
||||
@@ -908,11 +913,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;
|
|
@ -1,31 +0,0 @@
|
|||
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");
|
|
@ -1,26 +0,0 @@
|
|||
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 e728b9f317d12c3c452db70ba7d1e930c84e345d..7277c9b82c127cd38db2daec3df4d33e8376b8dc 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -892,7 +892,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));
|
|
@ -1,30 +0,0 @@
|
|||
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 6048e80241246cabf0390e11d217cd8c291d31b6..8316e0703b6c1ad81d6745f29eb697017e84c65a 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");
|
|
@ -1,118 +0,0 @@
|
|||
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 f15c388434a0a501f86868de35cc138756975027..5044a7dc120c8b040ee23365d2bf97e6180e3ee4 100644
|
||||
--- a/src/main/java/net/minecraft/commands/Commands.java
|
||||
+++ b/src/main/java/net/minecraft/commands/Commands.java
|
||||
@@ -342,7 +342,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 6e31678d1b49584208b7c0ed1f6cfd394f597362..92cb9a0a479f3dc1c78eda42191d020106d059dd 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -909,6 +909,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) {
|
||||
@@ -923,6 +924,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();
|
||||
@@ -1027,6 +1029,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 970d1ddf0a014b47b0ac97440489706137324991..e4086bea596e5f5d71491e0b7ad650d76939b8f9 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
@@ -62,6 +62,10 @@ public class ServerConfigurationPacketListenerImpl extends ServerCommonPacketLis
|
||||
|
||||
@Override
|
||||
public void onDisconnect(Component reason) {
|
||||
+ // 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, reason.getString());
|
||||
super.onDisconnect(reason);
|
||||
}
|
||||
@@ -149,6 +153,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 af99292c4461819c4c7d304134f3f3ffb88c175d..9cc6f2ae2f0ae71d550f0da5f81412a434b0bdf7 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -1036,6 +1036,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();
|
|
@ -1,24 +0,0 @@
|
|||
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 7277c9b82c127cd38db2daec3df4d33e8376b8dc..d0ce184da22352b591f4783918104a4c473cc873 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1540,6 +1540,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;
|
|
@ -1,798 +0,0 @@
|
|||
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 2caa4c8e250a7925e7d6f9ba00a95956b5328568..69b5d39f57a63130c0b83f6238898bdf68fa1e9a 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 9cc6f2ae2f0ae71d550f0da5f81412a434b0bdf7..13ef7ed49526b9f0d1ec376ec3242e14f66f0a23 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2923,5 +2923,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
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
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
|
||||
}
|
|
@ -1,113 +0,0 @@
|
|||
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 8007d323023655052acd0cf1f3a753101e9ee74a..a933061d4f0c45a34b5678c2b317b670f20b8a45 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
|
||||
@@ -241,6 +241,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) -> {
|
||||
@@ -267,6 +268,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
|
||||
@@ -353,7 +359,7 @@ public class ExperienceOrb extends Entity {
|
||||
|
||||
itemstack.setDamageValue(itemstack.getDamageValue() - j);
|
||||
int k = amount - this.durabilityToXp(j);
|
||||
- this.value = k; // CraftBukkit - update exp value of orb for PlayerItemMendEvent calls
|
||||
+ // this.value = k; // 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 k > 0 ? this.repairPlayerItems(player, k) : 0;
|
||||
} else {
|
||||
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 18d1e2ff18cae10ec6f1b7adf480bd6bfe738584..943c452e1d3d1273a2ef304aa2a52f328dfb5d37 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -703,15 +703,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
|
|
@ -1,60 +0,0 @@
|
|||
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 539280a0265a4746ebc9ede6667df3699dfb8125..a5026d470b8651ddf4b79fc29cbc598ac55217ff 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
@@ -483,7 +483,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;
|
||||
}
|
||||
|
||||
@@ -504,7 +504,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
|
||||
@@ -516,7 +516,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) {
|
|
@ -1,44 +0,0 @@
|
|||
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");
|
|
@ -1,60 +0,0 @@
|
|||
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 92cb9a0a479f3dc1c78eda42191d020106d059dd..2575129d1647eda4acb1ce4f19619f42257cb6f8 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -936,6 +936,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 13ef7ed49526b9f0d1ec376ec3242e14f66f0a23..91b8fefc2c97c1f487bde1559d4ccf76795ca954 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -1047,6 +1047,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);
|
|
@ -1,19 +0,0 @@
|
|||
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 f81d5abedec0f2fa7ae81421edda8b3dfcb7690b..9f54e46b870e78d1d360ea79604708db08276ae3 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/raid/Raider.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/raid/Raider.java
|
||||
@@ -334,6 +334,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)))) {
|
|
@ -1,20 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kickash32 <kickash32@gmail.com>
|
||||
Date: Fri, 15 May 2020 01:10:03 -0400
|
||||
Subject: [PATCH] Ensure safe gateway teleport
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.Entity teleportPassengers()V
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java
|
||||
index f8053b42fbf144d427cc4ed44b3b735358c58a20..93bd70c1dc2ba8b893a6087730071c81fb1132f4 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java
|
||||
@@ -214,6 +214,7 @@ public class TheEndGatewayBlockEntity extends TheEndPortalBlockEntity {
|
||||
|
||||
entity1.setPortalCooldown();
|
||||
((ServerPlayer) entity1).connection.teleport(teleEvent.getTo());
|
||||
+ entity1.teleportPassengers(); // Paper - teleport passengers as well, preventing invisible passengers post teleport.
|
||||
TheEndGatewayBlockEntity.triggerCooldown(world, pos, state, blockEntity); // CraftBukkit - call at end of method
|
||||
return;
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
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
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
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() {
|
|
@ -1,31 +0,0 @@
|
|||
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()) {
|
|
@ -1,20 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 7 Jun 2020 19:25:13 -0400
|
||||
Subject: [PATCH] Use seed based lookup for Treasure Maps - Fixes lag from
|
||||
carto/sunken maps
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/item/MapItem.java b/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
index 36de7c63370c529579d31ba1d77ec12b754ef313..ce461b1a8d7fab87ae28e30205f6fab67f1808b6 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
@@ -206,7 +206,7 @@ public class MapItem extends ComplexItem {
|
||||
|
||||
for (int n = 0; n < 128; n++) {
|
||||
for (int o = 0; o < 128; o++) {
|
||||
- Holder<Biome> holder = world.getBiome(mutableBlockPos.set((l + o) * i, 0, (m + n) * i));
|
||||
+ Holder<Biome> holder = world.getUncachedNoiseBiome((l + o) * i, 0, (m + n) * i); // Paper - Perf: Use seed based lookup for treasure maps
|
||||
bls[n * 128 + o] = holder.is(BiomeTags.WATER_ON_MAP_OUTLINES);
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: ossi <oser0002@gmail.com>
|
||||
Date: Fri, 12 Jun 2020 01:38:06 +0300
|
||||
Subject: [PATCH] Fix CraftScheduler#runTaskTimerAsynchronously(Plugin,
|
||||
Consumer<BukkitTask>, long, long) scheduling a non-repeating task instead of
|
||||
a repeating one.
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
index c6ce8ed5fa73ee6221332083b3376b30bfe61bd0..71a147df3bcbd5bb82934da3e6e14326746cf2e3 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
@@ -198,7 +198,7 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
|
||||
@Override
|
||||
public void runTaskTimerAsynchronously(Plugin plugin, Consumer<? super BukkitTask> task, long delay, long period) throws IllegalArgumentException {
|
||||
- this.runTaskTimerAsynchronously(plugin, (Object) task, delay, CraftTask.NO_REPEATING);
|
||||
+ this.runTaskTimerAsynchronously(plugin, (Object) task, delay, period); // Paper
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,80 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 11 Jun 2020 17:29:42 -0700
|
||||
Subject: [PATCH] Fix piston physics inconsistency - MC-188840
|
||||
|
||||
Pistons invoke physics when they move blocks. The physics can cause
|
||||
tnt blocks to ignite. However, pistons (when storing the blocks they "moved")
|
||||
don't actually go back to the world state sometimes to check if something
|
||||
like that happened. As a result they end up moving the tnt like it was
|
||||
never ignited. This resulted in the ability to create machines
|
||||
that can duplicate tnt, called "world eaters".
|
||||
This patch makes the piston logic retrieve the block state from the world
|
||||
prevent this from occuring.
|
||||
|
||||
This patch also sets the moved pos to air immediately after creating
|
||||
the moving piston TE. This prevents the block from being updated from
|
||||
other physics calls by the piston.
|
||||
|
||||
Tested against the following tnt duper design:
|
||||
https://www.youtube.com/watch?v=mS7xxNGhjxs
|
||||
|
||||
This patch also affects every type of machine that utilises
|
||||
this mechanic. For example, dead coral is removed by a physics
|
||||
update when being moved while it is attached to slimeblocks.
|
||||
|
||||
Standard piston machines that don't destroy or modify the
|
||||
blocks they move by physics updates should be entirely
|
||||
unaffected.
|
||||
|
||||
This patch fixes https://bugs.mojang.com/browse/MC-188840
|
||||
|
||||
This patch also fixes rail duping and carpet duping.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
|
||||
index 530b6af1ca2e0ac81c0a8a55dbc7cf5c796c93ce..4aa34b7df734bb755906b228e0df9eb629569ea0 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
|
||||
@@ -414,14 +414,26 @@ public class PistonBaseBlock extends DirectionalBlock {
|
||||
}
|
||||
|
||||
for (j = list.size() - 1; j >= 0; --j) {
|
||||
- blockposition3 = (BlockPos) list.get(j);
|
||||
- iblockdata1 = world.getBlockState(blockposition3);
|
||||
+ // Paper start - fix a variety of piston desync dupes
|
||||
+ boolean allowDesync = io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication;
|
||||
+ BlockPos oldPos = blockposition3 = (BlockPos) list.get(j);
|
||||
+ iblockdata1 = allowDesync ? world.getBlockState(oldPos) : null;
|
||||
+ // Paper end - fix a variety of piston desync dupes
|
||||
blockposition3 = blockposition3.relative(enumdirection1);
|
||||
map.remove(blockposition3);
|
||||
BlockState iblockdata2 = (BlockState) Blocks.MOVING_PISTON.defaultBlockState().setValue(PistonBaseBlock.FACING, dir);
|
||||
|
||||
world.setBlock(blockposition3, iblockdata2, 68);
|
||||
- world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(blockposition3, iblockdata2, (BlockState) list1.get(j), dir, retract, false));
|
||||
+ // Paper start - fix a variety of piston desync dupes
|
||||
+ if (!allowDesync) {
|
||||
+ iblockdata1 = world.getBlockState(oldPos);
|
||||
+ map.replace(oldPos, iblockdata1);
|
||||
+ }
|
||||
+ world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(blockposition3, iblockdata2, allowDesync ? list1.get(j) : iblockdata1, dir, retract, false));
|
||||
+ if (!allowDesync) {
|
||||
+ world.setBlock(oldPos, Blocks.AIR.defaultBlockState(), Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE | Block.UPDATE_MOVE_BY_PISTON | 1024); // set air to prevent later physics updates from seeing this block
|
||||
+ }
|
||||
+ // Paper end - fix a variety of piston desync dupes
|
||||
aiblockdata[i++] = iblockdata1;
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||
index 8ea7d7da26e7d5644a8ee1a8d9e4c828c6b70a00..d7b963571c900f0f68005d6954bcd9ef1d9e0b7c 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||
@@ -297,7 +297,7 @@ public class PistonMovingBlockEntity extends BlockEntity {
|
||||
if (world.getBlockState(pos).is(Blocks.MOVING_PISTON)) {
|
||||
BlockState blockState = Block.updateFromNeighbourShapes(blockEntity.movedState, world, pos);
|
||||
if (blockState.isAir()) {
|
||||
- world.setBlock(pos, blockEntity.movedState, 84);
|
||||
+ world.setBlock(pos, blockEntity.movedState, io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication ? 84 : (84 | Block.UPDATE_CLIENTS)); // Paper - fix a variety of piston desync dupes; force notify (flag 2), it's possible the set type by the piston block (which doesn't notify) set this block to air
|
||||
Block.updateOrDestroy(blockEntity.movedState, blockState, world, pos, 3);
|
||||
} else {
|
||||
if (blockState.hasProperty(BlockStateProperties.WATERLOGGED) && blockState.getValue(BlockStateProperties.WATERLOGGED)) {
|
|
@ -1,29 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: David Slovikosky <davidslovikosky@gmail.com>
|
||||
Date: Tue, 9 Jun 2020 00:10:03 -0700
|
||||
Subject: [PATCH] Fix missing chunks due to integer overflow
|
||||
|
||||
This patch fixes a bug in the EndIslandDensityFunction class where the distance
|
||||
from 0,0 squared overflows the maximum size of an integer. The overflow leads
|
||||
to hard chunk borders around 370,000 blocks from 0,0. After this cutoff there
|
||||
is a few hundred thousand block gap before end land resuming to generate at
|
||||
530,000 blocks from spawn. This is due to the integer flipping back and forth.
|
||||
|
||||
The fix for the issue is quite simple, casting chunk coordinates to longs
|
||||
allows the distance calculation to avoid overflow and work as intended.
|
||||
|
||||
This issue is being tracked in Mojira ticket MC-159283
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java b/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java
|
||||
index 6171d57a0e5d1aecadfb2c23a72a92d897ca41ee..b09bc1dac649ce9f4826edc1923c843804226993 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java
|
||||
@@ -521,7 +521,7 @@ public final class DensityFunctions {
|
||||
int j = z / 2;
|
||||
int k = x % 2;
|
||||
int l = z % 2;
|
||||
- float f = 100.0F - Mth.sqrt((float)(x * x + z * z)) * 8.0F;
|
||||
+ float f = 100.0F - Mth.sqrt((long) x * (long) x + (long) z * (long) z) * 8.0F; // Paper - cast ints to long to avoid integer overflow
|
||||
f = Mth.clamp(f, -100.0F, 80.0F);
|
||||
|
||||
for (int m = -12; m <= 12; m++) {
|
|
@ -1,30 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Fri, 12 Jun 2020 16:51:39 -0700
|
||||
Subject: [PATCH] Prevent position desync causing tp exploit
|
||||
|
||||
Caused the server to revert to the player's overworld coordinates
|
||||
after teleporting into the end.
|
||||
|
||||
Sidenote: The underlying issue is that the move call can teleport
|
||||
entities and do other things like kill the entity. In the future,
|
||||
to fix all exploits derieved from this usually unexpected
|
||||
behaviour, we need to move all of this dangerous logic outside
|
||||
of the move call and into an appropriate place in the tick method.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index d0ce184da22352b591f4783918104a4c473cc873..7fab3281116aa917c96223c1a1caf6280293df65 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1355,6 +1355,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
|
||||
this.player.move(MoverType.PLAYER, new Vec3(d6, d7, d8));
|
||||
this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
|
||||
+ // Paper start - prevent position desync
|
||||
+ if (this.awaitingPositionFromClient != null) {
|
||||
+ return; // ... thanks Mojang for letting move calls teleport across dimensions.
|
||||
+ }
|
||||
+ // Paper end - prevent position desync
|
||||
double d11 = d7;
|
||||
|
||||
d6 = d0 - this.player.getX();
|
|
@ -1,42 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Phoenix616 <mail@moep.tv>
|
||||
Date: Wed, 10 Jun 2020 23:55:15 +0100
|
||||
Subject: [PATCH] Inventory getHolder method without block snapshot
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
|
||||
index 75eb794f796b31c0c5ef80a6d27a56711a522f5e..e824fe361286a5f41b137be92d799eef54ae4b87 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
|
||||
@@ -543,6 +543,13 @@ public class CraftInventory implements Inventory {
|
||||
return this.inventory.getOwner();
|
||||
}
|
||||
|
||||
+ // Paper start - getHolder without snapshot
|
||||
+ @Override
|
||||
+ public InventoryHolder getHolder(boolean useSnapshot) {
|
||||
+ return inventory instanceof net.minecraft.world.level.block.entity.BlockEntity ? ((net.minecraft.world.level.block.entity.BlockEntity) inventory).getOwner(useSnapshot) : getHolder();
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public int getMaxStackSize() {
|
||||
return this.inventory.getMaxStackSize();
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java
|
||||
index c00c787a73b0796b645667427666b7ec4e333992..c3e2c9e2c3cbec2eda38096b6482bac1a0ea1dce 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java
|
||||
@@ -63,6 +63,13 @@ public class CraftInventoryDoubleChest extends CraftInventory implements DoubleC
|
||||
return new DoubleChest(this);
|
||||
}
|
||||
|
||||
+ // Paper start - getHolder without snapshot
|
||||
+ @Override
|
||||
+ public DoubleChest getHolder(boolean useSnapshot) {
|
||||
+ return getHolder();
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
return this.getLeftSide().getLocation().add(this.getRightSide().getLocation()).multiply(0.5);
|
|
@ -1,55 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: JRoy <joshroy126@gmail.com>
|
||||
Date: Fri, 5 Jun 2020 18:24:06 -0400
|
||||
Subject: [PATCH] Add PlayerRecipeBookClickEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 7fab3281116aa917c96223c1a1caf6280293df65..591f4f43dd023facf0a8990682069190c388d64b 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -3041,16 +3041,40 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
if (!this.player.containerMenu.stillValid(this.player)) {
|
||||
ServerGamePacketListenerImpl.LOGGER.debug("Player {} interacted with invalid menu {}", this.player, this.player.containerMenu);
|
||||
} else {
|
||||
+ // Paper start - Add PlayerRecipeBookClickEvent
|
||||
+ ResourceLocation recipeName = packet.getRecipe();
|
||||
+ boolean makeAll = packet.isShiftDown();
|
||||
+ com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent paperEvent = new com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent(
|
||||
+ this.player.getBukkitEntity(), org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(recipeName), makeAll
|
||||
+ );
|
||||
+ if (!paperEvent.callEvent()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ recipeName = CraftNamespacedKey.toMinecraft(paperEvent.getRecipe());
|
||||
+ makeAll = paperEvent.isMakeAll();
|
||||
+ if (org.bukkit.event.player.PlayerRecipeBookClickEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
||||
+ // Paper end - Add PlayerRecipeBookClickEvent
|
||||
// CraftBukkit start - implement PlayerRecipeBookClickEvent
|
||||
- org.bukkit.inventory.Recipe recipe = this.cserver.getRecipe(CraftNamespacedKey.fromMinecraft(packet.getRecipe()));
|
||||
+ org.bukkit.inventory.Recipe recipe = this.cserver.getRecipe(CraftNamespacedKey.fromMinecraft(recipeName)); // Paper
|
||||
if (recipe == null) {
|
||||
return;
|
||||
}
|
||||
- org.bukkit.event.player.PlayerRecipeBookClickEvent event = CraftEventFactory.callRecipeBookClickEvent(this.player, recipe, packet.isShiftDown());
|
||||
+ // Paper start - Add PlayerRecipeBookClickEvent
|
||||
+ org.bukkit.event.player.PlayerRecipeBookClickEvent event = CraftEventFactory.callRecipeBookClickEvent(this.player, recipe, makeAll);
|
||||
+ recipeName = CraftNamespacedKey.toMinecraft(((org.bukkit.Keyed) event.getRecipe()).getKey());
|
||||
+ makeAll = event.isShiftClick();
|
||||
+ }
|
||||
+ if (!(this.player.containerMenu instanceof RecipeBookMenu<?> recipeBookMenu)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Add PlayerRecipeBookClickEvent
|
||||
|
||||
// Cast to keyed should be safe as the recipe will never be a MerchantRecipe.
|
||||
- this.server.getRecipeManager().byKey(CraftNamespacedKey.toMinecraft(((org.bukkit.Keyed) event.getRecipe()).getKey())).ifPresent((recipeholder) -> {
|
||||
- ((RecipeBookMenu) this.player.containerMenu).handlePlacement(event.isShiftClick(), recipeholder, this.player);
|
||||
+ // Paper start - Add PlayerRecipeBookClickEvent
|
||||
+ final boolean finalMakeAll = makeAll;
|
||||
+ this.server.getRecipeManager().byKey(recipeName).ifPresent((recipeholder) -> {
|
||||
+ recipeBookMenu.handlePlacement(finalMakeAll, recipeholder, this.player);
|
||||
+ // Paper end - Add PlayerRecipeBookClickEvent
|
||||
});
|
||||
// CraftBukkit end
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Fri, 26 Jun 2020 22:35:08 -0700
|
||||
Subject: [PATCH] Hide sync chunk writes behind flag
|
||||
|
||||
Syncing writes on each write call has terrible performance
|
||||
on harddrives.
|
||||
|
||||
-DPaper.enable-sync-chunk-writes=true to enable
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
||||
index 502e5386ec4306de93148266f60810ec52ae5ab2..9d10cdacb3aed2c00dc60aeb6f2cbeb48905e21f 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
||||
@@ -145,7 +145,7 @@ public class DedicatedServerProperties extends Settings<DedicatedServerPropertie
|
||||
this.maxWorldSize = this.get("max-world-size", (integer) -> {
|
||||
return Mth.clamp(integer, 1, 29999984);
|
||||
}, 29999984);
|
||||
- this.syncChunkWrites = this.get("sync-chunk-writes", true);
|
||||
+ this.syncChunkWrites = this.get("sync-chunk-writes", true) && Boolean.getBoolean("Paper.enable-sync-chunk-writes"); // Paper - Hide sync chunk writes behind flag
|
||||
this.regionFileComression = this.get("region-file-compression", "deflate");
|
||||
this.enableJmxMonitoring = this.get("enable-jmx-monitoring", false);
|
||||
this.enableStatus = this.get("enable-status", true);
|
|
@ -1,79 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mariell Hoversholm <proximyst@proximyst.com>
|
||||
Date: Sat, 16 May 2020 10:05:30 +0200
|
||||
Subject: [PATCH] Add permission for command blocks
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
index cbb17ce25cb6218bcf95c2f1c3d0288eeee13a46..84c31fe944fc39109d48b6dc68d0c2b15bef6cf2 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
@@ -400,7 +400,7 @@ public class ServerPlayerGameMode {
|
||||
BlockEntity tileentity = this.level.getBlockEntity(pos);
|
||||
Block block = iblockdata.getBlock();
|
||||
|
||||
- if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks()) {
|
||||
+ if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks() && !(block instanceof net.minecraft.world.level.block.CommandBlock && (this.player.isCreative() && this.player.getBukkitEntity().hasPermission("minecraft.commandblock")))) { // Paper - command block permission
|
||||
this.level.sendBlockUpdated(pos, iblockdata, iblockdata, 3);
|
||||
return false;
|
||||
} else if (this.player.blockActionRestricted(this.level, pos, this.gameModeForPlayer)) {
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 591f4f43dd023facf0a8990682069190c388d64b..299a2e78f4a83d224038c80287636a5d6b9b7450 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -803,7 +803,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
|
||||
if (!this.server.isCommandBlockEnabled()) {
|
||||
this.player.sendSystemMessage(Component.translatable("advMode.notEnabled"));
|
||||
- } else if (!this.player.canUseGameMasterBlocks()) {
|
||||
+ } else if (!this.player.canUseGameMasterBlocks() && (!this.player.isCreative() || !this.player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission
|
||||
this.player.sendSystemMessage(Component.translatable("advMode.notAllowed"));
|
||||
} else {
|
||||
BaseCommandBlock commandblocklistenerabstract = null;
|
||||
@@ -870,7 +870,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
|
||||
if (!this.server.isCommandBlockEnabled()) {
|
||||
this.player.sendSystemMessage(Component.translatable("advMode.notEnabled"));
|
||||
- } else if (!this.player.canUseGameMasterBlocks()) {
|
||||
+ } else if (!this.player.canUseGameMasterBlocks() && (!this.player.isCreative() || !this.player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission
|
||||
this.player.sendSystemMessage(Component.translatable("advMode.notAllowed"));
|
||||
} else {
|
||||
BaseCommandBlock commandblocklistenerabstract = packet.getCommandBlock(this.player.level());
|
||||
diff --git a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java
|
||||
index efd6fcb0528d3c903e720edeb2f704347b34c18d..8c2dcc4134d96351cee75773214f3f47e71533e9 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java
|
||||
@@ -204,7 +204,7 @@ public abstract class BaseCommandBlock implements CommandSource {
|
||||
}
|
||||
|
||||
public InteractionResult usedBy(Player player) {
|
||||
- if (!player.canUseGameMasterBlocks()) {
|
||||
+ if (!player.canUseGameMasterBlocks() && (!player.isCreative() || !player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission
|
||||
return InteractionResult.PASS;
|
||||
} else {
|
||||
if (player.getCommandSenderWorld().isClientSide) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/CommandBlock.java b/src/main/java/net/minecraft/world/level/block/CommandBlock.java
|
||||
index 0530b2a6324ec3ac0b3929aab7c0fa89de8bd9b9..ec1a8c60ccac50e5131f937c4262128fd2768331 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/CommandBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/CommandBlock.java
|
||||
@@ -141,7 +141,7 @@ public class CommandBlock extends BaseEntityBlock implements GameMasterBlock {
|
||||
protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) {
|
||||
BlockEntity tileentity = world.getBlockEntity(pos);
|
||||
|
||||
- if (tileentity instanceof CommandBlockEntity && player.canUseGameMasterBlocks()) {
|
||||
+ if (tileentity instanceof CommandBlockEntity && (player.canUseGameMasterBlocks() || (player.isCreative() && player.getBukkitEntity().hasPermission("minecraft.commandblock")))) { // Paper - command block permission
|
||||
player.openCommandBlock((CommandBlockEntity) tileentity);
|
||||
return InteractionResult.sidedSuccess(world.isClientSide);
|
||||
} else {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java b/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java
|
||||
index 245ad120a36b6defca7e6889faae1ca5fc33d0c7..e0e61115ada9a49d4c528c5d4e02a1ca571d9531 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java
|
||||
@@ -16,6 +16,7 @@ public final class CraftDefaultPermissions {
|
||||
DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".nbt.copy", "Gives the user the ability to copy NBT in creative", org.bukkit.permissions.PermissionDefault.TRUE, parent);
|
||||
DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".debugstick", "Gives the user the ability to use the debug stick in creative", org.bukkit.permissions.PermissionDefault.OP, parent);
|
||||
DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".debugstick.always", "Gives the user the ability to use the debug stick in all game modes", org.bukkit.permissions.PermissionDefault.FALSE/* , parent */); // Paper - should not have this parent, as it's not a "vanilla" utility
|
||||
+ DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".commandblock", "Gives the user the ability to use command blocks.", org.bukkit.permissions.PermissionDefault.OP, parent); // Paper
|
||||
// Spigot end
|
||||
parent.recalculatePermissibles();
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 10 May 2020 22:12:46 -0400
|
||||
Subject: [PATCH] Ensure Entity position and AABB are never invalid
|
||||
|
||||
Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index fcdfe37d2135190e44527190976a718b2f9359c5..084824335dc4c83d331cac2da8fdd5604d650b5d 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -664,8 +664,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
|
||||
public void setPos(double x, double y, double z) {
|
||||
- this.setPosRaw(x, y, z);
|
||||
- this.setBoundingBox(this.makeBoundingBox());
|
||||
+ this.setPosRaw(x, y, z, true); // Paper - Block invalid positions and bounding box; force update
|
||||
+ // this.setBoundingBox(this.makeBoundingBox()); // Paper - Block invalid positions and bounding box; move into setPosRaw
|
||||
}
|
||||
|
||||
protected AABB makeBoundingBox() {
|
||||
@@ -4180,7 +4180,29 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
return this.getZ((2.0D * this.random.nextDouble() - 1.0D) * widthScale);
|
||||
}
|
||||
|
||||
+ // Paper start - Block invalid positions and bounding box
|
||||
+ public static boolean checkPosition(Entity entity, double newX, double newY, double newZ) {
|
||||
+ if (Double.isFinite(newX) && Double.isFinite(newY) && Double.isFinite(newZ)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ String entityInfo;
|
||||
+ try {
|
||||
+ entityInfo = entity.toString();
|
||||
+ } catch (Exception ex) {
|
||||
+ entityInfo = "[Entity info unavailable] ";
|
||||
+ }
|
||||
+ LOGGER.error("New entity position is invalid! Tried to set invalid position ({},{},{}) for entity {} located at {}, entity info: {}", newX, newY, newZ, entity.getClass().getName(), entity.position, entityInfo, new Throwable());
|
||||
+ return false;
|
||||
+ }
|
||||
public final void setPosRaw(double x, double y, double z) {
|
||||
+ this.setPosRaw(x, y, z, false);
|
||||
+ }
|
||||
+ public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) {
|
||||
+ if (!checkPosition(this, x, y, z)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Block invalid positions and bounding box
|
||||
if (this.position.x != x || this.position.y != y || this.position.z != z) {
|
||||
this.position = new Vec3(x, y, z);
|
||||
int i = Mth.floor(x);
|
||||
@@ -4198,6 +4220,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
this.levelCallback.onMove();
|
||||
}
|
||||
|
||||
+ // Paper start - Block invalid positions and bounding box; don't allow desync of pos and AABB
|
||||
+ // hanging has its own special logic
|
||||
+ if (!(this instanceof net.minecraft.world.entity.decoration.HangingEntity) && (forceBoundingBoxUpdate || this.position.x != x || this.position.y != y || this.position.z != z)) {
|
||||
+ this.setBoundingBox(this.makeBoundingBox());
|
||||
+ }
|
||||
+ // Paper end - Block invalid positions and bounding box
|
||||
}
|
||||
|
||||
public void checkDespawn() {}
|
|
@ -1,131 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 28 Jun 2020 03:59:10 -0400
|
||||
Subject: [PATCH] Fix Per World Difficulty / Remembering Difficulty
|
||||
|
||||
Fixes per world difficulty with /difficulty command and also
|
||||
makes it so that the server keeps the last difficulty used instead
|
||||
of restoring the server.properties every single load.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 2575129d1647eda4acb1ce4f19619f42257cb6f8..f5a2645afc64f3ba9ee21e6442697d6eb2fabb13 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -830,7 +830,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
worldloadlistener.stop();
|
||||
// CraftBukkit start
|
||||
// this.updateMobSpawningFlags();
|
||||
- worldserver.setSpawnSettings(this.isSpawningMonsters(), this.isSpawningAnimals());
|
||||
+ worldserver.setSpawnSettings(worldserver.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && ((DedicatedServer) this).settings.getProperties().spawnMonsters, this.isSpawningAnimals()); // Paper - per level difficulty (from setDifficulty(ServerLevel, Difficulty, boolean))
|
||||
|
||||
this.forceTicks = false;
|
||||
// CraftBukkit end
|
||||
@@ -1826,11 +1826,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
}
|
||||
|
||||
- public void setDifficulty(Difficulty difficulty, boolean forceUpdate) {
|
||||
- if (forceUpdate || !this.worldData.isDifficultyLocked()) {
|
||||
- this.worldData.setDifficulty(this.worldData.isHardcore() ? Difficulty.HARD : difficulty);
|
||||
- this.updateMobSpawningFlags();
|
||||
- this.getPlayerList().getPlayers().forEach(this::sendDifficultyUpdate);
|
||||
+ // Paper start - per level difficulty
|
||||
+ public void setDifficulty(ServerLevel level, Difficulty difficulty, boolean forceUpdate) {
|
||||
+ PrimaryLevelData worldData = level.serverLevelData;
|
||||
+ if (forceUpdate || !worldData.isDifficultyLocked()) {
|
||||
+ worldData.setDifficulty(worldData.isHardcore() ? Difficulty.HARD : difficulty);
|
||||
+ level.setSpawnSettings(worldData.getDifficulty() != Difficulty.PEACEFUL && ((DedicatedServer) this).settings.getProperties().spawnMonsters, this.isSpawningAnimals());
|
||||
+ // this.getPlayerList().getPlayers().forEach(this::sendDifficultyUpdate);
|
||||
+ // Paper end - per level difficulty
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1844,7 +1847,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
while (iterator.hasNext()) {
|
||||
ServerLevel worldserver = (ServerLevel) iterator.next();
|
||||
|
||||
- worldserver.setSpawnSettings(this.isSpawningMonsters(), this.isSpawningAnimals());
|
||||
+ worldserver.setSpawnSettings(worldserver.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && ((DedicatedServer) this).settings.getProperties().spawnMonsters, this.isSpawningAnimals()); // Paper - per level difficulty (from setDifficulty(ServerLevel, Difficulty, boolean))
|
||||
}
|
||||
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/commands/DifficultyCommand.java b/src/main/java/net/minecraft/server/commands/DifficultyCommand.java
|
||||
index 997a96a21440ae72696d68f8031ece4ba487d3ef..3d8584929cee000ae7df10c5bd94f35820e70294 100644
|
||||
--- a/src/main/java/net/minecraft/server/commands/DifficultyCommand.java
|
||||
+++ b/src/main/java/net/minecraft/server/commands/DifficultyCommand.java
|
||||
@@ -49,7 +49,7 @@ public class DifficultyCommand {
|
||||
if (worldServer.getDifficulty() == difficulty) { // CraftBukkit
|
||||
throw DifficultyCommand.ERROR_ALREADY_DIFFICULT.create(difficulty.getKey());
|
||||
} else {
|
||||
- worldServer.serverLevelData.setDifficulty(difficulty); // CraftBukkit
|
||||
+ minecraftserver.setDifficulty(worldServer, difficulty, true); // Paper - per level difficulty; don't skip other difficulty-changing logic (fix upstream's fix)
|
||||
source.sendSuccess(() -> {
|
||||
return Component.translatable("commands.difficulty.success", difficulty.getDisplayName());
|
||||
}, true);
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 539a8ddfcf660bf824325516c88cf91f4a32a746..1bc8217cf1df95edadd57e18a91885808d31cb93 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -346,7 +346,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
|
||||
@Override
|
||||
public void forceDifficulty() {
|
||||
- this.setDifficulty(this.getProperties().difficulty, true);
|
||||
+ // this.setDifficulty(this.getProperties().difficulty, true); // Paper - per level difficulty; Don't overwrite level.dat's difficulty, keep current
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index bf6c81300d29c445a1012d1159866547c202d135..e6a24484ef11a1d815a85126aec221547479f7d3 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -1238,7 +1238,7 @@ public class ServerPlayer extends Player {
|
||||
this.isChangingDimension = true; // CraftBukkit - Set teleport invulnerability only if player changing worlds
|
||||
|
||||
this.connection.send(new ClientboundRespawnPacket(this.createCommonSpawnInfo(worldserver), (byte) 3));
|
||||
- this.connection.send(new ClientboundChangeDifficultyPacket(this.level().getDifficulty(), this.level().getLevelData().isDifficultyLocked()));
|
||||
+ this.connection.send(new ClientboundChangeDifficultyPacket(worldserver.getDifficulty(), this.level().getLevelData().isDifficultyLocked())); // Paper - per level difficulty
|
||||
PlayerList playerlist = this.server.getPlayerList();
|
||||
|
||||
playerlist.sendPlayerPermissionLevel(this);
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 299a2e78f4a83d224038c80287636a5d6b9b7450..95d20facdc43a356fd2e82f5d597f52ee61791dc 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -3244,7 +3244,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
public void handleChangeDifficulty(ServerboundChangeDifficultyPacket packet) {
|
||||
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
|
||||
if (this.player.hasPermissions(2) || this.isSingleplayerOwner()) {
|
||||
- this.server.setDifficulty(packet.getDifficulty(), false);
|
||||
+ // this.server.setDifficulty(packet.getDifficulty(), false); // Paper - per level difficulty; don't allow clients to change this
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 91b8fefc2c97c1f487bde1559d4ccf76795ca954..3e4cde7825634c4949312e44f19b03cc96c4aaa3 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -985,8 +985,8 @@ public final class CraftServer implements Server {
|
||||
org.spigotmc.SpigotConfig.init((File) this.console.options.valueOf("spigot-settings")); // Spigot
|
||||
this.console.paperConfigurations.reloadConfigs(this.console);
|
||||
for (ServerLevel world : this.console.getAllLevels()) {
|
||||
- world.serverLevelData.setDifficulty(config.difficulty);
|
||||
- world.setSpawnSettings(config.spawnMonsters, config.spawnAnimals);
|
||||
+ // world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty
|
||||
+ world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters, config.spawnAnimals); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean))
|
||||
|
||||
for (SpawnCategory spawnCategory : SpawnCategory.values()) {
|
||||
if (CraftSpawnCategory.isValidForLimits(spawnCategory)) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index 77395861f528b0443db84bf882351c7f5ccfd3ba..680733c3ccf8ff27478d43b3dfab6028cec5c829 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -1188,7 +1188,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
|
||||
@Override
|
||||
public void setDifficulty(Difficulty difficulty) {
|
||||
- this.getHandle().serverLevelData.setDifficulty(net.minecraft.world.Difficulty.byId(difficulty.getValue()));
|
||||
+ this.getHandle().getServer().setDifficulty(this.getHandle(), net.minecraft.world.Difficulty.byId(difficulty.getValue()), true); // Paper - per level difficulty; don't skip other difficulty-changing logic
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,158 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 28 Jun 2020 19:27:20 -0400
|
||||
Subject: [PATCH] Paper dumpitem command
|
||||
|
||||
Let's you quickly view the item in your hands NBT data
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/command/PaperCommand.java b/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
index 3010d57efcc97fb409bfe43b1fc9af198c099a67..cdad0fd5257ae842f83b9c1c98b4565b468d4f54 100644
|
||||
--- a/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
+++ b/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
@@ -39,6 +39,7 @@ public final class PaperCommand extends Command {
|
||||
commands.put(Set.of("version"), new VersionCommand());
|
||||
commands.put(Set.of("dumpplugins"), new DumpPluginsCommand());
|
||||
commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand());
|
||||
+ commands.put(Set.of("dumpitem"), new DumpItemCommand());
|
||||
|
||||
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/DumpItemCommand.java b/src/main/java/io/papermc/paper/command/subcommands/DumpItemCommand.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..522609d685159c71aeadbb16ee11caa826a20ff7
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/command/subcommands/DumpItemCommand.java
|
||||
@@ -0,0 +1,133 @@
|
||||
+package io.papermc.paper.command.subcommands;
|
||||
+
|
||||
+import io.papermc.paper.adventure.PaperAdventure;
|
||||
+import io.papermc.paper.command.CommandUtil;
|
||||
+import io.papermc.paper.command.PaperSubcommand;
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.Collections;
|
||||
+import java.util.IdentityHashMap;
|
||||
+import java.util.List;
|
||||
+import java.util.Map;
|
||||
+import java.util.Optional;
|
||||
+import java.util.Set;
|
||||
+import java.util.function.Consumer;
|
||||
+import net.kyori.adventure.text.Component;
|
||||
+import net.kyori.adventure.text.ComponentLike;
|
||||
+import net.kyori.adventure.text.JoinConfiguration;
|
||||
+import net.kyori.adventure.text.TextComponent;
|
||||
+import net.minecraft.core.Registry;
|
||||
+import net.minecraft.core.RegistryAccess;
|
||||
+import net.minecraft.core.component.DataComponentMap;
|
||||
+import net.minecraft.core.component.DataComponentPatch;
|
||||
+import net.minecraft.core.component.DataComponentType;
|
||||
+import net.minecraft.core.component.TypedDataComponent;
|
||||
+import net.minecraft.core.registries.Registries;
|
||||
+import net.minecraft.nbt.NbtOps;
|
||||
+import net.minecraft.nbt.NbtUtils;
|
||||
+import net.minecraft.nbt.SnbtPrinterTagVisitor;
|
||||
+import net.minecraft.nbt.Tag;
|
||||
+import net.minecraft.resources.RegistryOps;
|
||||
+import net.minecraft.world.item.ItemStack;
|
||||
+import org.bukkit.command.CommandSender;
|
||||
+import org.bukkit.craftbukkit.CraftServer;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
+import org.bukkit.entity.Player;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+import static net.kyori.adventure.text.Component.join;
|
||||
+import static net.kyori.adventure.text.Component.text;
|
||||
+import static net.kyori.adventure.text.Component.textOfChildren;
|
||||
+import static net.kyori.adventure.text.event.ClickEvent.copyToClipboard;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.AQUA;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.GRAY;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.RED;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.WHITE;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.YELLOW;
|
||||
+import static net.kyori.adventure.text.format.TextColor.color;
|
||||
+import static net.kyori.adventure.text.format.TextDecoration.ITALIC;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public final class DumpItemCommand implements PaperSubcommand {
|
||||
+ @Override
|
||||
+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) {
|
||||
+ this.doDumpItem(sender, args.length > 0 && "all".equals(args[0]));
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ @SuppressWarnings({"unchecked", "OptionalAssignedToNull", "rawtypes"})
|
||||
+ private void doDumpItem(final CommandSender sender, final boolean includeAllComponents) {
|
||||
+ if (!(sender instanceof final Player player)) {
|
||||
+ sender.sendMessage("Only players can use this command");
|
||||
+ return;
|
||||
+ }
|
||||
+ final ItemStack itemStack = CraftItemStack.asNMSCopy(player.getInventory().getItemInMainHand());
|
||||
+ final TextComponent.Builder visualOutput = Component.text();
|
||||
+ final StringBuilder itemCommandBuilder = new StringBuilder();
|
||||
+ final String itemName = itemStack.getItemHolder().unwrapKey().orElseThrow().location().toString();
|
||||
+ itemCommandBuilder.append(itemName);
|
||||
+ visualOutput.append(text(itemName, YELLOW)); // item type
|
||||
+ final Set<DataComponentType<?>> referencedComponentTypes = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||
+ final DataComponentPatch patch = itemStack.getComponentsPatch();
|
||||
+ referencedComponentTypes.addAll(patch.entrySet().stream().map(Map.Entry::getKey).toList());
|
||||
+ final DataComponentMap prototype = itemStack.getItem().components();
|
||||
+ if (includeAllComponents) {
|
||||
+ referencedComponentTypes.addAll(prototype.keySet());
|
||||
+ }
|
||||
+
|
||||
+ final RegistryAccess.Frozen access = ((CraftServer) sender.getServer()).getServer().registryAccess();
|
||||
+ final RegistryOps<Tag> ops = access.createSerializationContext(NbtOps.INSTANCE);
|
||||
+ final Registry<DataComponentType<?>> registry = access.registryOrThrow(Registries.DATA_COMPONENT_TYPE);
|
||||
+ final List<ComponentLike> componentComponents = new ArrayList<>();
|
||||
+ final List<String> commandComponents = new ArrayList<>();
|
||||
+ for (final DataComponentType<?> type : referencedComponentTypes) {
|
||||
+ final String path = registry.getResourceKey(type).orElseThrow().location().getPath();
|
||||
+ final @Nullable Optional<?> patchedValue = patch.get(type);
|
||||
+ final @Nullable TypedDataComponent<?> prototypeValue = prototype.getTyped(type);
|
||||
+ if (patchedValue != null) {
|
||||
+ if (patchedValue.isEmpty()) {
|
||||
+ componentComponents.add(text().append(text('!', RED), text(path, AQUA)));
|
||||
+ commandComponents.add("!" + path);
|
||||
+ } else {
|
||||
+ final Tag serialized = (Tag) ((DataComponentType) type).codecOrThrow().encodeStart(ops, patchedValue.get()).getOrThrow();
|
||||
+ writeComponentValue(componentComponents::add, commandComponents::add, path, serialized);
|
||||
+ }
|
||||
+ } else if (includeAllComponents && prototypeValue != null) {
|
||||
+ final Tag serialized = prototypeValue.encodeValue(ops).getOrThrow();
|
||||
+ writeComponentValue(componentComponents::add, commandComponents::add, path, serialized);
|
||||
+ }
|
||||
+ }
|
||||
+ if (!componentComponents.isEmpty()) {
|
||||
+ visualOutput.append(
|
||||
+ text("[", color(0x8910CE)),
|
||||
+ join(JoinConfiguration.separator(text(",", GRAY)), componentComponents),
|
||||
+ text("]", color(0x8910CE))
|
||||
+ );
|
||||
+ itemCommandBuilder
|
||||
+ .append("[")
|
||||
+ .append(String.join(",", commandComponents))
|
||||
+ .append("]");
|
||||
+ }
|
||||
+ player.sendMessage(visualOutput.build().compact());
|
||||
+ final Component copyMsg = text("Click to copy item definition to clipboard for use with /pgive", GRAY, ITALIC);
|
||||
+ sender.sendMessage(copyMsg.clickEvent(copyToClipboard(itemCommandBuilder.toString())));
|
||||
+ }
|
||||
+
|
||||
+ private static void writeComponentValue(final Consumer<Component> visualOutput, final Consumer<String> commandOutput, final String path, final Tag serialized) {
|
||||
+ visualOutput.accept(textOfChildren(
|
||||
+ text(path, color(0xFF7FD7)),
|
||||
+ text("=", WHITE),
|
||||
+ PaperAdventure.asAdventure(NbtUtils.toPrettyComponent(serialized))
|
||||
+ ));
|
||||
+ commandOutput.accept(path + "=" + new SnbtPrinterTagVisitor("", 0, new ArrayList<>()).visit(serialized));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public List<String> tabComplete(final CommandSender sender, final String subCommand, final String[] args) {
|
||||
+ if (args.length == 1) {
|
||||
+ return CommandUtil.getListMatchingLast(sender, args, "all");
|
||||
+ }
|
||||
+ return Collections.emptyList();
|
||||
+ }
|
||||
+}
|
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