9
0
mirror of https://github.com/SparklyPower/SparklyPaper.git synced 2025-12-29 20:09:07 +00:00
Files
SparklyPaperMC/patches/server/0004-Rewrite-framed-map-tracker-ticking.patch
MrPowerGamerBR 7a80199414 Update upstream (yay finally)
Not tested in production yet, but soon it will be
2024-02-18 15:02:29 -03:00

299 lines
15 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] Rewrite framed map tracker ticking
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 529ab44baaf573b97cf7e89560c548642733188f..7ee0335b02741f6b06d0c697a19faf479db2ae4b 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
}
}
@@ -372,6 +385,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 80303f9466b8c7097151be313afc9a383693d18a..4ddcda7783750e485e283a7f7df3f52c9bed5c45 100644
--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
@@ -483,6 +483,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 45269115e63cfc3bd7dc740a5694e2cc7c35bcb1..ad0c4660dd15a7dc6cf3639223dda5d704f96a4c 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
// CraftBukkit start
public final CraftMapView mapView;
@@ -332,6 +342,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) {
@@ -427,6 +438,7 @@ public class MapItemSavedData extends SavedData {
}
this.setDecorationsDirty();
+ if (type.isRenderedOnFrame() || (mapicon1 != null && mapicon.type().isRenderedOnFrame())) this.dirtyFrameDecorations = true; // Paper
}
}
@@ -440,6 +452,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()) {
@@ -522,6 +548,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) {
@@ -579,6 +606,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;