9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2025-12-21 16:09:19 +00:00
Files
Leaf/patches/server/0053-PaperPR-Rewrite-framed-map-tracker-ticking.patch
Dreeam d4fcc796c6 Add Leaf Bootstrap
Also fixed Ignore terminal provider warning not working
2024-07-31 22:24:37 +08:00

302 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 97e793c971614299504605aeb4f99cadbcc2abf0..8721a93e184354727b439c794ce0aea5321b6675 100644
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
@@ -124,27 +124,40 @@ public class ServerEntity {
Entity entity = this.entity;
- if (!this.trackedPlayers.isEmpty() && entity instanceof ItemFrame entityitemframe) { // Paper - Perf: Only tick item frames if players can see it
+ if (!this.trackedPlayers.isEmpty() && entity instanceof ItemFrame entityitemframe && entityitemframe.cachedMapId != null) { // Paper - Perf: Only tick item frames if players can see it // Paper
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
MapId mapid = entityitemframe.cachedMapId; // Paper - Perf: Cache map ids on item frames
MapItemSavedData worldmap = MapItem.getSavedData(mapid, 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(mapid, 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(mapid, entityplayer);
+ //worldmap.tickCarriedBy(entityplayer, itemstack); // Paper
+ Packet<?> packet = worldmap.framedUpdatePacket(mapid, entityplayer); // Paper
if (packet != null) {
entityplayer.connection.send(packet);
}
}
+ } // Paper
}
}
@@ -385,6 +398,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
}
public Vec3 getPositionBase() {
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 cf78531b193ba56991ccb0c4f62844208e4a5706..d6cecc788be59676f0d011323bb5bdab9e5ab417 100644
--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
@@ -425,6 +425,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);
itemstack.consume(1, player);
}
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 d6c704d8e933d689c3a946d7ef0e8396ac024841..1c0b24699e5a076cefd6f7e153d7a51e7a3b8a6e 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
@@ -80,6 +80,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
@@ -353,6 +363,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, Holder<MapDecorationType> decorationType) {
@@ -434,6 +445,7 @@ public class MapItemSavedData extends SavedData {
}
this.setDecorationsDirty();
+ if (type.value().showOnItemFrame() || (mapicon1 != null && mapicon.type().value().showOnItemFrame())) this.dirtyFrameDecorations = true; // Paper
}
}
@@ -447,6 +459,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()) {
@@ -529,6 +555,7 @@ public class MapItemSavedData extends SavedData {
public void removedFromFrame(BlockPos pos, int id) {
this.removeDecoration(MapItemSavedData.getFrameKey(id));
this.frameMarkers.remove(MapFrame.frameId(pos));
+ this.dirtyFrameDecorations = true; // Paper
}
public boolean updateColor(int x, int z, byte color) {
@@ -590,6 +617,93 @@ public class MapItemSavedData extends SavedData {
return "frame-" + id;
}
+ // Paper start
+ public final @Nullable Packet<?> framedUpdatePacket(MapId mapid, @Nullable Player player) {
+ return createUpdatePacket(mapid, player, false);
+ }
+
+ public final @Nullable Packet<?> fullUpdatePacket(MapId mapid, @Nullable Player player) {
+ return createUpdatePacket(mapid, player, true);
+ }
+
+ public final @Nullable Packet<?> createUpdatePacket(MapId mapid, @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(CraftMapCursor.CraftType.bukkitToMinecraftHolder(cursor.getType()), cursor.getX(), cursor.getY(), cursor.getDirection(), CraftChatMessage.fromStringOrOptional(cursor.getCaption()))); // 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(MapDecorationTypes.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 a15cdf64575841edfe30f2b2c522f8fdfe2caae3..ce20060e48226cc1cbe476a404ef6e1f6bdb9137 100644
--- a/src/main/java/org/bukkit/craftbukkit/map/CraftMapView.java
+++ b/src/main/java/org/bukkit/craftbukkit/map/CraftMapView.java
@@ -101,6 +101,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
}
}
@@ -116,6 +120,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;