9
0
mirror of https://github.com/SparklyPower/SparklyPaper.git synced 2025-12-22 16:39:33 +00:00
Files
SparklyPaperMC/patches/server/0004-Rewrite-framed-map-tracker-ticking.patch
MrPowerGamerBR 8bd484c287 Patch changes
2023-11-19 20:39:51 -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 35674f92a67f93382103c2766df4b678ba5c862f..bfdd0ce9acfae75a403d3689b391dd8fff7416a0 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 - Only tick item frames if players can see it
+ if (!this.trackedPlayers.isEmpty() && entity instanceof ItemFrame frame && frame.cachedMapId != null) { // Paper - 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
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
}
}
@@ -366,6 +379,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 759ecd79534a7706f7d4a63eb9dacbefcfe54674..0780dd4abf035cdd4001fb9702494c54be83361a 100644
--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
@@ -488,6 +488,16 @@ public class ItemFrame extends HangingEntity {
}
this.setItem(ItemStack.fromBukkitCopy(event.getItemStack()));
// Paper end
+ // 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 e4c4948e076cd64686dfd16ae0568fafc1437140..0e7c7593eec47bc266f53ee8b2053917a84ae61e 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;