Rewrite framed map tracker ticking
This commit is contained in:
parent
a73ed9572e
commit
bd7c062778
1 changed files with 298 additions and 0 deletions
298
patches/server/1005-Rewrite-framed-map-tracker-ticking.patch
Normal file
298
patches/server/1005-Rewrite-framed-map-tracker-ticking.patch
Normal file
|
@ -0,0 +1,298 @@
|
|||
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 196280f54e397c69d32bd4d1f6ae666efdd93773..8ef1c11969310f64d06c8421969d171b6c399ab6 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -108,29 +108,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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,6 +386,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 50713f03c783c63f93710d986d94af544be0615a..5a0978c2342647d6293cd370e489a727c5d652ee 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
|
||||
@@ -66,6 +66,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;
|
||||
@@ -325,6 +335,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) {
|
||||
@@ -420,6 +431,7 @@ public class MapItemSavedData extends SavedData {
|
||||
}
|
||||
|
||||
this.setDecorationsDirty();
|
||||
+ if (type.isRenderedOnFrame() || (mapicon1 != null && mapicon.getType().isRenderedOnFrame())) this.dirtyFrameDecorations = true; // Paper
|
||||
}
|
||||
|
||||
}
|
||||
@@ -433,6 +445,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()) {
|
||||
@@ -515,6 +541,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) {
|
||||
@@ -572,6 +599,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 115ac54d13a8ca189a69526b1b3baf48be8a64e9..f878bed0503b183e636c15a16b766e15844f4a3f 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;
|
Loading…
Reference in a new issue