mirror of
https://github.com/SparklyPower/SparklyPaper.git
synced 2025-12-19 15:09:27 +00:00
298 lines
16 KiB
Diff
298 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] 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 90eb4927fa51ce3df86aa7b6c71f49150a03e337..9938d359de5b179ff486390288d481d6ece1ecf3 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
|
@@ -128,27 +128,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
|
|
}
|
|
}
|
|
|
|
@@ -421,6 +434,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 bbdaaa1cc0b4aed28bc39385508d221055b99d4d..7562147721fc8c6aa6c435f027a1757cf5b61818 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
|
@@ -175,6 +175,16 @@ public class ItemFrame extends HangingEntity {
|
|
this.setItem(ItemStack.fromBukkitCopy(event.getItemStack()), false);
|
|
}
|
|
// 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.dropItem(world, source.getEntity(), false);
|
|
this.gameEvent(GameEvent.BLOCK_CHANGE, source.getEntity());
|
|
this.playSound(this.getRemoveItemSound(), 1.0F, 1.0F);
|
|
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 ae321b3b8d98e42ef07fd1f0f738c1a2b428f6db..3515ce1e69b35cc8072b833e4f95632c7aa53bc1 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
|
|
@@ -81,6 +81,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;
|
|
@@ -370,7 +380,7 @@ public class MapItemSavedData extends SavedData {
|
|
--this.trackedDecorationCount;
|
|
}
|
|
|
|
- if (mapicon != null) this.setDecorationsDirty(); // Paper - only mark dirty if a change occurs
|
|
+ if (mapicon != null && mapicon.renderOnFrame()) this.dirtyFrameDecorations = true; // Paper
|
|
}
|
|
|
|
public static void addTargetDecoration(ItemStack stack, BlockPos pos, String id, Holder<MapDecorationType> decorationType) {
|
|
@@ -407,6 +417,7 @@ public class MapItemSavedData extends SavedData {
|
|
}
|
|
|
|
this.setDecorationsDirty();
|
|
+ if (mapicon.renderOnFrame()) this.dirtyFrameDecorations = true; // Paper
|
|
}
|
|
|
|
}
|
|
@@ -478,6 +489,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()) {
|
|
@@ -561,6 +586,7 @@ public class MapItemSavedData extends SavedData {
|
|
this.removeDecoration(MapItemSavedData.getFrameKey(id));
|
|
this.frameMarkers.remove(MapFrame.frameId(pos));
|
|
this.setDirty();
|
|
+ this.dirtyFrameDecorations = true; // Paper
|
|
}
|
|
|
|
public boolean updateColor(int x, int z, byte color) {
|
|
@@ -622,6 +648,93 @@ public class MapItemSavedData extends SavedData {
|
|
return "frame-" + id;
|
|
}
|
|
|
|
+ // Paper start
|
|
+ public final @Nullable Packet<?> framedUpdatePacket(MapId id, @Nullable Player player) {
|
|
+ return createUpdatePacket(id, player, false);
|
|
+ }
|
|
+
|
|
+ public final @Nullable Packet<?> fullUpdatePacket(MapId id, @Nullable Player player) {
|
|
+ return createUpdatePacket(id, player, true);
|
|
+ }
|
|
+
|
|
+ public final @Nullable Packet<?> createUpdatePacket(MapId 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(CraftMapCursor.CraftType.bukkitToMinecraftHolder(cursor.getType()), cursor.getX(), cursor.getY(), cursor.getDirection(), Optional.ofNullable(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(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;
|