Skip to content

Commit ac9eabf

Browse files
committed
MapItemSavedData
Requires review on the constructed codec BS.
1 parent 731f1d1 commit ac9eabf

File tree

1 file changed

+126
-107
lines changed

1 file changed

+126
-107
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
1-
From 3aeeaf31b7a7f888f54e47826e8ec0ddbe65c4bf Mon Sep 17 00:00:00 2001
2-
From: File <[email protected]>
3-
Date: Sun, 20 Apr 1997 14:37:42 +0100
4-
Subject: [PATCH] paper File Patches
5-
6-
7-
diff --git a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
8-
index 3bfdc4df0db8944db6c671f53499cf07f3a3e7be..3c1c89aade5ff092b880ba1bf1de83f54d3d62cc 100644
91
--- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
102
+++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
11-
@@ -61,6 +61,7 @@ public class MapItemSavedData extends SavedData {
3+
@@ -50,7 +_,7 @@
4+
private static final String FRAME_PREFIX = "frame-";
5+
public static final Codec<MapItemSavedData> CODEC = RecordCodecBuilder.create(
6+
instance -> instance.group(
7+
- Level.RESOURCE_KEY_CODEC.fieldOf("dimension").forGetter(mapItemSavedData -> mapItemSavedData.dimension),
8+
+ createUUIDBackedDimensionKeyCodec().forGetter(MapItemSavedData::packUUIDBackedDimension), // Paper - store target world by uuid in addition to dimension
9+
Codec.INT.fieldOf("xCenter").forGetter(mapItemSavedData -> mapItemSavedData.centerX),
10+
Codec.INT.fieldOf("zCenter").forGetter(mapItemSavedData -> mapItemSavedData.centerZ),
11+
Codec.BYTE.optionalFieldOf("scale", (byte)0).forGetter(mapItemSavedData -> mapItemSavedData.scale),
12+
@@ -74,6 +_,7 @@
1213
public byte scale;
1314
public byte[] colors = new byte[16384];
1415
public boolean locked;
1516
+ private final org.bukkit.craftbukkit.map.RenderData vanillaRender = new org.bukkit.craftbukkit.map.RenderData(); // Paper - Use Vanilla map renderer when possible
1617
public final List<MapItemSavedData.HoldingPlayer> carriedBy = Lists.newArrayList();
1718
public final Map<Player, MapItemSavedData.HoldingPlayer> carriedByPlayers = Maps.newHashMap();
1819
private final Map<String, MapBanner> bannerMarkers = Maps.newHashMap();
19-
@@ -68,6 +69,13 @@ public class MapItemSavedData extends SavedData {
20+
@@ -81,6 +_,13 @@
2021
private final Map<String, MapFrame> frameMarkers = Maps.newHashMap();
2122
private int trackedDecorationCount;
2223

@@ -27,120 +28,66 @@ index 3bfdc4df0db8944db6c671f53499cf07f3a3e7be..3c1c89aade5ff092b880ba1bf1de83f5
2728
+ public MapId id;
2829
+ // CraftBukkit end
2930
+
30-
public static SavedData.Factory<MapItemSavedData> factory() {
31-
return new SavedData.Factory<>(() -> {
31+
public static SavedDataType<MapItemSavedData> type(MapId mapId) {
32+
return new SavedDataType<>(mapId.key(), () -> {
3233
throw new IllegalStateException("Should never create an empty map saved data");
33-
@@ -82,6 +90,11 @@ public class MapItemSavedData extends SavedData {
34+
@@ -95,7 +_,29 @@
3435
this.trackingPosition = trackingPosition;
3536
this.unlimitedTracking = unlimitedTracking;
3637
this.locked = locked;
38+
- }
3739
+ // CraftBukkit start
3840
+ this.mapView = new org.bukkit.craftbukkit.map.CraftMapView(this);
3941
+ this.server = (org.bukkit.craftbukkit.CraftServer) org.bukkit.Bukkit.getServer();
4042
+ this.vanillaRender.buffer = colors; // Paper - Use Vanilla map renderer when possible
4143
+ // CraftBukkit end
42-
}
43-
44-
public static MapItemSavedData createFresh(
45-
@@ -100,9 +113,47 @@ public class MapItemSavedData extends SavedData {
46-
}
44+
+ }
45+
+
46+
+ // Paper start - store target world by uuid in addition to dimension
47+
+ private MapItemSavedData(
48+
+ UUIDBackedDimension dimension,
49+
+ int x,
50+
+ int z,
51+
+ byte scale,
52+
+ ByteBuffer colors,
53+
+ boolean trackingPosition,
54+
+ boolean unlimitedTracking,
55+
+ boolean locked,
56+
+ List<MapBanner> banners,
57+
+ List<MapFrame> frames
58+
+ ) {
59+
+ this(dimension.resolveOrThrow(), x, z, scale, colors, trackingPosition, unlimitedTracking, locked, banners, frames);
60+
+ }
61+
+ // Paper end - store target world by uuid in addition to dimension
4762

48-
public static MapItemSavedData load(CompoundTag tag, HolderLookup.Provider levelRegistry) {
49-
- ResourceKey<Level> resourceKey = DimensionType.parseLegacy(new Dynamic<>(NbtOps.INSTANCE, tag.get("dimension")))
50-
- .resultOrPartial(LOGGER::error)
51-
- .orElseThrow(() -> new IllegalArgumentException("Invalid map dimension: " + tag.get("dimension")));
52-
+ // Paper start - fix "Not a string" spam
53-
+ Tag dimension = tag.get("dimension");
54-
+ if (dimension instanceof final net.minecraft.nbt.NumericTag numericTag && numericTag.getAsInt() >= org.bukkit.craftbukkit.CraftWorld.CUSTOM_DIMENSION_OFFSET) {
55-
+ long least = tag.getLong("UUIDLeast");
56-
+ long most = tag.getLong("UUIDMost");
57-
+
58-
+ if (least != 0L && most != 0L) {
59-
+ java.util.UUID uuid = new java.util.UUID(most, least);
60-
+ org.bukkit.craftbukkit.CraftWorld world = (org.bukkit.craftbukkit.CraftWorld) org.bukkit.Bukkit.getWorld(uuid);
61-
+ if (world != null) {
62-
+ dimension = net.minecraft.nbt.StringTag.valueOf("minecraft:" + world.getName().toLowerCase(java.util.Locale.ENGLISH));
63-
+ } else {
64-
+ dimension = net.minecraft.nbt.StringTag.valueOf("bukkit:_invalidworld_");
65-
+ }
66-
+ } else {
67-
+ dimension = net.minecraft.nbt.StringTag.valueOf("bukkit:_invalidworld_");
68-
+ }
69-
+ }
70-
+ com.mojang.serialization.DataResult<ResourceKey<Level>> dataresult = DimensionType.parseLegacy(new Dynamic(NbtOps.INSTANCE, dimension)); // CraftBukkit - decompile error
71-
+ // Paper end - fix "Not a string" spam
72-
+ // CraftBukkit start
73-
+ ResourceKey<Level> resourceKey = dataresult.resultOrPartial(LOGGER::error).orElseGet(() -> {
74-
+ long least = tag.getLong("UUIDLeast");
75-
+ long most = tag.getLong("UUIDMost");
76-
+
77-
+ if (least != 0L && most != 0L) {
78-
+ java.util.UUID uniqueId = new java.util.UUID(most, least);
79-
+
80-
+ org.bukkit.craftbukkit.CraftWorld world = (org.bukkit.craftbukkit.CraftWorld) org.bukkit.Bukkit.getWorld(uniqueId);
81-
+ // Check if the stored world details are correct.
82-
+ if (world == null) {
83-
+ /* All Maps which do not have their valid world loaded are set to a dimension which hopefully won't be reached.
84-
+ This is to prevent them being corrupted with the wrong map data. */
85-
+ // PAIL: Use Vanilla exception handling for now
86-
+ } else {
87-
+ return world.getHandle().dimension();
88-
+ }
89-
+ }
90-
+ throw new IllegalArgumentException("Invalid map dimension: " + String.valueOf(tag.get("dimension")));
91-
+ // CraftBukkit end
92-
+ });
93-
int _int = tag.getInt("xCenter");
94-
int _int1 = tag.getInt("zCenter");
95-
byte b = (byte)Mth.clamp(tag.getByte("scale"), 0, 4);
96-
@@ -114,6 +165,7 @@ public class MapItemSavedData extends SavedData {
97-
if (byteArray.length == 16384) {
98-
mapItemSavedData.colors = byteArray;
63+
private MapItemSavedData(
64+
ResourceKey<Level> dimension,
65+
@@ -127,6 +_,8 @@
66+
MapDecorationTypes.FRAME, null, getFrameKey(mapFrame.entityId()), mapFrame.pos().getX(), mapFrame.pos().getZ(), mapFrame.rotation(), null
67+
);
9968
}
100-
+ mapItemSavedData.vanillaRender.buffer = byteArray; // Paper - Use Vanilla map renderer when possible
101-
102-
RegistryOps<Tag> registryOps = levelRegistry.createSerializationContext(NbtOps.INSTANCE);
69+
+
70+
+ this.vanillaRender.buffer = colors.array(); // Paper - Use Vanilla map renderer when possible
71+
}
10372

104-
@@ -154,6 +206,25 @@ public class MapItemSavedData extends SavedData {
105-
.encodeStart(NbtOps.INSTANCE, this.dimension.location())
106-
.resultOrPartial(LOGGER::error)
107-
.ifPresent(dimension -> tag.put("dimension", dimension));
108-
+ // CraftBukkit start
109-
+ if (true) {
110-
+ if (this.uniqueId == null) {
111-
+ for (org.bukkit.World world : this.server.getWorlds()) {
112-
+ org.bukkit.craftbukkit.CraftWorld cWorld = (org.bukkit.craftbukkit.CraftWorld) world;
113-
+ if (cWorld.getHandle().dimension() == this.dimension) {
114-
+ this.uniqueId = cWorld.getUID();
115-
+ break;
116-
+ }
117-
+ }
118-
+ }
119-
+ /* Perform a second check to see if a matching world was found, this is a necessary
120-
+ change incase Maps are forcefully unlinked from a World and lack a UID.*/
121-
+ if (this.uniqueId != null) {
122-
+ tag.putLong("UUIDLeast", this.uniqueId.getLeastSignificantBits());
123-
+ tag.putLong("UUIDMost", this.uniqueId.getMostSignificantBits());
124-
+ }
125-
+ }
126-
+ // CraftBukkit end
127-
tag.putInt("xCenter", this.centerX);
128-
tag.putInt("zCenter", this.centerZ);
129-
tag.putByte("scale", this.scale);
130-
@@ -233,10 +304,12 @@ public class MapItemSavedData extends SavedData {
73+
public static MapItemSavedData createFresh(
74+
@@ -204,6 +_,7 @@
13175
}
13276

13377
MapFrame mapFrame1 = new MapFrame(pos, frame.getDirection().get2DDataValue() * 90, frame.getId());
13478
+ if (this.decorations.size() < player.level().paperConfig().maps.itemFrameCursorLimit) { // Paper - Limit item frame cursors on maps
13579
this.addDecoration(
13680
MapDecorationTypes.FRAME, player.level(), getFrameKey(frame.getId()), pos.getX(), pos.getZ(), frame.getDirection().get2DDataValue() * 90, null
13781
);
138-
this.frameMarkers.put(mapFrame1.getId(), mapFrame1);
82+
@@ -211,6 +_,7 @@
83+
if (!mapFrame1.equals(mapFrame2)) {
84+
this.setDirty();
85+
}
13986
+ } // Paper - Limit item frame cursors on maps
14087
}
14188

14289
MapDecorations mapDecorations = mapStack.getOrDefault(DataComponents.MAP_DECORATIONS, MapDecorations.EMPTY);
143-
@@ -267,7 +340,7 @@ public class MapItemSavedData extends SavedData {
90+
@@ -241,7 +_,7 @@
14491
this.trackedDecorationCount--;
14592
}
14693

@@ -149,16 +96,16 @@ index 3bfdc4df0db8944db6c671f53499cf07f3a3e7be..3c1c89aade5ff092b880ba1bf1de83f5
14996
}
15097

15198
public static void addTargetDecoration(ItemStack stack, BlockPos pos, String type, Holder<MapDecorationType> mapDecorationType) {
152-
@@ -421,7 +494,7 @@ public class MapItemSavedData extends SavedData {
99+
@@ -395,7 +_,7 @@
153100
return true;
154101
}
155102

156103
- if (!this.isTrackedCountOverLimit(256)) {
157104
+ if (!this.isTrackedCountOverLimit(((Level) accessor).paperConfig().maps.itemFrameCursorLimit)) { // Paper - Limit item frame cursors on maps
158105
this.bannerMarkers.put(mapBanner.getId(), mapBanner);
159106
this.addDecoration(mapBanner.getDecoration(), accessor, mapBanner.getId(), d, d1, 180.0, mapBanner.name().orElse(null));
160-
return true;
161-
@@ -521,7 +594,7 @@ public class MapItemSavedData extends SavedData {
107+
this.setDirty();
108+
@@ -497,7 +_,7 @@
162109
this.player = player;
163110
}
164111

@@ -167,7 +114,7 @@ index 3bfdc4df0db8944db6c671f53499cf07f3a3e7be..3c1c89aade5ff092b880ba1bf1de83f5
167114
int i = this.minDirtyX;
168115
int i1 = this.minDirtyY;
169116
int i2 = this.maxDirtyX + 1 - this.minDirtyX;
170-
@@ -530,7 +603,7 @@ public class MapItemSavedData extends SavedData {
117+
@@ -506,7 +_,7 @@
171118

172119
for (int i4 = 0; i4 < i2; i4++) {
173120
for (int i5 = 0; i5 < i3; i5++) {
@@ -176,7 +123,7 @@ index 3bfdc4df0db8944db6c671f53499cf07f3a3e7be..3c1c89aade5ff092b880ba1bf1de83f5
176123
}
177124
}
178125

179-
@@ -540,17 +613,38 @@ public class MapItemSavedData extends SavedData {
126+
@@ -516,17 +_,38 @@
180127
@Nullable
181128
Packet<?> nextUpdatePacket(MapId mapId) {
182129
MapItemSavedData.MapPatch mapPatch;
@@ -218,7 +165,7 @@ index 3bfdc4df0db8944db6c671f53499cf07f3a3e7be..3c1c89aade5ff092b880ba1bf1de83f5
218165
} else {
219166
collection = null;
220167
}
221-
@@ -578,6 +672,23 @@ public class MapItemSavedData extends SavedData {
168+
@@ -554,6 +_,23 @@
222169
private void markDecorationsDirty() {
223170
this.dirtyDecorations = true;
224171
}
@@ -242,3 +189,75 @@ index 3bfdc4df0db8944db6c671f53499cf07f3a3e7be..3c1c89aade5ff092b880ba1bf1de83f5
242189
}
243190

244191
record MapDecorationLocation(Holder<MapDecorationType> type, byte x, byte y, byte rot) {
192+
@@ -598,4 +_,71 @@
193+
}
194+
}
195+
}
196+
+
197+
+ // Paper start - store target world by uuid in addition to dimension
198+
+ record UUIDAndError(java.util.UUID uuid, String faultyDimension) {
199+
+
200+
+ }
201+
+ record UUIDBackedDimension(@Nullable ResourceKey<Level> resourceKey, @Nullable UUIDAndError uuid) {
202+
+ public UUIDBackedDimension(final @org.jetbrains.annotations.NotNull ResourceKey<Level> resourceKey) {
203+
+ this(resourceKey, null);
204+
+ }
205+
+ public UUIDBackedDimension {
206+
+ com.google.common.base.Preconditions.checkArgument(resourceKey != null || uuid != null, "Created uuid backed dimension with null level and uuid. This is a bug");
207+
+ }
208+
+
209+
+ public @org.jetbrains.annotations.NotNull ResourceKey<Level> resolveOrThrow() {
210+
+ if (resourceKey != null) return resourceKey;
211+
+
212+
+ final org.bukkit.World worldByUUID = org.bukkit.Bukkit.getWorld(uuid.uuid());
213+
+ if (worldByUUID != null) return ((org.bukkit.craftbukkit.CraftWorld) worldByUUID).getHandle().dimension();
214+
+
215+
+ throw new IllegalArgumentException("Invalid dimension " + uuid.faultyDimension() + " and unknown world uuid " + uuid.uuid);
216+
+ }
217+
+ }
218+
+
219+
+ private UUIDBackedDimension packUUIDBackedDimension() {
220+
+ final net.minecraft.server.level.ServerLevel mappedLevel = net.minecraft.server.MinecraftServer.getServer().getLevel(this.dimension);
221+
+ return new UUIDBackedDimension(this.dimension, mappedLevel == null ? null : new UUIDAndError(mappedLevel.uuid, ""));
222+
+ }
223+
+
224+
+ private static com.mojang.serialization.MapCodec<UUIDBackedDimension> createUUIDBackedDimensionKeyCodec() {
225+
+ return new com.mojang.serialization.MapCodec<>() {
226+
+ @Override
227+
+ public <T> java.util.stream.Stream<T> keys(final com.mojang.serialization.DynamicOps<T> ops) {
228+
+ return java.util.stream.Stream.of("dimension", "UUIDLeast", "UUIDMost").map(ops::createString);
229+
+ }
230+
+
231+
+ @Override
232+
+ public <T> com.mojang.serialization.DataResult<UUIDBackedDimension> decode(final com.mojang.serialization.DynamicOps<T> ops,
233+
+ final com.mojang.serialization.MapLike<T> input) {
234+
+ final com.mojang.serialization.DataResult<UUIDBackedDimension> foundDimension = Level.RESOURCE_KEY_CODEC.decode(ops, input.get("dimension"))
235+
+ .map(Pair::getFirst)
236+
+ .map(UUIDBackedDimension::new); // Do not pack uuid when reading as the level itself might reference an unloaded world. UUID lookup would be faulty + should be re-generated when written.
237+
+ if (foundDimension.isSuccess()) return foundDimension;
238+
+
239+
+ // Fallback attempt at parsing the uuid
240+
+ final com.mojang.serialization.DataResult<UUIDBackedDimension> fromUUID = Codec.LONG.decode(ops, input.get("UUIDMost")).map(Pair::getFirst).apply2(
241+
+ java.util.UUID::new,
242+
+ Codec.LONG.decode(ops, input.get("UUIDLeast")).map(Pair::getFirst)
243+
+ ).map(uuid -> new UUIDBackedDimension(null, new UUIDAndError(uuid, String.valueOf(input.get("dimension")))));
244+
+ if (fromUUID.isSuccess()) return fromUUID;
245+
+
246+
+ return foundDimension; // Return the found dimension instead, it's error is more "accurate" over the bukkit added uuids.
247+
+ }
248+
+
249+
+ @Override
250+
+ public <T> com.mojang.serialization.RecordBuilder<T> encode(final UUIDBackedDimension input,
251+
+ final com.mojang.serialization.DynamicOps<T> ops,
252+
+ final com.mojang.serialization.RecordBuilder<T> prefix) {
253+
+ prefix.add("dimension", input.resourceKey(), Level.RESOURCE_KEY_CODEC);
254+
+ if (input.uuid != null) {
255+
+ prefix.add("UUIDMost", input.uuid.uuid().getMostSignificantBits(), Codec.LONG);
256+
+ prefix.add("UUIDLeast", input.uuid.uuid().getLeastSignificantBits(), Codec.LONG);
257+
+ }
258+
+ return prefix;
259+
+ }
260+
+ };
261+
+ }
262+
+ // Paper end - store target world by uuid in addition to dimension
263+
}

0 commit comments

Comments
 (0)