Patching patched patched patches
This commit is contained in:
parent
7f3d2ff503
commit
d0620624d7
326 changed files with 1262 additions and 1279 deletions
|
@ -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 84bcabdd92cefe16f7bf5270e1d2989dd7d010d7..90992b652941365a46f9e01985365447ba2ff461 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -622,7 +622,7 @@ public class ServerPlayer extends Player {
|
||||
containerUpdateDelay = level.paperConfig().tickRates.containerUpdate;
|
||||
}
|
||||
// Paper end
|
||||
- if (!this.level.isClientSide && !this.containerMenu.stillValid(this)) {
|
||||
+ if (!this.level.isClientSide && this.containerMenu != this.inventoryMenu && (isImmobile() || !this.containerMenu.stillValid(this))) { // Paper - auto close while frozen
|
||||
this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.CANT_USE); // Paper
|
||||
this.containerMenu = this.inventoryMenu;
|
||||
}
|
||||
@@ -1500,7 +1500,7 @@ public class ServerPlayer extends Player {
|
||||
} else {
|
||||
// CraftBukkit start
|
||||
this.containerMenu = container;
|
||||
- this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle()));
|
||||
+ if (!isImmobile()) this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle())); // Paper
|
||||
// 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 883b6245f44f3fb82d7678e1092177ca646d484a..f5f30e1408892b4e728053bc5005e551396583a5 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
|
||||
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
|
||||
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 fc498652272cb4990668b3ac05d5aa1f0b627a67..67c3e02bf4ee61237a7d0ea72e7bb0260af159e9 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3340,10 +3340,24 @@ public abstract class LivingEntity extends Entity {
|
||||
protected void serverAiStep() {}
|
||||
|
||||
protected void pushEntities() {
|
||||
+ // 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 && 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 - move up
|
||||
int j;
|
||||
|
||||
if (i > 0 && list.size() > i - 1 && this.random.nextInt(4) == 0) {
|
|
@ -1,174 +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 90992b652941365a46f9e01985365447ba2ff461..fd2bc49f713cccdcb2a3e49db52f56374690c5de 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -1861,9 +1861,24 @@ public class ServerPlayer extends Player {
|
||||
return s;
|
||||
}
|
||||
|
||||
+ // 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 String locale = null; // CraftBukkit - add, lowercase // Paper - default to null
|
||||
public java.util.Locale adventure$locale = java.util.Locale.US; // Paper
|
||||
public void updateOptions(ServerboundClientInformationPacket packet) {
|
||||
+ new com.destroystokyo.paper.event.player.PlayerClientOptionsChangeEvent(getBukkitEntity(), getClientOptionMap(packet.language, packet.viewDistance, com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(packet.chatVisibility().name()), packet.chatColors(), new com.destroystokyo.paper.PaperSkinParts(packet.modelCustomisation()), packet.mainHand() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT, packet.allowsListing(), packet.textFilteringEnabled())).callEvent(); // Paper - settings event
|
||||
// CraftBukkit start
|
||||
if (getMainArm() != packet.mainHand()) {
|
||||
PlayerChangedMainHandEvent event = new PlayerChangedMainHandEvent(this.getBukkitEntity(), getMainArm() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index cdc4ef88c8369b3bd1c607ff5301fc1b04ec4582..a9ec1f77b7b9e60d735c72a01f0bce32d3083cb9 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -615,6 +615,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..fab3063fffa959ac7f0eb5937f2fae94d11b6591
|
||||
--- /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.Assert;
|
||||
+import org.junit.Test;
|
||||
+
|
||||
+public class TranslationKeyTest {
|
||||
+
|
||||
+ @Test
|
||||
+ public void testChatVisibilityKeys() {
|
||||
+ for (ClientOption.ChatVisibility chatVisibility : ClientOption.ChatVisibility.values()) {
|
||||
+ if (chatVisibility == ClientOption.ChatVisibility.UNKNOWN) continue;
|
||||
+ Assert.assertEquals(chatVisibility + "'s translation key doesn't match", ChatVisiblity.valueOf(chatVisibility.name()).getKey(), chatVisibility.translationKey());
|
||||
+ }
|
||||
+ }
|
||||
+}
|
|
@ -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 ffa1e457decf8502c3283352bf5be94d419ff165..d3c3db919e9b0507e8543313d9028394e5163673 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
@@ -153,8 +153,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); // Paper - no longer used
|
|
@ -1,113 +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] Fix Longstanding Broken behavior of PlayerJoinEvent
|
||||
|
||||
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 9fbdb834559df0da45ea4a61eb3963fa8e371af3..1bf18259505997c39e7880abf49e583cc763beb1 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1024,6 +1024,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
+ ": " + entity + (this.entityMap.containsKey(entity.getId()) ? " ALREADY CONTAINED (This would have crashed your server)" : ""), new Throwable());
|
||||
return;
|
||||
}
|
||||
+ if (entity instanceof ServerPlayer && ((ServerPlayer) entity).supressTrackerForLogin) return; // Delay adding to tracker until after list packets
|
||||
// Paper end
|
||||
if (!(entity instanceof EnderDragonPart)) {
|
||||
EntityType<?> entitytypes = entity.getType();
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index fd2bc49f713cccdcb2a3e49db52f56374690c5de..8660fc4bc748131d9bc3088afb5bb9af073300f8 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -254,6 +254,7 @@ public class ServerPlayer extends Player {
|
||||
public double maxHealthCache;
|
||||
public boolean joining = true;
|
||||
public boolean sentListPacket = false;
|
||||
+ public boolean supressTrackerForLogin = false; // Paper
|
||||
public Integer clientViewDistance;
|
||||
public String kickLeaveMessage = null; // SPIGOT-3034: Forward leave message to PlayerQuitEvent
|
||||
// CraftBukkit end
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 89d45ae9b2856aaed265d7333ba2e69a3836bb2e..6cc70d6eb84fb819fb7f1b8b1ef1bbb4715315e5 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -282,6 +282,12 @@ public abstract class PlayerList {
|
||||
this.playersByUUID.put(player.getUUID(), player);
|
||||
// this.broadcastAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, new EntityPlayer[]{entityplayer})); // CraftBukkit - replaced with loop below
|
||||
|
||||
+ // Paper start - 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);
|
||||
+ mountSavedVehicle(player, worldserver1, nbttagcompound);
|
||||
+ // Paper end
|
||||
// CraftBukkit start
|
||||
CraftPlayer bukkitPlayer = player.getBukkitEntity();
|
||||
|
||||
@@ -320,6 +326,8 @@ public abstract class PlayerList {
|
||||
player.connection.send(new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.ADD_PLAYER, new ServerPlayer[]{entityplayer1}));
|
||||
}
|
||||
player.sentListPacket = true;
|
||||
+ player.supressTrackerForLogin = false; // Paper
|
||||
+ ((ServerLevel)player.level).getChunkSource().chunkMap.addEntity(player); // Paper - track entity now
|
||||
// CraftBukkit end
|
||||
|
||||
player.connection.send(new ClientboundSetEntityDataPacket(player.getId(), player.getEntityData(), true)); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn
|
||||
@@ -345,6 +353,11 @@ public abstract class PlayerList {
|
||||
playerconnection.send(new ClientboundUpdateMobEffectPacket(player.getId(), mobeffect));
|
||||
}
|
||||
|
||||
+ // Paper start - move vehicle into method so it can be called above - short circuit around that code
|
||||
+ onPlayerJoinFinish(player, worldserver1, s1);
|
||||
+ }
|
||||
+ private void mountSavedVehicle(ServerPlayer player, ServerLevel worldserver1, CompoundTag nbttagcompound) {
|
||||
+ // Paper end
|
||||
if (nbttagcompound != null && nbttagcompound.contains("RootVehicle", 10)) {
|
||||
CompoundTag nbttagcompound1 = nbttagcompound.getCompound("RootVehicle");
|
||||
// CraftBukkit start
|
||||
@@ -393,6 +406,10 @@ public abstract class PlayerList {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ }
|
||||
+ public void onPlayerJoinFinish(ServerPlayer player, ServerLevel worldserver1, String s1) {
|
||||
+ // Paper end
|
||||
player.initInventoryMenu();
|
||||
// CraftBukkit - Moved from above, added world
|
||||
// Paper start - Add to collideRule team if needed
|
||||
@@ -402,6 +419,7 @@ public abstract class PlayerList {
|
||||
scoreboard.addPlayerToTeam(player.getScoreboardName(), collideRuleTeam);
|
||||
}
|
||||
// Paper end
|
||||
+ // CraftBukkit - Moved from above, added world
|
||||
PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", player.getName().getString(), s1, player.getId(), worldserver1.serverLevelData.getLevelName(), player.getX(), player.getY(), player.getZ());
|
||||
}
|
||||
|
|
@ -1,280 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 19 Apr 2020 04:28:29 -0400
|
||||
Subject: [PATCH] Load Chunks for Login Asynchronously
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index ceab806cf008f8c9306283c86a92164176f8f1c5..d18337c4c123819e4d5f55b65985e548da492627 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -170,6 +170,7 @@ import org.bukkit.event.world.GenericGameEvent;
|
||||
import org.bukkit.event.world.TimeSkipEvent;
|
||||
// CraftBukkit end
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList; // Paper
|
||||
+import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; // Paper
|
||||
|
||||
public class ServerLevel extends Level implements WorldGenLevel {
|
||||
|
||||
@@ -436,6 +437,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
return player != null && player.level == this ? player : null;
|
||||
}
|
||||
// Paper end
|
||||
+ public final ReferenceOpenHashSet<ServerPlayer> pendingLogin = new ReferenceOpenHashSet<>(); // Paper
|
||||
|
||||
// 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, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) {
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 8660fc4bc748131d9bc3088afb5bb9af073300f8..7ad1d2cd3b2d4b1f9b21f0de5ddbf2626aea0310 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -182,6 +182,7 @@ public class ServerPlayer extends Player {
|
||||
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32;
|
||||
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10;
|
||||
public ServerGamePacketListenerImpl connection;
|
||||
+ public net.minecraft.network.Connection networkManager; // Paper
|
||||
public final MinecraftServer server;
|
||||
public final ServerPlayerGameMode gameMode;
|
||||
private final PlayerAdvancements advancements;
|
||||
@@ -255,6 +256,7 @@ public class ServerPlayer extends Player {
|
||||
public boolean joining = true;
|
||||
public boolean sentListPacket = false;
|
||||
public boolean supressTrackerForLogin = false; // Paper
|
||||
+ public boolean didPlayerJoinEvent = false; // Paper
|
||||
public Integer clientViewDistance;
|
||||
public String kickLeaveMessage = null; // SPIGOT-3034: Forward leave message to PlayerQuitEvent
|
||||
// CraftBukkit end
|
||||
diff --git a/src/main/java/net/minecraft/server/level/TicketType.java b/src/main/java/net/minecraft/server/level/TicketType.java
|
||||
index 97d1ff2af23bac14e67bca5896843325aaa5bfc1..e9bc61590d33dc341074371859ceec54599e6c47 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/TicketType.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/TicketType.java
|
||||
@@ -23,6 +23,7 @@ public class TicketType<T> {
|
||||
public static final TicketType<ChunkPos> FORCED = TicketType.create("forced", Comparator.comparingLong(ChunkPos::toLong));
|
||||
public static final TicketType<ChunkPos> LIGHT = TicketType.create("light", Comparator.comparingLong(ChunkPos::toLong));
|
||||
public static final TicketType<BlockPos> PORTAL = TicketType.create("portal", Vec3i::compareTo, 300);
|
||||
+ public static final TicketType<Long> LOGIN = create("login", Long::compareTo, 100); // Paper
|
||||
public static final TicketType<Integer> POST_TELEPORT = TicketType.create("post_teleport", Integer::compareTo, 5);
|
||||
public static final TicketType<ChunkPos> UNKNOWN = TicketType.create("unknown", Comparator.comparingLong(ChunkPos::toLong), 1);
|
||||
public static final TicketType<Unit> PLUGIN = TicketType.create("plugin", (a, b) -> 0); // CraftBukkit
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index c40da6e0f5da3a6663aba74720c530713b94650b..2a75c77ac51b620098f5cc49a8a6bebafdfc06a1 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -346,6 +346,10 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
+ // Paper start - login async
|
||||
+ // Don't tick if not valid (dead), otherwise we load chunks below
|
||||
+ if (this.player.valid) {
|
||||
+ // Paper end
|
||||
if (this.ackBlockChangesUpTo > -1) {
|
||||
this.send(new ClientboundBlockChangedAckPacket(this.ackBlockChangesUpTo));
|
||||
this.ackBlockChangesUpTo = -1;
|
||||
@@ -392,7 +396,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
this.lastVehicle = null;
|
||||
this.clientVehicleIsFloating = false;
|
||||
this.aboveGroundVehicleTickCount = 0;
|
||||
- }
|
||||
+ }} // Paper - end if (valid)
|
||||
|
||||
this.server.getProfiler().push("keepAlive");
|
||||
// Paper Start - give clients a longer time to respond to pings as per pre 1.12.2 timings
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index 3a20c6e2214ad075e4cdd3fbdf0b59e1891b0f2b..42cdb2c70f6b906d27c4b1409df92f7459bf2c1b 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -89,7 +89,7 @@ public class ServerLoginPacketListenerImpl implements TickablePacketListener, Se
|
||||
}
|
||||
// Paper end
|
||||
} else if (this.state == ServerLoginPacketListenerImpl.State.DELAY_ACCEPT) {
|
||||
- ServerPlayer entityplayer = this.server.getPlayerList().getPlayer(this.gameProfile.getId());
|
||||
+ ServerPlayer entityplayer = this.server.getPlayerList().getActivePlayer(this.gameProfile.getId()); // Paper
|
||||
|
||||
if (entityplayer == null) {
|
||||
this.state = ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT;
|
||||
@@ -188,7 +188,7 @@ public class ServerLoginPacketListenerImpl implements TickablePacketListener, Se
|
||||
}
|
||||
|
||||
this.connection.send(new ClientboundGameProfilePacket(this.gameProfile));
|
||||
- ServerPlayer entityplayer = this.server.getPlayerList().getPlayer(this.gameProfile.getId());
|
||||
+ ServerPlayer entityplayer = this.server.getPlayerList().getActivePlayer(this.gameProfile.getId()); // Paper
|
||||
|
||||
try {
|
||||
ServerPlayer entityplayer1 = this.server.getPlayerList().getPlayerForLogin(this.gameProfile, s); // CraftBukkit - add player reference
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 6cc70d6eb84fb819fb7f1b8b1ef1bbb4715315e5..1ec5facab133f265b280738afe9917592384984e 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -139,6 +139,7 @@ public abstract class PlayerList {
|
||||
private final IpBanList ipBans;
|
||||
private final ServerOpList ops;
|
||||
private final UserWhiteList whitelist;
|
||||
+ private final Map<UUID, ServerPlayer> pendingPlayers = Maps.newHashMap(); // Paper
|
||||
// CraftBukkit start
|
||||
// private final Map<UUID, ServerStatisticManager> stats;
|
||||
// private final Map<UUID, AdvancementDataPlayer> advancements;
|
||||
@@ -180,6 +181,13 @@ public abstract class PlayerList {
|
||||
public void placeNewPlayer(Connection connection, ServerPlayer player) {
|
||||
player.isRealPlayer = true; // Paper
|
||||
player.loginTime = System.currentTimeMillis(); // Paper
|
||||
+ // Paper start
|
||||
+ ServerPlayer prev = pendingPlayers.put(player.getUUID(), player);
|
||||
+ if (prev != null) {
|
||||
+ disconnectPendingPlayer(prev);
|
||||
+ }
|
||||
+ player.networkManager = connection;
|
||||
+ // Paper end
|
||||
GameProfile gameprofile = player.getGameProfile();
|
||||
GameProfileCache usercache = this.server.getProfileCache();
|
||||
Optional<GameProfile> optional = usercache.get(gameprofile.getId());
|
||||
@@ -192,7 +200,7 @@ public abstract class PlayerList {
|
||||
if (nbttagcompound != null && nbttagcompound.contains("bukkit")) {
|
||||
CompoundTag bukkit = nbttagcompound.getCompound("bukkit");
|
||||
s = bukkit.contains("lastKnownName", 8) ? bukkit.getString("lastKnownName") : s;
|
||||
- }
|
||||
+ }String lastKnownName = s; // Paper
|
||||
// CraftBukkit end
|
||||
|
||||
if (nbttagcompound != null) {
|
||||
@@ -219,11 +227,15 @@ public abstract class PlayerList {
|
||||
if (nbttagcompound == null) player.fudgeSpawnLocation(worldserver1); // Paper - only move to spawn on first login, otherwise, stay where you are....
|
||||
|
||||
player.setLevel(worldserver1);
|
||||
- String s1 = "local";
|
||||
+ // Paper start - make s1 final
|
||||
+ final String s1;
|
||||
|
||||
if (connection.getRemoteAddress() != null) {
|
||||
s1 = connection.getRemoteAddress().toString();
|
||||
+ } else {
|
||||
+ s1 = "local";
|
||||
}
|
||||
+ // Paper end
|
||||
|
||||
// Spigot start - spawn location event
|
||||
Player spawnPlayer = player.getBukkitEntity();
|
||||
@@ -265,6 +277,56 @@ public abstract class PlayerList {
|
||||
player.getRecipeBook().sendInitialRecipeBook(player);
|
||||
this.updateEntireScoreboard(worldserver1.getScoreboard(), player);
|
||||
this.server.invalidateStatus();
|
||||
+ // Paper start - async load spawn in chunk
|
||||
+ ServerLevel finalWorldserver = worldserver1;
|
||||
+ finalWorldserver.pendingLogin.add(player);
|
||||
+ int chunkX = loc.getBlockX() >> 4;
|
||||
+ int chunkZ = loc.getBlockZ() >> 4;
|
||||
+ final net.minecraft.world.level.ChunkPos pos = new net.minecraft.world.level.ChunkPos(chunkX, chunkZ);
|
||||
+ net.minecraft.server.level.ChunkMap playerChunkMap = worldserver1.getChunkSource().chunkMap;
|
||||
+ net.minecraft.server.level.DistanceManager distanceManager = playerChunkMap.distanceManager;
|
||||
+ io.papermc.paper.chunk.system.ChunkSystem.scheduleTickingState(
|
||||
+ worldserver1, chunkX, chunkZ, net.minecraft.server.level.ChunkHolder.FullChunkStatus.ENTITY_TICKING, true,
|
||||
+ ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.HIGHEST,
|
||||
+ (chunk) -> {
|
||||
+ MinecraftServer.getServer().scheduleOnMain(() -> {
|
||||
+ try {
|
||||
+ if (!playerconnection.connection.isConnected()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ PlayerList.this.postChunkLoadJoin(
|
||||
+ player, finalWorldserver, connection, playerconnection,
|
||||
+ nbttagcompound, s1, lastKnownName
|
||||
+ );
|
||||
+ distanceManager.addTicket(net.minecraft.server.level.TicketType.LOGIN, pos, 31, pos.toLong());
|
||||
+ } finally {
|
||||
+ finalWorldserver.pendingLogin.remove(player);
|
||||
+ }
|
||||
+ });
|
||||
+ }
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ public ServerPlayer getActivePlayer(UUID uuid) {
|
||||
+ ServerPlayer player = this.playersByUUID.get(uuid);
|
||||
+ return player != null ? player : pendingPlayers.get(uuid);
|
||||
+ }
|
||||
+
|
||||
+ void disconnectPendingPlayer(ServerPlayer entityplayer) {
|
||||
+ Component msg = Component.translatable("multiplayer.disconnect.duplicate_login");
|
||||
+ entityplayer.networkManager.send(new net.minecraft.network.protocol.game.ClientboundDisconnectPacket(msg), net.minecraft.network.PacketSendListener.thenRun(() -> {
|
||||
+ entityplayer.networkManager.disconnect(msg);
|
||||
+ entityplayer.networkManager = null;
|
||||
+ }));
|
||||
+ }
|
||||
+
|
||||
+ private void postChunkLoadJoin(ServerPlayer player, ServerLevel worldserver1, Connection networkmanager, ServerGamePacketListenerImpl playerconnection, CompoundTag nbttagcompound, String s1, String s) {
|
||||
+ pendingPlayers.remove(player.getUUID(), player);
|
||||
+ if (!networkmanager.isConnected()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ player.didPlayerJoinEvent = true;
|
||||
+ // Paper end
|
||||
MutableComponent ichatmutablecomponent;
|
||||
|
||||
if (player.getGameProfile().getName().equalsIgnoreCase(s)) {
|
||||
@@ -506,6 +568,7 @@ public abstract class PlayerList {
|
||||
|
||||
protected void save(ServerPlayer player) {
|
||||
if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit
|
||||
+ if (!player.didPlayerJoinEvent) return; // Paper - If we never fired PJE, we disconnected during login. Data has not changed, and additionally, our saved vehicle is not loaded! If we save now, we will lose our vehicle (CraftBukkit bug)
|
||||
this.playerIo.save(player);
|
||||
ServerStatsCounter serverstatisticmanager = (ServerStatsCounter) player.getStats(); // CraftBukkit
|
||||
|
||||
@@ -533,7 +596,7 @@ public abstract class PlayerList {
|
||||
}
|
||||
|
||||
PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(entityplayer.getScoreboardName())));
|
||||
- this.cserver.getPluginManager().callEvent(playerQuitEvent);
|
||||
+ if (entityplayer.didPlayerJoinEvent) this.cserver.getPluginManager().callEvent(playerQuitEvent); // Paper - if we disconnected before join ever fired, don't fire quit
|
||||
entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage());
|
||||
|
||||
if (server.isSameThread()) entityplayer.doTick(); // SPIGOT-924 // Paper - don't tick during emergency shutdowns (Watchdog)
|
||||
@@ -578,6 +641,13 @@ public abstract class PlayerList {
|
||||
// this.advancements.remove(uuid);
|
||||
// CraftBukkit end
|
||||
}
|
||||
+ // Paper start
|
||||
+ entityplayer1 = pendingPlayers.get(uuid);
|
||||
+ if (entityplayer1 == entityplayer) {
|
||||
+ pendingPlayers.remove(uuid);
|
||||
+ }
|
||||
+ entityplayer.networkManager = null;
|
||||
+ // Paper end
|
||||
|
||||
// CraftBukkit start
|
||||
// this.broadcastAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, new EntityPlayer[]{entityplayer}));
|
||||
@@ -595,7 +665,7 @@ public abstract class PlayerList {
|
||||
this.cserver.getScoreboardManager().removePlayer(entityplayer.getBukkitEntity());
|
||||
// CraftBukkit end
|
||||
|
||||
- return playerQuitEvent.quitMessage(); // Paper - Adventure
|
||||
+ return entityplayer.didPlayerJoinEvent ? playerQuitEvent.quitMessage() : null; // CraftBukkit // Paper - Adventure // Paper - don't print quit if we never printed join
|
||||
}
|
||||
|
||||
// CraftBukkit start - Whole method, SocketAddress to LoginListener, added hostname to signature, return EntityPlayer
|
||||
@@ -614,6 +684,13 @@ public abstract class PlayerList {
|
||||
list.add(entityplayer);
|
||||
}
|
||||
}
|
||||
+ // Paper start - check pending players too
|
||||
+ entityplayer = pendingPlayers.get(uuid);
|
||||
+ if (entityplayer != null) {
|
||||
+ this.pendingPlayers.remove(uuid);
|
||||
+ disconnectPendingPlayer(entityplayer);
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
Iterator iterator = list.iterator();
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index a2750cba8540caa9f12f5d5179b51f7753d38bba..e5c5a514e6b7bdf663d33074557e34372f18ea77 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -1219,7 +1219,7 @@ public final class CraftServer implements Server {
|
||||
return false;
|
||||
}
|
||||
|
||||
- if (handle.players().size() > 0) {
|
||||
+ if (handle.players().size() > 0 || handle.pendingLogin.size() > 0) { // Paper
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1,27 +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
|
||||
|
||||
The code following this has better support for null worlds to move
|
||||
them back to the world spawn.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 5de420c0a2f0881abb03c16b2621d081ef7ad4fd..58a8bbda3ddff1ed561d9035d45176c6ca689115 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -2162,9 +2162,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
bworld = server.getWorld(worldName);
|
||||
}
|
||||
|
||||
- if (bworld == null) {
|
||||
- bworld = ((org.bukkit.craftbukkit.CraftServer) server).getServer().getLevel(Level.OVERWORLD).getWorld();
|
||||
- }
|
||||
+ // Paper start - Move player to spawn point if spawn in unloaded world
|
||||
+// if (bworld == null) {
|
||||
+// bworld = ((org.bukkit.craftbukkit.CraftServer) server).getServer().getWorldServer(World.OVERWORLD).getWorld();
|
||||
+// }
|
||||
+ // Paper end - Move player to spawn point if spawn in unloaded world
|
||||
|
||||
((ServerPlayer) this).setLevel(bworld == null ? null : ((CraftWorld) bworld).getHandle());
|
||||
}
|
|
@ -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 67c3e02bf4ee61237a7d0ea72e7bb0260af159e9..df3aad08242b40fca5be719ae9fb13bc1c2e8091 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -2115,7 +2115,16 @@ public abstract class LivingEntity extends Entity {
|
||||
|
||||
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
|
||||
}
|
||||
if (event.isCancelled()) {
|
||||
return false;
|
|
@ -1,28 +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
|
||||
|
||||
Caused a deadlock
|
||||
|
||||
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 69903bad7b3e143b73b20624c06909458564396c..8d79612cdba48756bb0352c41b98f8a9ea489ff6 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/FireBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/FireBlock.java
|
||||
@@ -100,6 +100,7 @@ public class FireBlock extends BaseFireBlock {
|
||||
@Override
|
||||
public 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)) {
|
||||
@@ -115,7 +116,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 - 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 6fd874a83a248e6a7d427d18d11fc608544662c5..302676ef78ed5b3b7fc1b04851447ca72eed10c0 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||
@@ -27,6 +27,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> isInsomniac = (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
|
||||
|
||||
private EntitySelector() {}
|
||||
// Paper start
|
||||
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 0e96e9d7e4d636f4222f60cec556663f506c3906..5432b3eff8ac09e45c7e118ddc1bc5303005412b 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java
|
||||
@@ -558,6 +558,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.isInsomniac.test(entityhuman)) // Paper
|
||||
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 0dbb0c4d038379c6ffdae8528d98431e98faeb93..2093d08bccbfbe096ea24cc4f70cbfdfa07d6a56 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java
|
||||
@@ -51,7 +51,7 @@ public class PhantomSpawner implements CustomSpawner {
|
||||
while (iterator.hasNext()) {
|
||||
Player entityhuman = (Player) iterator.next();
|
||||
|
||||
- if (!entityhuman.isSpectator()) {
|
||||
+ if (!entityhuman.isSpectator() && (!world.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !entityhuman.isCreative())) { // Paper
|
||||
BlockPos blockposition = entityhuman.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 numerous item duplication issues 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 58a8bbda3ddff1ed561d9035d45176c6ca689115..32623f90a5bc4fb6fe99897c682ef4f55f056dea 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -2292,11 +2292,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
} 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 - clone 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
|
||||
@@ -3060,6 +3061,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
@Nullable
|
||||
public Entity teleportTo(ServerLevel worldserver, PositionImpl location) {
|
||||
// CraftBukkit end
|
||||
+ // Paper start - fix bad state entities causing dupes
|
||||
+ if (!isAlive() || !valid) {
|
||||
+ LOGGER.warn("Illegal Entity Teleport " + this + " to " + worldserver + ":" + location, new Throwable());
|
||||
+ return null;
|
||||
+ }
|
||||
+ // Paper end
|
||||
if (this.level instanceof ServerLevel && !this.isRemoved()) {
|
||||
this.level.getProfiler().push("changeDimension");
|
||||
// CraftBukkit start
|
||||
@@ -3086,6 +3093,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
// CraftBukkit end
|
||||
|
||||
this.level.getProfiler().popPush("reloading");
|
||||
+ // Paper start - Change lead drop timing to prevent dupe
|
||||
+ if (this instanceof Mob) {
|
||||
+ ((Mob) this).dropLeash(true, true); // Paper drop lead
|
||||
+ }
|
||||
+ // Paper end
|
||||
Entity entity = this.getType().create(worldserver);
|
||||
|
||||
if (entity != null) {
|
||||
@@ -3099,10 +3111,6 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -3223,7 +3231,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
}
|
||||
|
||||
public boolean canChangeDimensions() {
|
||||
- return true;
|
||||
+ return isAlive() && valid; // Paper
|
||||
}
|
||||
|
||||
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 df3aad08242b40fca5be719ae9fb13bc1c2e8091..a337ce97a31998a63e7c329ac94cad9a5f783a5c 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -1646,9 +1646,9 @@ public abstract class LivingEntity extends Entity {
|
||||
// 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 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) {
|
||||
@@ -1746,8 +1746,13 @@ public abstract class LivingEntity extends Entity {
|
||||
this.dropCustomDeathLoot(source, i, flag);
|
||||
this.clearEquipmentSlots = prev; // Paper
|
||||
}
|
||||
- // CraftBukkit start - Call death event
|
||||
- org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, 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, 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 e463ae13ce6f65675c2b6d553ecf91db5a047dbc..7ff1e7e4d493770bfdbc0ad5e8f10387cefc42d2 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
@@ -609,7 +609,7 @@ public class ArmorStand extends LivingEntity {
|
||||
for (i = 0; i < this.handItems.size(); ++i) {
|
||||
itemstack = (ItemStack) this.handItems.get(i);
|
||||
if (!itemstack.isEmpty()) {
|
||||
- drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack)); // CraftBukkit - add to drops
|
||||
+ 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);
|
||||
}
|
||||
}
|
||||
@@ -617,7 +617,7 @@ public class ArmorStand extends LivingEntity {
|
||||
for (i = 0; i < this.armorItems.size(); ++i) {
|
||||
itemstack = (ItemStack) this.armorItems.get(i);
|
||||
if (!itemstack.isEmpty()) {
|
||||
- drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack)); // CraftBukkit - add to drops
|
||||
+ 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 118d7068700bbd4aeaf766ee8d3984b474c6bf9a..751f376e175881d9e9f750c90143a7c39431ce6c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -809,6 +809,11 @@ public class CraftEventFactory {
|
||||
}
|
||||
|
||||
public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, List<org.bukkit.inventory.ItemStack> drops) {
|
||||
+ // Paper start
|
||||
+ return CraftEventFactory.callEntityDeathEvent(victim, drops, com.google.common.util.concurrent.Runnables.doNothing());
|
||||
+ }
|
||||
+ public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, List<org.bukkit.inventory.ItemStack> drops, Runnable lootCheck) {
|
||||
+ // Paper end
|
||||
CraftLivingEntity entity = (CraftLivingEntity) victim.getBukkitEntity();
|
||||
EntityDeathEvent event = new EntityDeathEvent(entity, drops, victim.getExpReward());
|
||||
populateFields(victim, event); // Paper - make cancellable
|
||||
@@ -822,11 +827,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 1400f8c0cac3d653465b3750078de4d2691ac2a1..1a8a49bd269ed52879866ff3853e131d04aa8bba 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
@@ -91,6 +91,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 2a75c77ac51b620098f5cc49a8a6bebafdfc06a1..6c17ae02e3c076b738037454afb7ea08f0f0e79e 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -967,7 +967,14 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
@Override
|
||||
public void handlePickItem(ServerboundPickItemPacket packet) {
|
||||
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel());
|
||||
- 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
|
||||
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,24 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Vainomaa <mikroskeem@mikroskeem.eu>
|
||||
Date: Fri, 1 May 2020 17:39:26 +0300
|
||||
Subject: [PATCH] Expose game version
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index e5c5a514e6b7bdf663d33074557e34372f18ea77..86402126b13e5e6542f880cbdc978eb581d33a8a 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -579,6 +579,13 @@ public final class CraftServer implements Server {
|
||||
return this.bukkitVersion;
|
||||
}
|
||||
|
||||
+ // Paper start - expose game version
|
||||
+ @Override
|
||||
+ public String getMinecraftVersion() {
|
||||
+ return console.getServerVersion();
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public List<CraftPlayer> getOnlinePlayers() {
|
||||
return this.playerView;
|
|
@ -1,121 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 3 May 2020 22:35:09 -0400
|
||||
Subject: [PATCH] Optimize Voxel Shape Merging
|
||||
|
||||
This method shows up as super hot in profiler, and also a high "self" time.
|
||||
|
||||
Upon analyzing, it appears most usages of this method fall down to the final
|
||||
else statement of the nasty ternary.
|
||||
|
||||
Upon even further analyzation, it appears then the majority of those have a
|
||||
consistent list 1.... One with Infinity head and Tails.
|
||||
|
||||
First optimization is to detect these infinite states and immediately return that
|
||||
VoxelShapeMergerList so we can avoid testing the rest for most cases.
|
||||
|
||||
Break the method into 2 to help the JVM promote inlining of this fast path.
|
||||
|
||||
Then it was also noticed that VoxelShapeMergerList constructor is also a hotspot
|
||||
with a high self time...
|
||||
|
||||
Well, knowing that in most cases our list 1 is actualy the same value, it allows
|
||||
us to know that with an infinite list1, the result on the merger is essentially
|
||||
list2 as the final values.
|
||||
|
||||
This let us analyze the 2 potential states (Infinite with 2 sources or 4 sources)
|
||||
and compute a deterministic result for the MergerList values.
|
||||
|
||||
Additionally, this lets us avoid even allocating new objects for this too, further
|
||||
reducing memory usage.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java b/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java
|
||||
index 9e0afab2329e560c4b2512548dd4b02dd1a2e69f..06662dbff8180751a8684841aa35f709007078ae 100644
|
||||
--- a/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java
|
||||
+++ b/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java
|
||||
@@ -10,12 +10,33 @@ public class IndirectMerger implements IndexMerger {
|
||||
private final int[] firstIndices;
|
||||
private final int[] secondIndices;
|
||||
private final int resultLength;
|
||||
+ // Paper start
|
||||
+ private static final int[] INFINITE_B_1 = new int[]{1, 1};
|
||||
+ private static final int[] INFINITE_B_0 = new int[]{0, 0};
|
||||
+ private static final int[] INFINITE_C = new int[]{0, 1};
|
||||
+ // Paper end
|
||||
|
||||
public IndirectMerger(DoubleList first, DoubleList second, boolean includeFirstOnly, boolean includeSecondOnly) {
|
||||
double d = Double.NaN;
|
||||
int i = first.size();
|
||||
int j = second.size();
|
||||
int k = i + j;
|
||||
+ // Paper start - optimize common path of infinity doublelist
|
||||
+ int size = first.size();
|
||||
+ double tail = first.getDouble(size - 1);
|
||||
+ double head = first.getDouble(0);
|
||||
+ if (head == Double.NEGATIVE_INFINITY && tail == Double.POSITIVE_INFINITY && !includeFirstOnly && !includeSecondOnly && (size == 2 || size == 4)) {
|
||||
+ this.result = second.toDoubleArray();
|
||||
+ this.resultLength = second.size();
|
||||
+ if (size == 2) {
|
||||
+ this.firstIndices = INFINITE_B_0;
|
||||
+ } else {
|
||||
+ this.firstIndices = INFINITE_B_1;
|
||||
+ }
|
||||
+ this.secondIndices = INFINITE_C;
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.result = new double[k];
|
||||
this.firstIndices = new int[k];
|
||||
this.secondIndices = new int[k];
|
||||
diff --git a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
|
||||
index 2d273be8145bbd86ffdf33358629da7fc08b4d4c..9176735c08a75854209f24113b0e78332249dc4d 100644
|
||||
--- a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
|
||||
+++ b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
|
||||
@@ -247,9 +247,21 @@ public final class Shapes {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
- protected static IndexMerger createIndexMerger(int size, DoubleList first, DoubleList second, boolean includeFirst, boolean includeSecond) {
|
||||
+ private static IndexMerger createIndexMerger(int size, DoubleList first, DoubleList second, boolean includeFirst, boolean includeSecond) { // Paper - private
|
||||
+ // Paper start - fast track the most common scenario
|
||||
+ // doublelist is usually a DoubleArrayList with Infinite head/tails that falls to the final else clause
|
||||
+ // This is actually the most common path, so jump to it straight away
|
||||
+ if (first.getDouble(0) == Double.NEGATIVE_INFINITY && first.getDouble(first.size() - 1) == Double.POSITIVE_INFINITY) {
|
||||
+ return new IndirectMerger(first, second, includeFirst, includeSecond);
|
||||
+ }
|
||||
+ // Split out rest to hopefully inline the above
|
||||
+ return lessCommonMerge(size, first, second, includeFirst, includeSecond);
|
||||
+ }
|
||||
+
|
||||
+ private static IndexMerger lessCommonMerge(int size, DoubleList first, DoubleList second, boolean includeFirst, boolean includeSecond) {
|
||||
int i = first.size() - 1;
|
||||
int j = second.size() - 1;
|
||||
+ // Paper note - Rewrite below as optimized order if instead of nasty ternary
|
||||
if (first instanceof CubePointRange && second instanceof CubePointRange) {
|
||||
long l = lcm(i, j);
|
||||
if ((long)size * l <= 256L) {
|
||||
@@ -257,13 +269,22 @@ public final class Shapes {
|
||||
}
|
||||
}
|
||||
|
||||
- if (first.getDouble(i) < second.getDouble(0) - 1.0E-7D) {
|
||||
+ // Paper start - Identical happens more often than Disjoint
|
||||
+ if (i == j && Objects.equals(first, second)) {
|
||||
+ if (first instanceof IdenticalMerger) {
|
||||
+ return (IndexMerger) first;
|
||||
+ } else if (second instanceof IdenticalMerger) {
|
||||
+ return (IndexMerger) second;
|
||||
+ }
|
||||
+ return new IdenticalMerger(first);
|
||||
+ } else if (first.getDouble(i) < second.getDouble(0) - 1.0E-7D) {
|
||||
return new NonOverlappingMerger(first, second, false);
|
||||
} else if (second.getDouble(j) < first.getDouble(0) - 1.0E-7D) {
|
||||
return new NonOverlappingMerger(second, first, true);
|
||||
} else {
|
||||
- return (IndexMerger)(i == j && Objects.equals(first, second) ? new IdenticalMerger(first) : new IndirectMerger(first, second, includeFirst, includeSecond));
|
||||
+ return new IndirectMerger(first, second, includeFirst, includeSecond);
|
||||
}
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
public interface DoubleLineConsumer {
|
|
@ -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 cce6886bb3973eed8f0c7ca7b1189547324fd4e2..0aef4fc4a89e627bc80504d7402f1ca2cdc95a74 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
@@ -28,6 +28,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
|
||||
OptionParser parser = new OptionParser() {
|
||||
{
|
||||
acceptsAll(Main.asList("?", "help"), "Show the help");
|
|
@ -1,87 +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..2d5494d2813b773e60ddba6790b750a9a08f21f8
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/util/TraceUtil.java
|
||||
@@ -0,0 +1,18 @@
|
||||
+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 = thread.getStackTrace();
|
||||
+ for (StackTraceElement traceElement : trace) {
|
||||
+ Bukkit.getLogger().warning("\tat " + traceElement);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static void dumpTraceForThread(String reason) {
|
||||
+ new Throwable(reason).printStackTrace();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index c5ecf010fff3af1c9b4ebf24ca80fb6b19afccfc..7c7114193fadc6c14d6d8a87cc2d734eaa68b864 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -881,6 +881,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
// CraftBukkit start
|
||||
private boolean hasStopped = false;
|
||||
public volatile boolean hasFullyShutdown = false; // Paper
|
||||
+ private boolean hasLoggedStop = false; // Paper
|
||||
private final Object stopLock = new Object();
|
||||
public final boolean hasStopped() {
|
||||
synchronized (this.stopLock) {
|
||||
@@ -895,6 +896,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
|
||||
// Paper start - kill main thread, and kill it hard
|
||||
shutdownThread = Thread.currentThread();
|
||||
org.spigotmc.WatchdogThread.doStop(); // Paper
|
||||
@@ -996,6 +998,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
public void safeShutdown(boolean flag, boolean isRestarting) {
|
||||
this.isRestarting = isRestarting;
|
||||
+ this.hasLoggedStop = true; // Paper
|
||||
+ if (isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper
|
||||
// Paper end
|
||||
this.running = false;
|
||||
if (flag) {
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index 42cdb2c70f6b906d27c4b1409df92f7459bf2c1b..930da83ff754bab6b6b6fff651df417baa76c46f 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -202,6 +202,11 @@ public class ServerLoginPacketListenerImpl implements TickablePacketListener, Se
|
||||
} catch (Exception exception) {
|
||||
ServerLoginPacketListenerImpl.LOGGER.error("Couldn't place player in world", exception);
|
||||
MutableComponent ichatmutablecomponent = Component.translatable("multiplayer.disconnect.invalid_player_data");
|
||||
+ // Paper start
|
||||
+ if (MinecraftServer.getServer().isDebugging()) {
|
||||
+ exception.printStackTrace();
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
this.connection.send(new ClientboundDisconnectPacket(ichatmutablecomponent));
|
||||
this.connection.disconnect(ichatmutablecomponent);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 86402126b13e5e6542f880cbdc978eb581d33a8a..8d4388df7e62016df262e377e5f75cc44e17e284 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -1002,6 +1002,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
|
||||
}
|
||||
this.loadPlugins();
|
||||
this.enablePlugins(PluginLoadOrder.STARTUP);
|
|
@ -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 6c17ae02e3c076b738037454afb7ea08f0f0e79e..8c8ccd61fb1592a9274e54ed6e06ec7737e942e0 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1632,6 +1632,13 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
}
|
||||
|
||||
public void internalTeleport(double d0, double d1, double d2, float f, float f1, Set<ClientboundPlayerPositionPacket.RelativeArgument> set, boolean flag) {
|
||||
+ // Paper start
|
||||
+ 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
|
||||
// CraftBukkit start
|
||||
if (Float.isNaN(f)) {
|
||||
f = 0;
|
|
@ -1,663 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
|
||||
Date: Sun, 20 Jun 2021 18:19:09 -0700
|
||||
Subject: [PATCH] Deobfuscate stacktraces in log messages, crash reports, and
|
||||
etc.
|
||||
|
||||
|
||||
diff --git a/build.gradle.kts b/build.gradle.kts
|
||||
index e260462933a9f7065b2360e6bf9e4ee56069a705..2ff278cdc3dfef4644b12755be2e3a69a43e1f07 100644
|
||||
--- a/build.gradle.kts
|
||||
+++ b/build.gradle.kts
|
||||
@@ -19,12 +19,14 @@ dependencies {
|
||||
Scanning takes about 1-2 seconds so adding this speeds up the server start.
|
||||
*/
|
||||
implementation("org.apache.logging.log4j:log4j-core:2.14.1") // Paper - implementation
|
||||
+ annotationProcessor("org.apache.logging.log4j:log4j-core:2.14.1") // Paper - Needed to generate meta for our Log4j plugins
|
||||
// Paper end
|
||||
implementation("org.apache.logging.log4j:log4j-iostreams:2.17.1") // Paper
|
||||
implementation("org.ow2.asm:asm:9.3")
|
||||
implementation("org.ow2.asm:asm-commons:9.3") // Paper - ASM event executor generation
|
||||
implementation("org.spongepowered:configurate-yaml:4.1.2") // Paper - config files
|
||||
implementation("commons-lang:commons-lang:2.6")
|
||||
+ implementation("net.fabricmc:mapping-io:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation
|
||||
runtimeOnly("org.xerial:sqlite-jdbc:3.36.0.3")
|
||||
runtimeOnly("mysql:mysql-connector-java:8.0.29")
|
||||
runtimeOnly("com.lmax:disruptor:3.4.4") // Paper
|
||||
@@ -104,6 +106,18 @@ tasks.check {
|
||||
}
|
||||
// Paper end
|
||||
|
||||
+// Paper start - include reobf mappings in jar for stacktrace deobfuscation
|
||||
+val includeMappings = tasks.register<io.papermc.paperweight.tasks.IncludeMappings>("includeMappings") {
|
||||
+ inputJar.set(tasks.fixJarForReobf.flatMap { it.outputJar })
|
||||
+ mappings.set(tasks.reobfJar.flatMap { it.mappingsFile })
|
||||
+ mappingsDest.set("META-INF/mappings/reobf.tiny")
|
||||
+}
|
||||
+
|
||||
+tasks.reobfJar {
|
||||
+ inputJar.set(includeMappings.flatMap { it.outputJar })
|
||||
+}
|
||||
+// Paper end - include reobf mappings in jar for stacktrace deobfuscation
|
||||
+
|
||||
tasks.test {
|
||||
exclude("org/bukkit/craftbukkit/inventory/ItemStack*Test.class")
|
||||
}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java b/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java
|
||||
index 0bb4aaa546939b67a5d22865190f30478a9337c1..d3e619655382e50e9ac9323ed942502d85c9599c 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java
|
||||
@@ -91,7 +91,7 @@ public class SyncLoadFinder {
|
||||
|
||||
final JsonArray traces = new JsonArray();
|
||||
|
||||
- for (StackTraceElement element : pair.getFirst().stacktrace) {
|
||||
+ for (StackTraceElement element : io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateStacktrace(pair.getFirst().stacktrace)) {
|
||||
traces.add(String.valueOf(element));
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/logging/StacktraceDeobfuscatingRewritePolicy.java b/src/main/java/io/papermc/paper/logging/StacktraceDeobfuscatingRewritePolicy.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..c701ef3c287f62aa0ebfbdbd6da6ed82a1c7793c
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/logging/StacktraceDeobfuscatingRewritePolicy.java
|
||||
@@ -0,0 +1,38 @@
|
||||
+package io.papermc.paper.logging;
|
||||
+
|
||||
+import io.papermc.paper.util.StacktraceDeobfuscator;
|
||||
+import org.apache.logging.log4j.core.Core;
|
||||
+import org.apache.logging.log4j.core.LogEvent;
|
||||
+import org.apache.logging.log4j.core.appender.rewrite.RewritePolicy;
|
||||
+import org.apache.logging.log4j.core.config.plugins.Plugin;
|
||||
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
|
||||
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+
|
||||
+@Plugin(
|
||||
+ name = "StacktraceDeobfuscatingRewritePolicy",
|
||||
+ category = Core.CATEGORY_NAME,
|
||||
+ elementType = "rewritePolicy",
|
||||
+ printObject = true
|
||||
+)
|
||||
+public final class StacktraceDeobfuscatingRewritePolicy implements RewritePolicy {
|
||||
+ private StacktraceDeobfuscatingRewritePolicy() {
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @NonNull LogEvent rewrite(final @NonNull LogEvent rewrite) {
|
||||
+ final Throwable thrown = rewrite.getThrown();
|
||||
+ if (thrown != null) {
|
||||
+ StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(thrown);
|
||||
+ return new Log4jLogEvent.Builder(rewrite)
|
||||
+ .setThrownProxy(null)
|
||||
+ .build();
|
||||
+ }
|
||||
+ return rewrite;
|
||||
+ }
|
||||
+
|
||||
+ @PluginFactory
|
||||
+ public static @NonNull StacktraceDeobfuscatingRewritePolicy createPolicy() {
|
||||
+ return new StacktraceDeobfuscatingRewritePolicy();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/util/ObfHelper.java b/src/main/java/io/papermc/paper/util/ObfHelper.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..b8b17d046f836c8652ab094db00ab1af84971b2c
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/util/ObfHelper.java
|
||||
@@ -0,0 +1,146 @@
|
||||
+package io.papermc.paper.util;
|
||||
+
|
||||
+import java.io.IOException;
|
||||
+import java.io.InputStream;
|
||||
+import java.io.InputStreamReader;
|
||||
+import java.nio.charset.StandardCharsets;
|
||||
+import java.util.HashMap;
|
||||
+import java.util.HashSet;
|
||||
+import java.util.Map;
|
||||
+import java.util.Set;
|
||||
+import java.util.function.Function;
|
||||
+import java.util.stream.Collectors;
|
||||
+import net.fabricmc.mappingio.MappingReader;
|
||||
+import net.fabricmc.mappingio.format.MappingFormat;
|
||||
+import net.fabricmc.mappingio.tree.MappingTree;
|
||||
+import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public enum ObfHelper {
|
||||
+ INSTANCE;
|
||||
+
|
||||
+ public static final String MOJANG_PLUS_YARN_NAMESPACE = "mojang+yarn";
|
||||
+ public static final String SPIGOT_NAMESPACE = "spigot";
|
||||
+
|
||||
+ private final @Nullable Map<String, ClassMapping> mappingsByObfName;
|
||||
+ private final @Nullable Map<String, ClassMapping> mappingsByMojangName;
|
||||
+
|
||||
+ ObfHelper() {
|
||||
+ final @Nullable Set<ClassMapping> maps = loadMappingsIfPresent();
|
||||
+ if (maps != null) {
|
||||
+ this.mappingsByObfName = maps.stream().collect(Collectors.toUnmodifiableMap(ClassMapping::obfName, map -> map));
|
||||
+ this.mappingsByMojangName = maps.stream().collect(Collectors.toUnmodifiableMap(ClassMapping::mojangName, map -> map));
|
||||
+ } else {
|
||||
+ this.mappingsByObfName = null;
|
||||
+ this.mappingsByMojangName = null;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public @Nullable Map<String, ClassMapping> mappingsByObfName() {
|
||||
+ return this.mappingsByObfName;
|
||||
+ }
|
||||
+
|
||||
+ public @Nullable Map<String, ClassMapping> mappingsByMojangName() {
|
||||
+ return this.mappingsByMojangName;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Attempts to get the obf name for a given class by its Mojang name. Will
|
||||
+ * return the input string if mappings are not present.
|
||||
+ *
|
||||
+ * @param fullyQualifiedMojangName fully qualified class name (dotted)
|
||||
+ * @return mapped or original fully qualified (dotted) class name
|
||||
+ */
|
||||
+ public String reobfClassName(final String fullyQualifiedMojangName) {
|
||||
+ if (this.mappingsByMojangName == null) {
|
||||
+ return fullyQualifiedMojangName;
|
||||
+ }
|
||||
+
|
||||
+ final ClassMapping map = this.mappingsByMojangName.get(fullyQualifiedMojangName);
|
||||
+ if (map == null) {
|
||||
+ return fullyQualifiedMojangName;
|
||||
+ }
|
||||
+
|
||||
+ return map.obfName();
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Attempts to get the Mojang name for a given class by its obf name. Will
|
||||
+ * return the input string if mappings are not present.
|
||||
+ *
|
||||
+ * @param fullyQualifiedObfName fully qualified class name (dotted)
|
||||
+ * @return mapped or original fully qualified (dotted) class name
|
||||
+ */
|
||||
+ public String deobfClassName(final String fullyQualifiedObfName) {
|
||||
+ if (this.mappingsByObfName == null) {
|
||||
+ return fullyQualifiedObfName;
|
||||
+ }
|
||||
+
|
||||
+ final ClassMapping map = this.mappingsByObfName.get(fullyQualifiedObfName);
|
||||
+ if (map == null) {
|
||||
+ return fullyQualifiedObfName;
|
||||
+ }
|
||||
+
|
||||
+ return map.mojangName();
|
||||
+ }
|
||||
+
|
||||
+ private static @Nullable Set<ClassMapping> loadMappingsIfPresent() {
|
||||
+ try (final @Nullable InputStream mappingsInputStream = ObfHelper.class.getClassLoader().getResourceAsStream("META-INF/mappings/reobf.tiny")) {
|
||||
+ if (mappingsInputStream == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ final MemoryMappingTree tree = new MemoryMappingTree();
|
||||
+ MappingReader.read(new InputStreamReader(mappingsInputStream, StandardCharsets.UTF_8), MappingFormat.TINY_2, tree);
|
||||
+ final Set<ClassMapping> classes = new HashSet<>();
|
||||
+
|
||||
+ final StringPool pool = new StringPool();
|
||||
+ for (final MappingTree.ClassMapping cls : tree.getClasses()) {
|
||||
+ final Map<String, String> methods = new HashMap<>();
|
||||
+
|
||||
+ for (final MappingTree.MethodMapping methodMapping : cls.getMethods()) {
|
||||
+ methods.put(
|
||||
+ pool.string(methodKey(
|
||||
+ methodMapping.getName(SPIGOT_NAMESPACE),
|
||||
+ methodMapping.getDesc(SPIGOT_NAMESPACE)
|
||||
+ )),
|
||||
+ pool.string(methodMapping.getName(MOJANG_PLUS_YARN_NAMESPACE))
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ final ClassMapping map = new ClassMapping(
|
||||
+ cls.getName(SPIGOT_NAMESPACE).replace('/', '.'),
|
||||
+ cls.getName(MOJANG_PLUS_YARN_NAMESPACE).replace('/', '.'),
|
||||
+ Map.copyOf(methods)
|
||||
+ );
|
||||
+ classes.add(map);
|
||||
+ }
|
||||
+
|
||||
+ return Set.copyOf(classes);
|
||||
+ } catch (final IOException ex) {
|
||||
+ System.err.println("Failed to load mappings for stacktrace deobfuscation.");
|
||||
+ ex.printStackTrace();
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static String methodKey(final String obfName, final String obfDescriptor) {
|
||||
+ return obfName + obfDescriptor;
|
||||
+ }
|
||||
+
|
||||
+ private static final class StringPool {
|
||||
+ private final Map<String, String> pool = new HashMap<>();
|
||||
+
|
||||
+ public String string(final String string) {
|
||||
+ return this.pool.computeIfAbsent(string, Function.identity());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public record ClassMapping(
|
||||
+ String obfName,
|
||||
+ String mojangName,
|
||||
+ Map<String, String> methodsByObf
|
||||
+ ) {}
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java b/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..eb910d4abf91488fa7cf1f5d47e0ee916c47f512
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java
|
||||
@@ -0,0 +1,163 @@
|
||||
+package io.papermc.paper.util;
|
||||
+
|
||||
+import io.papermc.paper.configuration.GlobalConfiguration;
|
||||
+import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
+import it.unimi.dsi.fastutil.ints.IntList;
|
||||
+import java.io.IOException;
|
||||
+import java.io.InputStream;
|
||||
+import java.util.Collections;
|
||||
+import java.util.HashMap;
|
||||
+import java.util.LinkedHashMap;
|
||||
+import java.util.Map;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+import org.objectweb.asm.ClassReader;
|
||||
+import org.objectweb.asm.ClassVisitor;
|
||||
+import org.objectweb.asm.Label;
|
||||
+import org.objectweb.asm.MethodVisitor;
|
||||
+import org.objectweb.asm.Opcodes;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public enum StacktraceDeobfuscator {
|
||||
+ INSTANCE;
|
||||
+
|
||||
+ private final Map<Class<?>, Map<String, IntList>> lineMapCache = Collections.synchronizedMap(new LinkedHashMap<>(128, 0.75f, true) {
|
||||
+ @Override
|
||||
+ protected boolean removeEldestEntry(final Map.Entry<Class<?>, Map<String, IntList>> eldest) {
|
||||
+ return this.size() > 127;
|
||||
+ }
|
||||
+ });
|
||||
+
|
||||
+ public void deobfuscateThrowable(final Throwable throwable) {
|
||||
+ if (GlobalConfiguration.get() != null && !GlobalConfiguration.get().logging.deobfuscateStacktraces) { // handle null as true
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ throwable.setStackTrace(this.deobfuscateStacktrace(throwable.getStackTrace()));
|
||||
+ final Throwable cause = throwable.getCause();
|
||||
+ if (cause != null) {
|
||||
+ this.deobfuscateThrowable(cause);
|
||||
+ }
|
||||
+ for (final Throwable suppressed : throwable.getSuppressed()) {
|
||||
+ this.deobfuscateThrowable(suppressed);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public StackTraceElement[] deobfuscateStacktrace(final StackTraceElement[] traceElements) {
|
||||
+ if (GlobalConfiguration.get() != null && !GlobalConfiguration.get().logging.deobfuscateStacktraces) { // handle null as true
|
||||
+ return traceElements;
|
||||
+ }
|
||||
+
|
||||
+ final @Nullable Map<String, ObfHelper.ClassMapping> mappings = ObfHelper.INSTANCE.mappingsByObfName();
|
||||
+ if (mappings == null || traceElements.length == 0) {
|
||||
+ return traceElements;
|
||||
+ }
|
||||
+ final StackTraceElement[] result = new StackTraceElement[traceElements.length];
|
||||
+ for (int i = 0; i < traceElements.length; i++) {
|
||||
+ final StackTraceElement element = traceElements[i];
|
||||
+
|
||||
+ final String className = element.getClassName();
|
||||
+ final String methodName = element.getMethodName();
|
||||
+
|
||||
+ final ObfHelper.ClassMapping classMapping = mappings.get(className);
|
||||
+ if (classMapping == null) {
|
||||
+ result[i] = element;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ final Class<?> clazz;
|
||||
+ try {
|
||||
+ clazz = Class.forName(className);
|
||||
+ } catch (final ClassNotFoundException ex) {
|
||||
+ throw new RuntimeException(ex);
|
||||
+ }
|
||||
+ final @Nullable String methodKey = this.determineMethodForLine(clazz, element.getLineNumber());
|
||||
+ final @Nullable String mappedMethodName = methodKey == null ? null : classMapping.methodsByObf().get(methodKey);
|
||||
+
|
||||
+ result[i] = new StackTraceElement(
|
||||
+ element.getClassLoaderName(),
|
||||
+ element.getModuleName(),
|
||||
+ element.getModuleVersion(),
|
||||
+ classMapping.mojangName(),
|
||||
+ mappedMethodName != null ? mappedMethodName : methodName,
|
||||
+ sourceFileName(classMapping.mojangName()),
|
||||
+ element.getLineNumber()
|
||||
+ );
|
||||
+ }
|
||||
+ return result;
|
||||
+ }
|
||||
+
|
||||
+ private @Nullable String determineMethodForLine(final Class<?> clazz, final int lineNumber) {
|
||||
+ final Map<String, IntList> lineMap = this.lineMapCache.computeIfAbsent(clazz, StacktraceDeobfuscator::buildLineMap);
|
||||
+ for (final var entry : lineMap.entrySet()) {
|
||||
+ final String methodKey = entry.getKey();
|
||||
+ final IntList lines = entry.getValue();
|
||||
+ for (int i = 0, linesSize = lines.size(); i < linesSize; i++) {
|
||||
+ final int num = lines.getInt(i);
|
||||
+ if (num == lineNumber) {
|
||||
+ return methodKey;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ private static String sourceFileName(final String fullClassName) {
|
||||
+ final int dot = fullClassName.lastIndexOf('.');
|
||||
+ final String className = dot == -1
|
||||
+ ? fullClassName
|
||||
+ : fullClassName.substring(dot + 1);
|
||||
+ final String rootClassName = className.split("\\$")[0];
|
||||
+ return rootClassName + ".java";
|
||||
+ }
|
||||
+
|
||||
+ private static Map<String, IntList> buildLineMap(final Class<?> key) {
|
||||
+ final Map<String, IntList> lineMap = new HashMap<>();
|
||||
+ final class LineCollectingMethodVisitor extends MethodVisitor {
|
||||
+ private final IntList lines = new IntArrayList();
|
||||
+ private final String name;
|
||||
+ private final String descriptor;
|
||||
+
|
||||
+ LineCollectingMethodVisitor(String name, String descriptor) {
|
||||
+ super(Opcodes.ASM9);
|
||||
+ this.name = name;
|
||||
+ this.descriptor = descriptor;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void visitLineNumber(int line, Label start) {
|
||||
+ super.visitLineNumber(line, start);
|
||||
+ this.lines.add(line);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void visitEnd() {
|
||||
+ super.visitEnd();
|
||||
+ lineMap.put(ObfHelper.methodKey(this.name, this.descriptor), this.lines);
|
||||
+ }
|
||||
+ }
|
||||
+ final ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM9) {
|
||||
+ @Override
|
||||
+ public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
||||
+ return new LineCollectingMethodVisitor(name, descriptor);
|
||||
+ }
|
||||
+ };
|
||||
+ try {
|
||||
+ final @Nullable InputStream inputStream = StacktraceDeobfuscator.class.getClassLoader()
|
||||
+ .getResourceAsStream(key.getName().replace('.', '/') + ".class");
|
||||
+ if (inputStream == null) {
|
||||
+ throw new IllegalStateException("Could not find class file: " + key.getName());
|
||||
+ }
|
||||
+ final byte[] classData;
|
||||
+ try (inputStream) {
|
||||
+ classData = inputStream.readAllBytes();
|
||||
+ }
|
||||
+ final ClassReader reader = new ClassReader(classData);
|
||||
+ reader.accept(classVisitor, 0);
|
||||
+ } catch (final IOException ex) {
|
||||
+ throw new RuntimeException(ex);
|
||||
+ }
|
||||
+ return lineMap;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/util/TraceUtil.java b/src/main/java/io/papermc/paper/util/TraceUtil.java
|
||||
index 2d5494d2813b773e60ddba6790b750a9a08f21f8..0b210bdf7c1f5962afbd44195af6f84f625635e3 100644
|
||||
--- a/src/main/java/io/papermc/paper/util/TraceUtil.java
|
||||
+++ b/src/main/java/io/papermc/paper/util/TraceUtil.java
|
||||
@@ -6,13 +6,20 @@ public final class TraceUtil {
|
||||
|
||||
public static void dumpTraceForThread(Thread thread, String reason) {
|
||||
Bukkit.getLogger().warning(thread.getName() + ": " + reason);
|
||||
- StackTraceElement[] trace = thread.getStackTrace();
|
||||
+ StackTraceElement[] trace = StacktraceDeobfuscator.INSTANCE.deobfuscateStacktrace(thread.getStackTrace());
|
||||
for (StackTraceElement traceElement : trace) {
|
||||
Bukkit.getLogger().warning("\tat " + traceElement);
|
||||
}
|
||||
}
|
||||
|
||||
public static void dumpTraceForThread(String reason) {
|
||||
- new Throwable(reason).printStackTrace();
|
||||
+ final Throwable throwable = new Throwable(reason);
|
||||
+ StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(throwable);
|
||||
+ throwable.printStackTrace();
|
||||
+ }
|
||||
+
|
||||
+ public static void printStackTrace(Throwable thr) {
|
||||
+ StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(thr);
|
||||
+ thr.printStackTrace();
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/CrashReport.java b/src/main/java/net/minecraft/CrashReport.java
|
||||
index 30a58229aa6dac5039511d0c0df5f2912ea7de9f..abe37c7c3c6f5ab73afd738ec78f06d7e4d2ed96 100644
|
||||
--- a/src/main/java/net/minecraft/CrashReport.java
|
||||
+++ b/src/main/java/net/minecraft/CrashReport.java
|
||||
@@ -32,6 +32,7 @@ public class CrashReport {
|
||||
private final SystemReport systemReport = new SystemReport();
|
||||
|
||||
public CrashReport(String message, Throwable cause) {
|
||||
+ io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(cause); // Paper
|
||||
this.title = message;
|
||||
this.exception = cause;
|
||||
this.systemReport.setDetail("CraftBukkit Information", new org.bukkit.craftbukkit.CraftCrashReport()); // CraftBukkit
|
||||
diff --git a/src/main/java/net/minecraft/CrashReportCategory.java b/src/main/java/net/minecraft/CrashReportCategory.java
|
||||
index 65231daec99d36d9ad3c1ca8561b6dbc49efde10..6df4d02020a14d17d9c5b1971bb5640b35411c45 100644
|
||||
--- a/src/main/java/net/minecraft/CrashReportCategory.java
|
||||
+++ b/src/main/java/net/minecraft/CrashReportCategory.java
|
||||
@@ -104,6 +104,7 @@ public class CrashReportCategory {
|
||||
} else {
|
||||
this.stackTrace = new StackTraceElement[stackTraceElements.length - 3 - ignoredCallCount];
|
||||
System.arraycopy(stackTraceElements, 3 + ignoredCallCount, this.stackTrace, 0, this.stackTrace.length);
|
||||
+ this.stackTrace = io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateStacktrace(this.stackTrace); // Paper
|
||||
return this.stackTrace.length;
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
|
||||
index 8bc8b6013ea5803e091cf3534130b72278b9c29e..dca0c978b30962d4216dc443d7d105e54a29ae1b 100644
|
||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
||||
@@ -62,13 +62,13 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
});
|
||||
public static final AttributeKey<ConnectionProtocol> ATTRIBUTE_PROTOCOL = AttributeKey.valueOf("protocol");
|
||||
public static final LazyLoadedValue<NioEventLoopGroup> NETWORK_WORKER_GROUP = new LazyLoadedValue<>(() -> {
|
||||
- return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Client IO #%d").setDaemon(true).build());
|
||||
+ return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Client IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()); // Paper
|
||||
});
|
||||
public static final LazyLoadedValue<EpollEventLoopGroup> NETWORK_EPOLL_WORKER_GROUP = new LazyLoadedValue<>(() -> {
|
||||
- return new EpollEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Epoll Client IO #%d").setDaemon(true).build());
|
||||
+ return new EpollEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Epoll Client IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()); // Paper
|
||||
});
|
||||
public static final LazyLoadedValue<DefaultEventLoopGroup> LOCAL_WORKER_GROUP = new LazyLoadedValue<>(() -> {
|
||||
- return new DefaultEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Local Client IO #%d").setDaemon(true).build());
|
||||
+ return new DefaultEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Local Client IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()); // Paper
|
||||
});
|
||||
private final PacketFlow receiving;
|
||||
private final Queue<Connection.PacketHolder> queue = Queues.newConcurrentLinkedQueue();
|
||||
@@ -193,7 +193,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
|
||||
}
|
||||
}
|
||||
- if (net.minecraft.server.MinecraftServer.getServer().isDebugging()) throwable.printStackTrace(); // Spigot
|
||||
+ if (net.minecraft.server.MinecraftServer.getServer().isDebugging()) io.papermc.paper.util.TraceUtil.printStackTrace(throwable); // Spigot // Paper
|
||||
}
|
||||
|
||||
protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet<?> packet) {
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 6fba140877e7369cdb7933ec225572c6b153e3a8..e3a62579067209c447f2fdcb76b2a11e489a376b 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -200,6 +200,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
org.spigotmc.SpigotConfig.registerCommands();
|
||||
// Spigot end
|
||||
// Paper start
|
||||
+ io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // Paper - load mappings for stacktrace deobf and etc.
|
||||
paperConfigurations.initializeGlobalConfiguration();
|
||||
paperConfigurations.initializeWorldDefaultsConfiguration();
|
||||
org.spigotmc.WatchdogThread.doStart(org.spigotmc.SpigotConfig.timeoutTime, org.spigotmc.SpigotConfig.restartOnCrash);
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index d18337c4c123819e4d5f55b65985e548da492627..6cdd0c13189f372dcf562c4190f4c6155b33dd13 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -218,7 +218,9 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
public final UUID uuid;
|
||||
public boolean hasPhysicsEvent = true; // Paper
|
||||
public static Throwable getAddToWorldStackTrace(Entity entity) {
|
||||
- return new Throwable(entity + " Added to world at " + new java.util.Date());
|
||||
+ final Throwable thr = new Throwable(entity + " Added to world at " + new java.util.Date());
|
||||
+ io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(thr);
|
||||
+ return thr;
|
||||
}
|
||||
|
||||
@Override public LevelChunk getChunkIfLoaded(int x, int z) { // Paper - this was added in world too but keeping here for NMS ABI
|
||||
@@ -1290,7 +1292,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
if (entity.isRemoved()) {
|
||||
// Paper start
|
||||
if (DEBUG_ENTITIES) {
|
||||
- new Throwable("Tried to add entity " + entity + " but it was marked as removed already").printStackTrace(); // CraftBukkit
|
||||
+ io.papermc.paper.util.TraceUtil.dumpTraceForThread("Tried to add entity " + entity + " but it was marked as removed already"); // CraftBukkit
|
||||
getAddToWorldStackTrace(entity).printStackTrace();
|
||||
}
|
||||
// Paper end
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
index a24ef433d0c9d06b86fd612978cfd6d877036791..1b38326c9a709536dc4cccf9af93aede98a1a782 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
@@ -54,10 +54,10 @@ public class ServerConnectionListener {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
public static final LazyLoadedValue<NioEventLoopGroup> SERVER_EVENT_GROUP = new LazyLoadedValue<>(() -> {
|
||||
- return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Server IO #%d").setDaemon(true).build());
|
||||
+ return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Server IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()); // Paper
|
||||
});
|
||||
public static final LazyLoadedValue<EpollEventLoopGroup> SERVER_EPOLL_EVENT_GROUP = new LazyLoadedValue<>(() -> {
|
||||
- return new EpollEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Epoll Server IO #%d").setDaemon(true).build());
|
||||
+ return new EpollEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Epoll Server IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()); // Paper
|
||||
});
|
||||
final MinecraftServer server;
|
||||
public volatile boolean running;
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index 930da83ff754bab6b6b6fff651df417baa76c46f..c3027735725c68eeb1b42a42ebb8646f3a35a518 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -204,7 +204,7 @@ public class ServerLoginPacketListenerImpl implements TickablePacketListener, Se
|
||||
MutableComponent ichatmutablecomponent = Component.translatable("multiplayer.disconnect.invalid_player_data");
|
||||
// Paper start
|
||||
if (MinecraftServer.getServer().isDebugging()) {
|
||||
- exception.printStackTrace();
|
||||
+ io.papermc.paper.util.TraceUtil.printStackTrace(exception);
|
||||
}
|
||||
// Paper end
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/players/OldUsersConverter.java b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||
index 6599f874d9f97e9ef4862039ecad7277bbc5fd91..7edd4b88eb0476f0630630bc4681e859bd145b2b 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||
@@ -364,7 +364,7 @@ public class OldUsersConverter {
|
||||
try {
|
||||
root = NbtIo.readCompressed(new java.io.FileInputStream(file5));
|
||||
} catch (Exception exception) {
|
||||
- exception.printStackTrace();
|
||||
+ io.papermc.paper.util.TraceUtil.printStackTrace(exception); // Paper
|
||||
ServerInternalException.reportInternalException(exception); // Paper
|
||||
}
|
||||
|
||||
@@ -378,7 +378,7 @@ public class OldUsersConverter {
|
||||
try {
|
||||
NbtIo.writeCompressed(root, new java.io.FileOutputStream(file2));
|
||||
} catch (Exception exception) {
|
||||
- exception.printStackTrace();
|
||||
+ io.papermc.paper.util.TraceUtil.printStackTrace(exception); // Paper
|
||||
ServerInternalException.reportInternalException(exception); // Paper
|
||||
}
|
||||
}
|
||||
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 b2d06181ad76b1db2abb1ddca075f4ec6dab55dc..aa3adc628178962ce89df0e372c925e8f4801606 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -640,7 +640,7 @@ public class LevelChunk extends ChunkAccess {
|
||||
+ " (" + getBlockState(blockposition) + ") where there was no entity tile!\n" +
|
||||
"Chunk coordinates: " + (this.chunkPos.x * 16) + "," + (this.chunkPos.z * 16) +
|
||||
"\nWorld: " + level.getLevel().dimension().location());
|
||||
- e.printStackTrace();
|
||||
+ io.papermc.paper.util.TraceUtil.printStackTrace(e);
|
||||
ServerInternalException.reportInternalException(e);
|
||||
// Paper end
|
||||
// CraftBukkit end
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java
|
||||
index 3c1992e212a6d6f1db4d5b807b38d71913619fc0..9c1aff17aabd062640e3f451a2ef8c50a7c62f10 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java
|
||||
@@ -40,9 +40,9 @@ public class CraftAsyncScheduler extends CraftScheduler {
|
||||
|
||||
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
|
||||
4, Integer.MAX_VALUE,30L, TimeUnit.SECONDS, new SynchronousQueue<>(),
|
||||
- new ThreadFactoryBuilder().setNameFormat("Craft Scheduler Thread - %1$d").build());
|
||||
+ new ThreadFactoryBuilder().setNameFormat("Craft Scheduler Thread - %1$d").setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(net.minecraft.server.MinecraftServer.LOGGER)).build()); // Paper
|
||||
private final Executor management = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder()
|
||||
- .setNameFormat("Craft Async Scheduler Management Thread").build());
|
||||
+ .setNameFormat("Craft Async Scheduler Management Thread").setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(net.minecraft.server.MinecraftServer.LOGGER)).build()); // Paper
|
||||
private final List<CraftTask> temp = new ArrayList<>();
|
||||
|
||||
CraftAsyncScheduler() {
|
||||
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
index 383c52c62f49b17db2fbf58009d6ea132d124bea..e0a71bfc1498a517456b21747ab6ef3f1067a3f3 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -105,7 +105,7 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
log.log( Level.SEVERE, "During the run of the server, a plugin set an excessive velocity on an entity" );
|
||||
log.log( Level.SEVERE, "This may be the cause of the issue, or it may be entirely unrelated" );
|
||||
log.log( Level.SEVERE, org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getMessage());
|
||||
- for ( StackTraceElement stack : org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getStackTrace() )
|
||||
+ for ( StackTraceElement stack : io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateStacktrace(org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getStackTrace()) ) // Paper
|
||||
{
|
||||
log.log( Level.SEVERE, "\t\t" + stack );
|
||||
}
|
||||
@@ -193,7 +193,7 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
}
|
||||
log.log( Level.SEVERE, "\tStack:" );
|
||||
//
|
||||
- for ( StackTraceElement stack : thread.getStackTrace() )
|
||||
+ for ( StackTraceElement stack : io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateStacktrace(thread.getStackTrace()) ) // Paper
|
||||
{
|
||||
log.log( Level.SEVERE, "\t\t" + stack );
|
||||
}
|
||||
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
|
||||
index d285dbec16272db6b8a71865e05924ad66087407..1a05d23ff886b015fb9396f119822c678a47ec6f 100644
|
||||
--- a/src/main/resources/log4j2.xml
|
||||
+++ b/src/main/resources/log4j2.xml
|
||||
@@ -30,10 +30,14 @@
|
||||
<DefaultRolloverStrategy max="1000"/>
|
||||
</RollingRandomAccessFile>
|
||||
<Async name="Async">
|
||||
+ <AppenderRef ref="rewrite"/>
|
||||
+ </Async>
|
||||
+ <Rewrite name="rewrite">
|
||||
+ <StacktraceDeobfuscatingRewritePolicy />
|
||||
<AppenderRef ref="File"/>
|
||||
<AppenderRef ref="TerminalConsole" level="info"/>
|
||||
<AppenderRef ref="ServerGuiConsole" level="info"/>
|
||||
- </Async>
|
||||
+ </Rewrite>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Root level="info">
|
|
@ -1,915 +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 2ff278cdc3dfef4644b12755be2e3a69a43e1f07..2d1e639bd2880469d849ca1242184b0af1f6903c 100644
|
||||
--- a/build.gradle.kts
|
||||
+++ b/build.gradle.kts
|
||||
@@ -35,6 +35,7 @@ dependencies {
|
||||
runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.7.3")
|
||||
runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.7.3")
|
||||
|
||||
+ testImplementation("io.github.classgraph:classgraph:4.8.47") // Paper - mob goal test
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
testImplementation("org.hamcrest:hamcrest-library:1.3")
|
||||
|
||||
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..c9901f8c7f3af57cb2e0bec315caa97adcb6f5ea
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java
|
||||
@@ -0,0 +1,371 @@
|
||||
+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.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.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(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);
|
||||
+ }
|
||||
+
|
||||
+ public static String getUsableName(Class<?> clazz) {
|
||||
+ String name = ObfHelper.INSTANCE.deobfClassName(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()) && !ignored.contains(name)) {
|
||||
+ System.out.println("need to map " + clazz.getName() + " (" + name.toLowerCase() + ")");
|
||||
+ }
|
||||
+
|
||||
+ // did we rename this key?
|
||||
+ return deobfuscationMap.getOrDefault(name, name);
|
||||
+ }
|
||||
+
|
||||
+ public static EnumSet<GoalType> vanillaToPaper(OptimizedSmallEnumSet<Goal.Flag> types) {
|
||||
+ EnumSet<GoalType> goals = EnumSet.noneOf(GoalType.class);
|
||||
+ for (GoalType type : GoalType.values()) {
|
||||
+ if (types.hasElement(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..26c745dd9ccdfdd5c5039f2acc5201b9b91fb274
|
||||
--- /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().addUnchecked(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..5e7b4a8698a00f72d6e817cc7c6716e7605a3484
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/PaperMobGoals.java
|
||||
@@ -0,0 +1,213 @@
|
||||
+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;
|
||||
+ getHandle(craftMob, goal.getTypes()).addGoal(priority, new PaperCustomGoal<>(goal));
|
||||
+ }
|
||||
+
|
||||
+ @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().hasElement(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().hasElement(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).getRunningGoals()
|
||||
+ .filter(item -> item.getGoal().getFlags().hasElement(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).getRunningGoals()
|
||||
+ .filter(item -> !item.getGoal().getFlags().hasElement(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..0d30e0b21b9024df939a9d070bd4a99b217e7c12
|
||||
--- /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.getFlags());
|
||||
+ }
|
||||
+
|
||||
+ 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 4379b9948f1eecfe6fd7dea98e298ad5f761019a..3f081183521603824430709886a9cc313c28e7cb 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
|
||||
@@ -7,6 +7,14 @@ public abstract class Goal {
|
||||
private final EnumSet<Goal.Flag> flags = EnumSet.noneOf(Goal.Flag.class); // Paper unused, but dummy to prevent plugins from crashing as hard. Theyll need to support paper in a special case if this is super important, but really doesn't seem like it would be.
|
||||
private final com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<net.minecraft.world.entity.ai.goal.Goal.Flag> goalTypes = new com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from pathfindergoalselector
|
||||
|
||||
+ // Paper start make sure goaltypes is never empty
|
||||
+ public Goal() {
|
||||
+ if (this.goalTypes.size() == 0) {
|
||||
+ this.goalTypes.addUnchecked(Flag.UNKNOWN_BEHAVIOR);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public abstract boolean canUse();
|
||||
|
||||
public boolean canContinueToUse() {
|
||||
@@ -34,6 +42,10 @@ public abstract class Goal {
|
||||
// Paper start - remove streams from pathfindergoalselector
|
||||
this.goalTypes.clear();
|
||||
this.goalTypes.addAllUnchecked(controls);
|
||||
+ // make sure its never empty
|
||||
+ if (this.goalTypes.size() == 0) {
|
||||
+ this.goalTypes.addUnchecked(Flag.UNKNOWN_BEHAVIOR);
|
||||
+ }
|
||||
// Paper end - remove streams from pathfindergoalselector
|
||||
}
|
||||
|
||||
@@ -56,7 +68,19 @@ public abstract class Goal {
|
||||
return Mth.positiveCeilDiv(serverTicks, 2);
|
||||
}
|
||||
|
||||
+ // Paper start - mob goal api
|
||||
+ private com.destroystokyo.paper.entity.ai.PaperVanillaGoal<?> vanillaGoal = null;
|
||||
+ 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 8d4388df7e62016df262e377e5f75cc44e17e284..f1134bce181e8ea5eebb241e3af9691390cd2533 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2691,5 +2691,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
|
||||
}
|
||||
diff --git a/src/test/java/com/destroystokyo/paper/entity/ai/VanillaMobGoalTest.java b/src/test/java/com/destroystokyo/paper/entity/ai/VanillaMobGoalTest.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..b2d510459bcf90a3611f3d91dae4ccc3d29b4079
|
||||
--- /dev/null
|
||||
+++ b/src/test/java/com/destroystokyo/paper/entity/ai/VanillaMobGoalTest.java
|
||||
@@ -0,0 +1,103 @@
|
||||
+package com.destroystokyo.paper.entity.ai;
|
||||
+
|
||||
+import org.junit.Assert;
|
||||
+import org.junit.Test;
|
||||
+
|
||||
+import java.lang.reflect.Field;
|
||||
+import java.lang.reflect.Modifier;
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.Collections;
|
||||
+import java.util.List;
|
||||
+import java.util.stream.Collectors;
|
||||
+
|
||||
+import org.bukkit.entity.Mob;
|
||||
+
|
||||
+import io.github.classgraph.ClassGraph;
|
||||
+import io.github.classgraph.ScanResult;
|
||||
+
|
||||
+public class VanillaMobGoalTest {
|
||||
+
|
||||
+ @Test
|
||||
+ public void testKeys() {
|
||||
+ List<GoalKey<?>> deprecated = new ArrayList<>();
|
||||
+ List<GoalKey<?>> keys = new ArrayList<>();
|
||||
+ for (Field field : VanillaGoal.class.getFields()) {
|
||||
+ if (field.getType().equals(GoalKey.class)) {
|
||||
+ try {
|
||||
+ GoalKey<?> goalKey = (GoalKey<?>) field.get(null);
|
||||
+ if (field.getAnnotation(Deprecated.class) != null) {
|
||||
+ deprecated.add(goalKey);
|
||||
+ } else {
|
||||
+ keys.add(goalKey);
|
||||
+ }
|
||||
+ } catch (IllegalAccessException e) {
|
||||
+ System.out.println("Skipping " + field.getName() + ": " + e.getMessage());
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ List<Class<?>> classes;
|
||||
+ try (ScanResult scanResult = new ClassGraph().enableAllInfo().whitelistPackages("net.minecraft").scan()) {
|
||||
+ classes = scanResult.getSubclasses(net.minecraft.world.entity.ai.goal.Goal.class.getName()).loadClasses();
|
||||
+ }
|
||||
+
|
||||
+ List<GoalKey<?>> vanillaNames = classes.stream()
|
||||
+ .filter(VanillaMobGoalTest::hasNoEnclosingClass)
|
||||
+ .filter(clazz -> !Modifier.isAbstract(clazz.getModifiers()))
|
||||
+ .filter(clazz -> !net.minecraft.world.entity.ai.goal.WrappedGoal.class.equals(clazz)) // TODO - properly fix
|
||||
+ .map(goalClass -> MobGoalHelper.getKey((Class<? extends net.minecraft.world.entity.ai.goal.Goal>) goalClass))
|
||||
+ .collect(Collectors.toList());
|
||||
+
|
||||
+ List<GoalKey<?>> missingFromAPI = new ArrayList<>(vanillaNames);
|
||||
+ missingFromAPI.removeAll(keys);
|
||||
+ missingFromAPI.removeIf(k -> MobGoalHelper.ignored.contains(k.getNamespacedKey().getKey()));
|
||||
+ List<GoalKey<?>> missingFromVanilla = new ArrayList<>(keys);
|
||||
+ missingFromVanilla.removeAll(vanillaNames);
|
||||
+
|
||||
+ boolean shouldFail = false;
|
||||
+ if (missingFromAPI.size() != 0) {
|
||||
+ System.out.println("Missing from API: ");
|
||||
+ for (GoalKey<?> key : missingFromAPI) {
|
||||
+ System.out.println("GoalKey<" + key.getEntityClass().getSimpleName() + "> " + key.getNamespacedKey().getKey().toUpperCase() +
|
||||
+ " = GoalKey.of(" + key.getEntityClass().getSimpleName() + ".class, NamespacedKey.minecraft(\"" + key.getNamespacedKey().getKey() + "\"));");
|
||||
+ }
|
||||
+ shouldFail = true;
|
||||
+ }
|
||||
+ if (missingFromVanilla.size() != 0) {
|
||||
+ System.out.println("Missing from vanilla: ");
|
||||
+ missingFromVanilla.forEach(System.out::println);
|
||||
+ shouldFail = true;
|
||||
+ }
|
||||
+
|
||||
+ if (deprecated.size() != 0) {
|
||||
+ System.out.println("Deprecated (might want to remove them at some point): ");
|
||||
+ deprecated.forEach(System.out::println);
|
||||
+ }
|
||||
+
|
||||
+ if (shouldFail) Assert.fail("See above");
|
||||
+ }
|
||||
+
|
||||
+ private static boolean hasNoEnclosingClass(Class<?> clazz) {
|
||||
+ return clazz.getEnclosingClass() == null || hasNoEnclosingClass(clazz.getSuperclass());
|
||||
+ }
|
||||
+
|
||||
+ @Test
|
||||
+ public void testBukkitMap() {
|
||||
+ List<Class<?>> classes;
|
||||
+ try (ScanResult scanResult = new ClassGraph().enableAllInfo().whitelistPackages("net.minecraft.world.entity").scan()) {
|
||||
+ classes = scanResult.getSubclasses("net.minecraft.world.entity.Mob").loadClasses();
|
||||
+ }
|
||||
+ Assert.assertNotEquals("There are supposed to be more than 0 entity types!", Collections.emptyList(), classes);
|
||||
+
|
||||
+ boolean shouldFail = false;
|
||||
+ for (Class<?> nmsClass : classes) {
|
||||
+ Class<? extends Mob> bukkitClass = MobGoalHelper.toBukkitClass((Class<? extends net.minecraft.world.entity.Mob>) nmsClass);
|
||||
+ if (bukkitClass == null) {
|
||||
+ shouldFail = true;
|
||||
+ System.out.println("Missing bukkitMap.put(" + nmsClass.getSimpleName() + ".class, " + nmsClass.getSimpleName().replace("Entity", "") + ".class);");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (shouldFail) Assert.fail("See above");
|
||||
+ }
|
||||
+}
|
|
@ -1,130 +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
|
||||
|
||||
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 76dfb546ddddb14497269d22ac1c8f84a0a9c15c..92beb137d86ae89d90b1963a024c0be308d81a42 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
|
||||
@@ -27,7 +27,7 @@ import net.minecraft.util.VisibleForDebug;
|
||||
|
||||
public class GossipContainer {
|
||||
public static final int DISCARD_THRESHOLD = 2;
|
||||
- private final Map<UUID, GossipContainer.EntityGossips> gossips = Maps.newHashMap();
|
||||
+ private final Map<UUID, GossipContainer.EntityGossips> gossips = Maps.newHashMap(); public Map<UUID, GossipContainer.EntityGossips> getReputations() { return this.gossips; } // Paper - add getter for reputations
|
||||
|
||||
@VisibleForDebug
|
||||
public Map<UUID, Object2IntMap<GossipType>> getGossipEntries() {
|
||||
@@ -226,6 +226,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
|
||||
}
|
||||
|
||||
static class GossipEntry {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
index 1a8a49bd269ed52879866ff3853e131d04aa8bba..d1f5e1292246e0fb252d3d3409bbf37cc8166bbc 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
@@ -17,6 +17,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) {
|
||||
@@ -146,4 +153,45 @@ public class CraftVillager extends CraftAbstractVillager implements Villager {
|
||||
public static VillagerProfession bukkitToNmsProfession(Profession bukkit) {
|
||||
return Registry.VILLAGER_PROFESSION.get(CraftNamespacedKey.toMinecraft(bukkit.getKey()));
|
||||
}
|
||||
+
|
||||
+ // Paper start - Add villager reputation API
|
||||
+ @Override
|
||||
+ public Reputation getReputation(UUID uniqueId) {
|
||||
+ net.minecraft.world.entity.ai.gossip.GossipContainer.EntityGossips rep = getHandle().getGossips().getReputations().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().getReputations().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().getReputations().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().getReputations().clear();
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -1,42 +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] Option for maximum exp value when merging orbs
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
index 751f376e175881d9e9f750c90143a7c39431ce6c..2dde21dea012f4531e737586752ae1b1f5023d99 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -630,16 +630,30 @@ public class CraftEventFactory {
|
||||
net.minecraft.world.entity.ExperienceOrb xp = (net.minecraft.world.entity.ExperienceOrb) entity;
|
||||
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 int maxValue = world.paperConfig().entities.behavior.experienceMergeMaxValue;
|
||||
+ final boolean mergeUnconditionally = world.paperConfig().entities.behavior.experienceMergeMaxValue <= 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) {
|
||||
net.minecraft.world.entity.ExperienceOrb loopItem = (net.minecraft.world.entity.ExperienceOrb) e;
|
||||
- if (!loopItem.isRemoved()) {
|
||||
+ // Paper start
|
||||
+ if (!loopItem.isRemoved() && !(maxValue > 0 && loopItem.value >= maxValue)) {
|
||||
+ long newTotal = (long)xp.value + (long)loopItem.value;
|
||||
+ if ((int) newTotal < 0) continue; // Overflow
|
||||
+ if (maxValue > 0 && newTotal > (long)maxValue) {
|
||||
+ loopItem.value = (int) (newTotal - maxValue);
|
||||
+ xp.value = maxValue;
|
||||
+ } else {
|
||||
xp.value += loopItem.value;
|
||||
loopItem.discard();
|
||||
+ } // Paper end
|
||||
}
|
||||
}
|
||||
}
|
||||
+ } // Paper end - End iteration skip check - All tweaking ends here
|
||||
}
|
||||
// Spigot end
|
||||
} else if (!(entity instanceof ServerPlayer)) {
|
|
@ -1,23 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 19 Dec 2017 22:57:26 -0500
|
||||
Subject: [PATCH] ExperienceOrbMergeEvent
|
||||
|
||||
Has to be reimplemented at one point maybe
|
||||
Fired when the server is about to merge 2 experience orbs
|
||||
Plugins can cancel this if they want to ensure experience orbs do not lose important
|
||||
metadata such as spawn reason, or conditionally move data from source to target.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
index 2dde21dea012f4531e737586752ae1b1f5023d99..359964cd8820b8ef8b8dba5501119164cebcf743 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -640,7 +640,7 @@ public class CraftEventFactory {
|
||||
if (e instanceof net.minecraft.world.entity.ExperienceOrb) {
|
||||
net.minecraft.world.entity.ExperienceOrb loopItem = (net.minecraft.world.entity.ExperienceOrb) e;
|
||||
// Paper start
|
||||
- if (!loopItem.isRemoved() && !(maxValue > 0 && loopItem.value >= maxValue)) {
|
||||
+ if (!loopItem.isRemoved() && !(maxValue > 0 && 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 (maxValue > 0 && newTotal > (long)maxValue) {
|
|
@ -1,19 +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
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
index efaf058e6d56f6aed29541e77da46fef058c496a..b9c3683fca1ac85d8f18ab7629a51836248169ca 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
@@ -414,7 +414,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
|
||||
|
||||
@Override
|
||||
public boolean addPotionEffect(PotionEffect effect, boolean force) {
|
||||
- this.getHandle().addEffect(new MobEffectInstance(MobEffect.byId(effect.getType().getId()), effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles()), EntityPotionEffectEvent.Cause.PLUGIN);
|
||||
+ this.getHandle().addEffect(new MobEffectInstance(MobEffect.byId(effect.getType().getId()), effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles(), effect.hasIcon()), EntityPotionEffectEvent.Cause.PLUGIN); // Paper - Don't ignore icon
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: virustotalop <virustotalop@gmail.com>
|
||||
Date: Thu, 16 Apr 2020 20:51:32 -0700
|
||||
Subject: [PATCH] Optimize brigadier child sorting performance
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java
|
||||
index 3384501f83d445f45aa8233e98c7597daa67b8ef..20a7cdf87f307878d66922aaac0c60cff218e46c 100644
|
||||
--- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java
|
||||
+++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java
|
||||
@@ -26,7 +26,7 @@ import java.util.function.Predicate;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
|
||||
public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
|
||||
- private final Map<String, CommandNode<S>> children = new LinkedHashMap<>();
|
||||
+ private Map<String, CommandNode<S>> children = com.google.common.collect.Maps.newTreeMap(); // Paper - Switch to tree map for automatic sorting
|
||||
private final Map<String, LiteralCommandNode<S>> literals = new LinkedHashMap<>();
|
||||
private final Map<String, ArgumentCommandNode<S, ?>> arguments = new LinkedHashMap<>();
|
||||
public Predicate<S> requirement;
|
||||
@@ -107,6 +107,8 @@ public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
|
||||
this.arguments.put(node.getName(), (ArgumentCommandNode<S, ?>) node);
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // Paper - Remove manual sorting, it is no longer needed
|
||||
}
|
||||
|
||||
public void findAmbiguities(final AmbiguityConsumer<S> consumer) {
|
|
@ -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 f5f30e1408892b4e728053bc5005e551396583a5..15f6e1c04fefa1334301534646b8ed2535d16fa9 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,63 +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 7c7114193fadc6c14d6d8a87cc2d734eaa68b864..fb2d02ad6f6a4a1c69dde06e7e193aaef8655028 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -921,6 +921,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
// CraftBukkit start
|
||||
if (this.server != null) {
|
||||
this.server.disablePlugins();
|
||||
+ this.server.waitForAsyncTasksShutdown(); // Paper
|
||||
}
|
||||
// CraftBukkit end
|
||||
if (this.getConnection() != null) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index f1134bce181e8ea5eebb241e3af9691390cd2533..e8e31ddaa7fa87b9854961dd44abff9ddb6a6142 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -1011,6 +1011,35 @@ public final class CraftServer implements Server {
|
||||
org.spigotmc.WatchdogThread.hasStarted = true; // Paper - Disable watchdog early timeout on reload
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ 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();
|
||||
+ String author = "<NoAuthorGiven>";
|
||||
+ if (plugin.getDescription().getAuthors().size() > 0) {
|
||||
+ author = plugin.getDescription().getAuthors().get(0);
|
||||
+ }
|
||||
+ getLogger().log(Level.SEVERE, String.format(
|
||||
+ "Nag author: '%s' of '%s' about the following: %s",
|
||||
+ author,
|
||||
+ plugin.getDescription().getName(),
|
||||
+ "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."
|
||||
+ ));
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public void reloadData() {
|
||||
ReloadCommand.reload(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 6babc2ccd99b739a03145e9ac6f676a46f06c773..4bb9730b6a42702e91467f980b9f045585039db3 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/raid/Raider.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/raid/Raider.java
|
||||
@@ -312,6 +312,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())) {
|
|
@ -1,169 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 13 May 2020 23:01:26 -0400
|
||||
Subject: [PATCH] Protect Bedrock and End Portal/Frames from being destroyed
|
||||
|
||||
This fixes exploits that let players destroy bedrock by Pistons, explosions
|
||||
and Mushrooom/Tree generation.
|
||||
|
||||
These blocks are designed to not be broken except by creative players/commands.
|
||||
So protect them from a multitude of methods of destroying them.
|
||||
|
||||
A config is provided if you rather let players use these exploits, and let
|
||||
them destroy the worlds End Portals and get on top of the nether easy.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
index 38bb502e9f1272020a23a3ef8ebb0cb1a5a251ef..b18b0e1b5e059f08fd3117eaa0fb28a10fac6562 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
@@ -172,6 +172,7 @@ public class Explosion {
|
||||
for (float f1 = 0.3F; f > 0.0F; f -= 0.22500001F) {
|
||||
BlockPos blockposition = new BlockPos(d4, d5, d6);
|
||||
BlockState iblockdata = this.level.getBlockState(blockposition);
|
||||
+ if (!iblockdata.isDestroyable()) continue; // Paper
|
||||
FluidState fluid = iblockdata.getFluidState(); // Paper
|
||||
|
||||
if (!this.level.isInWorldBounds(blockposition)) {
|
||||
@@ -350,7 +351,7 @@ public class Explosion {
|
||||
BlockState iblockdata = this.level.getBlockState(blockposition);
|
||||
Block block = iblockdata.getBlock();
|
||||
|
||||
- if (!iblockdata.isAir()) {
|
||||
+ if (!iblockdata.isAir() && iblockdata.isDestroyable()) { // Paper
|
||||
BlockPos blockposition1 = blockposition.immutable();
|
||||
|
||||
this.level.getProfiler().push("explosion_blocks");
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index cff803e60a7592fc55fc4a76e39f2254196c07f6..e58f576c1bd7a3b1f3d57ed384bbdbc13248147b 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -429,6 +429,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
public boolean setBlock(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) {
|
||||
// CraftBukkit start - tree generation
|
||||
if (this.captureTreeGeneration) {
|
||||
+ // Paper start
|
||||
+ BlockState type = getBlockState(pos);
|
||||
+ if (!type.isDestroyable()) return false;
|
||||
+ // Paper end
|
||||
CraftBlockState blockstate = this.capturedBlockStates.get(pos);
|
||||
if (blockstate == null) {
|
||||
blockstate = CapturedBlockState.getTreeBlockState(this, pos, flags);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java
|
||||
index 77125720fcbeb7bfc180effb27cfb78c74832ce5..cb11cef117fc896ddcb40993ddb852a2e717c2ad 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/Block.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/Block.java
|
||||
@@ -92,6 +92,19 @@ public class Block extends BlockBehaviour implements ItemLike {
|
||||
protected final StateDefinition<Block, BlockState> stateDefinition;
|
||||
private BlockState defaultBlockState;
|
||||
// Paper start
|
||||
+ public final boolean isDestroyable() {
|
||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits ||
|
||||
+ this != Blocks.BEDROCK &&
|
||||
+ this != Blocks.END_PORTAL_FRAME &&
|
||||
+ this != Blocks.END_PORTAL &&
|
||||
+ this != Blocks.END_GATEWAY &&
|
||||
+ this != Blocks.COMMAND_BLOCK &&
|
||||
+ this != Blocks.REPEATING_COMMAND_BLOCK &&
|
||||
+ this != Blocks.CHAIN_COMMAND_BLOCK &&
|
||||
+ this != Blocks.BARRIER &&
|
||||
+ this != Blocks.STRUCTURE_BLOCK &&
|
||||
+ this != Blocks.JIGSAW;
|
||||
+ }
|
||||
public co.aikar.timings.Timing timing;
|
||||
public co.aikar.timings.Timing getTiming() {
|
||||
if (timing == null) {
|
||||
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 76720517cd2d82065eb8430cf854b536295341db..29755807fdb6c30e31c0ec2bbf33bed9afd5d478 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
|
||||
@@ -199,6 +199,12 @@ public class PistonBaseBlock extends DirectionalBlock {
|
||||
@Override
|
||||
public boolean triggerEvent(BlockState state, Level world, BlockPos pos, int type, int data) {
|
||||
Direction enumdirection = (Direction) state.getValue(PistonBaseBlock.FACING);
|
||||
+ // Paper start - prevent retracting when we're facing the wrong way (we were replaced before retraction could occur)
|
||||
+ Direction directionQueuedAs = Direction.from3DDataValue(data & 7); // Paper - copied from below
|
||||
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits && enumdirection != directionQueuedAs) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end - prevent retracting when we're facing the wrong way
|
||||
|
||||
if (!world.isClientSide) {
|
||||
boolean flag = this.getNeighborSignal(world, pos, enumdirection);
|
||||
@@ -231,7 +237,7 @@ public class PistonBaseBlock extends DirectionalBlock {
|
||||
BlockState iblockdata1 = (BlockState) ((BlockState) Blocks.MOVING_PISTON.defaultBlockState().setValue(MovingPistonBlock.FACING, enumdirection)).setValue(MovingPistonBlock.TYPE, this.isSticky ? PistonType.STICKY : PistonType.DEFAULT);
|
||||
|
||||
world.setBlock(pos, iblockdata1, 20);
|
||||
- world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata1, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true));
|
||||
+ world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata1, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); // Paper - diff on change
|
||||
world.blockUpdated(pos, iblockdata1.getBlock());
|
||||
iblockdata1.updateNeighbourShapes(world, pos, 2);
|
||||
if (this.isSticky) {
|
||||
@@ -260,7 +266,14 @@ public class PistonBaseBlock extends DirectionalBlock {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
- world.removeBlock(pos.relative(enumdirection), false);
|
||||
+ // Paper start - fix headless pistons breaking blocks
|
||||
+ BlockPos headPos = pos.relative(enumdirection);
|
||||
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || world.getBlockState(headPos) == Blocks.PISTON_HEAD.defaultBlockState().setValue(FACING, enumdirection)) { // double check to make sure we're not a headless piston.
|
||||
+ world.removeBlock(headPos, false);
|
||||
+ } else {
|
||||
+ ((ServerLevel)world).getChunkSource().blockChanged(headPos); // ... fix client desync
|
||||
+ }
|
||||
+ // Paper end - fix headless pistons breaking blocks
|
||||
}
|
||||
|
||||
world.playSound((Player) null, pos, SoundEvents.PISTON_CONTRACT, SoundSource.BLOCKS, 0.5F, world.random.nextFloat() * 0.15F + 0.6F);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
index 61a792c5ccf3688d4f78c6e7461090f63a0cc26a..b2ab7749e3ddf124d5ef97271a76dc875a650771 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
@@ -223,7 +223,7 @@ public abstract class BlockBehaviour {
|
||||
/** @deprecated */
|
||||
@Deprecated
|
||||
public boolean canBeReplaced(BlockState state, BlockPlaceContext context) {
|
||||
- return this.material.isReplaceable() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem()));
|
||||
+ return this.material.isReplaceable() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem())) && (state.isDestroyable() || (context.getPlayer() != null && context.getPlayer().getAbilities().instabuild)); // Paper
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
@@ -741,6 +741,12 @@ public abstract class BlockBehaviour {
|
||||
return ((Block) this.owner).builtInRegistryHolder();
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public final boolean isDestroyable() {
|
||||
+ return getBlock().isDestroyable();
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public Material getMaterial() {
|
||||
return this.material;
|
||||
}
|
||||
@@ -838,7 +844,7 @@ public abstract class BlockBehaviour {
|
||||
}
|
||||
|
||||
public PushReaction getPistonPushReaction() {
|
||||
- return this.getBlock().getPistonPushReaction(this.asState());
|
||||
+ return !isDestroyable() ? PushReaction.BLOCK : this.getBlock().getPistonPushReaction(this.asState()); // Paper
|
||||
}
|
||||
|
||||
public boolean isSolidRender(BlockGetter world, BlockPos pos) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||
index 953a1dfd71605ac123133dc1d4e8133a33884f4a..1369d4f818d203e3092fd6ba4def106dda16d6d2 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||
@@ -215,6 +215,13 @@ public class PortalForcer {
|
||||
for (int j = -1; j < 3; ++j) {
|
||||
for (int k = -1; k < 4; ++k) {
|
||||
temp.setWithOffset(pos, portalDirection.getStepX() * j + enumdirection1.getStepX() * distanceOrthogonalToPortal, k, portalDirection.getStepZ() * j + enumdirection1.getStepZ() * distanceOrthogonalToPortal);
|
||||
+ // Paper start - prevent destroying unbreakable blocks
|
||||
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits) {
|
||||
+ if (!this.level.getBlockState(temp).isDestroyable()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - prevent destroying unbreakable blocks
|
||||
if (k < 0 && !this.level.getBlockState(temp).getMaterial().isSolid()) {
|
||||
return false;
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 27 Apr 2020 02:48:06 -0700
|
||||
Subject: [PATCH] Reduce MutableInt allocations from light engine
|
||||
|
||||
We can abuse the fact light is single threaded and share an instance
|
||||
per light engine instance
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/lighting/BlockLightEngine.java b/src/main/java/net/minecraft/world/level/lighting/BlockLightEngine.java
|
||||
index 729c4b1763a24bac3c0764bea505555a32e54f57..37d7165dfd17da03428f8dbbbf95aa8005be289c 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/lighting/BlockLightEngine.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/lighting/BlockLightEngine.java
|
||||
@@ -15,6 +15,7 @@ import org.apache.commons.lang3.mutable.MutableInt;
|
||||
public final class BlockLightEngine extends LayerLightEngine<BlockLightSectionStorage.BlockDataLayerStorageMap, BlockLightSectionStorage> {
|
||||
private static final Direction[] DIRECTIONS = Direction.values();
|
||||
private final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
|
||||
+ private final MutableInt mutableInt = new MutableInt(); // Paper
|
||||
|
||||
public BlockLightEngine(LightChunkGetter chunkProvider) {
|
||||
super(chunkProvider, LightLayer.BLOCK, new BlockLightSectionStorage(chunkProvider));
|
||||
@@ -44,7 +45,7 @@ public final class BlockLightEngine extends LayerLightEngine<BlockLightSectionSt
|
||||
if (direction == null) {
|
||||
return 15;
|
||||
} else {
|
||||
- MutableInt mutableInt = new MutableInt();
|
||||
+ //MutableInt mutableint = new MutableInt(); // Paper - share mutableint, single threaded
|
||||
BlockState blockState = this.getStateAndOpacity(targetId, mutableInt);
|
||||
if (mutableInt.getValue() >= 15) {
|
||||
return 15;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/lighting/SkyLightEngine.java b/src/main/java/net/minecraft/world/level/lighting/SkyLightEngine.java
|
||||
index 56b8f6ac53e7598da4dea2180825242222f86731..ca710a20e8b97341616463f4058b61cf4999af28 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/lighting/SkyLightEngine.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/lighting/SkyLightEngine.java
|
||||
@@ -15,6 +15,7 @@ import org.apache.commons.lang3.mutable.MutableInt;
|
||||
public final class SkyLightEngine extends LayerLightEngine<SkyLightSectionStorage.SkyDataLayerStorageMap, SkyLightSectionStorage> {
|
||||
private static final Direction[] DIRECTIONS = Direction.values();
|
||||
private static final Direction[] HORIZONTALS = new Direction[]{Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST};
|
||||
+ private final MutableInt mutableInt = new MutableInt(); // Paper
|
||||
|
||||
public SkyLightEngine(LightChunkGetter chunkProvider) {
|
||||
super(chunkProvider, LightLayer.SKY, new SkyLightSectionStorage(chunkProvider));
|
||||
@@ -26,7 +27,7 @@ public final class SkyLightEngine extends LayerLightEngine<SkyLightSectionStorag
|
||||
if (level >= 15) {
|
||||
return level;
|
||||
} else {
|
||||
- MutableInt mutableInt = new MutableInt();
|
||||
+ //MutableInt mutableint = new MutableInt(); // Paper - share mutableint, single threaded
|
||||
BlockState blockState = this.getStateAndOpacity(targetId, mutableInt);
|
||||
if (mutableInt.getValue() >= 15) {
|
||||
return 15;
|
|
@ -1,58 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 27 Apr 2020 00:04:16 -0700
|
||||
Subject: [PATCH] Reduce allocation of Vec3D by entity tracker
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/VecDeltaCodec.java b/src/main/java/net/minecraft/network/protocol/game/VecDeltaCodec.java
|
||||
index 3167f5c6be39757e3cc42cbb17ab0cf13a2fe470..3768a71491ef7836b9739bdaec7a077c523dbacd 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/game/VecDeltaCodec.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/game/VecDeltaCodec.java
|
||||
@@ -5,7 +5,7 @@ import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class VecDeltaCodec {
|
||||
private static final double TRUNCATION_STEPS = 4096.0D;
|
||||
- private Vec3 base = Vec3.ZERO;
|
||||
+ public Vec3 base = Vec3.ZERO; // Paper
|
||||
|
||||
private static long encode(double value) {
|
||||
return Mth.lfloor(value * 4096.0D);
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 1bf18259505997c39e7880abf49e583cc763beb1..2651e6d22658beea7247a93a6c73f99f1d258752 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1302,9 +1302,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
public void updatePlayer(ServerPlayer player) {
|
||||
org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot
|
||||
if (player != this.entity) {
|
||||
- Vec3 vec3d = player.position().subtract(this.entity.position());
|
||||
+ // Paper start - remove allocation of Vec3D here
|
||||
+ // Vec3 vec3d = player.position().subtract(this.entity.position());
|
||||
+ double vec3d_dx = player.getX() - this.entity.getX();
|
||||
+ double vec3d_dz = player.getZ() - this.entity.getZ();
|
||||
+ // Paper end - remove allocation of Vec3D here
|
||||
double d0 = (double) Math.min(this.getEffectiveRange(), io.papermc.paper.chunk.PlayerChunkLoader.getSendViewDistance(player) * 16); // Paper - per player view distance
|
||||
- double d1 = vec3d.x * vec3d.x + vec3d.z * vec3d.z;
|
||||
+ double d1 = vec3d_dx * vec3d_dx + vec3d_dz * vec3d_dz; // Paper
|
||||
double d2 = d0 * d0;
|
||||
boolean flag = d1 <= d2 && this.entity.broadcastToPlayer(player);
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
index 286a14aafe2e8b4662515165ede8a74833897f33..5d16d9dc07349c4193084ba9e70c16e58155c892 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -148,7 +148,13 @@ public class ServerEntity {
|
||||
i = Mth.floor(this.entity.getYRot() * 256.0F / 360.0F);
|
||||
j = Mth.floor(this.entity.getXRot() * 256.0F / 360.0F);
|
||||
Vec3 vec3d = this.entity.trackingPosition();
|
||||
- boolean flag1 = this.positionCodec.delta(vec3d).lengthSqr() >= 7.62939453125E-6D;
|
||||
+ // Paper start - reduce allocation of Vec3D here
|
||||
+ Vec3 base = this.positionCodec.base;
|
||||
+ double vec3d_dx = vec3d.x - base.x;
|
||||
+ double vec3d_dy = vec3d.y - base.y;
|
||||
+ double vec3d_dz = vec3d.z - base.z;
|
||||
+ boolean flag1 = (vec3d_dx * vec3d_dx + vec3d_dy * vec3d_dy + vec3d_dz * vec3d_dz) >= 7.62939453125E-6D;
|
||||
+ // Paper end - reduce allocation of Vec3D here
|
||||
Packet<?> packet1 = null;
|
||||
boolean flag2 = flag1 || this.tickCount % 60 == 0;
|
||||
boolean flag3 = Math.abs(i - this.yRotp) >= 1 || Math.abs(j - this.xRotp) >= 1;
|
|
@ -1,26 +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
|
||||
|
||||
|
||||
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 9bb730b489006c7baaaf55194ef796ff20771dd3..89bf5fc4fab2cf39378600aa8925ac4bb7707428 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
|
||||
@@ -105,7 +105,14 @@ public class TheEndGatewayBlockEntity extends TheEndPortalBlockEntity {
|
||||
List<Entity> list = world.getEntitiesOfClass(Entity.class, new AABB(pos), TheEndGatewayBlockEntity::canEntityTeleport);
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
- TheEndGatewayBlockEntity.teleportEntity(world, pos, state, (Entity) list.get(world.random.nextInt(list.size())), blockEntity);
|
||||
+ // Paper start
|
||||
+ for (Entity entity : list) {
|
||||
+ if (entity.canChangeDimensions()) {
|
||||
+ TheEndGatewayBlockEntity.teleportEntity(world, pos, state, entity, blockEntity);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
if (blockEntity.age % 2400L == 0L) {
|
|
@ -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 a6612cc0ea87aeb8e87521ff7b5fe58c7b06b9ef..dfc15cfd897316f64a063b8ae93a0882ab5b3993 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/command/CraftRemoteConsoleCommandSender.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/command/CraftRemoteConsoleCommandSender.java
|
||||
@@ -45,4 +45,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,346 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Tue, 5 May 2020 20:40:53 -0700
|
||||
Subject: [PATCH] Optimize anyPlayerCloseEnoughForSpawning to use distance maps
|
||||
|
||||
Use a distance map to find the players in range quickly
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
index 2ba3bb4e5670ece798a8882801a856d82851c00a..a61f55ed1fbe5aac5289014cb95cb6950b4c77fa 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
@@ -83,16 +83,29 @@ public class ChunkHolder {
|
||||
|
||||
// Paper start
|
||||
public void onChunkAdd() {
|
||||
-
|
||||
+ // Paper start - optimise anyPlayerCloseEnoughForSpawning
|
||||
+ long key = io.papermc.paper.util.MCUtil.getCoordinateKey(this.pos);
|
||||
+ this.playersInMobSpawnRange = this.chunkMap.playerMobSpawnMap.getObjectsInRange(key);
|
||||
+ this.playersInChunkTickRange = this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(key);
|
||||
+ // Paper end - optimise anyPlayerCloseEnoughForSpawning
|
||||
}
|
||||
|
||||
public void onChunkRemove() {
|
||||
-
|
||||
+ // Paper start - optimise anyPlayerCloseEnoughForSpawning
|
||||
+ this.playersInMobSpawnRange = null;
|
||||
+ this.playersInChunkTickRange = null;
|
||||
+ // Paper end - optimise anyPlayerCloseEnoughForSpawning
|
||||
}
|
||||
// Paper end
|
||||
|
||||
public final io.papermc.paper.chunk.system.scheduling.NewChunkHolder newChunkHolder; // Paper - rewrite chunk system
|
||||
|
||||
+ // Paper start - optimise anyPlayerCloseEnoughForSpawning
|
||||
+ // cached here to avoid a map lookup
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInMobSpawnRange;
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInChunkTickRange;
|
||||
+ // Paper end - optimise anyPlayerCloseEnoughForSpawning
|
||||
+
|
||||
public ChunkHolder(ChunkPos pos, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.PlayerProvider playersWatchingChunkProvider, io.papermc.paper.chunk.system.scheduling.NewChunkHolder newChunkHolder) { // Paper - rewrite chunk system
|
||||
this.newChunkHolder = newChunkHolder; // Paper - rewrite chunk system
|
||||
this.chunkToSaveHistory = null;
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 2651e6d22658beea7247a93a6c73f99f1d258752..c68be481bbedbe347651f73741bf378a501e450e 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -152,12 +152,24 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
// Paper start - distance maps
|
||||
private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets<ServerPlayer> pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>();
|
||||
public final io.papermc.paper.chunk.PlayerChunkLoader playerChunkManager = new io.papermc.paper.chunk.PlayerChunkLoader(this, this.pooledLinkedPlayerHashSets); // Paper - replace chunk loader
|
||||
+ // Paper start - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
||||
+ // A note about the naming used here:
|
||||
+ // Previously, mojang used a "spawn range" of 8 for controlling both ticking and
|
||||
+ // mob spawn range. However, spigot makes the spawn range configurable by
|
||||
+ // checking if the chunk is in the tick range (8) and the spawn range
|
||||
+ // obviously this means a spawn range > 8 cannot be implemented
|
||||
+
|
||||
+ // these maps are named after spigot's uses
|
||||
+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobSpawnMap; // this map is absent from updateMaps since it's controlled at the start of the chunkproviderserver tick
|
||||
+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerChunkTickRangeMap;
|
||||
+ // Paper end - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
||||
|
||||
void addPlayerToDistanceMaps(ServerPlayer player) {
|
||||
this.playerChunkManager.addPlayer(player); // Paper - replace chunk loader
|
||||
int chunkX = MCUtil.getChunkCoordinate(player.getX());
|
||||
int chunkZ = MCUtil.getChunkCoordinate(player.getZ());
|
||||
// Note: players need to be explicitly added to distance maps before they can be updated
|
||||
+ this.playerChunkTickRangeMap.add(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
||||
// Paper start - per player mob spawning
|
||||
if (this.playerMobDistanceMap != null) {
|
||||
this.playerMobDistanceMap.add(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player));
|
||||
@@ -168,6 +180,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
void removePlayerFromDistanceMaps(ServerPlayer player) {
|
||||
this.playerChunkManager.removePlayer(player); // Paper - replace chunk loader
|
||||
|
||||
+ // Paper start - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
||||
+ this.playerMobSpawnMap.remove(player);
|
||||
+ this.playerChunkTickRangeMap.remove(player);
|
||||
+ // Paper end - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
||||
// Paper start - per player mob spawning
|
||||
if (this.playerMobDistanceMap != null) {
|
||||
this.playerMobDistanceMap.remove(player);
|
||||
@@ -180,6 +196,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
int chunkZ = MCUtil.getChunkCoordinate(player.getZ());
|
||||
// Note: players need to be explicitly added to distance maps before they can be updated
|
||||
this.playerChunkManager.updatePlayer(player); // Paper - replace chunk loader
|
||||
+ this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
||||
// Paper start - per player mob spawning
|
||||
if (this.playerMobDistanceMap != null) {
|
||||
this.playerMobDistanceMap.update(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player));
|
||||
@@ -267,6 +284,38 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.regionManagers.add(this.dataRegionManager);
|
||||
// Paper end
|
||||
this.playerMobDistanceMap = this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets) : null; // Paper
|
||||
+ // Paper start - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
||||
+ this.playerChunkTickRangeMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
|
||||
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
|
||||
+ ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ));
|
||||
+ if (playerChunk != null) {
|
||||
+ playerChunk.playersInChunkTickRange = newState;
|
||||
+ }
|
||||
+ },
|
||||
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
|
||||
+ ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ));
|
||||
+ if (playerChunk != null) {
|
||||
+ playerChunk.playersInChunkTickRange = newState;
|
||||
+ }
|
||||
+ });
|
||||
+ this.playerMobSpawnMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
|
||||
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
|
||||
+ ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ));
|
||||
+ if (playerChunk != null) {
|
||||
+ playerChunk.playersInMobSpawnRange = newState;
|
||||
+ }
|
||||
+ },
|
||||
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
|
||||
+ ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ));
|
||||
+ if (playerChunk != null) {
|
||||
+ playerChunk.playersInMobSpawnRange = newState;
|
||||
+ }
|
||||
+ });
|
||||
+ // Paper end - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
||||
}
|
||||
|
||||
protected ChunkGenerator generator() {
|
||||
@@ -822,43 +871,48 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
return this.anyPlayerCloseEnoughForSpawning(pos, false);
|
||||
}
|
||||
|
||||
- boolean anyPlayerCloseEnoughForSpawning(ChunkPos chunkcoordintpair, boolean reducedRange) {
|
||||
- int chunkRange = level.spigotConfig.mobSpawnRange;
|
||||
- chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange;
|
||||
- chunkRange = (chunkRange > 8) ? 8 : chunkRange;
|
||||
-
|
||||
- final int finalChunkRange = chunkRange; // Paper for lambda below
|
||||
- //double blockRange = (reducedRange) ? Math.pow(chunkRange << 4, 2) : 16384.0D; // Paper - use from event
|
||||
- double blockRange = 16384.0D; // Paper
|
||||
- // Spigot end
|
||||
- long i = chunkcoordintpair.toLong();
|
||||
+ // Paper start - optimise anyPlayerCloseEnoughForSpawning
|
||||
+ final boolean anyPlayerCloseEnoughForSpawning(ChunkPos chunkcoordintpair, boolean reducedRange) {
|
||||
+ return this.anyPlayerCloseEnoughForSpawning(this.getUpdatingChunkIfPresent(chunkcoordintpair.toLong()), chunkcoordintpair, reducedRange);
|
||||
+ }
|
||||
|
||||
- if (!this.distanceManager.hasPlayersNearby(i)) {
|
||||
+ final boolean anyPlayerCloseEnoughForSpawning(ChunkHolder playerchunk, ChunkPos chunkcoordintpair, boolean reducedRange) {
|
||||
+ // this function is so hot that removing the map lookup call can have an order of magnitude impact on its performance
|
||||
+ // tested and confirmed via System.nanoTime()
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInRange = reducedRange ? playerchunk.playersInMobSpawnRange : playerchunk.playersInChunkTickRange;
|
||||
+ if (playersInRange == null) {
|
||||
return false;
|
||||
- } else {
|
||||
- Iterator iterator = this.playerMap.getPlayers(i).iterator();
|
||||
-
|
||||
- ServerPlayer entityplayer;
|
||||
+ }
|
||||
+ Object[] backingSet = playersInRange.getBackingSet();
|
||||
|
||||
- do {
|
||||
- if (!iterator.hasNext()) {
|
||||
- return false;
|
||||
+ if (reducedRange) {
|
||||
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
|
||||
+ Object raw = backingSet[i];
|
||||
+ if (!(raw instanceof ServerPlayer player)) {
|
||||
+ continue;
|
||||
}
|
||||
-
|
||||
- entityplayer = (ServerPlayer) iterator.next();
|
||||
- // Paper start - add PlayerNaturallySpawnCreaturesEvent
|
||||
- com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event;
|
||||
- blockRange = 16384.0D;
|
||||
- if (reducedRange) {
|
||||
- event = entityplayer.playerNaturallySpawnedEvent;
|
||||
- if (event == null || event.isCancelled()) return false;
|
||||
- blockRange = (double) ((event.getSpawnRadius() << 4) * (event.getSpawnRadius() << 4));
|
||||
+ // don't check spectator and whatnot, already handled by mob spawn map update
|
||||
+ if (euclideanDistanceSquared(chunkcoordintpair, player) < player.lastEntitySpawnRadiusSquared) {
|
||||
+ return true; // in range
|
||||
}
|
||||
- // Paper end
|
||||
- } while (!this.playerIsCloseEnoughForSpawning(entityplayer, chunkcoordintpair, blockRange)); // Spigot
|
||||
-
|
||||
- return true;
|
||||
+ }
|
||||
+ } else {
|
||||
+ final double range = (DistanceManager.MOB_SPAWN_RANGE * 16) * (DistanceManager.MOB_SPAWN_RANGE * 16);
|
||||
+ // before spigot, mob spawn range was actually mob spawn range + tick range, but it was split
|
||||
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
|
||||
+ Object raw = backingSet[i];
|
||||
+ if (!(raw instanceof ServerPlayer player)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ // don't check spectator and whatnot, already handled by mob spawn map update
|
||||
+ if (euclideanDistanceSquared(chunkcoordintpair, player) < range) {
|
||||
+ return true; // in range
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
+ // no players in range
|
||||
+ return false;
|
||||
+ // Paper end - optimise anyPlayerCloseEnoughForSpawning
|
||||
}
|
||||
|
||||
public List<ServerPlayer> getPlayersCloseForSpawning(ChunkPos pos) {
|
||||
diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
index d3c3db919e9b0507e8543313d9028394e5163673..52cba8f68d274cce106304aef1249a95474d3238 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
@@ -54,7 +54,7 @@ public abstract class DistanceManager {
|
||||
private static final int BLOCK_TICKING_LEVEL_THRESHOLD = 33;
|
||||
final Long2ObjectMap<ObjectSet<ServerPlayer>> playersPerChunk = new Long2ObjectOpenHashMap();
|
||||
// Paper - rewrite chunk system
|
||||
- private final DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter = new DistanceManager.FixedPlayerDistanceChunkTracker(8);
|
||||
+ public static final int MOB_SPAWN_RANGE = 8; // private final DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter = new DistanceManager.FixedPlayerDistanceChunkTracker(8); // Paper - no longer used
|
||||
//private final TickingTracker tickingTicketsTracker = new TickingTracker(); // Paper - no longer used
|
||||
//private final DistanceManager.PlayerTicketTracker playerTicketManager = new DistanceManager.PlayerTicketTracker(33); // Paper - no longer used
|
||||
// Paper - rewrite chunk system
|
||||
@@ -142,7 +142,7 @@ public abstract class DistanceManager {
|
||||
long i = chunkcoordintpair.toLong();
|
||||
|
||||
// Paper - no longer used
|
||||
- this.naturalSpawnChunkCounter.update(i, 0, true);
|
||||
+ //this.naturalSpawnChunkCounter.update(i, 0, true); // Paper - no longer used
|
||||
//this.playerTicketManager.update(i, 0, true); // Paper - no longer used
|
||||
//this.tickingTicketsTracker.addTicket(TicketType.PLAYER, chunkcoordintpair, this.getPlayerTicketLevel(), chunkcoordintpair); // Paper - no longer used
|
||||
}
|
||||
@@ -156,7 +156,7 @@ public abstract class DistanceManager {
|
||||
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.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false); // Paper - no longer used
|
||||
//this.playerTicketManager.update(i, Integer.MAX_VALUE, false); // Paper - no longer used
|
||||
//this.tickingTicketsTracker.removeTicket(TicketType.PLAYER, chunkcoordintpair, this.getPlayerTicketLevel(), chunkcoordintpair); // Paper - no longer used
|
||||
}
|
||||
@@ -198,13 +198,17 @@ public abstract class DistanceManager {
|
||||
}
|
||||
|
||||
public int getNaturalSpawnChunkCount() {
|
||||
- this.naturalSpawnChunkCounter.runAllUpdates();
|
||||
- return this.naturalSpawnChunkCounter.chunks.size();
|
||||
+ // Paper start - use distance map to implement
|
||||
+ // note: this is the spawn chunk count
|
||||
+ return this.chunkMap.playerChunkTickRangeMap.size();
|
||||
+ // Paper end - use distance map to implement
|
||||
}
|
||||
|
||||
public boolean hasPlayersNearby(long chunkPos) {
|
||||
- this.naturalSpawnChunkCounter.runAllUpdates();
|
||||
- return this.naturalSpawnChunkCounter.chunks.containsKey(chunkPos);
|
||||
+ // Paper start - use distance map to implement
|
||||
+ // note: this is the is spawn chunk method
|
||||
+ return this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(chunkPos) != null;
|
||||
+ // Paper end - use distance map to implement
|
||||
}
|
||||
|
||||
public String getDebugStatus() {
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index f0ab91b93dabd0c77a8537e40c8b504200b261fd..324a99ea21bccdf27c15248ae2811048efaa2595 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -657,6 +657,37 @@ public class ServerChunkCache extends ChunkSource {
|
||||
if (flag) {
|
||||
this.chunkMap.tick();
|
||||
} else {
|
||||
+ // Paper start - optimize isOutisdeRange
|
||||
+ ChunkMap playerChunkMap = this.chunkMap;
|
||||
+ for (ServerPlayer player : this.level.players) {
|
||||
+ if (!player.affectsSpawning || player.isSpectator()) {
|
||||
+ playerChunkMap.playerMobSpawnMap.remove(player);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ int viewDistance = this.chunkMap.getEffectiveViewDistance();
|
||||
+
|
||||
+ // copied and modified from isOutisdeRange
|
||||
+ int chunkRange = level.spigotConfig.mobSpawnRange;
|
||||
+ chunkRange = (chunkRange > viewDistance) ? (byte)viewDistance : chunkRange;
|
||||
+ chunkRange = (chunkRange > DistanceManager.MOB_SPAWN_RANGE) ? DistanceManager.MOB_SPAWN_RANGE : chunkRange;
|
||||
+
|
||||
+ com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(player.getBukkitEntity(), (byte)chunkRange);
|
||||
+ event.callEvent();
|
||||
+ if (event.isCancelled() || event.getSpawnRadius() < 0 || playerChunkMap.playerChunkTickRangeMap.getLastViewDistance(player) == -1) {
|
||||
+ playerChunkMap.playerMobSpawnMap.remove(player);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ int range = Math.min(event.getSpawnRadius(), 32); // limit to max view distance
|
||||
+ int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX());
|
||||
+ int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ());
|
||||
+
|
||||
+ playerChunkMap.playerMobSpawnMap.addOrUpdate(player, chunkX, chunkZ, range);
|
||||
+ player.lastEntitySpawnRadiusSquared = (double)((range << 4) * (range << 4)); // used in anyPlayerCloseEnoughForSpawning
|
||||
+ player.playerNaturallySpawnedEvent = event;
|
||||
+ }
|
||||
+ // Paper end - optimize isOutisdeRange
|
||||
LevelData worlddata = this.level.getLevelData();
|
||||
ProfilerFiller gameprofilerfiller = this.level.getProfiler();
|
||||
|
||||
@@ -700,15 +731,7 @@ public class ServerChunkCache extends ChunkSource {
|
||||
boolean flag2 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit
|
||||
|
||||
Collections.shuffle(list);
|
||||
- // Paper start - call player naturally spawn event
|
||||
- int chunkRange = level.spigotConfig.mobSpawnRange;
|
||||
- chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange;
|
||||
- chunkRange = Math.min(chunkRange, 8);
|
||||
- for (ServerPlayer entityPlayer : this.level.players()) {
|
||||
- entityPlayer.playerNaturallySpawnedEvent = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(entityPlayer.getBukkitEntity(), (byte) chunkRange);
|
||||
- entityPlayer.playerNaturallySpawnedEvent.callEvent();
|
||||
- };
|
||||
- // Paper end
|
||||
+ // Paper - moved natural spawn event up
|
||||
Iterator iterator1 = list.iterator();
|
||||
|
||||
while (iterator1.hasNext()) {
|
||||
@@ -716,9 +739,9 @@ public class ServerChunkCache extends ChunkSource {
|
||||
LevelChunk chunk1 = chunkproviderserver_a.chunk;
|
||||
ChunkPos chunkcoordintpair = chunk1.getPos();
|
||||
|
||||
- if (this.level.isNaturalSpawningAllowed(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkcoordintpair)) {
|
||||
+ if (this.level.isNaturalSpawningAllowed(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkproviderserver_a.holder, chunkcoordintpair, false)) { // Paper - optimise anyPlayerCloseEnoughForSpawning
|
||||
chunk1.incrementInhabitedTime(j);
|
||||
- if (flag2 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkcoordintpair, true)) { // Spigot
|
||||
+ if (flag2 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkproviderserver_a.holder, chunkcoordintpair, true)) { // Spigot // Paper - optimise anyPlayerCloseEnoughForSpawning
|
||||
NaturalSpawner.spawnForChunk(this.level, chunk1, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag1);
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 7ad1d2cd3b2d4b1f9b21f0de5ddbf2626aea0310..61904f4d3160d83f87d66fd9f86acf54ab31adc6 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -263,6 +263,7 @@ public class ServerPlayer extends Player {
|
||||
public PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper
|
||||
|
||||
public boolean isRealPlayer; // Paper
|
||||
+ public double lastEntitySpawnRadiusSquared; // Paper - optimise isOutsideRange, this field is in blocks
|
||||
public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleHashSet; // Paper
|
||||
|
||||
public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile, @Nullable ProfilePublicKey publicKey) {
|
|
@ -1,401 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Tue, 5 May 2020 20:18:05 -0700
|
||||
Subject: [PATCH] Use distance map to optimise entity tracker
|
||||
|
||||
Use the distance map to find candidate players for tracking.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index c68be481bbedbe347651f73741bf378a501e450e..f337b380c443016fc593dc768e32b751b7c7aa96 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -66,6 +66,7 @@ import net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket;
|
||||
import net.minecraft.network.protocol.game.DebugPackets;
|
||||
import io.papermc.paper.util.MCUtil;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.progress.ChunkProgressListener;
|
||||
import net.minecraft.server.network.ServerPlayerConnection;
|
||||
import net.minecraft.util.CsvOutput;
|
||||
@@ -163,6 +164,23 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobSpawnMap; // this map is absent from updateMaps since it's controlled at the start of the chunkproviderserver tick
|
||||
public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerChunkTickRangeMap;
|
||||
// Paper end - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
||||
+ // Paper start - use distance map to optimise tracker
|
||||
+ public static boolean isLegacyTrackingEntity(Entity entity) {
|
||||
+ return entity.isLegacyTrackingEntity;
|
||||
+ }
|
||||
+
|
||||
+ // inlined EnumMap, TrackingRange.TrackingRangeType
|
||||
+ static final org.spigotmc.TrackingRange.TrackingRangeType[] TRACKING_RANGE_TYPES = org.spigotmc.TrackingRange.TrackingRangeType.values();
|
||||
+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap[] playerEntityTrackerTrackMaps;
|
||||
+ final int[] entityTrackerTrackRanges;
|
||||
+ public final int getEntityTrackerRange(final int ordinal) {
|
||||
+ return this.entityTrackerTrackRanges[ordinal];
|
||||
+ }
|
||||
+
|
||||
+ private int convertSpigotRangeToVanilla(final int vanilla) {
|
||||
+ return MinecraftServer.getServer().getScaledTrackingDistance(vanilla);
|
||||
+ }
|
||||
+ // Paper end - use distance map to optimise tracker
|
||||
|
||||
void addPlayerToDistanceMaps(ServerPlayer player) {
|
||||
this.playerChunkManager.addPlayer(player); // Paper - replace chunk loader
|
||||
@@ -175,6 +193,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.playerMobDistanceMap.add(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player));
|
||||
}
|
||||
// Paper end - per player mob spawning
|
||||
+ // Paper start - use distance map to optimise entity tracker
|
||||
+ for (int i = 0, len = TRACKING_RANGE_TYPES.length; i < len; ++i) {
|
||||
+ com.destroystokyo.paper.util.misc.PlayerAreaMap trackMap = this.playerEntityTrackerTrackMaps[i];
|
||||
+ int trackRange = this.entityTrackerTrackRanges[i];
|
||||
+
|
||||
+ trackMap.add(player, chunkX, chunkZ, Math.min(trackRange, io.papermc.paper.chunk.system.ChunkSystem.getSendViewDistance(player)));
|
||||
+ }
|
||||
+ // Paper end - use distance map to optimise entity tracker
|
||||
}
|
||||
|
||||
void removePlayerFromDistanceMaps(ServerPlayer player) {
|
||||
@@ -189,6 +215,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.playerMobDistanceMap.remove(player);
|
||||
}
|
||||
// Paper end - per player mob spawning
|
||||
+ // Paper start - use distance map to optimise tracker
|
||||
+ for (int i = 0, len = TRACKING_RANGE_TYPES.length; i < len; ++i) {
|
||||
+ this.playerEntityTrackerTrackMaps[i].remove(player);
|
||||
+ }
|
||||
+ // Paper end - use distance map to optimise tracker
|
||||
}
|
||||
|
||||
void updateMaps(ServerPlayer player) {
|
||||
@@ -202,6 +233,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.playerMobDistanceMap.update(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player));
|
||||
}
|
||||
// Paper end - per player mob spawning
|
||||
+ // Paper start - use distance map to optimise entity tracker
|
||||
+ for (int i = 0, len = TRACKING_RANGE_TYPES.length; i < len; ++i) {
|
||||
+ com.destroystokyo.paper.util.misc.PlayerAreaMap trackMap = this.playerEntityTrackerTrackMaps[i];
|
||||
+ int trackRange = this.entityTrackerTrackRanges[i];
|
||||
+
|
||||
+ trackMap.update(player, chunkX, chunkZ, Math.min(trackRange, io.papermc.paper.chunk.system.ChunkSystem.getSendViewDistance(player)));
|
||||
+ }
|
||||
+ // Paper end - use distance map to optimise entity tracker
|
||||
}
|
||||
// Paper end
|
||||
// Paper start
|
||||
@@ -284,6 +323,45 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.regionManagers.add(this.dataRegionManager);
|
||||
// Paper end
|
||||
this.playerMobDistanceMap = this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets) : null; // Paper
|
||||
+ // Paper start - use distance map to optimise entity tracker
|
||||
+ this.playerEntityTrackerTrackMaps = new com.destroystokyo.paper.util.misc.PlayerAreaMap[TRACKING_RANGE_TYPES.length];
|
||||
+ this.entityTrackerTrackRanges = new int[TRACKING_RANGE_TYPES.length];
|
||||
+
|
||||
+ org.spigotmc.SpigotWorldConfig spigotWorldConfig = this.level.spigotConfig;
|
||||
+
|
||||
+ for (int ordinal = 0, len = TRACKING_RANGE_TYPES.length; ordinal < len; ++ordinal) {
|
||||
+ org.spigotmc.TrackingRange.TrackingRangeType trackingRangeType = TRACKING_RANGE_TYPES[ordinal];
|
||||
+ int configuredSpigotValue;
|
||||
+ switch (trackingRangeType) {
|
||||
+ case PLAYER:
|
||||
+ configuredSpigotValue = spigotWorldConfig.playerTrackingRange;
|
||||
+ break;
|
||||
+ case ANIMAL:
|
||||
+ configuredSpigotValue = spigotWorldConfig.animalTrackingRange;
|
||||
+ break;
|
||||
+ case MONSTER:
|
||||
+ configuredSpigotValue = spigotWorldConfig.monsterTrackingRange;
|
||||
+ break;
|
||||
+ case MISC:
|
||||
+ configuredSpigotValue = spigotWorldConfig.miscTrackingRange;
|
||||
+ break;
|
||||
+ case OTHER:
|
||||
+ configuredSpigotValue = spigotWorldConfig.otherTrackingRange;
|
||||
+ break;
|
||||
+ case ENDERDRAGON:
|
||||
+ configuredSpigotValue = EntityType.ENDER_DRAGON.clientTrackingRange() * 16;
|
||||
+ break;
|
||||
+ default:
|
||||
+ throw new IllegalStateException("Missing case for enum " + trackingRangeType);
|
||||
+ }
|
||||
+ configuredSpigotValue = convertSpigotRangeToVanilla(configuredSpigotValue);
|
||||
+
|
||||
+ int trackRange = (configuredSpigotValue >>> 4) + ((configuredSpigotValue & 15) != 0 ? 1 : 0);
|
||||
+ this.entityTrackerTrackRanges[ordinal] = trackRange;
|
||||
+
|
||||
+ this.playerEntityTrackerTrackMaps[ordinal] = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets);
|
||||
+ }
|
||||
+ // Paper end - use distance map to optimise entity tracker
|
||||
// Paper start - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
||||
this.playerChunkTickRangeMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
|
||||
(ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
||||
@@ -986,17 +1064,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
|
||||
public void move(ServerPlayer player) {
|
||||
- ObjectIterator objectiterator = this.entityMap.values().iterator();
|
||||
-
|
||||
- while (objectiterator.hasNext()) {
|
||||
- ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next();
|
||||
-
|
||||
- if (playerchunkmap_entitytracker.entity == player) {
|
||||
- playerchunkmap_entitytracker.updatePlayers(this.level.players());
|
||||
- } else {
|
||||
- playerchunkmap_entitytracker.updatePlayer(player);
|
||||
- }
|
||||
- }
|
||||
+ // Paper - delay this logic for the entity tracker tick, no need to duplicate it
|
||||
|
||||
int i = SectionPos.blockToSectionCoord(player.getBlockX());
|
||||
int j = SectionPos.blockToSectionCoord(player.getBlockZ());
|
||||
@@ -1095,7 +1163,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
entity.tracker = playerchunkmap_entitytracker; // Paper - Fast access to tracker
|
||||
this.entityMap.put(entity.getId(), playerchunkmap_entitytracker);
|
||||
- playerchunkmap_entitytracker.updatePlayers(this.level.players());
|
||||
+ playerchunkmap_entitytracker.updatePlayers(entity.getPlayersInTrackRange()); // Paper - don't search all players
|
||||
if (entity instanceof ServerPlayer) {
|
||||
ServerPlayer entityplayer = (ServerPlayer) entity;
|
||||
|
||||
@@ -1139,7 +1207,37 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
entity.tracker = null; // Paper - We're no longer tracked
|
||||
}
|
||||
|
||||
+ // Paper start - optimised tracker
|
||||
+ private final void processTrackQueue() {
|
||||
+ this.level.timings.tracker1.startTiming();
|
||||
+ try {
|
||||
+ for (TrackedEntity tracker : this.entityMap.values()) {
|
||||
+ // update tracker entry
|
||||
+ tracker.updatePlayers(tracker.entity.getPlayersInTrackRange());
|
||||
+ }
|
||||
+ } finally {
|
||||
+ this.level.timings.tracker1.stopTiming();
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ this.level.timings.tracker2.startTiming();
|
||||
+ try {
|
||||
+ for (TrackedEntity tracker : this.entityMap.values()) {
|
||||
+ tracker.serverEntity.sendChanges();
|
||||
+ }
|
||||
+ } finally {
|
||||
+ this.level.timings.tracker2.stopTiming();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - optimised tracker
|
||||
+
|
||||
protected void tick() {
|
||||
+ // Paper start - optimized tracker
|
||||
+ if (true) {
|
||||
+ this.processTrackQueue();
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - optimized tracker
|
||||
List<ServerPlayer> list = Lists.newArrayList();
|
||||
List<ServerPlayer> list1 = this.level.players();
|
||||
ObjectIterator objectiterator = this.entityMap.values().iterator();
|
||||
@@ -1213,46 +1311,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}));
|
||||
// Paper end
|
||||
DebugPackets.sendPoiPacketsForChunk(this.level, chunk.getPos());
|
||||
- List<Entity> list = Lists.newArrayList();
|
||||
- List<Entity> list1 = Lists.newArrayList();
|
||||
- ObjectIterator objectiterator = this.entityMap.values().iterator();
|
||||
-
|
||||
- while (objectiterator.hasNext()) {
|
||||
- ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next();
|
||||
- Entity entity = playerchunkmap_entitytracker.entity;
|
||||
-
|
||||
- if (entity != player && entity.chunkPosition().equals(chunk.getPos())) {
|
||||
- playerchunkmap_entitytracker.updatePlayer(player);
|
||||
- if (entity instanceof Mob && ((Mob) entity).getLeashHolder() != null) {
|
||||
- list.add(entity);
|
||||
- }
|
||||
-
|
||||
- if (!entity.getPassengers().isEmpty()) {
|
||||
- list1.add(entity);
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- Iterator iterator;
|
||||
- Entity entity1;
|
||||
-
|
||||
- if (!list.isEmpty()) {
|
||||
- iterator = list.iterator();
|
||||
-
|
||||
- while (iterator.hasNext()) {
|
||||
- entity1 = (Entity) iterator.next();
|
||||
- player.connection.send(new ClientboundSetEntityLinkPacket(entity1, ((Mob) entity1).getLeashHolder()));
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if (!list1.isEmpty()) {
|
||||
- iterator = list1.iterator();
|
||||
-
|
||||
- while (iterator.hasNext()) {
|
||||
- entity1 = (Entity) iterator.next();
|
||||
- player.connection.send(new ClientboundSetPassengersPacket(entity1));
|
||||
- }
|
||||
- }
|
||||
+ // Paper - no longer needed - this was used to account for clients bugging out since they needed a chunk to store entities, but they no longer need a chunk
|
||||
|
||||
}
|
||||
|
||||
@@ -1307,6 +1366,42 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.lastSectionPos = SectionPos.of((EntityAccess) entity);
|
||||
}
|
||||
|
||||
+ // Paper start - use distance map to optimise tracker
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> lastTrackerCandidates;
|
||||
+
|
||||
+ final void updatePlayers(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newTrackerCandidates) {
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> oldTrackerCandidates = this.lastTrackerCandidates;
|
||||
+ this.lastTrackerCandidates = newTrackerCandidates;
|
||||
+
|
||||
+ if (newTrackerCandidates != null) {
|
||||
+ Object[] rawData = newTrackerCandidates.getBackingSet();
|
||||
+ for (int i = 0, len = rawData.length; i < len; ++i) {
|
||||
+ Object raw = rawData[i];
|
||||
+ if (!(raw instanceof ServerPlayer)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ ServerPlayer player = (ServerPlayer)raw;
|
||||
+ this.updatePlayer(player);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (oldTrackerCandidates == newTrackerCandidates) {
|
||||
+ // this is likely the case.
|
||||
+ // means there has been no range changes, so we can just use the above for tracking.
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ // stuff could have been removed, so we need to check the trackedPlayers set
|
||||
+ // for players that were removed
|
||||
+
|
||||
+ for (ServerPlayerConnection conn : this.seenBy.toArray(new ServerPlayerConnection[0])) { // avoid CME
|
||||
+ if (newTrackerCandidates == null || !newTrackerCandidates.contains(conn.getPlayer())) {
|
||||
+ this.updatePlayer(conn.getPlayer());
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - use distance map to optimise tracker
|
||||
+
|
||||
public boolean equals(Object object) {
|
||||
return object instanceof ChunkMap.TrackedEntity ? ((ChunkMap.TrackedEntity) object).entity.getId() == this.entity.getId() : false;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 32623f90a5bc4fb6fe99897c682ef4f55f056dea..26c8b19d484032f5d0935ba8672a3121a3197d67 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -57,6 +57,7 @@ import net.minecraft.network.syncher.EntityDataSerializers;
|
||||
import net.minecraft.network.syncher.SynchedEntityData;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
+import io.papermc.paper.util.MCUtil;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
@@ -475,6 +476,38 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
|
||||
public boolean updatingSectionStatus = false;
|
||||
// Paper end
|
||||
+ // Paper start - optimise entity tracking
|
||||
+ final org.spigotmc.TrackingRange.TrackingRangeType trackingRangeType = org.spigotmc.TrackingRange.getTrackingRangeType(this);
|
||||
+
|
||||
+ public boolean isLegacyTrackingEntity = false;
|
||||
+
|
||||
+ public final void setLegacyTrackingEntity(final boolean isLegacyTrackingEntity) {
|
||||
+ this.isLegacyTrackingEntity = isLegacyTrackingEntity;
|
||||
+ }
|
||||
+
|
||||
+ public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> getPlayersInTrackRange() {
|
||||
+ // determine highest range of passengers
|
||||
+ if (this.passengers.isEmpty()) {
|
||||
+ return ((ServerLevel)this.level).getChunkSource().chunkMap.playerEntityTrackerTrackMaps[this.trackingRangeType.ordinal()]
|
||||
+ .getObjectsInRange(MCUtil.getCoordinateKey(this));
|
||||
+ }
|
||||
+ Iterable<Entity> passengers = this.getIndirectPassengers();
|
||||
+ net.minecraft.server.level.ChunkMap chunkMap = ((ServerLevel)this.level).getChunkSource().chunkMap;
|
||||
+ org.spigotmc.TrackingRange.TrackingRangeType type = this.trackingRangeType;
|
||||
+ int range = chunkMap.getEntityTrackerRange(type.ordinal());
|
||||
+
|
||||
+ for (Entity passenger : passengers) {
|
||||
+ org.spigotmc.TrackingRange.TrackingRangeType passengerType = passenger.trackingRangeType;
|
||||
+ int passengerRange = chunkMap.getEntityTrackerRange(passengerType.ordinal());
|
||||
+ if (passengerRange > range) {
|
||||
+ type = passengerType;
|
||||
+ range = passengerRange;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return chunkMap.playerEntityTrackerTrackMaps[type.ordinal()].getObjectsInRange(MCUtil.getCoordinateKey(this));
|
||||
+ }
|
||||
+ // Paper end - optimise entity tracking
|
||||
|
||||
public Entity(EntityType<?> type, Level world) {
|
||||
this.id = Entity.ENTITY_COUNTER.incrementAndGet();
|
||||
diff --git a/src/main/java/org/spigotmc/TrackingRange.java b/src/main/java/org/spigotmc/TrackingRange.java
|
||||
index 55ce69b5fe097841d00ef5c241459dce9bb0d4db..e5bcbfe175a697e04886d04543e1278b7e83a184 100644
|
||||
--- a/src/main/java/org/spigotmc/TrackingRange.java
|
||||
+++ b/src/main/java/org/spigotmc/TrackingRange.java
|
||||
@@ -24,6 +24,7 @@ public class TrackingRange
|
||||
{
|
||||
return defaultRange;
|
||||
}
|
||||
+ if (entity instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon) return defaultRange; // Paper - enderdragon is exempt
|
||||
SpigotWorldConfig config = entity.level.spigotConfig;
|
||||
if ( entity instanceof ServerPlayer )
|
||||
{
|
||||
@@ -47,8 +48,48 @@ public class TrackingRange
|
||||
return config.miscTrackingRange;
|
||||
} else
|
||||
{
|
||||
- if (entity instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon) return ((net.minecraft.server.level.ServerLevel)(entity.getCommandSenderWorld())).getChunkSource().chunkMap.getEffectiveViewDistance(); // Paper - enderdragon is exempt
|
||||
return config.otherTrackingRange;
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // Paper start - optimise entity tracking
|
||||
+ // copied from above, TODO check on update
|
||||
+ public static TrackingRangeType getTrackingRangeType(Entity entity)
|
||||
+ {
|
||||
+ if (entity instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon) return TrackingRangeType.ENDERDRAGON; // Paper - enderdragon is exempt
|
||||
+ if ( entity instanceof ServerPlayer )
|
||||
+ {
|
||||
+ return TrackingRangeType.PLAYER;
|
||||
+ // Paper start - Simplify and set water mobs to animal tracking range
|
||||
+ }
|
||||
+ switch (entity.activationType) {
|
||||
+ case RAIDER:
|
||||
+ case MONSTER:
|
||||
+ case FLYING_MONSTER:
|
||||
+ return TrackingRangeType.MONSTER;
|
||||
+ case WATER:
|
||||
+ case VILLAGER:
|
||||
+ case ANIMAL:
|
||||
+ return TrackingRangeType.ANIMAL;
|
||||
+ case MISC:
|
||||
+ }
|
||||
+ if ( entity instanceof ItemFrame || entity instanceof Painting || entity instanceof ItemEntity || entity instanceof ExperienceOrb )
|
||||
+ // Paper end
|
||||
+ {
|
||||
+ return TrackingRangeType.MISC;
|
||||
+ } else
|
||||
+ {
|
||||
+ return TrackingRangeType.OTHER;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static enum TrackingRangeType {
|
||||
+ PLAYER,
|
||||
+ ANIMAL,
|
||||
+ MONSTER,
|
||||
+ MISC,
|
||||
+ OTHER,
|
||||
+ ENDERDRAGON;
|
||||
+ }
|
||||
+ // Paper end - optimise entity tracking
|
||||
}
|
|
@ -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 987e65332058f364fcef0a29c97b206b14ad6457..8b46e494ecd0cce5ab0b2bf8e50cf50dc7e2a7e5 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java
|
||||
@@ -113,7 +113,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
|
||||
}
|
||||
|
||||
public ItemStack assemble() {
|
|
@ -1,32 +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 339dfd9fdffbc1c49b9112ba43ef6f05d85bdf86..44bfc5560a1b43925aabfd8137495e169da32fa2 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
@@ -131,9 +131,9 @@ public class MapItem extends ComplexItem {
|
||||
int k2 = (j / i + k1 - 64) * i;
|
||||
int l2 = (k / i + l1 - 64) * i;
|
||||
Multiset<MaterialColor> multiset = LinkedHashMultiset.create();
|
||||
- LevelChunk chunk = world.getChunkAt(new BlockPos(k2, 0, l2));
|
||||
+ LevelChunk chunk = world.getChunkIfLoaded(new BlockPos(k2, 0, l2)); // Paper - Maps shouldn't load chunks
|
||||
|
||||
- if (!chunk.isEmpty()) {
|
||||
+ if (chunk != null && !chunk.isEmpty()) { // Paper - Maps shouldn't load chunks
|
||||
ChunkPos chunkcoordintpair = chunk.getPos();
|
||||
int i3 = k2 & 15;
|
||||
int j3 = l2 & 15;
|
|
@ -1,27 +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 44bfc5560a1b43925aabfd8137495e169da32fa2..d407cf849a31a7a77fda07aa687ebb254f43d6ab 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
@@ -252,14 +252,13 @@ public class MapItem extends ComplexItem {
|
||||
boolean[] aboolean = new boolean[16384];
|
||||
int l = j / i - 64;
|
||||
int i1 = k / i - 64;
|
||||
- BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
|
||||
|
||||
int j1;
|
||||
int k1;
|
||||
|
||||
for (j1 = 0; j1 < 128; ++j1) {
|
||||
for (k1 = 0; k1 < 128; ++k1) {
|
||||
- Holder<Biome> holder = world.getBiome(blockposition_mutableblockposition.set((l + k1) * i, 0, (i1 + j1) * i));
|
||||
+ Holder<Biome> holder = world.getUncachedNoiseBiome((l + k1) * i, 0, (i1 + j1) * i); // Paper
|
||||
|
||||
aboolean[j1 * 128 + k1] = 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 ea7ebbc2674df727cf44856f172731ee083b8800..a423970cf7c927ea8a1bf842aaa236d3cf2d54c2 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
@@ -199,7 +199,7 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
|
||||
@Override
|
||||
public void runTaskTimerAsynchronously(Plugin plugin, Consumer<BukkitTask> task, long delay, long period) throws IllegalArgumentException {
|
||||
- this.runTaskTimerAsynchronously(plugin, (Object) task, delay, CraftTask.NO_REPEATING);
|
||||
+ this.runTaskTimerAsynchronously(plugin, (Object) task, delay, period);
|
||||
}
|
||||
|
||||
@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 29755807fdb6c30e31c0ec2bbf33bed9afd5d478..8d73893100884c08aa552ff41c2a07a3e714df47 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
|
||||
@@ -411,14 +411,26 @@ public class PistonBaseBlock extends DirectionalBlock {
|
||||
}
|
||||
|
||||
for (k = list.size() - 1; k >= 0; --k) {
|
||||
- blockposition3 = (BlockPos) list.get(k);
|
||||
- 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(k);
|
||||
+ 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(k), 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(k) : iblockdata1, dir, retract, false));
|
||||
+ if (!allowDesync) {
|
||||
+ world.setBlock(oldPos, Blocks.AIR.defaultBlockState(), 2 | 4 | 16 | 1024); // set air to prevent later physics updates from seeing this block
|
||||
+ }
|
||||
+ // Paper end - fix a variety of piston desync dupes
|
||||
aiblockdata[j++] = 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 1bcaed2abd1118804a362d6852e4a29d3064aa14..4b61602a1d2d6817272e02cfd282ac5dabbd976d 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
|
||||
@@ -285,7 +285,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 | 2)); // Paper - 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,37 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Fri, 12 Jun 2020 13:33:19 -0700
|
||||
Subject: [PATCH] Fix sand duping
|
||||
|
||||
If the falling block dies during teleportation (entity#move), then we need
|
||||
to detect that by placing a check after the move.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
index 108c9ea0eb4a7f381042bfe0203ac40a9c4f27a7..da00fab453f3fb580acc9de65a0853656f9b6fc4 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
@@ -126,6 +126,11 @@ public class FallingBlockEntity extends Entity {
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
+ // Paper start - fix sand duping
|
||||
+ if (this.isRemoved()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - fix sand duping
|
||||
if (this.blockState.isAir()) {
|
||||
this.discard();
|
||||
} else {
|
||||
@@ -138,6 +143,12 @@ public class FallingBlockEntity extends Entity {
|
||||
|
||||
this.move(MoverType.SELF, this.getDeltaMovement());
|
||||
|
||||
+ // Paper start - fix sand duping
|
||||
+ if (this.isRemoved()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - fix sand duping
|
||||
+
|
||||
// Paper start - Configurable EntityFallingBlock height nerf
|
||||
if (this.level.paperConfig().fixes.fallingBlockHeightNerf.test(v -> this.getY() > v)) {
|
||||
if (this.dropItem && this.level.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) {
|
|
@ -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 30b6c5839b0da1aea792b7e092f0fcf5e83835db..683474cd96d3a0cdfb3b22d0111c8d3231f01d92 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java
|
||||
@@ -501,7 +501,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,31 +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 in playerconnection 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 8c8ccd61fb1592a9274e54ed6e06ec7737e942e0..10efc010cf5c43d3e009972c1f5ee7c4083d21f8 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1446,6 +1446,11 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
|
||||
this.player.move(MoverType.PLAYER, new Vec3(d7, d8, d9));
|
||||
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 d12 = d8;
|
||||
|
||||
d7 = 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 3796f8b122ad981b6faacd2afcaf3696314aad6b..b17dab9e5c06d8789553b104602d7da35d926dd1 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
|
||||
@@ -532,6 +532,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 01d425d359f2d6d87b6c01b435a9cfcfe11caa20..4707a651dc80086efa852bcfba38a534e7f1f3d0 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java
|
||||
@@ -64,6 +64,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,38 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Nesaak <52047222+Nesaak@users.noreply.github.com>
|
||||
Date: Sat, 23 May 2020 10:31:11 -0400
|
||||
Subject: [PATCH] Improve Arrow API
|
||||
|
||||
Add method to get the arrow's itemstack and a method
|
||||
to set the arrow's "noclip" status
|
||||
|
||||
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java
|
||||
index 376885c8148da619a3b203145d315ebaf44994fb..15abd085eeb0a31a925c1a8d6de903c9d4625a29 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java
|
||||
@@ -102,6 +102,23 @@ public class CraftArrow extends AbstractProjectile implements AbstractArrow {
|
||||
this.getHandle().pickup = net.minecraft.world.entity.projectile.AbstractArrow.Pickup.byOrdinal(status.ordinal());
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public org.bukkit.craftbukkit.inventory.CraftItemStack getItemStack() {
|
||||
+ return org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(getHandle().getPickupItem());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setNoPhysics(boolean noPhysics) {
|
||||
+ this.getHandle().setNoPhysics(noPhysics);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasNoPhysics() {
|
||||
+ return this.getHandle().isNoPhysics();
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public void setTicksLived(int value) {
|
||||
super.setTicksLived(value);
|
|
@ -1,29 +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 and implement PlayerRecipeBookClickEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 10efc010cf5c43d3e009972c1f5ee7c4083d21f8..496fdfcf3e6a80f9f2f073105bc2819ce127c8ef 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -3229,9 +3229,15 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
if (!this.player.containerMenu.stillValid(this.player)) {
|
||||
ServerGamePacketListenerImpl.LOGGER.debug("Player {} interacted with invalid menu {}", this.player, this.player.containerMenu);
|
||||
} else {
|
||||
- this.server.getRecipeManager().byKey(packet.getRecipe()).ifPresent((irecipe) -> {
|
||||
- ((RecipeBookMenu) this.player.containerMenu).handlePlacement(packet.isShiftDown(), irecipe, this.player);
|
||||
- });
|
||||
+ // Paper start - fire event for clicking recipes in the recipe book
|
||||
+ com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent event = new com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent(
|
||||
+ player.getBukkitEntity(), org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(packet.getRecipe()), packet.isShiftDown());
|
||||
+ if (event.callEvent() && this.player.containerMenu instanceof RecipeBookMenu<?> recipeBookMenu) { // check if inventory changed during event handling
|
||||
+ this.server.getRecipeManager().byKey(org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(event.getRecipe())).ifPresent((irecipe) -> {
|
||||
+ recipeBookMenu.handlePlacement(event.isMakeAll(), irecipe, this.player);
|
||||
+ });
|
||||
+ }
|
||||
+ // Paper 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 1e01277448a3cf2b2045b54b182166a66c822e20..a32cfa75a9bea896f558bab646d0868391b069a9 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
||||
@@ -136,7 +136,7 @@ public class DedicatedServerProperties extends Settings<DedicatedServerPropertie
|
||||
this.maxWorldSize = this.get("max-world-size", (integer) -> {
|
||||
return Mth.clamp(integer, (int) 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 behind flag
|
||||
this.enableJmxMonitoring = this.get("enable-jmx-monitoring", false);
|
||||
this.enableStatus = this.get("enable-status", true);
|
||||
this.hideOnlinePlayers = this.get("hide-online-players", false);
|
|
@ -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 af00442931f9f6cf878bd61137c2f29fc7c8d0b1..431ff490760f54be76847c7b370dbbb4b65de102 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
@@ -396,7 +396,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 496fdfcf3e6a80f9f2f073105bc2819ce127c8ef..033c1038ccc5f4c340f853a89a72aeadbf15922e 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -878,7 +878,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel());
|
||||
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;
|
||||
@@ -945,7 +945,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel());
|
||||
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 7dac559fd35e7ba646b84bb28315001375723643..7c7e5f3c0f9cd1f16192a8fc8163da9b2d9519d5 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java
|
||||
@@ -198,7 +198,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 061a56e3828767cd6576d5a9edde5f3498e609d0..2e7c03b00bc941b86df6a7f1b2b188c9f0aede22 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/CommandBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/CommandBlock.java
|
||||
@@ -130,7 +130,7 @@ public class CommandBlock extends BaseEntityBlock implements GameMasterBlock {
|
||||
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, 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 70d3949616c63038ad3e9bd1069db5ea2fb3f3b8..8e06bc11fb28baee3407bbfe9d7b3689d6f85ff2 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,46 +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 AABB's are never invalid
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 26c8b19d484032f5d0935ba8672a3121a3197d67..1582da75f92aed598c1c076af7b94af7ab48d10a 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -713,8 +713,8 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
}
|
||||
|
||||
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 - force bounding box update
|
||||
+ // this.setBoundingBox(this.makeBoundingBox()); // Paper - move into setPositionRaw
|
||||
}
|
||||
|
||||
protected AABB makeBoundingBox() {
|
||||
@@ -3945,6 +3945,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
}
|
||||
|
||||
public final void setPosRaw(double x, double y, double z) {
|
||||
+ // Paper start
|
||||
+ this.setPosRaw(x, y, z, false);
|
||||
+ }
|
||||
+ public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) {
|
||||
+ // Paper end
|
||||
// Paper start - rewrite chunk system
|
||||
if (this.updatingSectionStatus) {
|
||||
LOGGER.error("Refusing to update position for entity " + this + " to position " + new Vec3(x, y, z) + " since it is processing a section status update", new Throwable());
|
||||
@@ -3968,6 +3973,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
this.levelCallback.onMove();
|
||||
}
|
||||
|
||||
+ // Paper start - never allow AABB to become desynced from position
|
||||
+ // 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
|
||||
}
|
||||
|
||||
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 fb2d02ad6f6a4a1c69dde06e7e193aaef8655028..dda33bd52d9c527c37f67b829010c27dba4b667a 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -791,7 +791,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
chunkproviderserver.getLightEngine().setTaskPerBatch(worldserver.paperConfig().misc.lightQueueSize); // Paper - increase light queue size
|
||||
// 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
|
||||
@@ -1704,11 +1704,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 - remember 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1722,7 +1725,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 4bb29f86538552bb62125cc61210fd77b1ec671d..817193ca5fc15134d2985187bc2226ccbb4f0108 100644
|
||||
--- a/src/main/java/net/minecraft/server/commands/DifficultyCommand.java
|
||||
+++ b/src/main/java/net/minecraft/server/commands/DifficultyCommand.java
|
||||
@@ -47,7 +47,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 - don't skip other difficulty-changing logic (fix upstream's fix)
|
||||
source.sendSuccess(Component.translatable("commands.difficulty.success", difficulty.getDisplayName()), true);
|
||||
return 0;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index e3a62579067209c447f2fdcb76b2a11e489a376b..a8e18a168e8288ebea95bacd61a38039b3427d5e 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -332,7 +332,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 - 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 61904f4d3160d83f87d66fd9f86acf54ab31adc6..c32f09e993ef25876373a34d148b0452ea03bcf0 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -1129,7 +1129,7 @@ public class ServerPlayer extends Player {
|
||||
this.isChangingDimension = true; // CraftBukkit - Set teleport invulnerability only if player changing worlds
|
||||
|
||||
this.connection.send(new ClientboundRespawnPacket(worldserver.dimensionTypeId(), worldserver.dimension(), BiomeManager.obfuscateSeed(worldserver.getSeed()), this.gameMode.getGameModeForPlayer(), this.gameMode.getPreviousGameModeForPlayer(), worldserver.isDebug(), worldserver.isFlat(), true, this.getLastDeathLocation()));
|
||||
- this.connection.send(new ClientboundChangeDifficultyPacket(this.level.getDifficulty(), this.level.getLevelData().isDifficultyLocked()));
|
||||
+ this.connection.send(new ClientboundChangeDifficultyPacket(worldserver.getDifficulty(), this.level.getLevelData().isDifficultyLocked())); // Paper - fix difficulty sync issue
|
||||
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 033c1038ccc5f4c340f853a89a72aeadbf15922e..f6012bf8134f0606710511150dd296a1d677334d 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -3499,7 +3499,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
public void handleChangeDifficulty(ServerboundChangeDifficultyPacket packet) {
|
||||
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel());
|
||||
if (this.player.hasPermissions(2) || this.isSingleplayerOwner()) {
|
||||
- this.server.setDifficulty(packet.getDifficulty(), false);
|
||||
+ // this.server.setDifficulty(packet.getDifficulty(), false); // Paper - 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 e8e31ddaa7fa87b9854961dd44abff9ddb6a6142..4c6c9aa8b3305f5ab4f7b8d356e860da169fb1db 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -951,8 +951,8 @@ public final class CraftServer implements Server {
|
||||
org.spigotmc.SpigotConfig.init((File) 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 c3703933598ee96d856a18dcc0932061959c9791..298012beaf6f587a05d230b7208325ea8c3ad811 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -1147,7 +1147,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 - don't skip other difficulty-changing logic
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,92 +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 04bf08cbe45763f1338390c5ab4b0dcb334bd07a..a7b78508ef78229835805300e62a306a3f1ddf6d 100644
|
||||
--- a/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
+++ b/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.papermc.paper.command;
|
||||
|
||||
import io.papermc.paper.command.subcommands.ChunkDebugCommand;
|
||||
+import io.papermc.paper.command.subcommands.DumpItemCommand;
|
||||
import io.papermc.paper.command.subcommands.EntityCommand;
|
||||
import io.papermc.paper.command.subcommands.FixLightCommand;
|
||||
import io.papermc.paper.command.subcommands.HeapDumpCommand;
|
||||
@@ -46,6 +47,7 @@ public final class PaperCommand extends Command {
|
||||
commands.put(Set.of("fixlight"), new FixLightCommand());
|
||||
commands.put(Set.of("debug", "chunkinfo", "holderinfo"), new ChunkDebugCommand());
|
||||
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..771503ff637fea10d4d8be0f37f3f146c41791d9
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/command/subcommands/DumpItemCommand.java
|
||||
@@ -0,0 +1,59 @@
|
||||
+package io.papermc.paper.command.subcommands;
|
||||
+
|
||||
+import io.papermc.paper.adventure.PaperAdventure;
|
||||
+import io.papermc.paper.command.PaperSubcommand;
|
||||
+import java.util.Objects;
|
||||
+import net.kyori.adventure.text.Component;
|
||||
+import net.kyori.adventure.text.event.ClickEvent;
|
||||
+import net.minecraft.core.Registry;
|
||||
+import net.minecraft.nbt.CompoundTag;
|
||||
+import net.minecraft.world.item.ItemStack;
|
||||
+import org.bukkit.Bukkit;
|
||||
+import org.bukkit.command.CommandSender;
|
||||
+import org.bukkit.craftbukkit.CraftWorld;
|
||||
+import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
+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.text;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.GRAY;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.YELLOW;
|
||||
+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);
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ private void doDumpItem(final CommandSender sender) {
|
||||
+ if (!(sender instanceof Player)) {
|
||||
+ sender.sendMessage("Only players can use this command");
|
||||
+ return;
|
||||
+ }
|
||||
+ final ItemStack itemStack = CraftItemStack.asNMSCopy(((CraftPlayer) sender).getItemInHand());
|
||||
+ final @Nullable CompoundTag tag = itemStack.getTag();
|
||||
+ final @Nullable Component nbtComponent = tag == null ? null : PaperAdventure.asAdventure(net.minecraft.nbt.NbtUtils.toPrettyComponent(tag));
|
||||
+ final String itemId = Objects.requireNonNull(((CraftWorld) ((CraftPlayer) sender).getWorld()).getHandle().registryAccess()
|
||||
+ .registryOrThrow(Registry.ITEM_REGISTRY).getKey(itemStack.getItem())).toString();
|
||||
+ final Component message = text()
|
||||
+ .append(text(itemId, YELLOW))
|
||||
+ .apply(b -> {
|
||||
+ if (nbtComponent != null) {
|
||||
+ b.append(nbtComponent);
|
||||
+ }
|
||||
+ })
|
||||
+ .build();
|
||||
+ Bukkit.getConsoleSender().sendMessage(message);
|
||||
+ sender.sendMessage(message);
|
||||
+ sender.sendMessage(text().content(" Click to copy item to clipboard")
|
||||
+ .color(GRAY)
|
||||
+ .decorate(ITALIC)
|
||||
+ .clickEvent(ClickEvent.copyToClipboard(tag == null ? itemId : (itemId + tag))));
|
||||
+ }
|
||||
+}
|
|
@ -1,23 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 28 Jun 2020 19:36:55 -0400
|
||||
Subject: [PATCH] Don't allow null UUID's for chat
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/chat/ChatSender.java b/src/main/java/net/minecraft/network/chat/ChatSender.java
|
||||
index eb33c74d51f9b096ac39adf167fa09afdaa5e56b..d3d5487e9a4e95271a88c094058ec9d37a10d370 100644
|
||||
--- a/src/main/java/net/minecraft/network/chat/ChatSender.java
|
||||
+++ b/src/main/java/net/minecraft/network/chat/ChatSender.java
|
||||
@@ -8,6 +8,12 @@ import net.minecraft.world.entity.player.ProfilePublicKey;
|
||||
public record ChatSender(UUID profileId, @Nullable ProfilePublicKey profilePublicKey) {
|
||||
public static final ChatSender SYSTEM = new ChatSender(Util.NIL_UUID, (ProfilePublicKey)null);
|
||||
|
||||
+ // Paper start
|
||||
+ public ChatSender {
|
||||
+ com.google.common.base.Preconditions.checkNotNull(profileId, "uuid cannot be null");
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public boolean isSystem() {
|
||||
return SYSTEM.equals(this);
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 28 Jun 2020 19:08:41 -0400
|
||||
Subject: [PATCH] Improve Legacy Component serialization size
|
||||
|
||||
Don't constantly send format: false for all formatting options when parent already
|
||||
has it false
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java b/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java
|
||||
index 4fede2161792ba3e7cdf0cc5a1f533188becc6f7..0f70be614f8f5350ad558d0ae645cdf0027e1e76 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java
|
||||
@@ -47,6 +47,7 @@ public final class CraftChatMessage {
|
||||
// Separate pattern with no group 3, new lines are part of previous string
|
||||
private static final Pattern INCREMENTAL_PATTERN_KEEP_NEWLINES = Pattern.compile("(" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + "[0-9a-fk-orx])|((?:(?:https?):\\/\\/)?(?:[-\\w_\\.]{2,}\\.[a-z]{2,4}.*?(?=[\\.\\?!,;:]?(?:[" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + " ]|$))))", Pattern.CASE_INSENSITIVE);
|
||||
// ChatColor.b does not explicitly reset, its more of empty
|
||||
+ private static final Style EMPTY = Style.EMPTY.withItalic(false); // Paper - OBFHELPER
|
||||
private static final Style RESET = Style.EMPTY.withBold(false).withItalic(false).withUnderlined(false).withStrikethrough(false).withObfuscated(false);
|
||||
|
||||
private final List<Component> list = new ArrayList<Component>();
|
||||
@@ -68,6 +69,7 @@ public final class CraftChatMessage {
|
||||
Matcher matcher = (keepNewlines ? StringMessage.INCREMENTAL_PATTERN_KEEP_NEWLINES : StringMessage.INCREMENTAL_PATTERN).matcher(message);
|
||||
String match = null;
|
||||
boolean needsAdd = false;
|
||||
+ boolean hasReset = false; // Paper
|
||||
while (matcher.find()) {
|
||||
int groupId = 0;
|
||||
while ((match = matcher.group(++groupId)) == null) {
|
||||
@@ -113,7 +115,26 @@ public final class CraftChatMessage {
|
||||
throw new AssertionError("Unexpected message format");
|
||||
}
|
||||
} else { // Color resets formatting
|
||||
- this.modifier = StringMessage.RESET.withColor(format);
|
||||
+ // Paper start - improve legacy formatting
|
||||
+ Style previous = modifier;
|
||||
+ modifier = (!hasReset ? RESET : EMPTY).withColor(format);
|
||||
+ hasReset = true;
|
||||
+ if (previous.isBold()) {
|
||||
+ modifier = modifier.withBold(false);
|
||||
+ }
|
||||
+ if (previous.isItalic()) {
|
||||
+ modifier = modifier.withItalic(false);
|
||||
+ }
|
||||
+ if (previous.isObfuscated()) {
|
||||
+ modifier = modifier.withObfuscated(false);
|
||||
+ }
|
||||
+ if (previous.isStrikethrough()) {
|
||||
+ modifier = modifier.withStrikethrough(false);
|
||||
+ }
|
||||
+ if (previous.isUnderlined()) {
|
||||
+ modifier = modifier.withUnderlined(false);
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
needsAdd = true;
|
||||
break;
|
|
@ -1,213 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 4 Jun 2020 02:24:49 -0400
|
||||
Subject: [PATCH] Optimize Bit Operations by inlining
|
||||
|
||||
Inline bit operations and reduce instruction count to make these hot
|
||||
operations faster
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java
|
||||
index f8361dcf9d0378497ec5a34ea53b4e0019700851..e68cd32a7db88f29d3224b0908119232ab3cf71a 100644
|
||||
--- a/src/main/java/net/minecraft/core/BlockPos.java
|
||||
+++ b/src/main/java/net/minecraft/core/BlockPos.java
|
||||
@@ -30,15 +30,16 @@ public class BlockPos extends Vec3i {
|
||||
}).stable();
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
public static final BlockPos ZERO = new BlockPos(0, 0, 0);
|
||||
- private static final int PACKED_X_LENGTH = 1 + Mth.log2(Mth.smallestEncompassingPowerOfTwo(30000000));
|
||||
- private static final int PACKED_Z_LENGTH = PACKED_X_LENGTH;
|
||||
- public static final int PACKED_Y_LENGTH = 64 - PACKED_X_LENGTH - PACKED_Z_LENGTH;
|
||||
- private static final long PACKED_X_MASK = (1L << PACKED_X_LENGTH) - 1L;
|
||||
- private static final long PACKED_Y_MASK = (1L << PACKED_Y_LENGTH) - 1L;
|
||||
- private static final long PACKED_Z_MASK = (1L << PACKED_Z_LENGTH) - 1L;
|
||||
- private static final int Y_OFFSET = 0;
|
||||
- private static final int Z_OFFSET = PACKED_Y_LENGTH;
|
||||
- private static final int X_OFFSET = PACKED_Y_LENGTH + PACKED_Z_LENGTH;
|
||||
+ // Paper start - static constants
|
||||
+ private static final int PACKED_X_LENGTH = 26;
|
||||
+ private static final int PACKED_Z_LENGTH = 26;
|
||||
+ public static final int PACKED_Y_LENGTH = 12;
|
||||
+ private static final long PACKED_X_MASK = 67108863;
|
||||
+ private static final long PACKED_Y_MASK = 4095;
|
||||
+ private static final long PACKED_Z_MASK = 67108863;
|
||||
+ private static final int Z_OFFSET = 12;
|
||||
+ private static final int X_OFFSET = 38;
|
||||
+ // Paper end
|
||||
|
||||
public BlockPos(int x, int y, int z) {
|
||||
super(x, y, z);
|
||||
@@ -60,28 +61,29 @@ public class BlockPos extends Vec3i {
|
||||
this(pos.getX(), pos.getY(), pos.getZ());
|
||||
}
|
||||
|
||||
+ public static long getAdjacent(int baseX, int baseY, int baseZ, Direction enumdirection) { return asLong(baseX + enumdirection.getStepX(), baseY + enumdirection.getStepY(), baseZ + enumdirection.getStepZ()); } // Paper
|
||||
public static long offset(long value, Direction direction) {
|
||||
return offset(value, direction.getStepX(), direction.getStepY(), direction.getStepZ());
|
||||
}
|
||||
|
||||
public static long offset(long value, int x, int y, int z) {
|
||||
- return asLong(getX(value) + x, getY(value) + y, getZ(value) + z);
|
||||
+ return asLong((int) (value >> 38) + x, (int) ((value << 52) >> 52) + y, (int) ((value << 26) >> 38) + z); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static int getX(long packedPos) {
|
||||
- return (int)(packedPos << 64 - X_OFFSET - PACKED_X_LENGTH >> 64 - PACKED_X_LENGTH);
|
||||
+ return (int) (packedPos >> 38); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static int getY(long packedPos) {
|
||||
- return (int)(packedPos << 64 - PACKED_Y_LENGTH >> 64 - PACKED_Y_LENGTH);
|
||||
+ return (int) ((packedPos << 52) >> 52); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static int getZ(long packedPos) {
|
||||
- return (int)(packedPos << 64 - Z_OFFSET - PACKED_Z_LENGTH >> 64 - PACKED_Z_LENGTH);
|
||||
+ return (int) ((packedPos << 26) >> 38); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static BlockPos of(long packedPos) {
|
||||
- return new BlockPos(getX(packedPos), getY(packedPos), getZ(packedPos));
|
||||
+ return new BlockPos((int) (packedPos >> 38), (int) ((packedPos << 52) >> 52), (int) ((packedPos << 26) >> 38)); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public long asLong() {
|
||||
@@ -89,10 +91,7 @@ public class BlockPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static long asLong(int x, int y, int z) {
|
||||
- long l = 0L;
|
||||
- l |= ((long)x & PACKED_X_MASK) << X_OFFSET;
|
||||
- l |= ((long)y & PACKED_Y_MASK) << 0;
|
||||
- return l | ((long)z & PACKED_Z_MASK) << Z_OFFSET;
|
||||
+ return (((long) x & (long) 67108863) << 38) | (((long) y & (long) 4095)) | (((long) z & (long) 67108863) << 12); // Paper - inline constants and simplify
|
||||
}
|
||||
|
||||
public static long getFlatIndex(long y) {
|
||||
diff --git a/src/main/java/net/minecraft/core/SectionPos.java b/src/main/java/net/minecraft/core/SectionPos.java
|
||||
index a481bd6328fe9e66f6911bf32ed11947c504c93c..a9d0d72aad7b1b708617a082c5efcd881a0f00d3 100644
|
||||
--- a/src/main/java/net/minecraft/core/SectionPos.java
|
||||
+++ b/src/main/java/net/minecraft/core/SectionPos.java
|
||||
@@ -38,7 +38,7 @@ public class SectionPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static SectionPos of(BlockPos pos) {
|
||||
- return new SectionPos(blockToSectionCoord(pos.getX()), blockToSectionCoord(pos.getY()), blockToSectionCoord(pos.getZ()));
|
||||
+ return new SectionPos(pos.getX() >> 4, pos.getY() >> 4, pos.getZ() >> 4); // Paper
|
||||
}
|
||||
|
||||
public static SectionPos of(ChunkPos chunkPos, int y) {
|
||||
@@ -54,7 +54,7 @@ public class SectionPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static SectionPos of(long packed) {
|
||||
- return new SectionPos(x(packed), y(packed), z(packed));
|
||||
+ return new SectionPos((int) (packed >> 42), (int) (packed << 44 >> 44), (int) (packed << 22 >> 42)); // Paper
|
||||
}
|
||||
|
||||
public static SectionPos bottomOf(ChunkAccess chunk) {
|
||||
@@ -65,8 +65,16 @@ public class SectionPos extends Vec3i {
|
||||
return offset(packed, direction.getStepX(), direction.getStepY(), direction.getStepZ());
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public static long getAdjacentFromBlockPos(int x, int y, int z, Direction enumdirection) {
|
||||
+ return (((long) ((x >> 4) + enumdirection.getStepX()) & 4194303L) << 42) | (((long) ((y >> 4) + enumdirection.getStepY()) & 1048575L)) | (((long) ((z >> 4) + enumdirection.getStepZ()) & 4194303L) << 20);
|
||||
+ }
|
||||
+ public static long getAdjacentFromSectionPos(int x, int y, int z, Direction enumdirection) {
|
||||
+ return (((long) (x + enumdirection.getStepX()) & 4194303L) << 42) | (((long) ((y) + enumdirection.getStepY()) & 1048575L)) | (((long) (z + enumdirection.getStepZ()) & 4194303L) << 20);
|
||||
+ }
|
||||
+ // Paper end
|
||||
public static long offset(long packed, int x, int y, int z) {
|
||||
- return asLong(x(packed) + x, y(packed) + y, z(packed) + z);
|
||||
+ return (((long) ((int) (packed >> 42) + x) & 4194303L) << 42) | (((long) ((int) (packed << 44 >> 44) + y) & 1048575L)) | (((long) ((int) (packed << 22 >> 42) + z) & 4194303L) << 20); // Simplify to reduce instruction count
|
||||
}
|
||||
|
||||
public static int posToSectionCoord(double coord) {
|
||||
@@ -86,10 +94,7 @@ public class SectionPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static short sectionRelativePos(BlockPos pos) {
|
||||
- int i = sectionRelative(pos.getX());
|
||||
- int j = sectionRelative(pos.getY());
|
||||
- int k = sectionRelative(pos.getZ());
|
||||
- return (short)(i << 8 | k << 4 | j << 0);
|
||||
+ return (short) ((pos.getX() & 15) << 8 | (pos.getZ() & 15) << 4 | pos.getY() & 15); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static int sectionRelativeX(short packedLocalPos) {
|
||||
@@ -152,16 +157,16 @@ public class SectionPos extends Vec3i {
|
||||
return this.getZ();
|
||||
}
|
||||
|
||||
- public int minBlockX() {
|
||||
- return sectionToBlockCoord(this.x());
|
||||
+ public final int minBlockX() { // Paper - make final
|
||||
+ return this.getX() << 4; // Paper - inline
|
||||
}
|
||||
|
||||
- public int minBlockY() {
|
||||
- return sectionToBlockCoord(this.y());
|
||||
+ public final int minBlockY() { // Paper - make final
|
||||
+ return this.getY() << 4; // Paper - inline
|
||||
}
|
||||
|
||||
- public int minBlockZ() {
|
||||
- return sectionToBlockCoord(this.z());
|
||||
+ public int minBlockZ() { // Paper - make final
|
||||
+ return this.getZ() << 4; // Paper - inline
|
||||
}
|
||||
|
||||
public int maxBlockX() {
|
||||
@@ -177,7 +182,8 @@ public class SectionPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static long blockToSection(long blockPos) {
|
||||
- return asLong(blockToSectionCoord(BlockPos.getX(blockPos)), blockToSectionCoord(BlockPos.getY(blockPos)), blockToSectionCoord(BlockPos.getZ(blockPos)));
|
||||
+ // b(a(BlockPosition.b(i)), a(BlockPosition.c(i)), a(BlockPosition.d(i)));
|
||||
+ return (((long) (int) (blockPos >> 42) & 4194303L) << 42) | (((long) (int) ((blockPos << 52) >> 56) & 1048575L)) | (((long) (int) ((blockPos << 26) >> 42) & 4194303L) << 20); // Simplify to reduce instruction count
|
||||
}
|
||||
|
||||
public static long getZeroNode(long pos) {
|
||||
@@ -201,15 +207,18 @@ public class SectionPos extends Vec3i {
|
||||
return asLong(blockToSectionCoord(pos.getX()), blockToSectionCoord(pos.getY()), blockToSectionCoord(pos.getZ()));
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public static long blockPosAsSectionLong(int i, int j, int k) {
|
||||
+ return (((long) (i >> 4) & 4194303L) << 42) | (((long) (j >> 4) & 1048575L)) | (((long) (k >> 4) & 4194303L) << 20);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public static long asLong(int x, int y, int z) {
|
||||
- long l = 0L;
|
||||
- l |= ((long)x & 4194303L) << 42;
|
||||
- l |= ((long)y & 1048575L) << 0;
|
||||
- return l | ((long)z & 4194303L) << 20;
|
||||
+ return (((long) x & 4194303L) << 42) | (((long) y & 1048575L)) | (((long) z & 4194303L) << 20); // Paper - Simplify to reduce instruction count
|
||||
}
|
||||
|
||||
public long asLong() {
|
||||
- return asLong(this.x(), this.y(), this.z());
|
||||
+ return (((long) getX() & 4194303L) << 42) | (((long) getY() & 1048575L)) | (((long) getZ() & 4194303L) << 20); // Paper - Simplify to reduce instruction count
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -222,16 +231,11 @@ public class SectionPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static Stream<SectionPos> cube(SectionPos center, int radius) {
|
||||
- int i = center.x();
|
||||
- int j = center.y();
|
||||
- int k = center.z();
|
||||
- return betweenClosedStream(i - radius, j - radius, k - radius, i + radius, j + radius, k + radius);
|
||||
+ return betweenClosedStream(center.getX() - radius, center.getY() - radius, center.getZ() - radius, center.getX() + radius, center.getY() + radius, center.getZ() + radius); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static Stream<SectionPos> aroundChunk(ChunkPos center, int radius, int minY, int maxY) {
|
||||
- int i = center.x;
|
||||
- int j = center.z;
|
||||
- return betweenClosedStream(i - radius, minY, j - radius, i + radius, maxY - 1, j + radius);
|
||||
+ return betweenClosedStream(center.x - radius, 0, center.z - radius, center.x + radius, 15, center.z + radius); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static Stream<SectionPos> betweenClosedStream(final int minX, final int minY, final int minZ, final int maxX, final int maxY, final int maxZ) {
|
|
@ -1,121 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 9 Jun 2020 03:33:03 -0400
|
||||
Subject: [PATCH] Add Plugin Tickets to API Chunk Methods
|
||||
|
||||
Like previous versions, plugins loading chunks kept them loaded until
|
||||
they garbage collected to avoid constant spamming of chunk loads
|
||||
|
||||
This adds tickets to a few more places so that they can be unloaded.
|
||||
|
||||
Additionally, this drops their ticket level to BORDER so they wont be ticking
|
||||
so they will just sit inactive instead.
|
||||
|
||||
Using .loadChunk to keep a chunk ticking was a horrible idea for upstream
|
||||
when we have TWO methods that are able to do that already in the API.
|
||||
|
||||
Also reduce their collection count down to a maximum of 1 second. Barely
|
||||
anyone knows what chunk-gc is in bukkit.yml as its less relevant now, and
|
||||
since this wasn't spigot behavior, this is safe to mostly ignore (unless someone
|
||||
wants it to collect even faster, they can restore that setting back to 1 instead of 20+)
|
||||
|
||||
Not adding it to .getType() though to keep behavior consistent with vanilla for performance reasons.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 4c6c9aa8b3305f5ab4f7b8d356e860da169fb1db..2aab13270af76bcc1b62787e9910d23d5ab56add 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -360,7 +360,7 @@ public final class CraftServer implements Server {
|
||||
this.overrideSpawnLimits();
|
||||
console.autosavePeriod = this.configuration.getInt("ticks-per.autosave");
|
||||
this.warningState = WarningState.value(this.configuration.getString("settings.deprecated-verbose"));
|
||||
- TicketType.PLUGIN.timeout = this.configuration.getInt("chunk-gc.period-in-ticks");
|
||||
+ TicketType.PLUGIN.timeout = Math.min(20, this.configuration.getInt("chunk-gc.period-in-ticks")); // Paper - cap plugin loads to 1 second
|
||||
this.minimumAPI = this.configuration.getString("settings.minimum-api");
|
||||
this.loadIcon();
|
||||
|
||||
@@ -931,7 +931,7 @@ public final class CraftServer implements Server {
|
||||
this.console.setMotd(config.motd);
|
||||
this.overrideSpawnLimits();
|
||||
this.warningState = WarningState.value(this.configuration.getString("settings.deprecated-verbose"));
|
||||
- TicketType.PLUGIN.timeout = this.configuration.getInt("chunk-gc.period-in-ticks");
|
||||
+ TicketType.PLUGIN.timeout = Math.min(20, configuration.getInt("chunk-gc.period-in-ticks")); // Paper - cap plugin loads to 1 second
|
||||
this.minimumAPI = this.configuration.getString("settings.minimum-api");
|
||||
this.printSaveWarning = false;
|
||||
console.autosavePeriod = this.configuration.getInt("ticks-per.autosave");
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index 298012beaf6f587a05d230b7208325ea8c3ad811..f19bfe6d6d4d915876cea3e6ef792639300fced1 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -282,8 +282,21 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
|
||||
@Override
|
||||
public Chunk getChunkAt(int x, int z) {
|
||||
- return this.world.getChunkSource().getChunk(x, z, true).bukkitChunk;
|
||||
+ // Paper start - add ticket to hold chunk for a little while longer if plugin accesses it
|
||||
+ net.minecraft.world.level.chunk.LevelChunk chunk = world.getChunkSource().getChunkAtIfLoadedImmediately(x, z);
|
||||
+ if (chunk == null) {
|
||||
+ addTicket(x, z);
|
||||
+ chunk = this.world.getChunkSource().getChunk(x, z, true);
|
||||
+ }
|
||||
+ return chunk.bukkitChunk;
|
||||
+ // Paper end
|
||||
+ }
|
||||
+
|
||||
+ // Paper start
|
||||
+ private void addTicket(int x, int z) {
|
||||
+ io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> world.getChunkSource().addRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 0, Unit.INSTANCE)); // Paper
|
||||
}
|
||||
+ // Paper end
|
||||
|
||||
@Override
|
||||
public Chunk getChunkAt(Block block) {
|
||||
@@ -350,7 +363,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
public boolean unloadChunkRequest(int x, int z) {
|
||||
org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot
|
||||
if (this.isChunkLoaded(x, z)) {
|
||||
- this.world.getChunkSource().removeRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 1, Unit.INSTANCE);
|
||||
+ this.world.getChunkSource().removeRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 0, Unit.INSTANCE); // Paper
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -436,9 +449,12 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot
|
||||
// Paper start - Optimize this method
|
||||
ChunkPos chunkPos = new ChunkPos(x, z);
|
||||
+ ChunkAccess immediate = world.getChunkSource().getChunkAtIfLoadedImmediately(x, z); // Paper
|
||||
+ if (immediate != null) return true; // Paper
|
||||
|
||||
if (!generate) {
|
||||
- ChunkAccess immediate = world.getChunkSource().getChunkAtImmediately(x, z);
|
||||
+
|
||||
+ //IChunkAccess immediate = world.getChunkProvider().getChunkAtImmediately(x, z); // Paper
|
||||
if (immediate == null) {
|
||||
immediate = world.getChunkSource().chunkMap.getUnloadingChunk(x, z);
|
||||
}
|
||||
@@ -446,7 +462,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
if (!(immediate instanceof ImposterProtoChunk) && !(immediate instanceof net.minecraft.world.level.chunk.LevelChunk)) {
|
||||
return false; // not full status
|
||||
}
|
||||
- world.getChunkSource().addRegionTicket(TicketType.PLUGIN, chunkPos, 1, Unit.INSTANCE);
|
||||
+ world.getChunkSource().addRegionTicket(TicketType.PLUGIN, chunkPos, 0, Unit.INSTANCE); // Paper
|
||||
world.getChunk(x, z); // make sure we're at ticket level 32 or lower
|
||||
return true;
|
||||
}
|
||||
@@ -472,7 +488,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
// we do this so we do not re-read the chunk data on disk
|
||||
}
|
||||
|
||||
- world.getChunkSource().addRegionTicket(TicketType.PLUGIN, chunkPos, 1, Unit.INSTANCE);
|
||||
+ world.getChunkSource().addRegionTicket(TicketType.PLUGIN, chunkPos, 0, Unit.INSTANCE); // Paper
|
||||
world.getChunkSource().getChunk(x, z, ChunkStatus.FULL, true);
|
||||
return true;
|
||||
// Paper end
|
||||
@@ -2148,6 +2164,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
io.papermc.paper.chunk.system.ChunkSystem.scheduleChunkLoad(this.getHandle(), x, z, gen, ChunkStatus.FULL, true, priority, (c) -> {
|
||||
net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> {
|
||||
net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk)c;
|
||||
+ if (chunk != null) addTicket(x, z); // Paper
|
||||
ret.complete(chunk == null ? null : chunk.getBukkitChunk());
|
||||
});
|
||||
});
|
|
@ -1,164 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Sun, 9 Jun 2019 03:53:22 +0100
|
||||
Subject: [PATCH] incremental chunk and player saving
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index dda33bd52d9c527c37f67b829010c27dba4b667a..e42b12839faab0c040495b00368b107b35b93283 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -864,7 +864,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
try {
|
||||
this.isSaving = true;
|
||||
- this.getPlayerList().saveAll();
|
||||
+ this.getPlayerList().saveAll(); // Diff on change
|
||||
flag3 = this.saveAllChunks(suppressLogs, flush, force);
|
||||
} finally {
|
||||
this.isSaving = false;
|
||||
@@ -1394,13 +1394,28 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
}
|
||||
|
||||
- if (this.autosavePeriod > 0 && this.tickCount % this.autosavePeriod == 0) { // CraftBukkit
|
||||
- MinecraftServer.LOGGER.debug("Autosave started");
|
||||
- this.profiler.push("save");
|
||||
- this.saveEverything(true, false, false);
|
||||
- this.profiler.pop();
|
||||
- MinecraftServer.LOGGER.debug("Autosave finished");
|
||||
+ // Paper start - incremental chunk and player saving
|
||||
+ int playerSaveInterval = io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.rate;
|
||||
+ if (playerSaveInterval < 0) {
|
||||
+ playerSaveInterval = autosavePeriod;
|
||||
}
|
||||
+ this.profiler.push("save");
|
||||
+ final boolean fullSave = autosavePeriod > 0 && this.tickCount % autosavePeriod == 0;
|
||||
+ try {
|
||||
+ this.isSaving = true;
|
||||
+ if (playerSaveInterval > 0) {
|
||||
+ this.playerList.saveAll(playerSaveInterval);
|
||||
+ }
|
||||
+ for (ServerLevel level : this.getAllLevels()) {
|
||||
+ if (level.paperConfig().chunks.autoSaveInterval.value() > 0) {
|
||||
+ level.saveIncrementally(fullSave);
|
||||
+ }
|
||||
+ }
|
||||
+ } finally {
|
||||
+ this.isSaving = false;
|
||||
+ }
|
||||
+ this.profiler.pop();
|
||||
+ // Paper end
|
||||
io.papermc.paper.util.CachedLists.reset(); // Paper
|
||||
// Paper start - move executeAll() into full server tick timing
|
||||
try (co.aikar.timings.Timing ignored = MinecraftTimings.processTasksTimer.startTiming()) {
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 324a99ea21bccdf27c15248ae2811048efaa2595..998c333c0b7064e9077c2b30d6b36623ffc419c7 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -601,6 +601,15 @@ public class ServerChunkCache extends ChunkSource {
|
||||
} // Paper - Timings
|
||||
}
|
||||
|
||||
+ // Paper start - duplicate save, but call incremental
|
||||
+ public void saveIncrementally() {
|
||||
+ this.runDistanceManagerUpdates();
|
||||
+ try (co.aikar.timings.Timing timed = level.timings.chunkSaveData.startTiming()) { // Paper - Timings
|
||||
+ this.chunkMap.saveIncrementally();
|
||||
+ } // Paper - Timings
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
// CraftBukkit start
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 6cdd0c13189f372dcf562c4190f4c6155b33dd13..5537903d6e1233489d31127f3af3d99c40258eb4 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1123,6 +1123,37 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
return !this.server.isUnderSpawnProtection(this, pos, player) && this.getWorldBorder().isWithinBounds(pos);
|
||||
}
|
||||
|
||||
+ // Paper start - derived from below
|
||||
+ public void saveIncrementally(boolean doFull) {
|
||||
+ ServerChunkCache chunkproviderserver = this.getChunkSource();
|
||||
+
|
||||
+ if (doFull) {
|
||||
+ org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld()));
|
||||
+ }
|
||||
+
|
||||
+ try (co.aikar.timings.Timing ignored = this.timings.worldSave.startTiming()) {
|
||||
+ if (doFull) {
|
||||
+ this.saveLevelData();
|
||||
+ }
|
||||
+
|
||||
+ this.timings.worldSaveChunks.startTiming(); // Paper
|
||||
+ if (!this.noSave()) chunkproviderserver.saveIncrementally();
|
||||
+ this.timings.worldSaveChunks.stopTiming(); // Paper
|
||||
+
|
||||
+ // Copied from save()
|
||||
+ // CraftBukkit start - moved from MinecraftServer.saveChunks
|
||||
+ if (doFull) { // Paper
|
||||
+ ServerLevel worldserver1 = this;
|
||||
+
|
||||
+ this.serverLevelData.setWorldBorder(worldserver1.getWorldBorder().createSettings());
|
||||
+ this.serverLevelData.setCustomBossEvents(this.server.getCustomBossEvents().save());
|
||||
+ this.convertable.saveDataTag(this.server.registryHolder, this.serverLevelData, this.server.getPlayerList().getSingleplayerData());
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public void save(@Nullable ProgressListener progressListener, boolean flush, boolean savingDisabled) {
|
||||
// Paper start - rewrite chunk system - add close param
|
||||
this.save(progressListener, flush, savingDisabled, false);
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index c32f09e993ef25876373a34d148b0452ea03bcf0..b41fddf5225b9d7cccf73b91dd0c14897c990346 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -179,6 +179,7 @@ import org.bukkit.inventory.MainHand;
|
||||
public class ServerPlayer extends Player {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
+ public long lastSave = MinecraftServer.currentTick; // Paper
|
||||
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32;
|
||||
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10;
|
||||
public ServerGamePacketListenerImpl connection;
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 1ec5facab133f265b280738afe9917592384984e..80c98d35293cd5a25982d04c980c9fd7e7b4670c 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -569,6 +569,7 @@ public abstract class PlayerList {
|
||||
protected void save(ServerPlayer player) {
|
||||
if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit
|
||||
if (!player.didPlayerJoinEvent) return; // Paper - If we never fired PJE, we disconnected during login. Data has not changed, and additionally, our saved vehicle is not loaded! If we save now, we will lose our vehicle (CraftBukkit bug)
|
||||
+ player.lastSave = MinecraftServer.currentTick; // Paper
|
||||
this.playerIo.save(player);
|
||||
ServerStatsCounter serverstatisticmanager = (ServerStatsCounter) player.getStats(); // CraftBukkit
|
||||
|
||||
@@ -1171,10 +1172,22 @@ public abstract class PlayerList {
|
||||
}
|
||||
|
||||
public void saveAll() {
|
||||
+ // Paper start - incremental player saving
|
||||
+ this.saveAll(-1);
|
||||
+ }
|
||||
+
|
||||
+ public void saveAll(int interval) {
|
||||
io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main
|
||||
MinecraftTimings.savePlayers.startTiming(); // Paper
|
||||
+ int numSaved = 0;
|
||||
+ long now = MinecraftServer.currentTick;
|
||||
for (int i = 0; i < this.players.size(); ++i) {
|
||||
- this.save(this.players.get(i));
|
||||
+ ServerPlayer entityplayer = this.players.get(i);
|
||||
+ if (interval == -1 || now - entityplayer.lastSave >= interval) {
|
||||
+ this.save(entityplayer);
|
||||
+ if (interval != -1 && ++numSaved <= io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.maxPerTick()) { break; }
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
MinecraftTimings.savePlayers.stopTiming(); // Paper
|
||||
return null; }); // Paper - ensure main
|
|
@ -1,297 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 27 Apr 2020 04:05:38 -0700
|
||||
Subject: [PATCH] Stop copy-on-write operations for updating light data
|
||||
|
||||
Causes huge memory allocations + gc issues
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/lighting/BlockLightSectionStorage.java b/src/main/java/net/minecraft/world/level/lighting/BlockLightSectionStorage.java
|
||||
index 573cdb0897978eef8f5fc906ed4928293f4b2ab9..314b46f0becd088d26956b45981217b128d539cb 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/lighting/BlockLightSectionStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/lighting/BlockLightSectionStorage.java
|
||||
@@ -9,7 +9,7 @@ import net.minecraft.world.level.chunk.LightChunkGetter;
|
||||
|
||||
public class BlockLightSectionStorage extends LayerLightSectionStorage<BlockLightSectionStorage.BlockDataLayerStorageMap> {
|
||||
protected BlockLightSectionStorage(LightChunkGetter chunkProvider) {
|
||||
- super(LightLayer.BLOCK, chunkProvider, new BlockLightSectionStorage.BlockDataLayerStorageMap(new Long2ObjectOpenHashMap<>()));
|
||||
+ super(LightLayer.BLOCK, chunkProvider, new BlockLightSectionStorage.BlockDataLayerStorageMap(new com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<>(), false)); // Paper - avoid copying light data
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -20,13 +20,13 @@ public class BlockLightSectionStorage extends LayerLightSectionStorage<BlockLigh
|
||||
}
|
||||
|
||||
protected static final class BlockDataLayerStorageMap extends DataLayerStorageMap<BlockLightSectionStorage.BlockDataLayerStorageMap> {
|
||||
- public BlockDataLayerStorageMap(Long2ObjectOpenHashMap<DataLayer> arrays) {
|
||||
- super(arrays);
|
||||
+ public BlockDataLayerStorageMap(com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<DataLayer> long2objectopenhashmap, boolean isVisible) { // Paper - avoid copying light data
|
||||
+ super(long2objectopenhashmap, isVisible); // Paper - avoid copying light data
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockLightSectionStorage.BlockDataLayerStorageMap copy() {
|
||||
- return new BlockLightSectionStorage.BlockDataLayerStorageMap(this.map.clone());
|
||||
+ return new BlockDataLayerStorageMap(this.data, true); // Paper - avoid copying light data
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/lighting/DataLayerStorageMap.java b/src/main/java/net/minecraft/world/level/lighting/DataLayerStorageMap.java
|
||||
index 67ff66e232592203cf8dad605ad01eabc4dded89..f357a3473682c2d37a20fb862522c67b9979402a 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/lighting/DataLayerStorageMap.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/lighting/DataLayerStorageMap.java
|
||||
@@ -9,10 +9,23 @@ public abstract class DataLayerStorageMap<M extends DataLayerStorageMap<M>> {
|
||||
private final long[] lastSectionKeys = new long[2];
|
||||
private final DataLayer[] lastSections = new DataLayer[2];
|
||||
private boolean cacheEnabled;
|
||||
- protected final Long2ObjectOpenHashMap<DataLayer> map;
|
||||
+ protected final com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<DataLayer> data; // Paper - avoid copying light data
|
||||
+ protected final boolean isVisible; // Paper - avoid copying light data
|
||||
+ java.util.function.Function<Long, DataLayer> lookup; // Paper - faster branchless lookup
|
||||
|
||||
- protected DataLayerStorageMap(Long2ObjectOpenHashMap<DataLayer> arrays) {
|
||||
- this.map = arrays;
|
||||
+ // Paper start - avoid copying light data
|
||||
+ protected DataLayerStorageMap(com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<DataLayer> data, boolean isVisible) {
|
||||
+ if (isVisible) {
|
||||
+ data.performUpdatesLockMap();
|
||||
+ }
|
||||
+ this.data = data;
|
||||
+ this.isVisible = isVisible;
|
||||
+ if (isVisible) {
|
||||
+ lookup = data::getVisibleAsync;
|
||||
+ } else {
|
||||
+ lookup = data::getUpdating;
|
||||
+ }
|
||||
+ // Paper end - avoid copying light data
|
||||
this.clearCache();
|
||||
this.cacheEnabled = true;
|
||||
}
|
||||
@@ -20,16 +33,17 @@ public abstract class DataLayerStorageMap<M extends DataLayerStorageMap<M>> {
|
||||
public abstract M copy();
|
||||
|
||||
public void copyDataLayer(long pos) {
|
||||
- this.map.put(pos, this.map.get(pos).copy());
|
||||
+ if (this.isVisible) { throw new IllegalStateException("writing to visible data"); } // Paper - avoid copying light data
|
||||
+ this.data.queueUpdate(pos, ((DataLayer) this.data.getUpdating(pos)).copy()); // Paper - avoid copying light data
|
||||
this.clearCache();
|
||||
}
|
||||
|
||||
public boolean hasLayer(long chunkPos) {
|
||||
- return this.map.containsKey(chunkPos);
|
||||
+ return lookup.apply(chunkPos) != null; // Paper - avoid copying light data
|
||||
}
|
||||
|
||||
@Nullable
|
||||
- public DataLayer getLayer(long chunkPos) {
|
||||
+ public final DataLayer getLayer(long chunkPos) { // Paper - final
|
||||
if (this.cacheEnabled) {
|
||||
for(int i = 0; i < 2; ++i) {
|
||||
if (chunkPos == this.lastSectionKeys[i]) {
|
||||
@@ -38,7 +52,7 @@ public abstract class DataLayerStorageMap<M extends DataLayerStorageMap<M>> {
|
||||
}
|
||||
}
|
||||
|
||||
- DataLayer dataLayer = this.map.get(chunkPos);
|
||||
+ DataLayer dataLayer = lookup.apply(chunkPos); // Paper - avoid copying light data
|
||||
if (dataLayer == null) {
|
||||
return null;
|
||||
} else {
|
||||
@@ -58,11 +72,13 @@ public abstract class DataLayerStorageMap<M extends DataLayerStorageMap<M>> {
|
||||
|
||||
@Nullable
|
||||
public DataLayer removeLayer(long chunkPos) {
|
||||
- return this.map.remove(chunkPos);
|
||||
+ if (this.isVisible) { throw new IllegalStateException("writing to visible data"); } // Paper - avoid copying light data
|
||||
+ return (DataLayer) this.data.queueRemove(chunkPos); // Paper - avoid copying light data
|
||||
}
|
||||
|
||||
public void setLayer(long pos, DataLayer data) {
|
||||
- this.map.put(pos, data);
|
||||
+ if (this.isVisible) { throw new IllegalStateException("writing to visible data"); } // Paper - avoid copying light data
|
||||
+ this.data.queueUpdate(pos, data); // Paper - avoid copying light data
|
||||
}
|
||||
|
||||
public void clearCache() {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java b/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java
|
||||
index c899674ee24167ee3abdf1588d7396df0ab4f0aa..85175b01b1623b3bc66c65805cec26eaead48265 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java
|
||||
@@ -27,7 +27,7 @@ public abstract class LayerLightSectionStorage<M extends DataLayerStorageMap<M>>
|
||||
protected final LongSet dataSectionSet = new LongOpenHashSet();
|
||||
protected final LongSet toMarkNoData = new LongOpenHashSet();
|
||||
protected final LongSet toMarkData = new LongOpenHashSet();
|
||||
- protected volatile M visibleSectionData;
|
||||
+ protected volatile M e_visible; protected final Object visibleUpdateLock = new Object(); // Paper - diff on change, should be "visible" - force compile fail on usage change
|
||||
protected final M updatingSectionData;
|
||||
protected final LongSet changedSections = new LongOpenHashSet();
|
||||
protected final LongSet sectionsAffectedByLightUpdates = new LongOpenHashSet();
|
||||
@@ -42,8 +42,8 @@ public abstract class LayerLightSectionStorage<M extends DataLayerStorageMap<M>>
|
||||
this.layer = lightType;
|
||||
this.chunkSource = chunkProvider;
|
||||
this.updatingSectionData = lightData;
|
||||
- this.visibleSectionData = lightData.copy();
|
||||
- this.visibleSectionData.disableCache();
|
||||
+ this.e_visible = lightData.copy(); // Paper - avoid copying light dat
|
||||
+ this.e_visible.disableCache(); // Paper - avoid copying light dat
|
||||
}
|
||||
|
||||
protected boolean storingLightForSection(long sectionPos) {
|
||||
@@ -52,7 +52,15 @@ public abstract class LayerLightSectionStorage<M extends DataLayerStorageMap<M>>
|
||||
|
||||
@Nullable
|
||||
protected DataLayer getDataLayer(long sectionPos, boolean cached) {
|
||||
- return this.getDataLayer((M)(cached ? this.updatingSectionData : this.visibleSectionData), sectionPos);
|
||||
+ // Paper start - avoid copying light data
|
||||
+ if (cached) {
|
||||
+ return this.getDataLayer(this.updatingSectionData, sectionPos);
|
||||
+ } else {
|
||||
+ synchronized (this.visibleUpdateLock) {
|
||||
+ return this.getDataLayer(this.e_visible, sectionPos);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - avoid copying light data
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -342,9 +350,11 @@ public abstract class LayerLightSectionStorage<M extends DataLayerStorageMap<M>>
|
||||
|
||||
protected void swapSectionMap() {
|
||||
if (!this.changedSections.isEmpty()) {
|
||||
+ synchronized (this.visibleUpdateLock) { // Paper - avoid copying light data
|
||||
M dataLayerStorageMap = this.updatingSectionData.copy();
|
||||
dataLayerStorageMap.disableCache();
|
||||
- this.visibleSectionData = dataLayerStorageMap;
|
||||
+ this.e_visible = dataLayerStorageMap; // Paper - avoid copying light data
|
||||
+ } // Paper - avoid copying light data
|
||||
this.changedSections.clear();
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/lighting/SkyLightSectionStorage.java b/src/main/java/net/minecraft/world/level/lighting/SkyLightSectionStorage.java
|
||||
index 59d2af9f883541518c203302257f03dbe957aa0b..e6c857c8b4e4e65e3cf6a75ce6d844ff61acb566 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/lighting/SkyLightSectionStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/lighting/SkyLightSectionStorage.java
|
||||
@@ -21,7 +21,7 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
private volatile boolean hasSourceInconsistencies;
|
||||
|
||||
protected SkyLightSectionStorage(LightChunkGetter chunkProvider) {
|
||||
- super(LightLayer.SKY, chunkProvider, new SkyLightSectionStorage.SkyDataLayerStorageMap(new Long2ObjectOpenHashMap<>(), new Long2IntOpenHashMap(), Integer.MAX_VALUE));
|
||||
+ super(LightLayer.SKY, chunkProvider, new SkyLightSectionStorage.SkyDataLayerStorageMap(new com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<>(), new com.destroystokyo.paper.util.map.QueuedChangesMapLong2Int(), Integer.MAX_VALUE, false)); // Paper - avoid copying light data
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -32,8 +32,9 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
protected int getLightValue(long blockPos, boolean cached) {
|
||||
long l = SectionPos.blockToSection(blockPos);
|
||||
int i = SectionPos.y(l);
|
||||
- SkyLightSectionStorage.SkyDataLayerStorageMap skyDataLayerStorageMap = cached ? this.updatingSectionData : this.visibleSectionData;
|
||||
- int j = skyDataLayerStorageMap.topSections.get(SectionPos.getZeroNode(l));
|
||||
+ synchronized (this.visibleUpdateLock) { // Paper - avoid copying light data
|
||||
+ SkyLightSectionStorage.SkyDataLayerStorageMap skyDataLayerStorageMap = (SkyLightSectionStorage.SkyDataLayerStorageMap) this.e_visible; // Paper - avoid copying light data - must be after lock acquire
|
||||
+ int j = skyDataLayerStorageMap.otherData.getVisibleAsync(SectionPos.getZeroNode(l)); // Paper - avoid copying light data
|
||||
if (j != skyDataLayerStorageMap.currentLowestY && i < j) {
|
||||
DataLayer dataLayer = this.getDataLayer(skyDataLayerStorageMap, l);
|
||||
if (dataLayer == null) {
|
||||
@@ -52,6 +53,7 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
} else {
|
||||
return cached && !this.lightOnInSection(l) ? 0 : 15;
|
||||
}
|
||||
+ } // Paper - avoid copying light data
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,13 +61,13 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
int i = SectionPos.y(sectionPos);
|
||||
if ((this.updatingSectionData).currentLowestY > i) {
|
||||
(this.updatingSectionData).currentLowestY = i;
|
||||
- (this.updatingSectionData).topSections.defaultReturnValue((this.updatingSectionData).currentLowestY);
|
||||
+ (this.updatingSectionData).otherData.queueDefaultReturnValue((this.updatingSectionData).currentLowestY); // Paper - avoid copying light data
|
||||
}
|
||||
|
||||
long l = SectionPos.getZeroNode(sectionPos);
|
||||
- int j = (this.updatingSectionData).topSections.get(l);
|
||||
+ int j = (this.updatingSectionData).otherData.getUpdating(l); // Paper - avoid copying light data
|
||||
if (j < i + 1) {
|
||||
- (this.updatingSectionData).topSections.put(l, i + 1);
|
||||
+ (this.updatingSectionData).otherData.queueUpdate(l, i + 1); // Paper - avoid copying light data
|
||||
if (this.columnsWithSkySources.contains(l)) {
|
||||
this.queueAddSource(sectionPos);
|
||||
if (j > (this.updatingSectionData).currentLowestY) {
|
||||
@@ -102,19 +104,19 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
}
|
||||
|
||||
int i = SectionPos.y(sectionPos);
|
||||
- if ((this.updatingSectionData).topSections.get(l) == i + 1) {
|
||||
+ if ((this.updatingSectionData).otherData.getUpdating(l) == i + 1) { // Paper - avoid copying light data
|
||||
long m;
|
||||
for(m = sectionPos; !this.storingLightForSection(m) && this.hasSectionsBelow(i); m = SectionPos.offset(m, Direction.DOWN)) {
|
||||
--i;
|
||||
}
|
||||
|
||||
if (this.storingLightForSection(m)) {
|
||||
- (this.updatingSectionData).topSections.put(l, i + 1);
|
||||
+ (this.updatingSectionData).otherData.queueUpdate(l, i + 1); // Paper - avoid copying light data
|
||||
if (bl) {
|
||||
this.queueAddSource(m);
|
||||
}
|
||||
} else {
|
||||
- (this.updatingSectionData).topSections.remove(l);
|
||||
+ (this.updatingSectionData).otherData.queueRemove(l); // Paper - avoid copying light data
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +130,7 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
protected void enableLightSources(long columnPos, boolean enabled) {
|
||||
this.runAllUpdates();
|
||||
if (enabled && this.columnsWithSkySources.add(columnPos)) {
|
||||
- int i = (this.updatingSectionData).topSections.get(columnPos);
|
||||
+ int i = (this.updatingSectionData).otherData.getUpdating(columnPos); // Paper - avoid copying light data
|
||||
if (i != (this.updatingSectionData).currentLowestY) {
|
||||
long l = SectionPos.asLong(SectionPos.x(columnPos), i - 1, SectionPos.z(columnPos));
|
||||
this.queueAddSource(l);
|
||||
@@ -152,7 +154,7 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
return dataLayer;
|
||||
} else {
|
||||
long l = SectionPos.offset(sectionPos, Direction.UP);
|
||||
- int i = (this.updatingSectionData).topSections.get(SectionPos.getZeroNode(sectionPos));
|
||||
+ int i = (this.updatingSectionData).otherData.getUpdating(SectionPos.getZeroNode(sectionPos)); // Paper - avoid copying light data
|
||||
if (i != (this.updatingSectionData).currentLowestY && SectionPos.y(l) < i) {
|
||||
DataLayer dataLayer2;
|
||||
while((dataLayer2 = this.getDataLayer(l, true)) == null) {
|
||||
@@ -275,7 +277,7 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
|
||||
protected boolean isAboveData(long sectionPos) {
|
||||
long l = SectionPos.getZeroNode(sectionPos);
|
||||
- int i = (this.updatingSectionData).topSections.get(l);
|
||||
+ int i = (this.updatingSectionData).otherData.getUpdating(l); // Paper - avoid copying light data
|
||||
return i == (this.updatingSectionData).currentLowestY || SectionPos.y(sectionPos) >= i;
|
||||
}
|
||||
|
||||
@@ -286,18 +288,21 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
|
||||
protected static final class SkyDataLayerStorageMap extends DataLayerStorageMap<SkyLightSectionStorage.SkyDataLayerStorageMap> {
|
||||
int currentLowestY;
|
||||
- final Long2IntOpenHashMap topSections;
|
||||
-
|
||||
- public SkyDataLayerStorageMap(Long2ObjectOpenHashMap<DataLayer> arrays, Long2IntOpenHashMap columnToTopSection, int minSectionY) {
|
||||
- super(arrays);
|
||||
- this.topSections = columnToTopSection;
|
||||
- columnToTopSection.defaultReturnValue(minSectionY);
|
||||
+ private final com.destroystokyo.paper.util.map.QueuedChangesMapLong2Int otherData; // Paper - avoid copying light data
|
||||
+
|
||||
+ // Paper start - avoid copying light data
|
||||
+ public SkyDataLayerStorageMap(com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<DataLayer> arrays, com.destroystokyo.paper.util.map.QueuedChangesMapLong2Int columnToTopSection, int minSectionY, boolean isVisible) {
|
||||
+ super(arrays, isVisible);
|
||||
+ this.otherData = columnToTopSection;
|
||||
+ otherData.queueDefaultReturnValue(minSectionY);
|
||||
+ // Paper end
|
||||
this.currentLowestY = minSectionY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SkyLightSectionStorage.SkyDataLayerStorageMap copy() {
|
||||
- return new SkyLightSectionStorage.SkyDataLayerStorageMap(this.map.clone(), this.topSections.clone(), this.currentLowestY);
|
||||
+ this.otherData.performUpdatesLockMap(); // Paper - avoid copying light data
|
||||
+ return new SkyLightSectionStorage.SkyDataLayerStorageMap(this.data, this.otherData, this.currentLowestY, true); // Paper - avoid copying light data
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Mon, 29 Jun 2020 03:26:17 -0400
|
||||
Subject: [PATCH] Support old UUID format for NBT
|
||||
|
||||
We have stored UUID in plenty of places that did not get DFU'd
|
||||
|
||||
So just look for old format and load it if it exists.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/nbt/CompoundTag.java b/src/main/java/net/minecraft/nbt/CompoundTag.java
|
||||
index 0778fdd4f47015787f7ffbfb39c31ec0e1c039bd..912fd5135e89348bdd3c0a8b6c07860ebc106df3 100644
|
||||
--- a/src/main/java/net/minecraft/nbt/CompoundTag.java
|
||||
+++ b/src/main/java/net/minecraft/nbt/CompoundTag.java
|
||||
@@ -181,6 +181,12 @@ public class CompoundTag implements Tag {
|
||||
}
|
||||
|
||||
public void putUUID(String key, UUID value) {
|
||||
+ // Paper start - support old format
|
||||
+ if (this.contains(key + "Most", 99) && this.contains(key + "Least", 99)) {
|
||||
+ this.tags.remove(key + "Most");
|
||||
+ this.tags.remove(key + "Least");
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.tags.put(key, NbtUtils.createUUID(value));
|
||||
}
|
||||
|
||||
@@ -189,10 +195,20 @@ public class CompoundTag implements Tag {
|
||||
* You must use {@link #hasUUID(String)} before or else it <b>will</b> throw an NPE.
|
||||
*/
|
||||
public UUID getUUID(String key) {
|
||||
+ // Paper start - support old format
|
||||
+ if (!contains(key, 11) && this.contains(key + "Most", 99) && this.contains(key + "Least", 99)) {
|
||||
+ return new UUID(this.getLong(key + "Most"), this.getLong(key + "Least"));
|
||||
+ }
|
||||
+ // Paper end
|
||||
return NbtUtils.loadUUID(this.get(key));
|
||||
}
|
||||
|
||||
public boolean hasUUID(String key) {
|
||||
+ // Paper start - support old format
|
||||
+ if (this.contains(key + "Most", 99) && this.contains(key + "Least", 99)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Paper end
|
||||
Tag tag = this.get(key);
|
||||
return tag != null && tag.getType() == IntArrayTag.TYPE && ((IntArrayTag)tag).getAsIntArray().length == 4;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/nbt/NbtUtils.java b/src/main/java/net/minecraft/nbt/NbtUtils.java
|
||||
index d6d8adf1e49cdb74dc5d8e2e60bcaca7c5e1c16d..b31741a9c3363e4288636ceff9b38c598a84aa43 100644
|
||||
--- a/src/main/java/net/minecraft/nbt/NbtUtils.java
|
||||
+++ b/src/main/java/net/minecraft/nbt/NbtUtils.java
|
||||
@@ -75,6 +75,11 @@ public final class NbtUtils {
|
||||
if (nbt.contains("Name", 8)) {
|
||||
string = nbt.getString("Name");
|
||||
}
|
||||
+ // Paper start - support string UUID's
|
||||
+ if (nbt.contains("Id", 8)) {
|
||||
+ uUID = UUID.fromString(nbt.getString("Id"));
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
if (nbt.hasUUID("Id")) {
|
||||
uUID = nbt.getUUID("Id");
|
|
@ -1,47 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 1 Jul 2020 03:12:06 -0400
|
||||
Subject: [PATCH] Clean up duplicated GameProfile Properties
|
||||
|
||||
We had a bug where we accidently cloned properties resulting in skulls
|
||||
growing to large sizes and preventing login.
|
||||
|
||||
This now automatically cleans up the extra properties.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/nbt/NbtUtils.java b/src/main/java/net/minecraft/nbt/NbtUtils.java
|
||||
index b31741a9c3363e4288636ceff9b38c598a84aa43..46681f3fa63516aa750de11cf1dee17cb3734fcd 100644
|
||||
--- a/src/main/java/net/minecraft/nbt/NbtUtils.java
|
||||
+++ b/src/main/java/net/minecraft/nbt/NbtUtils.java
|
||||
@@ -93,7 +93,8 @@ public final class NbtUtils {
|
||||
for(String string2 : compoundTag.getAllKeys()) {
|
||||
ListTag listTag = compoundTag.getList(string2, 10);
|
||||
|
||||
- for(int i = 0; i < listTag.size(); ++i) {
|
||||
+ if (listTag.size() == 0) continue; // Paper - remove duplicate properties
|
||||
+ for (int i = listTag.size() - 1; i < listTag.size(); ++i) { // Paper - remove duplicate properties
|
||||
CompoundTag compoundTag2 = listTag.getCompound(i);
|
||||
String string3 = compoundTag2.getString("Value");
|
||||
if (compoundTag2.contains("Signature", 8)) {
|
||||
diff --git a/src/main/java/net/minecraft/world/item/PlayerHeadItem.java b/src/main/java/net/minecraft/world/item/PlayerHeadItem.java
|
||||
index 2fb1500e9d3202b6377bf4d8e50102a98f409148..72a0c7ad03b18c3156b4f3c7240f7551583f981c 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/PlayerHeadItem.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/PlayerHeadItem.java
|
||||
@@ -52,6 +52,18 @@ public class PlayerHeadItem extends StandingAndWallBlockItem {
|
||||
});
|
||||
// CraftBukkit start
|
||||
} else {
|
||||
+ // Paper start - clean up old duplicated properties
|
||||
+ CompoundTag properties = nbt.getCompound("SkullOwner").getCompound("Properties");
|
||||
+ for (String key : properties.getAllKeys()) {
|
||||
+ net.minecraft.nbt.ListTag values = properties.getList(key, 10);
|
||||
+ if (values.size() > 1) {
|
||||
+ net.minecraft.nbt.Tag texture = values.get(values.size() - 1);
|
||||
+ values = new net.minecraft.nbt.ListTag();
|
||||
+ values.add(texture);
|
||||
+ properties.put(key, values);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
net.minecraft.nbt.ListTag textures = nbt.getCompound("SkullOwner").getCompound("Properties").getList("textures", 10); // Safe due to method contracts
|
||||
for (int i = 0; i < textures.size(); i++) {
|
||||
if (textures.get(i) instanceof CompoundTag && !((CompoundTag) textures.get(i)).contains("Signature", 8) && ((CompoundTag) textures.get(i)).getString("Value").trim().isEmpty()) {
|
|
@ -1,44 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 1 Jul 2020 04:50:22 -0400
|
||||
Subject: [PATCH] Convert legacy attributes in Item Meta
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java
|
||||
index 0520c45197629cbdc2777d9ae11eef572e793160..46c313d581b9af6aa0a48f97ae3cc800a88535f2 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java
|
||||
@@ -11,6 +11,20 @@ import org.bukkit.craftbukkit.util.CraftNamespacedKey;
|
||||
public class CraftAttributeMap implements Attributable {
|
||||
|
||||
private final AttributeMap handle;
|
||||
+ // Paper start - convert legacy attributes
|
||||
+ private static final com.google.common.collect.ImmutableMap<String, String> legacyNMS = com.google.common.collect.ImmutableMap.<String, String>builder().put("generic.maxHealth", "generic.max_health").put("Max Health", "generic.max_health").put("zombie.spawnReinforcements", "zombie.spawn_reinforcements").put("Spawn Reinforcements Chance", "zombie.spawn_reinforcements").put("horse.jumpStrength", "horse.jump_strength").put("Jump Strength", "horse.jump_strength").put("generic.followRange", "generic.follow_range").put("Follow Range", "generic.follow_range").put("generic.knockbackResistance", "generic.knockback_resistance").put("Knockback Resistance", "generic.knockback_resistance").put("generic.movementSpeed", "generic.movement_speed").put("Movement Speed", "generic.movement_speed").put("generic.flyingSpeed", "generic.flying_speed").put("Flying Speed", "generic.flying_speed").put("generic.attackDamage", "generic.attack_damage").put("generic.attackKnockback", "generic.attack_knockback").put("generic.attackSpeed", "generic.attack_speed").put("generic.armorToughness", "generic.armor_toughness").build();
|
||||
+
|
||||
+ public static String convertIfNeeded(String nms) {
|
||||
+ if (nms == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ nms = legacyNMS.getOrDefault(nms, nms);
|
||||
+ if (!nms.toLowerCase().equals(nms) || nms.indexOf(' ') != -1) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ return nms;
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
public CraftAttributeMap(AttributeMap handle) {
|
||||
this.handle = handle;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
index 4304ee35a9bd912c2ae4058febf22f0eea25adbd..4a91da3561d16995e8cfe04ebbc104da009a2503 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
@@ -480,7 +480,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
|
||||
AttributeModifier attribMod = CraftAttributeInstance.convert(nmsModifier);
|
||||
|
||||
- String attributeName = entry.getString(ATTRIBUTES_IDENTIFIER.NBT);
|
||||
+ String attributeName = CraftAttributeMap.convertIfNeeded(entry.getString(ATTRIBUTES_IDENTIFIER.NBT)); // Paper
|
||||
if (attributeName == null || attributeName.isEmpty()) {
|
||||
continue;
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: JRoy <joshroy126@gmail.com>
|
||||
Date: Mon, 29 Jun 2020 17:03:06 -0400
|
||||
Subject: [PATCH] Remove some streams from structures
|
||||
|
||||
This showed up a lot in the spark profiler, should have a low-medium performance improvement.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java b/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java
|
||||
index 24f58441ae7b43a62d74aa55e9808c1c65f466e4..99e329d374b60ebf77f93551f6bf83b9bca1e4b8 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java
|
||||
@@ -36,9 +36,10 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
|
||||
int j = pos.getMinBlockZ();
|
||||
ObjectList<Beardifier.Rigid> objectList = new ObjectArrayList<>(10);
|
||||
ObjectList<JigsawJunction> objectList2 = new ObjectArrayList<>(32);
|
||||
- world.startsForStructure(pos, (structure) -> {
|
||||
+ // Paper start - replace for each
|
||||
+ for (net.minecraft.world.level.levelgen.structure.StructureStart start : world.startsForStructure(pos, (structure) -> {
|
||||
return structure.terrainAdaptation() != TerrainAdjustment.NONE;
|
||||
- }).forEach((start) -> {
|
||||
+ })) { // Paper end
|
||||
TerrainAdjustment terrainAdjustment = start.getStructure().terrainAdaptation();
|
||||
|
||||
for(StructurePiece structurePiece : start.getPieces()) {
|
||||
@@ -51,9 +52,11 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
|
||||
}
|
||||
|
||||
for(JigsawJunction jigsawJunction : poolElementStructurePiece.getJunctions()) {
|
||||
- int i = jigsawJunction.getSourceX();
|
||||
- int j = jigsawJunction.getSourceZ();
|
||||
- if (i > i - 12 && j > j - 12 && i < i + 15 + 12 && j < j + 15 + 12) {
|
||||
+ // Paper start - decompile fix
|
||||
+ int i2 = jigsawJunction.getSourceX();
|
||||
+ int j2 = jigsawJunction.getSourceZ();
|
||||
+ if (i2 > i - 12 && j2 > j - 12 && i2 < i + 15 + 12 && j2 < j + 15 + 12) {
|
||||
+ // Paper end
|
||||
objectList2.add(jigsawJunction);
|
||||
}
|
||||
}
|
||||
@@ -63,7 +66,7 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
|
||||
}
|
||||
}
|
||||
|
||||
- });
|
||||
+ } // Paper
|
||||
return new Beardifier(objectList.iterator(), objectList2.iterator());
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: JRoy <joshroy126@gmail.com>
|
||||
Date: Wed, 1 Jul 2020 18:01:49 -0400
|
||||
Subject: [PATCH] Remove streams from classes related villager gossip
|
||||
|
||||
|
||||
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 92beb137d86ae89d90b1963a024c0be308d81a42..e377dd95b7824804611d0e4ce825576ed533e73e 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
|
||||
@@ -58,8 +58,21 @@ public class GossipContainer {
|
||||
});
|
||||
}
|
||||
|
||||
+ // Paper start - Remove streams from reputation
|
||||
+ private List<GossipContainer.GossipEntry> decompress() {
|
||||
+ List<GossipContainer.GossipEntry> list = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
|
||||
+ for (Map.Entry<UUID, GossipContainer.EntityGossips> entry : getReputations().entrySet()) {
|
||||
+ for (GossipContainer.GossipEntry cur : entry.getValue().decompress(entry.getKey())) {
|
||||
+ if (cur.weightedValue() != 0)
|
||||
+ list.add(cur);
|
||||
+ }
|
||||
+ }
|
||||
+ return list;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
private Collection<GossipContainer.GossipEntry> selectGossipsForTransfer(RandomSource random, int count) {
|
||||
- List<GossipContainer.GossipEntry> list = this.unpack().collect(Collectors.toList());
|
||||
+ List<GossipContainer.GossipEntry> list = this.decompress(); // Paper - Remove streams from reputation
|
||||
if (list.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
@@ -153,7 +166,7 @@ public class GossipContainer {
|
||||
}
|
||||
|
||||
public <T> Dynamic<T> store(DynamicOps<T> ops) {
|
||||
- return new Dynamic<>(ops, ops.createList(this.unpack().map((entry) -> {
|
||||
+ return new Dynamic<>(ops, ops.createList(this.decompress().stream().map((entry) -> { // Paper - remove streams from reputation
|
||||
return entry.store(ops);
|
||||
}).map(Dynamic::getValue)));
|
||||
}
|
||||
@@ -179,11 +192,23 @@ public class GossipContainer {
|
||||
final Object2IntMap<GossipType> entries = new Object2IntOpenHashMap<>();
|
||||
|
||||
public int weightedValue(Predicate<GossipType> gossipTypeFilter) {
|
||||
- return this.entries.object2IntEntrySet().stream().filter((entry) -> {
|
||||
- return gossipTypeFilter.test(entry.getKey());
|
||||
- }).mapToInt((entry) -> {
|
||||
- return entry.getIntValue() * (entry.getKey()).weight;
|
||||
- }).sum();
|
||||
+ // Paper start - Remove streams from reputation
|
||||
+ int weight = 0;
|
||||
+ for (Object2IntMap.Entry<GossipType> entry : entries.object2IntEntrySet()) {
|
||||
+ if (gossipTypeFilter.test(entry.getKey())) {
|
||||
+ weight += entry.getIntValue() * entry.getKey().weight;
|
||||
+ }
|
||||
+ }
|
||||
+ return weight;
|
||||
+ }
|
||||
+
|
||||
+ public List<GossipContainer.GossipEntry> decompress(UUID uuid) {
|
||||
+ List<GossipContainer.GossipEntry> list = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
|
||||
+ for (Object2IntMap.Entry<GossipType> entry : entries.object2IntEntrySet()) {
|
||||
+ list.add(new GossipContainer.GossipEntry(uuid, entry.getKey(), entry.getIntValue()));
|
||||
+ }
|
||||
+ return list;
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
public Stream<GossipContainer.GossipEntry> unpack(UUID target) {
|
|
@ -1,83 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MiniDigger <admin@benndorf.dev>
|
||||
Date: Sat, 6 Jun 2020 18:13:42 +0200
|
||||
Subject: [PATCH] Support components in ItemMeta
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
index 4a91da3561d16995e8cfe04ebbc104da009a2503..c475ddea1c995df1dfcaf4f491f341761a5f8802 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
@@ -874,11 +874,23 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
return CraftChatMessage.fromJSONComponent(displayName);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public net.md_5.bungee.api.chat.BaseComponent[] getDisplayNameComponent() {
|
||||
+ return displayName == null ? new net.md_5.bungee.api.chat.BaseComponent[0] : net.md_5.bungee.chat.ComponentSerializer.parse(displayName);
|
||||
+ }
|
||||
+ // Paper end
|
||||
@Override
|
||||
public final void setDisplayName(String name) {
|
||||
this.displayName = CraftChatMessage.fromStringOrNullToJSON(name);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void setDisplayNameComponent(net.md_5.bungee.api.chat.BaseComponent[] component) {
|
||||
+ this.displayName = net.md_5.bungee.chat.ComponentSerializer.toString(component);
|
||||
+ }
|
||||
+ // Paper end
|
||||
@Override
|
||||
public boolean hasDisplayName() {
|
||||
return this.displayName != null;
|
||||
@@ -1021,6 +1033,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
return this.lore == null ? null : new ArrayList<String>(Lists.transform(this.lore, CraftChatMessage::fromJSONComponent));
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public List<net.md_5.bungee.api.chat.BaseComponent[]> getLoreComponents() {
|
||||
+ return this.lore == null ? null : new ArrayList<>(this.lore.stream().map(entry ->
|
||||
+ net.md_5.bungee.chat.ComponentSerializer.parse(entry)
|
||||
+ ).collect(java.util.stream.Collectors.toList()));
|
||||
+ }
|
||||
+ // Paper end
|
||||
@Override
|
||||
public void setLore(List<String> lore) {
|
||||
if (lore == null || lore.isEmpty()) {
|
||||
@@ -1035,6 +1055,21 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void setLoreComponents(List<net.md_5.bungee.api.chat.BaseComponent[]> lore) {
|
||||
+ if (lore == null) {
|
||||
+ this.lore = null;
|
||||
+ } else {
|
||||
+ if (this.lore == null) {
|
||||
+ safelyAdd(lore, this.lore = new ArrayList<>(lore.size()), false);
|
||||
+ } else {
|
||||
+ this.lore.clear();
|
||||
+ safelyAdd(lore, this.lore, false);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
@Override
|
||||
public boolean hasCustomModelData() {
|
||||
return this.customModelData != null;
|
||||
@@ -1502,6 +1537,11 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
}
|
||||
|
||||
for (Object object : addFrom) {
|
||||
+ // Paper start - support components
|
||||
+ if(object instanceof net.md_5.bungee.api.chat.BaseComponent[]) {
|
||||
+ addTo.add(net.md_5.bungee.chat.ComponentSerializer.toString((net.md_5.bungee.api.chat.BaseComponent[]) object));
|
||||
+ } else
|
||||
+ // Paper end
|
||||
if (!(object instanceof String)) {
|
||||
if (object != null) {
|
||||
throw new IllegalArgumentException(addFrom + " cannot contain non-string " + object.getClass().getName());
|
|
@ -1,59 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Fri, 3 Jul 2020 15:03:33 -0700
|
||||
Subject: [PATCH] Improve EntityTargetLivingEntityEvent for 1.16 mobs
|
||||
|
||||
CraftBukkit has a bug in their implementation and is incorrectly handling forget
|
||||
Also adds more target reasons for why it forgot target.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java b/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java
|
||||
index 44d3c9da39389b72bfc5ee39c1abb6baf9dccdb1..565691aaed71de3efe15dd751fbbbe7849ef56b7 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java
|
||||
@@ -56,15 +56,15 @@ public class StopAttackingIfTargetInvalid<E extends Mob> extends Behavior<E> {
|
||||
LivingEntity entityliving = this.getAttackTarget(entity);
|
||||
|
||||
if (!entity.canAttack(entityliving)) {
|
||||
- this.clearAttackTarget(entity);
|
||||
+ this.clearAttackTarget(entity, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_INVALID); // Paper
|
||||
} else if (this.canGrowTiredOfTryingToReachTarget && StopAttackingIfTargetInvalid.isTiredOfTryingToReachTarget(entity)) {
|
||||
- this.clearAttackTarget(entity);
|
||||
+ this.clearAttackTarget(entity, org.bukkit.event.entity.EntityTargetEvent.TargetReason.FORGOT_TARGET); // Paper
|
||||
} else if (this.isCurrentTargetDeadOrRemoved(entity)) {
|
||||
- this.clearAttackTarget(entity);
|
||||
+ this.clearAttackTarget(entity, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_DIED); // Paper
|
||||
} else if (this.isCurrentTargetInDifferentLevel(entity)) {
|
||||
- this.clearAttackTarget(entity);
|
||||
+ this.clearAttackTarget(entity, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_OTHER_LEVEL); // Paper
|
||||
} else if (this.stopAttackingWhen.test(this.getAttackTarget(entity))) {
|
||||
- this.clearAttackTarget(entity);
|
||||
+ this.clearAttackTarget(entity, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_INVALID); // Paper
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,17 +88,20 @@ public class StopAttackingIfTargetInvalid<E extends Mob> extends Behavior<E> {
|
||||
return optional.isPresent() && !((LivingEntity) optional.get()).isAlive();
|
||||
}
|
||||
|
||||
- protected void clearAttackTarget(E entity) {
|
||||
+ protected void clearAttackTarget(E entity, EntityTargetEvent.TargetReason reason) {
|
||||
// CraftBukkit start
|
||||
- LivingEntity old = entity.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).orElse(null);
|
||||
- EntityTargetEvent event = CraftEventFactory.callEntityTargetLivingEvent(entity, null, (old != null && !old.isAlive()) ? EntityTargetEvent.TargetReason.TARGET_DIED : EntityTargetEvent.TargetReason.FORGOT_TARGET);
|
||||
+ // Paper start - fix this event
|
||||
+ // LivingEntity old = entity.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).orElse(null);
|
||||
+ EntityTargetEvent event = CraftEventFactory.callEntityTargetLivingEvent(entity, null, reason);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
- if (event.getTarget() != null) {
|
||||
+ // comment out, bad logic - bad
|
||||
+ /*if (event.getTarget() != null) {
|
||||
entity.getBrain().setMemory(MemoryModuleType.ATTACK_TARGET, ((CraftLivingEntity) event.getTarget()).getHandle());
|
||||
return;
|
||||
- }
|
||||
+ }*/
|
||||
+ // Paper end
|
||||
// CraftBukkit end
|
||||
this.onTargetErased.accept(entity, this.getAttackTarget(entity));
|
||||
entity.getBrain().eraseMemory(MemoryModuleType.ATTACK_TARGET);
|
|
@ -1,54 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Thu, 2 Jul 2020 18:11:43 -0500
|
||||
Subject: [PATCH] Add entity liquid API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.Entity isInRain()Z
|
||||
public net.minecraft.world.entity.Entity isInBubbleColumn()Z
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
index 3bda8128c2956d817677e28ff87c9c5ed61c8bd2..ceb7123362ba85df825a50c035a399174b6634dc 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
@@ -1271,5 +1271,40 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason getEntitySpawnReason() {
|
||||
return getHandle().spawnReason;
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isUnderWater() {
|
||||
+ return getHandle().isUnderWater();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isInRain() {
|
||||
+ return getHandle().isInRain();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isInBubbleColumn() {
|
||||
+ return getHandle().isInBubbleColumn();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isInWaterOrRain() {
|
||||
+ return getHandle().isInWaterOrRain();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isInWaterOrBubbleColumn() {
|
||||
+ return getHandle().isInWaterOrBubble();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isInWaterOrRainOrBubbleColumn() {
|
||||
+ return getHandle().isInWaterRainOrBubble();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isInLava() {
|
||||
+ return getHandle().isInLava();
|
||||
+ }
|
||||
// Paper end
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Wed, 1 Jul 2020 11:57:40 -0500
|
||||
Subject: [PATCH] Update itemstack legacy name and lore
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
|
||||
index 2650deb381bae30593128fc003c042f42110802c..85dead69d41ca10ad76fdab13da8548d359142b0 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
|
||||
@@ -166,6 +166,44 @@ public final class ItemStack {
|
||||
list.sort((java.util.Comparator<? super net.minecraft.nbt.Tag>) enchantSorter); // Paper
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
+
|
||||
+ private void processText() {
|
||||
+ CompoundTag display = getTagElement("display");
|
||||
+ if (display != null) {
|
||||
+ if (display.contains("Name", 8)) {
|
||||
+ String json = display.getString("Name");
|
||||
+ if (json != null && json.contains("\u00A7")) {
|
||||
+ try {
|
||||
+ display.put("Name", convert(json));
|
||||
+ } catch (com.google.gson.JsonParseException jsonparseexception) {
|
||||
+ display.remove("Name");
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ if (display.contains("Lore", 9)) {
|
||||
+ ListTag list = display.getList("Lore", 8);
|
||||
+ for (int index = 0; index < list.size(); index++) {
|
||||
+ String json = list.getString(index);
|
||||
+ if (json != null && json.contains("\u00A7")) { // Only try if it has legacy in the unparsed json
|
||||
+ try {
|
||||
+ list.set(index, convert(json));
|
||||
+ } catch (com.google.gson.JsonParseException e) {
|
||||
+ list.set(index, net.minecraft.nbt.StringTag.valueOf(org.bukkit.craftbukkit.util.CraftChatMessage.toJSON(net.minecraft.network.chat.Component.literal(""))));
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private net.minecraft.nbt.StringTag convert(String json) {
|
||||
+ Component component = Component.Serializer.fromJson(json);
|
||||
+ if (component.getContents() instanceof net.minecraft.network.chat.contents.LiteralContents literalContents && literalContents.text().contains("\u00A7") && component.getSiblings().isEmpty()) {
|
||||
+ // Only convert if the root component is a single comp with legacy in it, don't convert already normal components
|
||||
+ component = org.bukkit.craftbukkit.util.CraftChatMessage.fromString(literalContents.text())[0];
|
||||
+ }
|
||||
+ return net.minecraft.nbt.StringTag.valueOf(org.bukkit.craftbukkit.util.CraftChatMessage.toJSON(component));
|
||||
+ }
|
||||
// Paper end
|
||||
|
||||
public ItemStack(ItemLike item) {
|
||||
@@ -220,6 +258,7 @@ public final class ItemStack {
|
||||
this.tag = nbttagcompound.getCompound("tag").copy();
|
||||
// CraftBukkit end
|
||||
this.processEnchantOrder(this.tag); // Paper
|
||||
+ this.processText(); // Paper
|
||||
this.getItem().verifyTagAfterLoad(this.tag);
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Wyatt Childers <wchilders@nearce.com>
|
||||
Date: Fri, 3 Jul 2020 14:57:05 -0400
|
||||
Subject: [PATCH] Spawn player in correct world on login
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 80c98d35293cd5a25982d04c980c9fd7e7b4670c..55c5576bd76718a0cc5d8fbcb80eeeac8b6c9277 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -203,7 +203,18 @@ public abstract class PlayerList {
|
||||
}String lastKnownName = s; // Paper
|
||||
// CraftBukkit end
|
||||
|
||||
- if (nbttagcompound != null) {
|
||||
+ // Paper start - move logic in Entity to here, to use bukkit supplied world UUID.
|
||||
+ if (nbttagcompound != null && nbttagcompound.contains("WorldUUIDMost") && nbttagcompound.contains("WorldUUIDLeast")) {
|
||||
+ UUID uid = new UUID(nbttagcompound.getLong("WorldUUIDMost"), nbttagcompound.getLong("WorldUUIDLeast"));
|
||||
+ org.bukkit.World bWorld = org.bukkit.Bukkit.getServer().getWorld(uid);
|
||||
+ if (bWorld != null) {
|
||||
+ resourcekey = ((CraftWorld) bWorld).getHandle().dimension();
|
||||
+ } else {
|
||||
+ resourcekey = Level.OVERWORLD;
|
||||
+ }
|
||||
+ } else if (nbttagcompound != null) {
|
||||
+ // Vanilla migration support
|
||||
+ // Paper end
|
||||
DataResult<ResourceKey<Level>> dataresult = DimensionType.parseLegacy(new Dynamic(NbtOps.INSTANCE, nbttagcompound.get("Dimension"))); // CraftBukkit - decompile error
|
||||
Logger logger = PlayerList.LOGGER;
|
||||
|
|
@ -1,152 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Fri, 3 Jul 2020 11:58:56 -0500
|
||||
Subject: [PATCH] Add PrepareResultEvent
|
||||
|
||||
Adds a new event for all crafting stations that generate a result slot item
|
||||
|
||||
Anvil, Grindstone and Smithing now extend this event
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
|
||||
index eb22059fe008c3d3fc0364a7f85f91b4cca8b328..506d758efbf16da9467f120321d2359a8832e477 100644
|
||||
--- a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
|
||||
+++ b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
|
||||
@@ -316,6 +316,7 @@ public class AnvilMenu extends ItemCombinerMenu {
|
||||
}
|
||||
|
||||
this.createResult();
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper
|
||||
}
|
||||
|
||||
public int getCost() {
|
||||
diff --git a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java
|
||||
index fc2b400c58ddbd7b012707c61d9a37363d351251..4f5593d387545545e30475d3edaa92a4306ba96b 100644
|
||||
--- a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java
|
||||
+++ b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java
|
||||
@@ -150,6 +150,7 @@ public class CartographyTableMenu extends AbstractContainerMenu {
|
||||
this.setupResultSlot(itemstack, itemstack1, itemstack2);
|
||||
}
|
||||
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper
|
||||
}
|
||||
|
||||
private void setupResultSlot(ItemStack map, ItemStack item, ItemStack oldResult) {
|
||||
diff --git a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
|
||||
index aa0ba9c7dcb0ee81c9081031c447eeab61d92a10..7a0c38c743ef02f5b9c052f88c2d6429a53b8286 100644
|
||||
--- a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
|
||||
+++ b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
|
||||
@@ -159,6 +159,7 @@ public class GrindstoneMenu extends AbstractContainerMenu {
|
||||
super.slotsChanged(inventory);
|
||||
if (inventory == this.repairSlots) {
|
||||
this.createResult();
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper
|
||||
}
|
||||
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java
|
||||
index f5e52220abc5c678c090b32d83eb9644fa91ce9d..35575434f3c90f1bd23df6584ee8a5a991f93f9f 100644
|
||||
--- a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java
|
||||
+++ b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java
|
||||
@@ -78,6 +78,7 @@ public abstract class ItemCombinerMenu extends AbstractContainerMenu {
|
||||
super.slotsChanged(inventory);
|
||||
if (inventory == this.inputSlots) {
|
||||
this.createResult();
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper
|
||||
}
|
||||
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/inventory/LoomMenu.java b/src/main/java/net/minecraft/world/inventory/LoomMenu.java
|
||||
index d028ad0ab0e800b0fd93362d21942dff392f24af..942b4cc710bede4c942d269dcfc14ae105ab848d 100644
|
||||
--- a/src/main/java/net/minecraft/world/inventory/LoomMenu.java
|
||||
+++ b/src/main/java/net/minecraft/world/inventory/LoomMenu.java
|
||||
@@ -248,7 +248,8 @@ public class LoomMenu extends AbstractContainerMenu {
|
||||
this.resultSlot.set(ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
- this.broadcastChanges();
|
||||
+ // this.broadcastChanges(); // Paper - done below
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, 3); // Paper
|
||||
} else {
|
||||
this.resultSlot.set(ItemStack.EMPTY);
|
||||
this.selectablePatterns = List.of();
|
||||
diff --git a/src/main/java/net/minecraft/world/inventory/SmithingMenu.java b/src/main/java/net/minecraft/world/inventory/SmithingMenu.java
|
||||
index 92dd2ea23185bba311e184b2ac9744a423c102ea..71bb09e3d31f098503d0e1bdf073b60f07d76ed0 100644
|
||||
--- a/src/main/java/net/minecraft/world/inventory/SmithingMenu.java
|
||||
+++ b/src/main/java/net/minecraft/world/inventory/SmithingMenu.java
|
||||
@@ -76,6 +76,7 @@ public class SmithingMenu extends ItemCombinerMenu {
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java
|
||||
index cdebd0cdf6eb901464cf4c16089b10ea0147b54d..b47dc7671fab2117b989d647d7e8e36d12af5f76 100644
|
||||
--- a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java
|
||||
+++ b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java
|
||||
@@ -176,6 +176,7 @@ public class StonecutterMenu extends AbstractContainerMenu {
|
||||
this.setupRecipeList(inventory, itemstack);
|
||||
}
|
||||
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper
|
||||
}
|
||||
|
||||
private void setupRecipeList(Container input, ItemStack stack) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
index 359964cd8820b8ef8b8dba5501119164cebcf743..2809ec8fcd43d096a187fc2fbda042a81d301c0c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -1584,19 +1584,44 @@ public class CraftEventFactory {
|
||||
return event;
|
||||
}
|
||||
|
||||
- public static PrepareAnvilEvent callPrepareAnvilEvent(InventoryView view, ItemStack item) {
|
||||
- PrepareAnvilEvent event = new PrepareAnvilEvent(view, CraftItemStack.asCraftMirror(item).clone());
|
||||
- event.getView().getPlayer().getServer().getPluginManager().callEvent(event);
|
||||
+ // Paper start - disable this method, handled below
|
||||
+ public static void callPrepareAnvilEvent(InventoryView view, ItemStack item) { // Paper - verify nothing uses return - handled below in PrepareResult
|
||||
+ PrepareAnvilEvent event = new PrepareAnvilEvent(view, CraftItemStack.asCraftMirror(item)); // Paper - remove clone
|
||||
+ //event.getView().getPlayer().getServer().getPluginManager().callEvent(event); // disable event
|
||||
event.getInventory().setItem(2, event.getResult());
|
||||
- return event;
|
||||
+ //return event; // Paper
|
||||
}
|
||||
+ // Paper end
|
||||
|
||||
- public static PrepareSmithingEvent callPrepareSmithingEvent(InventoryView view, ItemStack item) {
|
||||
- PrepareSmithingEvent event = new PrepareSmithingEvent(view, CraftItemStack.asCraftMirror(item).clone());
|
||||
- event.getView().getPlayer().getServer().getPluginManager().callEvent(event);
|
||||
+ // Paper start - disable this method, handled in callPrepareResultEvent
|
||||
+ public static void callPrepareSmithingEvent(InventoryView view, ItemStack item) { // Paper - verify nothing uses return - handled below in PrepareResult
|
||||
+ PrepareSmithingEvent event = new PrepareSmithingEvent(view, CraftItemStack.asCraftMirror(item)); // Paper - remove clone
|
||||
+ //event.getView().getPlayer().getServer().getPluginManager().callEvent(event); // Paper - disable event
|
||||
event.getInventory().setItem(2, event.getResult());
|
||||
- return event;
|
||||
+ //return event; // Paper
|
||||
}
|
||||
+ // Paper end
|
||||
+
|
||||
+ // Paper start - support specific overrides for prepare result
|
||||
+ public static void callPrepareResultEvent(AbstractContainerMenu container, int resultSlot) {
|
||||
+ com.destroystokyo.paper.event.inventory.PrepareResultEvent event;
|
||||
+ InventoryView view = container.getBukkitView();
|
||||
+ org.bukkit.inventory.ItemStack origItem = view.getTopInventory().getItem(resultSlot);
|
||||
+ CraftItemStack result = origItem != null ? CraftItemStack.asCraftCopy(origItem) : null;
|
||||
+ if (view.getTopInventory() instanceof org.bukkit.inventory.AnvilInventory) {
|
||||
+ event = new PrepareAnvilEvent(view, result);
|
||||
+ } else if (view.getTopInventory() instanceof org.bukkit.inventory.GrindstoneInventory) {
|
||||
+ event = new com.destroystokyo.paper.event.inventory.PrepareGrindstoneEvent(view, result);
|
||||
+ } else if (view.getTopInventory() instanceof org.bukkit.inventory.SmithingInventory) {
|
||||
+ event = new PrepareSmithingEvent(view, result);
|
||||
+ } else {
|
||||
+ event = new com.destroystokyo.paper.event.inventory.PrepareResultEvent(view, result);
|
||||
+ }
|
||||
+ event.callEvent();
|
||||
+ event.getInventory().setItem(resultSlot, event.getResult());
|
||||
+ container.broadcastChanges();;
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
/**
|
||||
* Mob spawner event.
|
|
@ -1,19 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 5 Jul 2020 14:59:31 -0400
|
||||
Subject: [PATCH] Don't check chunk for portal on world gen entity add
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index a337ce97a31998a63e7c329ac94cad9a5f783a5c..9c5421b9aa35c5f90a51ed097e68c5143054e966 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3446,7 +3446,7 @@ public abstract class LivingEntity extends Entity {
|
||||
Entity entity = this.getVehicle();
|
||||
|
||||
super.stopRiding(suppressCancellation); // Paper - suppress
|
||||
- if (entity != null && entity != this.getVehicle() && !this.level.isClientSide) {
|
||||
+ if (entity != null && entity != this.getVehicle() && !this.level.isClientSide && entity.valid) { // Paper - don't process on world gen
|
||||
this.dismountVehicle(entity);
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Steinborn <git@steinborn.me>
|
||||
Date: Sun, 5 Jul 2020 22:38:18 -0400
|
||||
Subject: [PATCH] Optimize NetworkManager Exception Handling
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/ConnectionProtocol.java b/src/main/java/net/minecraft/network/ConnectionProtocol.java
|
||||
index 672e296cec289abd3bf797d84e16983ca50907be..aec921477e035095d569eab3335175b93a65e672 100644
|
||||
--- a/src/main/java/net/minecraft/network/ConnectionProtocol.java
|
||||
+++ b/src/main/java/net/minecraft/network/ConnectionProtocol.java
|
||||
@@ -302,6 +302,7 @@ public enum ConnectionProtocol {
|
||||
|
||||
@Nullable
|
||||
public Packet<?> createPacket(int id, FriendlyByteBuf buf) {
|
||||
+ if (id < 0 || id >= this.idToDeserializer.size()) return null; // Paper
|
||||
Function<FriendlyByteBuf, ? extends Packet<T>> function = this.idToDeserializer.get(id);
|
||||
return function != null ? function.apply(buf) : null;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/network/Varint21FrameDecoder.java b/src/main/java/net/minecraft/network/Varint21FrameDecoder.java
|
||||
index 99b581052f937b0f2d6b5d73de699008c1d51774..81ec2011a93bb94200ad750f4666ba1cd8be11c5 100644
|
||||
--- a/src/main/java/net/minecraft/network/Varint21FrameDecoder.java
|
||||
+++ b/src/main/java/net/minecraft/network/Varint21FrameDecoder.java
|
||||
@@ -8,9 +8,20 @@ import io.netty.handler.codec.CorruptedFrameException;
|
||||
import java.util.List;
|
||||
|
||||
public class Varint21FrameDecoder extends ByteToMessageDecoder {
|
||||
+ private final byte[] lenBuf = new byte[3]; // Paper
|
||||
+ @Override
|
||||
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) {
|
||||
+ // Paper start - if channel is not active just discard the packet
|
||||
+ if (!channelHandlerContext.channel().isActive()) {
|
||||
+ byteBuf.skipBytes(byteBuf.readableBytes());
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
byteBuf.markReaderIndex();
|
||||
- byte[] bs = new byte[3];
|
||||
+ // Paper start - reuse temporary length buffer
|
||||
+ byte[] bs = lenBuf;
|
||||
+ java.util.Arrays.fill(bs, (byte) 0);
|
||||
+ // Paper end
|
||||
|
||||
for(int i = 0; i < bs.length; ++i) {
|
||||
if (!byteBuf.isReadable()) {
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/PacketUtils.java b/src/main/java/net/minecraft/network/protocol/PacketUtils.java
|
||||
index 049e64c355d5f064009b1107ad15d28c44f999dd..acfa1907bfc9c29d261cfccc00d65bad9ad1a002 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/PacketUtils.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/PacketUtils.java
|
||||
@@ -30,11 +30,15 @@ public class PacketUtils {
|
||||
try (co.aikar.timings.Timing ignored = timing.startTiming()) { // Paper - timings
|
||||
packet.handle(listener);
|
||||
} catch (Exception exception) {
|
||||
- if (listener.shouldPropagateHandlingExceptions()) {
|
||||
- throw exception;
|
||||
+ net.minecraft.network.Connection networkmanager = listener.getConnection();
|
||||
+ if (networkmanager.getPlayer() != null) {
|
||||
+ LOGGER.error("Error whilst processing packet {} for {}[{}]", packet, networkmanager.getPlayer().getScoreboardName(), networkmanager.getRemoteAddress(), exception);
|
||||
+ } else {
|
||||
+ LOGGER.error("Error whilst processing packet {} for connection from {}", packet, networkmanager.getRemoteAddress(), exception);
|
||||
}
|
||||
-
|
||||
- PacketUtils.LOGGER.error("Failed to handle packet {}, suppressing error", packet, exception);
|
||||
+ net.minecraft.network.chat.Component error = net.minecraft.network.chat.Component.literal("Packet processing error");
|
||||
+ networkmanager.send(new net.minecraft.network.protocol.game.ClientboundDisconnectPacket(error), net.minecraft.network.PacketSendListener.thenRun(() -> networkmanager.disconnect(error)));
|
||||
+ networkmanager.setReadOnly();
|
||||
}
|
||||
} else {
|
||||
PacketUtils.LOGGER.debug("Ignoring packet due to disconnection: {}", packet);
|
|
@ -1,54 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Wyatt Childers <wchilders@nearce.com>
|
||||
Date: Sat, 4 Jul 2020 23:07:43 -0400
|
||||
Subject: [PATCH] Optimize the advancement data player iteration to be O(N)
|
||||
rather than O(N^2)
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/PlayerAdvancements.java b/src/main/java/net/minecraft/server/PlayerAdvancements.java
|
||||
index 3f7f6a43ac0bf2efb0e66dc96438febbd92113e9..0c2f12e7930646a3da53a50f38be62e0cb1ed2b7 100644
|
||||
--- a/src/main/java/net/minecraft/server/PlayerAdvancements.java
|
||||
+++ b/src/main/java/net/minecraft/server/PlayerAdvancements.java
|
||||
@@ -435,6 +435,16 @@ public class PlayerAdvancements {
|
||||
}
|
||||
|
||||
private void ensureVisibility(Advancement advancement) {
|
||||
+ // Paper start
|
||||
+ ensureVisibility(advancement, IterationEntryPoint.ROOT);
|
||||
+ }
|
||||
+ private enum IterationEntryPoint {
|
||||
+ ROOT,
|
||||
+ ITERATOR,
|
||||
+ PARENT_OF_ITERATOR
|
||||
+ }
|
||||
+ private void ensureVisibility(Advancement advancement, IterationEntryPoint entryPoint) {
|
||||
+ // Paper end
|
||||
boolean flag = this.shouldBeVisible(advancement);
|
||||
boolean flag1 = this.visible.contains(advancement);
|
||||
|
||||
@@ -450,15 +460,23 @@ public class PlayerAdvancements {
|
||||
}
|
||||
|
||||
if (flag != flag1 && advancement.getParent() != null) {
|
||||
- this.ensureVisibility(advancement.getParent());
|
||||
+ // Paper start - If we're not coming from an iterator consider this to be a root entry, otherwise
|
||||
+ // market that we're entering from the parent of an iterator.
|
||||
+ this.ensureVisibility(advancement.getParent(), entryPoint == IterationEntryPoint.ITERATOR ? IterationEntryPoint.PARENT_OF_ITERATOR : IterationEntryPoint.ROOT);
|
||||
}
|
||||
|
||||
+ // If this is true, we've went through a child iteration, entered the parent, processed the parent
|
||||
+ // and are about to reprocess the children. Stop processing here to prevent O(N^2) processing.
|
||||
+ if (entryPoint == IterationEntryPoint.PARENT_OF_ITERATOR) {
|
||||
+ return;
|
||||
+ } // Paper end
|
||||
+
|
||||
Iterator iterator = advancement.getChildren().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Advancement advancement1 = (Advancement) iterator.next();
|
||||
|
||||
- this.ensureVisibility(advancement1);
|
||||
+ this.ensureVisibility(advancement1, IterationEntryPoint.ITERATOR); // Paper - Mark this call as being from iteration
|
||||
}
|
||||
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Wed, 8 Jul 2020 11:24:30 -0500
|
||||
Subject: [PATCH] Fix arrows never despawning MC-125757
|
||||
|
||||
This forces the despawn counter to start ticking regardless of
|
||||
state after the arrow has been alive for 200 ticks (10 seconds)
|
||||
instead of getting stuck in a never despawn state (bubble columns,
|
||||
etc).
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
|
||||
index da92f324322f4fb18f9aa72c4298ffc8ab040953..3b1e17a8733de823b36315c81e8ca5884e83368e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
|
||||
@@ -199,6 +199,7 @@ public abstract class AbstractArrow extends Projectile {
|
||||
|
||||
++this.inGroundTime;
|
||||
} else {
|
||||
+ if (tickCount > 200) this.tickDespawn(); // Paper - tick despawnCounter regardless after 10 seconds
|
||||
this.inGroundTime = 0;
|
||||
Vec3 vec3d2 = this.position();
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 11 Jul 2020 03:54:28 -0400
|
||||
Subject: [PATCH] Thread Safe Vanilla Command permission checking
|
||||
|
||||
Datapacks check this on load and are built concurrently. This was breaking them badly due
|
||||
to race conditions.
|
||||
|
||||
Plus, .canUse we want to be safe for async anyways.
|
||||
|
||||
diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java
|
||||
index 20a7cdf87f307878d66922aaac0c60cff218e46c..39844531b03eb8a6c70700b4ecbf0ff1a557424d 100644
|
||||
--- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java
|
||||
+++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java
|
||||
@@ -75,10 +75,10 @@ public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
|
||||
public synchronized boolean canUse(final S source) {
|
||||
if (source instanceof CommandSourceStack) {
|
||||
try {
|
||||
- ((CommandSourceStack) source).currentCommand = this;
|
||||
+ ((CommandSourceStack) source).currentCommand.put(Thread.currentThread(), this); // Paper
|
||||
return this.requirement.test(source);
|
||||
} finally {
|
||||
- ((CommandSourceStack) source).currentCommand = null;
|
||||
+ ((CommandSourceStack) source).currentCommand.remove(Thread.currentThread()); // Paper
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
||||
index 891d1fb88d8de9d1b34f300ba640cfc6fbd8a4de..2ff021966426dd6c7c1081fbcfacf4677b404264 100644
|
||||
--- a/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
||||
+++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
||||
@@ -59,7 +59,7 @@ public class CommandSourceStack implements SharedSuggestionProvider, com.destroy
|
||||
private final Vec2 rotation;
|
||||
private final CommandSigningContext signingContext;
|
||||
private final TaskChainer chatMessageChainer;
|
||||
- public volatile CommandNode currentCommand; // CraftBukkit
|
||||
+ public java.util.Map<Thread, CommandNode> currentCommand = new java.util.concurrent.ConcurrentHashMap<>(); // CraftBukkit // Paper
|
||||
public boolean bypassSelectorPermissions = false; // Paper
|
||||
|
||||
public CommandSourceStack(CommandSource output, Vec3 pos, Vec2 rot, ServerLevel world, int level, String name, Component displayName, MinecraftServer server, @Nullable Entity entity) {
|
||||
@@ -196,9 +196,11 @@ public class CommandSourceStack implements SharedSuggestionProvider, com.destroy
|
||||
@Override
|
||||
public boolean hasPermission(int level) {
|
||||
// CraftBukkit start
|
||||
- CommandNode currentCommand = this.currentCommand;
|
||||
+ // Paper start - fix concurrency issue
|
||||
+ CommandNode currentCommand = this.currentCommand.get(Thread.currentThread());
|
||||
if (currentCommand != null) {
|
||||
return this.hasPermission(level, org.bukkit.craftbukkit.command.VanillaCommandWrapper.getPermission(currentCommand));
|
||||
+ // Paper end
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: JRoy <joshroy126@gmail.com>
|
||||
Date: Wed, 15 Jul 2020 21:42:52 -0400
|
||||
Subject: [PATCH] Fix SPIGOT-5989
|
||||
|
||||
Before this fix, if a player was respawning to a respawn anchor and
|
||||
the respawn location was modified away from the anchor with the
|
||||
PlayerRespawnEvent, the anchor would still lose some charge.
|
||||
This fixes that by checking if the modified spawn location is
|
||||
still at a respawn anchor.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 55c5576bd76718a0cc5d8fbcb80eeeac8b6c9277..7528491e129b250da5cb505d7befceee8cfe74e6 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -842,6 +842,7 @@ public abstract class PlayerList {
|
||||
// Paper start
|
||||
boolean isBedSpawn = false;
|
||||
boolean isRespawn = false;
|
||||
+ boolean isLocAltered = false; // Paper - Fix SPIGOT-5989
|
||||
// Paper end
|
||||
|
||||
// CraftBukkit start - fire PlayerRespawnEvent
|
||||
@@ -852,7 +853,7 @@ public abstract class PlayerList {
|
||||
Optional optional;
|
||||
|
||||
if (blockposition != null) {
|
||||
- optional = net.minecraft.world.entity.player.Player.findRespawnPositionAndUseSpawnBlock(worldserver1, blockposition, f, flag1, flag);
|
||||
+ optional = net.minecraft.world.entity.player.Player.findRespawnPositionAndUseSpawnBlock(worldserver1, blockposition, f, flag1, true); // Paper - Fix SPIGOT-5989
|
||||
} else {
|
||||
optional = Optional.empty();
|
||||
}
|
||||
@@ -896,7 +897,12 @@ public abstract class PlayerList {
|
||||
}
|
||||
// Spigot End
|
||||
|
||||
- location = respawnEvent.getRespawnLocation();
|
||||
+ // Paper start - Fix SPIGOT-5989
|
||||
+ if (!location.equals(respawnEvent.getRespawnLocation()) ) {
|
||||
+ location = respawnEvent.getRespawnLocation();
|
||||
+ isLocAltered = true;
|
||||
+ }
|
||||
+ // Paper end
|
||||
if (!flag) entityplayer.reset(); // SPIGOT-4785
|
||||
isRespawn = true; // Paper
|
||||
} else {
|
||||
@@ -934,8 +940,12 @@ public abstract class PlayerList {
|
||||
}
|
||||
// entityplayer1.initInventoryMenu();
|
||||
entityplayer1.setHealth(entityplayer1.getHealth());
|
||||
- if (flag2) {
|
||||
- entityplayer1.connection.send(new ClientboundSoundPacket(SoundEvents.RESPAWN_ANCHOR_DEPLETE, SoundSource.BLOCKS, (double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ(), 1.0F, 1.0F, worldserver1.getRandom().nextLong()));
|
||||
+ // Paper start - Fix SPIGOT-5989
|
||||
+ if (flag2 && !isLocAltered) {
|
||||
+ BlockState data = worldserver1.getBlockState(blockposition);
|
||||
+ worldserver1.setBlock(blockposition, data.setValue(net.minecraft.world.level.block.RespawnAnchorBlock.CHARGE, data.getValue(net.minecraft.world.level.block.RespawnAnchorBlock.CHARGE) - 1), 3);
|
||||
+ entityplayer1.connection.send(new ClientboundSoundPacket(SoundEvents.RESPAWN_ANCHOR_DEPLETE, SoundSource.BLOCKS, (double) location.getX(), (double) location.getY(), (double) location.getZ(), 1.0F, 1.0F, worldserver1.getRandom().nextLong()));
|
||||
+ // Paper end
|
||||
}
|
||||
// Added from changeDimension
|
||||
this.sendAllPlayerInfo(entityplayer); // Update health, etc...
|
|
@ -1,50 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Fri, 10 Jul 2020 13:12:33 -0500
|
||||
Subject: [PATCH] Fix SPIGOT-5824 Bukkit world-container is not used
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
|
||||
index 151b13e257c09fc5c4bbccfc388b15ad76133909..3f7dde4fe1fdce3638d1db5e96a546b9fae90269 100644
|
||||
--- a/src/main/java/net/minecraft/server/Main.java
|
||||
+++ b/src/main/java/net/minecraft/server/Main.java
|
||||
@@ -154,8 +154,17 @@ public class Main {
|
||||
return;
|
||||
}
|
||||
|
||||
- File file = (File) optionset.valueOf("universe"); // CraftBukkit
|
||||
- Services services = Services.create(new com.destroystokyo.paper.profile.PaperAuthenticationService(Proxy.NO_PROXY), file, optionset); // Paper
|
||||
+ // Paper start - fix SPIGOT-5824
|
||||
+ File file;
|
||||
+ File userCacheFile = new File(Services.USERID_CACHE_FILE);
|
||||
+ if (optionset.has("universe")) {
|
||||
+ file = (File) optionset.valueOf("universe"); // CraftBukkit
|
||||
+ userCacheFile = new File(file, Services.USERID_CACHE_FILE);
|
||||
+ } else {
|
||||
+ file = new File(bukkitConfiguration.getString("settings.world-container", "."));
|
||||
+ }
|
||||
+ // Paper end - fix SPIGOT-5824
|
||||
+ Services services = Services.create(new com.destroystokyo.paper.profile.PaperAuthenticationService(Proxy.NO_PROXY), file, userCacheFile, optionset); // Paper
|
||||
// CraftBukkit start
|
||||
String s = (String) Optional.ofNullable((String) optionset.valueOf("world")).orElse(dedicatedserversettings.getProperties().levelName);
|
||||
LevelStorageSource convertable = LevelStorageSource.createDefault(file.toPath());
|
||||
diff --git a/src/main/java/net/minecraft/server/Services.java b/src/main/java/net/minecraft/server/Services.java
|
||||
index d7d65d0faefa5551480a4090de3a881828238ffd..ef6ff78af2ae747e939895b82ee9d11c75012dcd 100644
|
||||
--- a/src/main/java/net/minecraft/server/Services.java
|
||||
+++ b/src/main/java/net/minecraft/server/Services.java
|
||||
@@ -19,12 +19,12 @@ public record Services(MinecraftSessionService sessionService, SignatureValidato
|
||||
return java.util.Objects.requireNonNull(this.paperConfigurations);
|
||||
}
|
||||
// Paper end
|
||||
- private static final String USERID_CACHE_FILE = "usercache.json";
|
||||
+ public static final String USERID_CACHE_FILE = "usercache.json"; // Paper - private -> public
|
||||
|
||||
- public static Services create(YggdrasilAuthenticationService authenticationService, File rootDirectory, joptsimple.OptionSet optionSet) throws Exception { // Paper
|
||||
+ public static Services create(YggdrasilAuthenticationService authenticationService, File rootDirectory, File userCacheFile, joptsimple.OptionSet optionSet) throws Exception { // Paper
|
||||
MinecraftSessionService minecraftSessionService = authenticationService.createMinecraftSessionService();
|
||||
GameProfileRepository gameProfileRepository = authenticationService.createProfileRepository();
|
||||
- GameProfileCache gameProfileCache = new GameProfileCache(gameProfileRepository, new File(rootDirectory, "usercache.json"));
|
||||
+ GameProfileCache gameProfileCache = new GameProfileCache(gameProfileRepository, userCacheFile); // Paper
|
||||
SignatureValidator signatureValidator = SignatureValidator.from(authenticationService.getServicesKey());
|
||||
// Paper start
|
||||
final java.nio.file.Path legacyConfigPath = ((File) optionSet.valueOf("paper-settings")).toPath();
|
|
@ -1,18 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Fri, 10 Jul 2020 12:38:12 -0500
|
||||
Subject: [PATCH] Fix SPIGOT-5885 Unable to disable advancements
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
|
||||
index 3f7dde4fe1fdce3638d1db5e96a546b9fae90269..13ef3bb2b84fac9a1be72b09e7e3c022fa08221a 100644
|
||||
--- a/src/main/java/net/minecraft/server/Main.java
|
||||
+++ b/src/main/java/net/minecraft/server/Main.java
|
||||
@@ -154,6 +154,7 @@ public class Main {
|
||||
return;
|
||||
}
|
||||
|
||||
+ org.spigotmc.SpigotConfig.disabledAdvancements = spigotConfiguration.getStringList("advancements.disabled"); // Paper - fix SPIGOT-5885, must be set early in init
|
||||
// Paper start - fix SPIGOT-5824
|
||||
File file;
|
||||
File userCacheFile = new File(Services.USERID_CACHE_FILE);
|
|
@ -1,74 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 13 Jul 2020 06:22:54 -0700
|
||||
Subject: [PATCH] Fix AdvancementDataPlayer leak due from quitting early in
|
||||
login
|
||||
|
||||
Move the criterion storage to the AdvancementDataPlayer object
|
||||
itself, so the criterion object stores no references - and thus
|
||||
needs no cleanup.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java b/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java
|
||||
index 06fc39b19385d36fd0c5bb9a7042a238eb6e8a57..bb1f0e9dbcb792d015d1cb65664a96fdd3e0489e 100644
|
||||
--- a/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java
|
||||
+++ b/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java
|
||||
@@ -14,22 +14,24 @@ import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.storage.loot.LootContext;
|
||||
|
||||
public abstract class SimpleCriterionTrigger<T extends AbstractCriterionTriggerInstance> implements CriterionTrigger<T> {
|
||||
- private final Map<PlayerAdvancements, Set<CriterionTrigger.Listener<T>>> players = Maps.newIdentityHashMap();
|
||||
+ //private final Map<PlayerAdvancements, Set<CriterionTrigger.Listener<T>>> players = Maps.newIdentityHashMap(); // Paper - moved into AdvancementDataPlayer to fix memory leak
|
||||
+
|
||||
+ public SimpleCriterionTrigger() {}
|
||||
|
||||
@Override
|
||||
public final void addPlayerListener(PlayerAdvancements manager, CriterionTrigger.Listener<T> conditions) {
|
||||
- this.players.computeIfAbsent(manager, (managerx) -> {
|
||||
+ manager.criterionData.computeIfAbsent(this, (managerx) -> { // Paper - fix AdvancementDataPlayer leak
|
||||
return Sets.newHashSet();
|
||||
}).add(conditions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void removePlayerListener(PlayerAdvancements manager, CriterionTrigger.Listener<T> conditions) {
|
||||
- Set<CriterionTrigger.Listener<T>> set = this.players.get(manager);
|
||||
+ Set<CriterionTrigger.Listener<T>> set = (Set) manager.criterionData.get(this); // Paper - fix AdvancementDataPlayer leak
|
||||
if (set != null) {
|
||||
set.remove(conditions);
|
||||
if (set.isEmpty()) {
|
||||
- this.players.remove(manager);
|
||||
+ manager.criterionData.remove(this); // Paper - fix AdvancementDataPlayer leak
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +39,7 @@ public abstract class SimpleCriterionTrigger<T extends AbstractCriterionTriggerI
|
||||
|
||||
@Override
|
||||
public final void removePlayerListeners(PlayerAdvancements tracker) {
|
||||
- this.players.remove(tracker);
|
||||
+ tracker.criterionData.remove(this); // Paper - fix AdvancementDataPlayer leak
|
||||
}
|
||||
|
||||
protected abstract T createInstance(JsonObject obj, EntityPredicate.Composite playerPredicate, DeserializationContext predicateDeserializer);
|
||||
@@ -50,7 +52,7 @@ public abstract class SimpleCriterionTrigger<T extends AbstractCriterionTriggerI
|
||||
|
||||
protected void trigger(ServerPlayer player, Predicate<T> predicate) {
|
||||
PlayerAdvancements playerAdvancements = player.getAdvancements();
|
||||
- Set<CriterionTrigger.Listener<T>> set = this.players.get(playerAdvancements);
|
||||
+ Set<CriterionTrigger.Listener<T>> set = (Set) playerAdvancements.criterionData.get(this); // Paper - fix AdvancementDataPlayer leak
|
||||
if (set != null && !set.isEmpty()) {
|
||||
LootContext lootContext = EntityPredicate.createContext(player, player);
|
||||
List<CriterionTrigger.Listener<T>> list = null;
|
||||
diff --git a/src/main/java/net/minecraft/server/PlayerAdvancements.java b/src/main/java/net/minecraft/server/PlayerAdvancements.java
|
||||
index 0c2f12e7930646a3da53a50f38be62e0cb1ed2b7..e7ec5e1144c1596b035f97fb1fb86d18e61be3c9 100644
|
||||
--- a/src/main/java/net/minecraft/server/PlayerAdvancements.java
|
||||
+++ b/src/main/java/net/minecraft/server/PlayerAdvancements.java
|
||||
@@ -68,6 +68,8 @@ public class PlayerAdvancements {
|
||||
private Advancement lastSelectedTab;
|
||||
private boolean isFirstPacket = true;
|
||||
|
||||
+ public final Map<net.minecraft.advancements.critereon.SimpleCriterionTrigger, Set<CriterionTrigger.Listener>> criterionData = Maps.newIdentityHashMap(); // Paper - fix advancement data player leakage
|
||||
+
|
||||
public PlayerAdvancements(DataFixer dataFixer, PlayerList playerManager, ServerAdvancementManager advancementLoader, File advancementFile, ServerPlayer owner) {
|
||||
this.dataFixer = dataFixer;
|
||||
this.playerList = playerManager;
|
|
@ -1,19 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Sun, 26 Jul 2020 12:11:39 +0100
|
||||
Subject: [PATCH] Add missing strikeLighting call to
|
||||
World#spigot()#strikeLightningEffect
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index f19bfe6d6d4d915876cea3e6ef792639300fced1..643b682db12560fc3409ede861a4e0aea8fc5360 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -2134,6 +2134,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
lightning.moveTo( loc.getX(), loc.getY(), loc.getZ() );
|
||||
lightning.visualOnly = true;
|
||||
lightning.isSilent = isSilent;
|
||||
+ world.strikeLightning( lightning );
|
||||
return (LightningStrike) lightning.getBukkitEntity();
|
||||
}
|
||||
};
|
|
@ -1,84 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Fri, 24 Jul 2020 15:56:05 -0700
|
||||
Subject: [PATCH] Fix some rails connecting improperly
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/BaseRailBlock.java b/src/main/java/net/minecraft/world/level/block/BaseRailBlock.java
|
||||
index 9ae45eaf77ead0a6801046d8946d50eec24612fa..a3f877bf03f75cbfbd128c856322bcd427b95d21 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/BaseRailBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/BaseRailBlock.java
|
||||
@@ -65,6 +65,7 @@ public abstract class BaseRailBlock extends Block implements SimpleWaterloggedBl
|
||||
state = this.updateDir(world, pos, state, true);
|
||||
if (this.isStraight) {
|
||||
world.neighborChanged(state, pos, this, pos, notify);
|
||||
+ state = world.getBlockState(pos); // Paper - don't desync, update again
|
||||
}
|
||||
|
||||
return state;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/DetectorRailBlock.java b/src/main/java/net/minecraft/world/level/block/DetectorRailBlock.java
|
||||
index fe9b6c89a1f0c98a9c73a409f2aca6a4a1c0f9e7..932a2c279f46c951182d2604b525b473b6945895 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/DetectorRailBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/DetectorRailBlock.java
|
||||
@@ -70,6 +70,7 @@ public class DetectorRailBlock extends BaseRailBlock {
|
||||
|
||||
private void checkPressed(Level world, BlockPos pos, BlockState state) {
|
||||
if (this.canSurvive(state, world, pos)) {
|
||||
+ if (state.getBlock() != this) { return; } // Paper - not our block, don't do anything
|
||||
boolean flag = (Boolean) state.getValue(DetectorRailBlock.POWERED);
|
||||
boolean flag1 = false;
|
||||
List<AbstractMinecart> list = this.getInteractingMinecartOfType(world, pos, AbstractMinecart.class, (entity) -> {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/RailState.java b/src/main/java/net/minecraft/world/level/block/RailState.java
|
||||
index 0cbfad97371b59de95963a09aa16f3dad7a37222..d873625c1b8439a727d39ce207b5e84a1d86e5eb 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/RailState.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/RailState.java
|
||||
@@ -17,6 +17,12 @@ public class RailState {
|
||||
private final boolean isStraight;
|
||||
private final List<BlockPos> connections = Lists.newArrayList();
|
||||
|
||||
+ // Paper start - prevent desync
|
||||
+ public boolean isValid() {
|
||||
+ return this.level.getBlockState(this.pos).getBlock() == this.state.getBlock();
|
||||
+ }
|
||||
+ // Paper end - prevent desync
|
||||
+
|
||||
public RailState(Level world, BlockPos pos, BlockState state) {
|
||||
this.level = world;
|
||||
this.pos = pos;
|
||||
@@ -143,6 +149,11 @@ public class RailState {
|
||||
}
|
||||
|
||||
private void connectTo(RailState placementHelper) {
|
||||
+ // Paper start - prevent desync
|
||||
+ if (!this.isValid() || !placementHelper.isValid()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - prevent desync
|
||||
this.connections.add(placementHelper.pos);
|
||||
BlockPos blockPos = this.pos.north();
|
||||
BlockPos blockPos2 = this.pos.south();
|
||||
@@ -333,10 +344,15 @@ public class RailState {
|
||||
this.state = this.state.setValue(this.block.getShapeProperty(), railShape2);
|
||||
if (forceUpdate || this.level.getBlockState(this.pos) != this.state) {
|
||||
this.level.setBlock(this.pos, this.state, 3);
|
||||
+ // Paper start - prevent desync
|
||||
+ if (!this.isValid()) {
|
||||
+ return this;
|
||||
+ }
|
||||
+ // Paper end - prevent desync
|
||||
|
||||
for(int i = 0; i < this.connections.size(); ++i) {
|
||||
RailState railState = this.getRail(this.connections.get(i));
|
||||
- if (railState != null) {
|
||||
+ if (railState != null && railState.isValid()) { // Paper - prevent desync
|
||||
railState.removeSoftConnections();
|
||||
if (railState.canConnectTo(this)) {
|
||||
railState.connectTo(this);
|
||||
@@ -349,6 +365,6 @@ public class RailState {
|
||||
}
|
||||
|
||||
public BlockState getState() {
|
||||
- return this.state;
|
||||
+ return this.level.getBlockState(this.pos); // Paper - prevent desync
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: mbax <matt@phozop.net>
|
||||
Date: Mon, 17 Aug 2020 12:17:37 -0400
|
||||
Subject: [PATCH] Fix regex mistake in CB NBT int deserialization
|
||||
|
||||
The existing regex is too open and allows for the absence of any actual
|
||||
number data, detecting an NBT entry of just the letter "i" in upper or
|
||||
lower case. This causes a single-character NBT entry to be processed as
|
||||
an integer ending in "i", passing an empty String to to Integer.parseInt,
|
||||
triggering an exception in loading the item.
|
||||
|
||||
This commit forces numbers to be present prior to the ending "i"
|
||||
letter.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftNBTTagConfigSerializer.java b/src/main/java/org/bukkit/craftbukkit/util/CraftNBTTagConfigSerializer.java
|
||||
index a7f4054002bd176fccf8357e9a23de66dd9e0dc5..207e4302161b3abe2ade56c9dc9c31820010fa42 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftNBTTagConfigSerializer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftNBTTagConfigSerializer.java
|
||||
@@ -19,7 +19,7 @@ import net.minecraft.nbt.TagParser;
|
||||
public class CraftNBTTagConfigSerializer {
|
||||
|
||||
private static final Pattern ARRAY = Pattern.compile("^\\[.*]");
|
||||
- private static final Pattern INTEGER = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)?i", Pattern.CASE_INSENSITIVE);
|
||||
+ private static final Pattern INTEGER = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)i", Pattern.CASE_INSENSITIVE); // Paper - fix regex
|
||||
private static final Pattern DOUBLE = Pattern.compile("[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?d", Pattern.CASE_INSENSITIVE);
|
||||
private static final TagParser MOJANGSON_PARSER = new TagParser(new StringReader(""));
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <zach@zachbr.io>
|
||||
Date: Tue, 23 Jul 2019 20:44:47 -0500
|
||||
Subject: [PATCH] Do not let the server load chunks from newer versions
|
||||
|
||||
If the server attempts to load a chunk generated by a newer version of
|
||||
the game, immediately stop the server to prevent data corruption.
|
||||
|
||||
You can override this functionality at your own peril.
|
||||
|
||||
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 89c367f542aee35ba9f596d678bfeb5412c1697d..4236cf65b893bc21d2597010a2f9745fc0e107a4 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
|
||||
@@ -126,9 +126,22 @@ public class ChunkSerializer {
|
||||
return holder.protoChunk;
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ private static final int CURRENT_DATA_VERSION = SharedConstants.getCurrentVersion().getDataVersion().getVersion();
|
||||
+ private static final boolean JUST_CORRUPT_IT = Boolean.getBoolean("Paper.ignoreWorldDataVersion");
|
||||
+ // Paper end
|
||||
public static InProgressChunkHolder loadChunk(ServerLevel world, PoiManager poiStorage, ChunkPos chunkPos, CompoundTag nbt, boolean distinguish) {
|
||||
java.util.ArrayDeque<Runnable> tasksToExecuteOnMain = new java.util.ArrayDeque<>();
|
||||
// Paper end
|
||||
+ // Paper start - Do NOT attempt to load chunks saved with newer versions
|
||||
+ if (nbt.contains("DataVersion", 99)) {
|
||||
+ int dataVersion = nbt.getInt("DataVersion");
|
||||
+ if (!JUST_CORRUPT_IT && dataVersion > CURRENT_DATA_VERSION) {
|
||||
+ new RuntimeException("Server attempted to load chunk saved with newer version of minecraft! " + dataVersion + " > " + CURRENT_DATA_VERSION).printStackTrace();
|
||||
+ System.exit(1);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
ChunkPos chunkcoordintpair1 = new ChunkPos(nbt.getInt("xPos"), nbt.getInt("zPos")); // Paper - diff on change, see ChunkSerializer#getChunkCoordinate
|
||||
|
||||
if (!Objects.equals(chunkPos, chunkcoordintpair1)) {
|
|
@ -1,75 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: DigitalRegent <misterwener@gmail.com>
|
||||
Date: Sat, 11 Apr 2020 13:10:58 +0200
|
||||
Subject: [PATCH] Brand support
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index f6012bf8134f0606710511150dd296a1d677334d..6e7d909bd87a1732e99c68d2baf57042d7e930fe 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -298,6 +298,8 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
private static final long KEEPALIVE_LIMIT = Long.getLong("paper.playerconnection.keepalive", 30) * 1000; // Paper - provide property to set keepalive limit
|
||||
private static final int MAX_SIGN_LINE_LENGTH = Integer.getInteger("Paper.maxSignLength", 80); // Paper
|
||||
|
||||
+ private String clientBrandName = null; // Paper - Brand name
|
||||
+
|
||||
public ServerGamePacketListenerImpl(MinecraftServer server, Connection connection, ServerPlayer player) {
|
||||
this.lastChatTimeStamp = new AtomicReference(Instant.EPOCH);
|
||||
this.lastSeenMessagesValidator = new LastSeenMessagesValidator();
|
||||
@@ -3454,6 +3456,8 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
private static final ResourceLocation CUSTOM_REGISTER = new ResourceLocation("register");
|
||||
private static final ResourceLocation CUSTOM_UNREGISTER = new ResourceLocation("unregister");
|
||||
|
||||
+ private static final ResourceLocation MINECRAFT_BRAND = new ResourceLocation("brand"); // Paper - Brand support
|
||||
+
|
||||
@Override
|
||||
public void handleCustomPayload(ServerboundCustomPayloadPacket packet) {
|
||||
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel());
|
||||
@@ -3481,6 +3485,15 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
try {
|
||||
byte[] data = new byte[packet.data.readableBytes()];
|
||||
packet.data.readBytes(data);
|
||||
+ // Paper start - Brand support
|
||||
+ if (packet.identifier.equals(MINECRAFT_BRAND)) {
|
||||
+ try {
|
||||
+ this.clientBrandName = new net.minecraft.network.FriendlyByteBuf(io.netty.buffer.Unpooled.copiedBuffer(data)).readUtf(256);
|
||||
+ } catch (StringIndexOutOfBoundsException ex) {
|
||||
+ this.clientBrandName = "illegal";
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.cserver.getMessenger().dispatchIncomingMessage(this.player.getBukkitEntity(), packet.identifier.toString(), data);
|
||||
} catch (Exception ex) {
|
||||
ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t dispatch custom payload", ex);
|
||||
@@ -3490,6 +3503,12 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
|
||||
}
|
||||
|
||||
+ // Paper start - brand support
|
||||
+ public String getClientBrandName() {
|
||||
+ return clientBrandName;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public final boolean isDisconnected() {
|
||||
return (!this.player.joining && !this.connection.isConnected()) || this.processedDisconnect; // Paper
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index a9ec1f77b7b9e60d735c72a01f0bce32d3083cb9..d06d1bb3c426304aa222721285574368db24368e 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -2764,6 +2764,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
// Paper end
|
||||
};
|
||||
|
||||
+ // Paper start - brand support
|
||||
+ @Override
|
||||
+ public String getClientBrandName() {
|
||||
+ return getHandle().connection != null ? getHandle().connection.getClientBrandName() : null;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public Player.Spigot spigot()
|
||||
{
|
||||
return this.spigot;
|
|
@ -1,37 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mariell Hoversholm <proximyst@proximyst.com>
|
||||
Date: Sat, 22 Aug 2020 23:59:30 +0200
|
||||
Subject: [PATCH] Add #setMaxPlayers API
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 7528491e129b250da5cb505d7befceee8cfe74e6..fcd2f8514e60e1faafec787f162baf98663fb734 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -147,7 +147,7 @@ public abstract class PlayerList {
|
||||
public final PlayerDataStorage playerIo;
|
||||
private boolean doWhiteList;
|
||||
private final RegistryAccess.Frozen registryHolder;
|
||||
- protected final int maxPlayers;
|
||||
+ protected int maxPlayers; public final void setMaxPlayers(int maxPlayers) { this.maxPlayers = maxPlayers; } // Paper - remove final and add setter
|
||||
private int viewDistance;
|
||||
private int simulationDistance;
|
||||
private boolean allowCheatsForAllPlayers;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 2aab13270af76bcc1b62787e9910d23d5ab56add..50a540f796f4d418ae5f5377b39a08bc3e02543e 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -674,6 +674,13 @@ public final class CraftServer implements Server {
|
||||
return this.playerList.getMaxPlayers();
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void setMaxPlayers(int maxPlayers) {
|
||||
+ this.playerList.setMaxPlayers(maxPlayers);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
// NOTE: These are dependent on the corresponding call in MinecraftServer
|
||||
// so if that changes this will need to as well
|
||||
@Override
|
|
@ -1,21 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <blake.galbreath@gmail.com>
|
||||
Date: Sun, 23 Aug 2020 19:36:22 +0200
|
||||
Subject: [PATCH] Add playPickupItemAnimation to LivingEntity
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
index b9c3683fca1ac85d8f18ab7629a51836248169ca..128db5db4b15b933520f2e864be4d8f7a5c845af 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
@@ -884,5 +884,10 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
|
||||
((Mob) getHandle()).getJumpControl().jump();
|
||||
}
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public void playPickupItemAnimation(org.bukkit.entity.Item item, int quantity) {
|
||||
+ getHandle().take(((CraftItem) item).getHandle(), quantity);
|
||||
+ }
|
||||
// Paper end
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mariell Hoversholm <proximyst@proximyst.com>
|
||||
Date: Sun, 23 Aug 2020 19:01:04 +0200
|
||||
Subject: [PATCH] Don't require FACING data
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java
|
||||
index da6a145b06e217ff82b0a1b04410238dc50d4869..1e6ba6d9cceda1d4867b183c3dbc03d317ed287f 100644
|
||||
--- a/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java
|
||||
+++ b/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java
|
||||
@@ -14,6 +14,7 @@ import org.bukkit.event.block.BlockDispenseEvent;
|
||||
// CraftBukkit end
|
||||
|
||||
public class DefaultDispenseItemBehavior implements DispenseItemBehavior {
|
||||
+ private Direction enumdirection; // Paper
|
||||
|
||||
// CraftBukkit start
|
||||
private boolean dropper;
|
||||
@@ -27,15 +28,16 @@ public class DefaultDispenseItemBehavior implements DispenseItemBehavior {
|
||||
|
||||
@Override
|
||||
public final ItemStack dispense(BlockSource pointer, ItemStack stack) {
|
||||
+ enumdirection = pointer.getBlockState().getValue(DispenserBlock.FACING); // Paper - cache facing direction
|
||||
ItemStack itemstack1 = this.execute(pointer, stack);
|
||||
|
||||
this.playSound(pointer);
|
||||
- this.playAnimation(pointer, (Direction) pointer.getBlockState().getValue(DispenserBlock.FACING));
|
||||
+ this.playAnimation(pointer, enumdirection); // Paper - cache facing direction
|
||||
return itemstack1;
|
||||
}
|
||||
|
||||
protected ItemStack execute(BlockSource pointer, ItemStack stack) {
|
||||
- Direction enumdirection = (Direction) pointer.getBlockState().getValue(DispenserBlock.FACING);
|
||||
+ // Paper - cached enum direction
|
||||
Position iposition = DispenserBlock.getDispensePosition(pointer);
|
||||
ItemStack itemstack1 = stack.split(1);
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <blake.galbreath@gmail.com>
|
||||
Date: Sat, 22 Aug 2020 23:36:21 +0200
|
||||
Subject: [PATCH] Fix SpawnChangeEvent not firing for all use-cases
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 5537903d6e1233489d31127f3af3d99c40258eb4..12534be05aa56930cde39e6fef90d402b5eb7c4e 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1893,6 +1893,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
//ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(new BlockPosition(this.worldData.a(), 0, this.worldData.c()));
|
||||
|
||||
this.levelData.setSpawn(pos, angle);
|
||||
+ new org.bukkit.event.world.SpawnChangeEvent(getWorld(), MCUtil.toLocation(this, prevSpawn)).callEvent(); // Paper
|
||||
if (this.keepSpawnInMemory) {
|
||||
// if this keepSpawnInMemory is false a plugin has already removed our tickets, do not re-add
|
||||
this.removeTicketsForSpawn(this.paperConfig().spawn.keepSpawnLoadedRange * 16, prevSpawn);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index 643b682db12560fc3409ede861a4e0aea8fc5360..ca768eea4f4ad7196f6f595516683b28372de71a 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -263,11 +263,13 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
public boolean setSpawnLocation(int x, int y, int z, float angle) {
|
||||
try {
|
||||
Location previousLocation = this.getSpawnLocation();
|
||||
- world.levelData.setSpawn(new BlockPos(x, y, z), angle);
|
||||
+ world.setDefaultSpawnPos(new BlockPos(x, y, z), angle); // Paper - use WorldServer#setSpawn
|
||||
|
||||
+ // Paper start - move to nms.World
|
||||
// Notify anyone who's listening.
|
||||
- SpawnChangeEvent event = new SpawnChangeEvent(this, previousLocation);
|
||||
- this.server.getPluginManager().callEvent(event);
|
||||
+ // SpawnChangeEvent event = new SpawnChangeEvent(this, previousLocation);
|
||||
+ // server.getPluginManager().callEvent(event);
|
||||
+ // Paper end
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
|
@ -1,22 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sun, 23 Aug 2020 16:32:11 +0200
|
||||
Subject: [PATCH] Add moon phase API
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
|
||||
index e395628ccf59c1b7a4efcabb3c38e8a879b95e38..ee5e59c37301d9a806e2f696d52d9d217b232833 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
|
||||
@@ -932,4 +932,11 @@ public abstract class CraftRegionAccessor implements RegionAccessor {
|
||||
|
||||
throw new IllegalArgumentException("Cannot spawn an entity for " + clazz.getName());
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public io.papermc.paper.world.MoonPhase getMoonPhase() {
|
||||
+ return io.papermc.paper.world.MoonPhase.getPhase(this.getHandle().dayTime() / 24000L);
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: commandblockguy <commandblockguy1@gmail.com>
|
||||
Date: Fri, 14 Aug 2020 14:44:14 -0500
|
||||
Subject: [PATCH] Prevent headless pistons from being created
|
||||
|
||||
Prevent headless pistons from being created by explosions or tree/mushroom growth.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
index b18b0e1b5e059f08fd3117eaa0fb28a10fac6562..01477e7240f9e33d08d416a7d40ee10f3e5d4abf 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
@@ -187,6 +187,15 @@ public class Explosion {
|
||||
|
||||
if (f > 0.0F && this.damageCalculator.shouldBlockExplode(this, this.level, blockposition, iblockdata, f)) {
|
||||
set.add(blockposition);
|
||||
+ // Paper start - prevent headless pistons from forming
|
||||
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowHeadlessPistons && iblockdata.getBlock() == Blocks.MOVING_PISTON) {
|
||||
+ BlockEntity extension = this.level.getBlockEntity(blockposition);
|
||||
+ if (extension instanceof net.minecraft.world.level.block.piston.PistonMovingBlockEntity blockEntity && blockEntity.isSourcePiston()) {
|
||||
+ net.minecraft.core.Direction direction = iblockdata.getValue(net.minecraft.world.level.block.piston.PistonHeadBlock.FACING);
|
||||
+ set.add(blockposition.relative(direction.getOpposite()));
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
d4 += d0 * 0.30000001192092896D;
|
|
@ -1,28 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eearslya Sleiarion <eearslya@gmail.com>
|
||||
Date: Sun, 23 Aug 2020 13:04:02 +0200
|
||||
Subject: [PATCH] Add BellRingEvent
|
||||
|
||||
Add a new event, BellRingEvent, to trigger whenever a player rings a
|
||||
village bell. Passes along the bell block and the player who rang it.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/BellBlock.java b/src/main/java/net/minecraft/world/level/block/BellBlock.java
|
||||
index 8ccf71bddb2637a9e468e3d958665bbd58c37647..8878d8882d7aee4d44ad8339daff180812912649 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/BellBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/BellBlock.java
|
||||
@@ -3,6 +3,7 @@ package net.minecraft.world.level.block;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
+import io.papermc.paper.util.MCUtil;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.stats.Stats;
|
||||
@@ -131,6 +132,7 @@ public class BellBlock extends BaseEntityBlock {
|
||||
direction = world.getBlockState(pos).getValue(FACING);
|
||||
}
|
||||
|
||||
+ if (!new io.papermc.paper.event.block.BellRingEvent(world.getWorld().getBlockAt(MCUtil.toLocation(world, pos)), entity == null ? null : entity.getBukkitEntity()).callEvent()) return false; // Paper - BellRingEvent
|
||||
((BellBlockEntity)blockEntity).onHit(direction);
|
||||
world.playSound((Player)null, pos, SoundEvents.BELL_BLOCK, SoundSource.BLOCKS, 2.0F, 1.0F);
|
||||
world.gameEvent(entity, GameEvent.BLOCK_CHANGE, pos);
|
|
@ -1,19 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sun, 23 Aug 2020 15:47:34 +0200
|
||||
Subject: [PATCH] Add zombie targets turtle egg config
|
||||
|
||||
|
||||
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 473782e8b6a760aec492fa28270a7eb05a484e78..d5633a869819b26376c01d38e08763457e3b7b68 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
@@ -107,7 +107,7 @@ public class Zombie extends Monster {
|
||||
|
||||
@Override
|
||||
protected void registerGoals() {
|
||||
- this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0D, 3));
|
||||
+ if (level.paperConfig().entities.behavior.zombiesTargetTurtleEggs) this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0D, 3)); // Paper
|
||||
this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F));
|
||||
this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
|
||||
this.addBehaviourGoals();
|
|
@ -1,37 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Wed, 19 Aug 2020 05:05:54 +0100
|
||||
Subject: [PATCH] Buffer joins to world
|
||||
|
||||
This patch buffers the number of logins which will attempt to join
|
||||
the world per tick, this attempts to reduce the impact that join floods
|
||||
has on the server
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
|
||||
index dca0c978b30962d4216dc443d7d105e54a29ae1b..3ae55dd6441b2dfdb67eb2f24ecf885bab89e7a6 100644
|
||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
||||
@@ -434,8 +434,23 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
}
|
||||
// Paper end
|
||||
|
||||
+ private static final int MAX_PER_TICK = io.papermc.paper.configuration.GlobalConfiguration.get().misc.maxJoinsPerTick; // Paper
|
||||
+ private static int joinAttemptsThisTick; // Paper
|
||||
+ private static int currTick; // Paper
|
||||
public void tick() {
|
||||
this.flushQueue();
|
||||
+ // Paper start
|
||||
+ if (currTick != net.minecraft.server.MinecraftServer.currentTick) {
|
||||
+ currTick = net.minecraft.server.MinecraftServer.currentTick;
|
||||
+ joinAttemptsThisTick = 0;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+ if (this.packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl) {
|
||||
+ if ( ((net.minecraft.server.network.ServerLoginPacketListenerImpl) this.packetListener).state != net.minecraft.server.network.ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT // Paper
|
||||
+ || (joinAttemptsThisTick++ < MAX_PER_TICK)) { // Paper - limit the number of joins which can be processed each tick
|
||||
+ ((net.minecraft.server.network.ServerLoginPacketListenerImpl) this.packetListener).tick();
|
||||
+ } // Paper
|
||||
+ }
|
||||
PacketListener packetlistener = this.packetListener;
|
||||
|
||||
if (packetlistener instanceof TickablePacketListener) {
|
File diff suppressed because it is too large
Load diff
|
@ -1,39 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: JRoy <joshroy126@gmail.com>
|
||||
Date: Thu, 27 Aug 2020 16:57:25 -0400
|
||||
Subject: [PATCH] Fix hex colors not working in some kick messages
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
|
||||
index 34e4d00ede62be50808a2782e54da987cc62c9af..e12c67bdfa326b3f52f6a4973063cef44359b804 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
|
||||
@@ -76,12 +76,12 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL
|
||||
}
|
||||
// CraftBukkit end
|
||||
if (packet.getProtocolVersion() != SharedConstants.getCurrentVersion().getProtocolVersion()) {
|
||||
- MutableComponent ichatmutablecomponent;
|
||||
+ Component ichatmutablecomponent; // Paper - Fix hex colors not working in some kick messages
|
||||
|
||||
if (packet.getProtocolVersion() < 754) {
|
||||
- ichatmutablecomponent = Component.literal( java.text.MessageFormat.format( org.spigotmc.SpigotConfig.outdatedClientMessage.replaceAll("'", "''"), SharedConstants.getCurrentVersion().getName() ) ); // Spigot
|
||||
+ ichatmutablecomponent = org.bukkit.craftbukkit.util.CraftChatMessage.fromString( java.text.MessageFormat.format( org.spigotmc.SpigotConfig.outdatedClientMessage.replaceAll("'", "''"), SharedConstants.getCurrentVersion().getName() ) , true )[0]; // Spigot // Paper - Fix hex colors not working in some kick messages
|
||||
} else {
|
||||
- ichatmutablecomponent = Component.literal( java.text.MessageFormat.format( org.spigotmc.SpigotConfig.outdatedServerMessage.replaceAll("'", "''"), SharedConstants.getCurrentVersion().getName() ) ); // Spigot
|
||||
+ ichatmutablecomponent = org.bukkit.craftbukkit.util.CraftChatMessage.fromString( java.text.MessageFormat.format( org.spigotmc.SpigotConfig.outdatedServerMessage.replaceAll("'", "''"), SharedConstants.getCurrentVersion().getName() ) , true )[0]; // Spigot // Paper - Fix hex colors not working in some kick messages
|
||||
}
|
||||
|
||||
this.connection.send(new ClientboundLoginDisconnectPacket(ichatmutablecomponent));
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index c3027735725c68eeb1b42a42ebb8646f3a35a518..8eec59b01b8366a0ee8c926d9bf77b22a8d75cb7 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -107,7 +107,7 @@ public class ServerLoginPacketListenerImpl implements TickablePacketListener, Se
|
||||
// CraftBukkit start
|
||||
@Deprecated
|
||||
public void disconnect(String s) {
|
||||
- this.disconnect(Component.literal(s));
|
||||
+ this.disconnect(org.bukkit.craftbukkit.util.CraftChatMessage.fromString(s, true)[0]); // Paper - Fix hex colors not working in some kick messages
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
|
@ -1,138 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mariell Hoversholm <proximyst@proximyst.com>
|
||||
Date: Fri, 21 Aug 2020 20:57:54 +0200
|
||||
Subject: [PATCH] PortalCreateEvent needs to know its entity
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
|
||||
index 85dead69d41ca10ad76fdab13da8548d359142b0..0bd7b64bd1c468221d3354494527b456bc02437a 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
|
||||
@@ -431,7 +431,7 @@ public final class ItemStack {
|
||||
net.minecraft.world.level.block.state.BlockState block = world.getBlockState(newblockposition);
|
||||
|
||||
if (!(block.getBlock() instanceof BaseEntityBlock)) { // Containers get placed automatically
|
||||
- block.getBlock().onPlace(block, world, newblockposition, oldBlock, true);
|
||||
+ block.getBlock().onPlace(block, world, newblockposition, oldBlock, true, itemactioncontext); // Paper - pass itemactioncontext
|
||||
}
|
||||
|
||||
world.notifyAndUpdatePhysics(newblockposition, null, oldBlock, block, world.getBlockState(newblockposition), updateFlag, 512); // send null chunk as chunk.k() returns false by this point
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/BaseFireBlock.java b/src/main/java/net/minecraft/world/level/block/BaseFireBlock.java
|
||||
index 378d4316a51d48cb84e2d8a553f7b28bae55630e..922b5b22a4ccfeead9d6d2b9a2a2b3cc8a1e6c55 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/BaseFireBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/BaseFireBlock.java
|
||||
@@ -139,20 +139,23 @@ public abstract class BaseFireBlock extends Block {
|
||||
super.entityInside(state, world, pos, entity);
|
||||
}
|
||||
|
||||
+ // Paper start - ItemActionContext param
|
||||
+ @Override public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) { this.onPlace(state, world, pos, oldState, notify, null); }
|
||||
@Override
|
||||
- public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) {
|
||||
- if (!oldState.is(state.getBlock())) {
|
||||
+ public void onPlace(BlockState iblockdata, Level world, BlockPos blockposition, BlockState iblockdata1, boolean flag, net.minecraft.world.item.context.UseOnContext itemActionContext) {
|
||||
+ // Paper end
|
||||
+ if (!iblockdata1.is(iblockdata.getBlock())) {
|
||||
if (BaseFireBlock.inPortalDimension(world)) {
|
||||
- Optional<PortalShape> optional = PortalShape.findEmptyPortalShape(world, pos, Direction.Axis.X);
|
||||
+ Optional<PortalShape> optional = PortalShape.findEmptyPortalShape(world, blockposition, Direction.Axis.X);
|
||||
|
||||
if (optional.isPresent()) {
|
||||
- ((PortalShape) optional.get()).createPortalBlocks();
|
||||
+ ((PortalShape) optional.get()).createPortalBlocks(itemActionContext); // Paper - pass ItemActionContext param
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
- if (!state.canSurvive(world, pos)) {
|
||||
- this.fireExtinguished(world, pos); // CraftBukkit - fuel block broke
|
||||
+ if (!iblockdata.canSurvive(world, blockposition)) {
|
||||
+ fireExtinguished(world, blockposition); // CraftBukkit - fuel block broke
|
||||
}
|
||||
|
||||
}
|
||||
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 8d79612cdba48756bb0352c41b98f8a9ea489ff6..f17233ea94d61af41b4db1696b114e9c721466f8 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/FireBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/FireBlock.java
|
||||
@@ -12,6 +12,7 @@ import net.minecraft.core.Direction;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
+import net.minecraft.world.item.context.UseOnContext;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.GameRules;
|
||||
import net.minecraft.world.level.Level;
|
||||
@@ -356,9 +357,11 @@ public class FireBlock extends BaseFireBlock {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) {
|
||||
- super.onPlace(state, world, pos, oldState, notify);
|
||||
- world.scheduleTick(pos, (Block) this, FireBlock.getFireTickDelay(world.random));
|
||||
+ // Paper start - ItemActionContext param
|
||||
+ public void onPlace(BlockState iblockdata, Level world, BlockPos blockposition, BlockState iblockdata1, boolean flag, UseOnContext itemActionContext) {
|
||||
+ super.onPlace(iblockdata, world, blockposition, iblockdata1, flag, itemActionContext);
|
||||
+ // Paper end
|
||||
+ world.scheduleTick(blockposition, this, getFireTickDelay(world.random));
|
||||
}
|
||||
|
||||
private static int getFireTickDelay(RandomSource random) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
index b2ab7749e3ddf124d5ef97271a76dc875a650771..97b0e820d353e8ab4ca9d9e2efd0a8819119b2ab 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
@@ -35,6 +35,7 @@ import net.minecraft.world.item.DyeColor;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
+import net.minecraft.world.item.context.UseOnContext;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.EmptyBlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
@@ -136,6 +137,12 @@ public abstract class BlockBehaviour {
|
||||
DebugPackets.sendNeighborsUpdatePacket(world, pos);
|
||||
}
|
||||
|
||||
+ // Paper start - add ItemActionContext param
|
||||
+ @Deprecated
|
||||
+ public void onPlace(BlockState iblockdata, Level world, BlockPos blockposition, BlockState iblockdata1, boolean flag, UseOnContext itemActionContext) {
|
||||
+ this.onPlace(iblockdata, world, blockposition, iblockdata1, flag);
|
||||
+ }
|
||||
+ // Paper end
|
||||
/** @deprecated */
|
||||
@Deprecated
|
||||
public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/portal/PortalShape.java b/src/main/java/net/minecraft/world/level/portal/PortalShape.java
|
||||
index 4d9023d1baa06802ab97af4be2739c13dee4f9b9..0ef049f0fac81312bee4f0e0c14dc3e74b09d272 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/portal/PortalShape.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/portal/PortalShape.java
|
||||
@@ -10,6 +10,7 @@ import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.EntityDimensions;
|
||||
+import net.minecraft.world.item.context.UseOnContext;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.NetherPortalBlock;
|
||||
@@ -184,7 +185,10 @@ public class PortalShape {
|
||||
}
|
||||
|
||||
// CraftBukkit start - return boolean
|
||||
- public boolean createPortalBlocks() {
|
||||
+ // Paper start - ItemActionContext param
|
||||
+ @Deprecated public boolean createPortalBlocks() { return this.createPortalBlocks(null); }
|
||||
+ public boolean createPortalBlocks(UseOnContext itemActionContext) {
|
||||
+ // Paper end
|
||||
org.bukkit.World bworld = this.level.getMinecraftWorld().getWorld();
|
||||
|
||||
// Copy below for loop
|
||||
@@ -194,7 +198,7 @@ public class PortalShape {
|
||||
this.blocks.setBlock(blockposition, iblockdata, 18);
|
||||
});
|
||||
|
||||
- PortalCreateEvent event = new PortalCreateEvent((java.util.List<org.bukkit.block.BlockState>) (java.util.List) this.blocks.getList(), bworld, null, PortalCreateEvent.CreateReason.FIRE);
|
||||
+ PortalCreateEvent event = new PortalCreateEvent((java.util.List<org.bukkit.block.BlockState>) (java.util.List) blocks.getList(), bworld, itemActionContext == null || itemActionContext.getPlayer() == null ? null : itemActionContext.getPlayer().getBukkitEntity(), PortalCreateEvent.CreateReason.FIRE); // Paper - pass entity param
|
||||
this.level.getMinecraftWorld().getServer().server.getPluginManager().callEvent(event);
|
||||
|
||||
if (event.isCancelled()) {
|
|
@ -1,19 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: foss-mc <69294560+foss-mc@users.noreply.github.com>
|
||||
Date: Sun, 30 Aug 2020 15:30:29 +0800
|
||||
Subject: [PATCH] Fix CraftTeam null check
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java
|
||||
index 18d5a26c34c848241c306241b3ad9825b5a0b9a9..60b1cffdccde4715832546d6edbf206fbab4e82f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java
|
||||
@@ -261,7 +261,7 @@ final class CraftTeam extends CraftScoreboardComponent implements Team {
|
||||
|
||||
@Override
|
||||
public boolean hasEntry(String entry) throws IllegalArgumentException, IllegalStateException {
|
||||
- Validate.notNull("Entry cannot be null");
|
||||
+ Validate.notNull(entry, "Entry cannot be null"); // Paper
|
||||
|
||||
CraftScoreboard scoreboard = this.checkState();
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sun, 23 Aug 2020 15:28:35 +0200
|
||||
Subject: [PATCH] Add more Evoker API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.monster.Evoker setWololoTarget(Lnet/minecraft/world/entity/animal/Sheep;)V
|
||||
public net.minecraft.world.entity.monster.Evoker getWololoTarget()Lnet/minecraft/world/entity/animal/Sheep;
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEvoker.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEvoker.java
|
||||
index 91d07e6996e315734689ea25336992b0ed21cf25..7e861636710aa44ed36e7f20c6320dabb809c35d 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEvoker.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEvoker.java
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.bukkit.craftbukkit.entity;
|
||||
|
||||
+import net.minecraft.world.entity.animal.Sheep;
|
||||
import net.minecraft.world.entity.monster.SpellcasterIllager;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.bukkit.entity.EntityType;
|
||||
@@ -35,4 +36,17 @@ public class CraftEvoker extends CraftSpellcaster implements Evoker {
|
||||
public void setCurrentSpell(Evoker.Spell spell) {
|
||||
this.getHandle().setIsCastingSpell(spell == null ? SpellcasterIllager.IllagerSpell.NONE : SpellcasterIllager.IllagerSpell.byId(spell.ordinal()));
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public org.bukkit.entity.Sheep getWololoTarget() {
|
||||
+ Sheep sheep = getHandle().getWololoTarget();
|
||||
+ return sheep == null ? null : (org.bukkit.entity.Sheep) sheep.getBukkitEntity();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setWololoTarget(org.bukkit.entity.Sheep sheep) {
|
||||
+ getHandle().setWololoTarget(sheep == null ? null : ((org.bukkit.craftbukkit.entity.CraftSheep) sheep).getHandle());
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Tue, 11 Aug 2020 19:16:09 +0200
|
||||
Subject: [PATCH] Add methods to get translation keys
|
||||
|
||||
== AT ==
|
||||
public org.bukkit.craftbukkit.inventory.CraftMetaFirework
|
||||
public org.bukkit.craftbukkit.inventory.CraftMetaFirework getNBT(Lorg/bukkit/FireworkEffect$Type;)I
|
||||
|
||||
Co-authored-by: MeFisto94 <MeFisto94@users.noreply.github.com>
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
index ea3358905dcd39a1a855d98570457c65dcd7513d..396fb96abed1e77893d8ee8a15cff18cad804475 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
@@ -668,5 +668,15 @@ public class CraftBlock implements Block {
|
||||
public org.bukkit.SoundGroup getBlockSoundGroup() {
|
||||
return org.bukkit.craftbukkit.CraftSoundGroup.getSoundGroup(this.getNMS().getSoundType());
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public String getTranslationKey() {
|
||||
+ return this.translationKey();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String translationKey() {
|
||||
+ return org.bukkit.Bukkit.getUnsafe().getTranslationKey(this);
|
||||
+ }
|
||||
// Paper end
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java b/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java
|
||||
index a859a675b4bc543e139358223cc92ad5eee3ddb5..31a22f26070059e5379730c1940ff1c5fb109be1 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java
|
||||
@@ -194,6 +194,11 @@ public class CraftEnchantment extends Enchantment {
|
||||
public net.kyori.adventure.text.Component displayName(int level) {
|
||||
return io.papermc.paper.adventure.PaperAdventure.asAdventure(getHandle().getFullname(level));
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public String translationKey() {
|
||||
+ return this.target.getDescriptionId();
|
||||
+ }
|
||||
// Paper end
|
||||
|
||||
public net.minecraft.world.item.enchantment.Enchantment getHandle() {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
index b38b2b3855583b26d7ed2ede041a73cf14cbe81c..8b0090ba3359c68aa98c0cf74e0dc0b3e9143577 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
@@ -483,6 +483,30 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
Preconditions.checkArgument(dataVersion <= getDataVersion(), "Newer version! Server downgrades are not supported!");
|
||||
return compound;
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public String getTranslationKey(Material mat) {
|
||||
+ if (mat.isBlock()) {
|
||||
+ return getBlock(mat).getDescriptionId();
|
||||
+ }
|
||||
+ return getItem(mat).getDescriptionId();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String getTranslationKey(org.bukkit.block.Block block) {
|
||||
+ return ((org.bukkit.craftbukkit.block.CraftBlock)block).getNMS().getBlock().getDescriptionId();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String getTranslationKey(org.bukkit.entity.EntityType type) {
|
||||
+ return net.minecraft.world.entity.EntityType.byString(type.getName()).map(net.minecraft.world.entity.EntityType::getDescriptionId).orElse(null);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String getTranslationKey(org.bukkit.inventory.ItemStack itemStack) {
|
||||
+ net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(itemStack);
|
||||
+ return nmsItemStack.getItem().getDescriptionId(nmsItemStack);
|
||||
+ }
|
||||
// Paper end
|
||||
|
||||
/**
|
||||
diff --git a/src/test/java/io/papermc/paper/world/TranslationKeyTest.java b/src/test/java/io/papermc/paper/world/TranslationKeyTest.java
|
||||
index fab3063fffa959ac7f0eb5937f2fae94d11b6591..9292a0119499d14c9ed170999ac3b8dfdd1f839a 100644
|
||||
--- a/src/test/java/io/papermc/paper/world/TranslationKeyTest.java
|
||||
+++ b/src/test/java/io/papermc/paper/world/TranslationKeyTest.java
|
||||
@@ -1,12 +1,29 @@
|
||||
package io.papermc.paper.world;
|
||||
|
||||
import com.destroystokyo.paper.ClientOption;
|
||||
+import net.minecraft.core.Registry;
|
||||
+import net.minecraft.core.RegistryAccess;
|
||||
+import net.minecraft.network.chat.contents.TranslatableContents;
|
||||
+import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.entity.player.ChatVisiblity;
|
||||
+import net.minecraft.world.item.CreativeModeTab;
|
||||
+import net.minecraft.world.level.GameType;
|
||||
+import net.minecraft.world.level.biome.Biome;
|
||||
import org.bukkit.Difficulty;
|
||||
+import org.bukkit.FireworkEffect;
|
||||
+import org.bukkit.GameMode;
|
||||
+import org.bukkit.GameRule;
|
||||
+import org.bukkit.attribute.Attribute;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftCreativeCategory;
|
||||
+import org.bukkit.inventory.CreativeCategory;
|
||||
+import org.bukkit.support.AbstractTestingBase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
-public class TranslationKeyTest {
|
||||
+import java.util.Map;
|
||||
+import java.util.Objects;
|
||||
+
|
||||
+public class TranslationKeyTest extends AbstractTestingBase {
|
||||
|
||||
@Test
|
||||
public void testChatVisibilityKeys() {
|
||||
@@ -15,4 +32,60 @@ public class TranslationKeyTest {
|
||||
Assert.assertEquals(chatVisibility + "'s translation key doesn't match", ChatVisiblity.valueOf(chatVisibility.name()).getKey(), chatVisibility.translationKey());
|
||||
}
|
||||
}
|
||||
+
|
||||
+ @Test
|
||||
+ public void testDifficultyKeys() {
|
||||
+ for (Difficulty bukkitDifficulty : Difficulty.values()) {
|
||||
+ Assert.assertEquals(bukkitDifficulty + "'s translation key doesn't match", ((TranslatableContents) net.minecraft.world.Difficulty.byId(bukkitDifficulty.ordinal()).getDisplayName().getContents()).getKey(), bukkitDifficulty.translationKey());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Test
|
||||
+ public void testGameruleKeys() {
|
||||
+ for (GameRule<?> rule : GameRule.values()) {
|
||||
+ Assert.assertEquals(rule.getName() + "'s translation doesn't match", org.bukkit.craftbukkit.CraftWorld.getGameRulesNMS().get(rule.getName()).getDescriptionId(), rule.translationKey());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Test
|
||||
+ public void testAttributeKeys() {
|
||||
+ for (Attribute attribute : Attribute.values()) {
|
||||
+ Assert.assertEquals("translation key mismatch for " + attribute, org.bukkit.craftbukkit.attribute.CraftAttributeMap.toMinecraft(attribute).getDescriptionId(), attribute.translationKey());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Test
|
||||
+ public void testFireworkEffectType() {
|
||||
+ for (FireworkEffect.Type type : FireworkEffect.Type.values()) {
|
||||
+ Assert.assertEquals("translation key mismatch for " + type, net.minecraft.world.item.FireworkRocketItem.Shape.byId(org.bukkit.craftbukkit.inventory.CraftMetaFirework.getNBT(type)).getName(), org.bukkit.FireworkEffect.Type.NAMES.key(type));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Test
|
||||
+ public void testCreativeCategory() {
|
||||
+ for (CreativeModeTab tab : CreativeModeTab.TABS) {
|
||||
+ if (tab == CreativeModeTab.TAB_SEARCH || tab == CreativeModeTab.TAB_HOTBAR || tab == CreativeModeTab.TAB_INVENTORY) { // not implemented in the api
|
||||
+ continue;
|
||||
+ }
|
||||
+ CreativeCategory category = Objects.requireNonNull(CraftCreativeCategory.fromNMS(tab));
|
||||
+ Assert.assertEquals("translation key mismatch for " + category, ((TranslatableContents) tab.getDisplayName().getContents()).getKey(), category.translationKey());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Test
|
||||
+ public void testGameMode() {
|
||||
+ for (GameType nms : GameType.values()) {
|
||||
+ GameMode bukkit = GameMode.getByValue(nms.getId());
|
||||
+ Assert.assertNotNull(bukkit);
|
||||
+ Assert.assertEquals("translation key mismatch for " + bukkit, ((TranslatableContents) nms.getLongDisplayName().getContents()).getKey(), bukkit.translationKey());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Test
|
||||
+ public void testBiome() {
|
||||
+ for (Map.Entry<ResourceKey<Biome>, Biome> nms : RegistryAccess.builtinCopy().registry(Registry.BIOME_REGISTRY).get().entrySet()) {
|
||||
+ org.bukkit.block.Biome bukkit = org.bukkit.block.Biome.valueOf(nms.getKey().location().getPath().toUpperCase());
|
||||
+ Assert.assertEquals("translation key mismatch for " + bukkit, nms.getKey().location().toLanguageKey("biome"), bukkit.translationKey());
|
||||
+ }
|
||||
+ }
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: ysl3000 <yannicklamprecht@live.de>
|
||||
Date: Mon, 6 Jul 2020 22:18:04 +0200
|
||||
Subject: [PATCH] Create HoverEvent from ItemStack Entity
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java
|
||||
index f05923a6292f02a01791627abce2770daff24b6a..f3a6a4d97b5be2e75c438a6f7010a8f588afe86c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java
|
||||
@@ -405,5 +405,40 @@ public final class CraftItemFactory implements ItemFactory {
|
||||
|
||||
return nms != null ? net.minecraft.locale.Language.getInstance().getOrDefault(nms.getItem().getDescriptionId(nms)) : null;
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(ItemStack itemStack) {
|
||||
+ net.md_5.bungee.api.chat.ItemTag itemTag = net.md_5.bungee.api.chat.ItemTag.ofNbt(CraftItemStack.asNMSCopy(itemStack).getOrCreateTag().toString());
|
||||
+ return new net.md_5.bungee.api.chat.hover.content.Item(
|
||||
+ itemStack.getType().getKey().toString(),
|
||||
+ itemStack.getAmount(),
|
||||
+ itemTag);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(org.bukkit.entity.Entity entity) {
|
||||
+ return hoverContentOf(entity, org.apache.commons.lang3.StringUtils.isBlank(entity.getCustomName()) ? null : new net.md_5.bungee.api.chat.TextComponent(entity.getCustomName()));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(org.bukkit.entity.Entity entity, String customName) {
|
||||
+ return hoverContentOf(entity, org.apache.commons.lang3.StringUtils.isBlank(customName) ? null : new net.md_5.bungee.api.chat.TextComponent(customName));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(org.bukkit.entity.Entity entity, net.md_5.bungee.api.chat.BaseComponent customName) {
|
||||
+ return new net.md_5.bungee.api.chat.hover.content.Entity(
|
||||
+ entity.getType().getKey().toString(),
|
||||
+ entity.getUniqueId().toString(),
|
||||
+ customName);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(org.bukkit.entity.Entity entity, net.md_5.bungee.api.chat.BaseComponent[] customName) {
|
||||
+ return new net.md_5.bungee.api.chat.hover.content.Entity(
|
||||
+ entity.getType().getKey().toString(),
|
||||
+ entity.getUniqueId().toString(),
|
||||
+ new net.md_5.bungee.api.chat.TextComponent(customName));
|
||||
+ }
|
||||
// Paper end
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: miclebrick <miclebrick@outlook.com>
|
||||
Date: Thu, 6 Dec 2018 19:52:50 -0500
|
||||
Subject: [PATCH] Cache block data strings
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index e42b12839faab0c040495b00368b107b35b93283..83a9c7f8a92055da43854d16fffe6892beff8c6b 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -2026,6 +2026,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.getPlayerList().reloadResources();
|
||||
this.functionManager.replaceLibrary(this.resources.managers.getFunctionLibrary());
|
||||
this.structureTemplateManager.onResourceManagerReload(this.resources.resourceManager);
|
||||
+ org.bukkit.craftbukkit.block.data.CraftBlockData.reloadCache(); // Paper - cache block data strings, they can be defined by datapacks so refresh it here
|
||||
}, this);
|
||||
|
||||
if (this.isSameThread()) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java
|
||||
index 514e1ab74cd24cfcf1dd031e69a8ebfaddf9d3dc..d02a5e383190fc4713141d953efc111bb2f7f89c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java
|
||||
@@ -506,9 +506,39 @@ public class CraftBlockData implements BlockData {
|
||||
Preconditions.checkState(CraftBlockData.MAP.put(nms, bukkit) == null, "Duplicate mapping %s->%s", nms, bukkit);
|
||||
}
|
||||
|
||||
+ // Paper start - cache block data strings
|
||||
+ private static Map<String, CraftBlockData> stringDataCache = new java.util.concurrent.ConcurrentHashMap<>();
|
||||
+
|
||||
+ static {
|
||||
+ // cache all of the default states at startup, will not cache ones with the custom states inside of the
|
||||
+ // brackets in a different order, though
|
||||
+ reloadCache();
|
||||
+ }
|
||||
+
|
||||
+ public static void reloadCache() {
|
||||
+ stringDataCache.clear();
|
||||
+ Block.BLOCK_STATE_REGISTRY.forEach(blockData -> stringDataCache.put(blockData.toString(), blockData.createCraftBlockData()));
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public static CraftBlockData newData(Material material, String data) {
|
||||
Preconditions.checkArgument(material == null || material.isBlock(), "Cannot get data for not block %s", material);
|
||||
|
||||
+ // Paper start - cache block data strings
|
||||
+ if (material != null) {
|
||||
+ Block block = CraftMagicNumbers.getBlock(material);
|
||||
+ if (block != null) {
|
||||
+ net.minecraft.resources.ResourceLocation key = Registry.BLOCK.getKey(block);
|
||||
+ data = data == null ? key.toString() : key + data;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ CraftBlockData cached = stringDataCache.computeIfAbsent(data, s -> createNewData(null, s));
|
||||
+ return (CraftBlockData) cached.clone();
|
||||
+ }
|
||||
+
|
||||
+ private static CraftBlockData createNewData(Material material, String data) {
|
||||
+ // Paper end - cache block data strings
|
||||
BlockState blockData;
|
||||
Block block = CraftMagicNumbers.getBlock(material);
|
||||
Map<Property<?>, Comparable<?>> parsed = null;
|
|
@ -1,83 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 25 Aug 2020 20:45:36 -0400
|
||||
Subject: [PATCH] Fix Entity Teleportation and cancel velocity if teleported
|
||||
|
||||
Uses correct setPositionRotation for Entity teleporting instead of setLocation
|
||||
as this is how Vanilla teleports entities.
|
||||
|
||||
Cancel any pending motion when teleported.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 6e7d909bd87a1732e99c68d2baf57042d7e930fe..434dc5ab5f02e66918f150c2db1d3cd35d58eece 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -760,7 +760,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
return;
|
||||
}
|
||||
|
||||
- this.player.absMoveTo(this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, this.player.getYRot(), this.player.getXRot());
|
||||
+ this.player.moveTo(this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, this.player.getYRot(), this.player.getXRot()); // Paper - use proper moveTo for teleportation
|
||||
this.lastGoodX = this.awaitingPositionFromClient.x;
|
||||
this.lastGoodY = this.awaitingPositionFromClient.y;
|
||||
this.lastGoodZ = this.awaitingPositionFromClient.z;
|
||||
@@ -1676,7 +1676,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
// CraftBukkit end
|
||||
|
||||
this.awaitingTeleportTime = this.tickCount;
|
||||
- this.player.absMoveTo(d0, d1, d2, f, f1);
|
||||
+ this.player.moveTo(d0, d1, d2, f, f1); // Paper - use proper moveTo for teleportation
|
||||
this.player.connection.send(new ClientboundPlayerPositionPacket(d0 - d3, d1 - d4, d2 - d5, f - f2, f1 - f3, set, this.awaitingTeleport, flag));
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 1582da75f92aed598c1c076af7b94af7ab48d10a..5a43e57d2e2146d324685808cfe980178bde03a2 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -158,6 +158,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
|
||||
// CraftBukkit start
|
||||
private static final int CURRENT_LEVEL = 2;
|
||||
+ public boolean preserveMotion = true; // Paper - keep initial motion on first setPositionRotation
|
||||
static boolean isLevelAtLeast(CompoundTag tag, int level) {
|
||||
return tag.contains("Bukkit.updateLevel") && tag.getInt("Bukkit.updateLevel") >= level;
|
||||
}
|
||||
@@ -1716,6 +1717,13 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
}
|
||||
|
||||
public void moveTo(double x, double y, double z, float yaw, float pitch) {
|
||||
+ // Paper - cancel entity velocity if teleported
|
||||
+ if (!preserveMotion) {
|
||||
+ this.deltaMovement = Vec3.ZERO;
|
||||
+ } else {
|
||||
+ this.preserveMotion = false;
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.setPosRaw(x, y, z);
|
||||
this.setYRot(yaw);
|
||||
this.setXRot(pitch);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
index 2e28bbd75c689ab5a004f0a2de4a89cde7a807ec..572982353530663825ab2d576c3277197a5715a3 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
@@ -163,6 +163,7 @@ public abstract class BaseSpawner {
|
||||
return;
|
||||
}
|
||||
|
||||
+ entity.preserveMotion = true; // Paper - preserve entity motion from tag
|
||||
entity.moveTo(entity.getX(), entity.getY(), entity.getZ(), randomsource.nextFloat() * 360.0F, 0.0F);
|
||||
if (entity instanceof Mob) {
|
||||
Mob entityinsentient = (Mob) entity;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
index ceb7123362ba85df825a50c035a399174b6634dc..52ccc5cb9c5512b30ce863062de85219adb801ae 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
@@ -561,7 +561,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
}
|
||||
|
||||
// entity.setLocation() throws no event, and so cannot be cancelled
|
||||
- this.entity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
|
||||
+ entity.moveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); // Paper - use proper moveTo, as per vanilla teleporting
|
||||
// SPIGOT-619: Force sync head rotation also
|
||||
this.entity.setYHeadRot(location.getYaw());
|
||||
|
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