9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2025-12-23 17:09:29 +00:00
Files
Leaf/patches/server/0059-PaperPR-Rewrite-framed-map-tracker-ticking.patch
2024-02-29 09:31:12 -05:00

304 lines
16 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Warrior <50800980+Warriorrrr@users.noreply.github.com>
Date: Mon, 14 Aug 2023 17:34:53 +0200
Subject: [PATCH] PaperPR: Rewrite framed map tracker ticking
Original license: GPLv3
Original project:
- https://github.com/PaperMC/Paper/pull/9605
- https://github.com/SparklyPower/SparklyPaper
Rewrites the tracking code for framed maps to remove the use of the tickCarriedBy method and the HoldingPlayer class.
The tickCarriedBy method contained a lot of code that did not apply to framed maps at all, and by moving the parts
that did elsewhere, we can essentially skip it. The only logic that's ran inside the ServerEntity#sendChanges for maps
now is just updating dirty map/decoration data.
When no bukkit renderers are added to the map, we also re-use the same packet for all players who are tracking it which avoids a lot of work.
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
index 60e8bfc89cfb92e2f7d4860b11c16b3bc5e2f095..b7c7e2727382d06c1ed83bac6e721e48f3d855d5 100644
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
@@ -111,29 +111,42 @@ public class ServerEntity {
Entity entity = this.entity;
- if (!this.trackedPlayers.isEmpty() && entity instanceof ItemFrame) { // Paper - Perf: Only tick item frames if players can see it
+ if (!this.trackedPlayers.isEmpty() && entity instanceof ItemFrame frame && frame.cachedMapId != null) { // Paper - Perf: Only tick item frames if players can see it // Paper
ItemFrame entityitemframe = (ItemFrame) entity;
if (true || this.tickCount % 10 == 0) { // CraftBukkit - Moved below, should always enter this block
- ItemStack itemstack = entityitemframe.getItem();
+ //ItemStack itemstack = entityitemframe.getItem(); // Paper - skip redundant getItem
- if (this.level.paperConfig().maps.itemFrameCursorUpdateInterval > 0 && this.tickCount % this.level.paperConfig().maps.itemFrameCursorUpdateInterval == 0 && itemstack.getItem() instanceof MapItem) { // CraftBukkit - Moved this.tickCounter % 10 logic here so item frames do not enter the other blocks // Paper - Make item frame map cursor update interval configurable
+ if (this.level.paperConfig().maps.itemFrameCursorUpdateInterval > 0 && this.tickCount % this.level.paperConfig().maps.itemFrameCursorUpdateInterval == 0 /*&& itemstack.getItem() instanceof MapItem*/) { // CraftBukkit - Moved this.tickCounter % 10 logic here so item frames do not enter the other blocks // Paper - Make item frame map cursor update interval configurable // Paper - skip redundant getItem
Integer integer = entityitemframe.cachedMapId; // Paper - Perf: Cache map ids on item frames
MapItemSavedData worldmap = MapItem.getSavedData(integer, this.level);
if (worldmap != null) {
+ // Paper start - re-use the same update packet when possible
+ if (!worldmap.hasContextualRenderer) {
+ // Pass in a "random" player when a non-contextual plugin renderer is added to make sure its called
+ final Packet<?> updatePacket = worldmap.framedUpdatePacket(integer, worldmap.hasPluginRenderer ? com.google.common.collect.Iterables.getFirst(this.trackedPlayers, null).getPlayer() : null);
+
+ if (updatePacket != null) {
+ for (ServerPlayerConnection connection : this.trackedPlayers) {
+ connection.send(updatePacket);
+ }
+ }
+ } else {
+ // Paper end
Iterator<ServerPlayerConnection> iterator = this.trackedPlayers.iterator(); // CraftBukkit
while (iterator.hasNext()) {
ServerPlayer entityplayer = iterator.next().getPlayer(); // CraftBukkit
- worldmap.tickCarriedBy(entityplayer, itemstack);
- Packet<?> packet = worldmap.getUpdatePacket(integer, entityplayer);
+ //worldmap.tickCarriedBy(entityplayer, itemstack); // Paper
+ Packet<?> packet = worldmap.framedUpdatePacket(integer, entityplayer); // Paper
if (packet != null) {
entityplayer.connection.send(packet);
}
}
+ } // Paper
}
}
@@ -378,6 +391,19 @@ public class ServerEntity {
}
}
+ // Paper start - send full map when tracked
+ if (this.entity instanceof ItemFrame frame && frame.cachedMapId != null) {
+ MapItemSavedData mapData = MapItem.getSavedData(frame.cachedMapId, this.level);
+
+ if (mapData != null) {
+ mapData.addFrameDecoration(frame);
+
+ final Packet<?> mapPacket = mapData.fullUpdatePacket(frame.cachedMapId, mapData.hasPluginRenderer ? player : null);
+ if (mapPacket != null)
+ sender.accept((Packet<ClientGamePacketListener>) mapPacket);
+ }
+ }
+ // Paper end
}
private void sendDirtyEntityData() {
diff --git a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
index e5b7598a5613a8281a991e42af5b950bcc2995ca..c8e2f5676aa121727a981c171b5b98f0ca34b2fa 100644
--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
@@ -489,6 +489,16 @@ public class ItemFrame extends HangingEntity {
}
this.setItem(ItemStack.fromBukkitCopy(event.getItemStack()));
// Paper end - Add PlayerItemFrameChangeEvent
+ // Paper start - add decoration and mark everything dirty for other players who are already tracking this frame
+ final ItemStack item = this.getItem();
+ if (item.is(Items.FILLED_MAP)) {
+ final MapItemSavedData data = MapItem.getSavedData(item, this.level());
+ if (data != null) {
+ data.addFrameDecoration(this);
+ data.markAllDirty();
+ }
+ }
+ // Paper end
this.gameEvent(GameEvent.BLOCK_CHANGE, player);
if (!player.getAbilities().instabuild) {
itemstack.shrink(1);
diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
index e1498d496aa01c433b6fa198608e33916eadecf3..80a3a17b86277df3edac32b7b81abee4fa14df79 100644
--- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
+++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
@@ -67,6 +67,16 @@ public class MapItemSavedData extends SavedData {
private final Map<String, MapFrame> frameMarkers = Maps.newHashMap();
private int trackedDecorationCount;
private org.bukkit.craftbukkit.map.RenderData vanillaRender = new org.bukkit.craftbukkit.map.RenderData(); // Paper
+ // Paper start - shared between all players tracking this map inside an item frame
+ public boolean dirtyColorData;
+ public int minDirtyX;
+ public int minDirtyY;
+ public int maxDirtyX;
+ public int maxDirtyY;
+ public boolean dirtyFrameDecorations;
+ public boolean hasPluginRenderer;
+ public boolean hasContextualRenderer;
+ // Paper end
public boolean isExplorerMap; // Purpur
// CraftBukkit start
@@ -333,6 +343,7 @@ public class MapItemSavedData extends SavedData {
}
this.setDecorationsDirty();
+ if (mapicon != null && mapicon.renderOnFrame()) this.dirtyFrameDecorations = true; // Paper
}
public static void addTargetDecoration(ItemStack stack, BlockPos pos, String id, MapDecoration.Type type) {
@@ -428,6 +439,7 @@ public class MapItemSavedData extends SavedData {
}
this.setDecorationsDirty();
+ if (type.isRenderedOnFrame() || (mapicon1 != null && mapicon.type().isRenderedOnFrame())) this.dirtyFrameDecorations = true; // Paper
}
}
@@ -441,6 +453,20 @@ public class MapItemSavedData extends SavedData {
public void setColorsDirty(int x, int z) {
this.setDirty();
+ // Paper start
+ if (this.dirtyColorData) {
+ this.minDirtyX = Math.min(this.minDirtyX, x);
+ this.minDirtyY = Math.min(this.minDirtyY, z);
+ this.maxDirtyX = Math.max(this.maxDirtyX, x);
+ this.maxDirtyY = Math.max(this.maxDirtyY, z);
+ } else {
+ this.dirtyColorData = true;
+ this.minDirtyX = x;
+ this.minDirtyY = z;
+ this.maxDirtyX = x;
+ this.maxDirtyY = z;
+ }
+ // Paper end
Iterator iterator = this.carriedBy.iterator();
while (iterator.hasNext()) {
@@ -523,6 +549,7 @@ public class MapItemSavedData extends SavedData {
public void removedFromFrame(BlockPos pos, int id) {
this.removeDecoration("frame-" + id);
this.frameMarkers.remove(MapFrame.frameId(pos));
+ this.dirtyFrameDecorations = true; // Paper
}
public boolean updateColor(int x, int z, byte color) {
@@ -580,6 +607,93 @@ public class MapItemSavedData extends SavedData {
return this.trackedDecorationCount >= iconCount;
}
+ // Paper start
+ public final @Nullable Packet<?> framedUpdatePacket(int id, @Nullable Player player) {
+ return createUpdatePacket(id, player, false);
+ }
+
+ public final @Nullable Packet<?> fullUpdatePacket(int id, @Nullable Player player) {
+ return createUpdatePacket(id, player, true);
+ }
+
+ public final @Nullable Packet<?> createUpdatePacket(int id, @Nullable Player player, boolean full) {
+ if (!dirtyColorData && !dirtyFrameDecorations && (player == null || server.getCurrentTick() % 5 != 0) && !full) // Periodically send update packets if a renderer is added
+ return null;
+
+ final org.bukkit.craftbukkit.map.RenderData render = player != null ? this.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) player.getBukkitEntity()) : this.vanillaRender;
+
+ final MapPatch patch;
+ if (full) {
+ patch = createPatch(render.buffer, 0, 0, 127, 127);
+ } else if (dirtyColorData) {
+ dirtyColorData = false;
+ patch = createPatch(render.buffer, this.minDirtyX, this.minDirtyY, this.maxDirtyX, this.maxDirtyY);
+ } else {
+ patch = null;
+ }
+
+ Collection<MapDecoration> decorations = null;
+ if (dirtyFrameDecorations || full || hasPluginRenderer) { // Always add decorations when a plugin renderer is added
+ dirtyFrameDecorations = false;
+ decorations = new java.util.ArrayList<>();
+
+ if (player == null) {
+ // We're using the vanilla renderer, add in vanilla decorations
+ for (MapDecoration decoration : this.decorations.values()) {
+ // Skip sending decorations that aren't rendered, i.e. player decorations.
+ // Skipping player decorations also allows us to send the same update packet to all tracking players, the only caveat
+ // being that it causes a slight flicker of the player decoration for anyone holding & looking at the map.
+ if (decoration.renderOnFrame()) {
+ decorations.add(decoration);
+ }
+ }
+ }
+
+ for (final org.bukkit.map.MapCursor cursor : render.cursors) {
+ if (cursor.isVisible()) {
+ decorations.add(new MapDecoration(MapDecoration.Type.byIcon(cursor.getRawType()), cursor.getX(), cursor.getY(), cursor.getDirection(), PaperAdventure.asVanilla(cursor.caption()))); // Paper - Adventure
+ }
+ }
+ }
+
+ return new ClientboundMapItemDataPacket(id, this.scale, this.locked, decorations, patch);
+ }
+
+ private MapPatch createPatch(byte[] buffer, int minDirtyX, int minDirtyY, int maxDirtyX, int maxDirtyY) {
+ int i = minDirtyX;
+ int j = minDirtyY;
+ int k = maxDirtyX + 1 - minDirtyX;
+ int l = maxDirtyY + 1 - minDirtyY;
+ byte[] abyte = new byte[k * l];
+
+ for (int i1 = 0; i1 < k; ++i1) {
+ for (int j1 = 0; j1 < l; ++j1) {
+ abyte[i1 + j1 * k] = buffer[i + i1 + (j + j1) * 128];
+ }
+ }
+
+ return new MapItemSavedData.MapPatch(i, j, k, l, abyte);
+ }
+
+ public void addFrameDecoration(net.minecraft.world.entity.decoration.ItemFrame frame) {
+ if (this.trackedDecorationCount >= frame.level().paperConfig().maps.itemFrameCursorLimit || this.frameMarkers.containsKey(MapFrame.frameId(frame.getPos())))
+ return;
+
+ MapFrame mapFrame = new MapFrame(frame.getPos(), frame.getDirection().get2DDataValue() * 90, frame.getId());
+ this.addDecoration(MapDecoration.Type.FRAME, frame.level(), "frame-" + frame.getId(), frame.getPos().getX(), frame.getPos().getZ(), mapFrame.getRotation(), (Component) null);
+ this.frameMarkers.put(mapFrame.getId(), mapFrame);
+ }
+
+ public void markAllDirty() {
+ this.dirtyColorData = true;
+ this.minDirtyX = 0;
+ this.minDirtyY = 0;
+ this.maxDirtyX = 127;
+ this.maxDirtyY = 127;
+ this.dirtyFrameDecorations = true;
+ }
+ // Paper end
+
public class HoldingPlayer {
// Paper start
diff --git a/src/main/java/org/bukkit/craftbukkit/map/CraftMapView.java b/src/main/java/org/bukkit/craftbukkit/map/CraftMapView.java
index c3266c43a073cb7d7eff10d1a1b15f0a2265b859..4d69e345117556bac2126edc5169ab01eed97377 100644
--- a/src/main/java/org/bukkit/craftbukkit/map/CraftMapView.java
+++ b/src/main/java/org/bukkit/craftbukkit/map/CraftMapView.java
@@ -108,6 +108,10 @@ public final class CraftMapView implements MapView {
this.renderers.add(renderer);
this.canvases.put(renderer, new HashMap<CraftPlayer, CraftMapCanvas>());
renderer.initialize(this);
+ // Paper start
+ this.worldMap.hasPluginRenderer |= !(renderer instanceof CraftMapRenderer);
+ this.worldMap.hasContextualRenderer |= renderer.isContextual();
+ // Paper end
}
}
@@ -123,6 +127,17 @@ public final class CraftMapView implements MapView {
}
}
this.canvases.remove(renderer);
+ // Paper start
+ this.worldMap.hasPluginRenderer = !(this.renderers.size() == 1 && this.renderers.get(0) instanceof CraftMapRenderer);
+ if (renderer.isContextual()) {
+ // Re-check all renderers
+ boolean contextualFound = false;
+ for (final MapRenderer mapRenderer : this.renderers) {
+ contextualFound |= mapRenderer.isContextual();
+ }
+ this.worldMap.hasContextualRenderer = contextualFound;
+ }
+ // Paper end
return true;
} else {
return false;