From f9f46ee85afb7d749a9944243b18d103e62de0f6 Mon Sep 17 00:00:00 2001 From: a6tumn Date: Tue, 21 Jul 2026 02:22:18 -0400 Subject: [PATCH 1/7] Initial map implementations and AT entry --- .../item/mapdata/TFMagicMapData.java | 182 ++++++++++-------- .../item/mapdata/TFMazeMapData.java | 137 ++++++++----- .../resources/META-INF/accesstransformer.cfg | 3 + 3 files changed, 198 insertions(+), 124 deletions(-) diff --git a/src/main/java/twilightforest/item/mapdata/TFMagicMapData.java b/src/main/java/twilightforest/item/mapdata/TFMagicMapData.java index b8f9040ed7..b3cf7bdfa3 100644 --- a/src/main/java/twilightforest/item/mapdata/TFMagicMapData.java +++ b/src/main/java/twilightforest/item/mapdata/TFMagicMapData.java @@ -3,8 +3,6 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.core.Holder; -import net.minecraft.core.HolderLookup; -import net.minecraft.nbt.*; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientboundMapItemDataPacket; import net.minecraft.resources.ResourceKey; @@ -13,114 +11,144 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.saveddata.SavedData; -import net.minecraft.world.level.saveddata.maps.MapDecoration; -import net.minecraft.world.level.saveddata.maps.MapDecorationType; -import net.minecraft.world.level.saveddata.maps.MapId; -import net.minecraft.world.level.saveddata.maps.MapItemSavedData; -import org.jetbrains.annotations.Nullable; +import net.minecraft.world.level.saveddata.SavedDataType; +import net.minecraft.world.level.saveddata.maps.*; +import org.jspecify.annotations.Nullable; import twilightforest.TwilightForestMod; import twilightforest.item.MagicMapItem; import twilightforest.network.MagicMapPacket; import twilightforest.util.Codecs; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class TFMagicMapData extends MapItemSavedData { - private static final Map CLIENT_DATA = new HashMap<>(); + private static final Map CLIENT_DATA = new HashMap<>(); public final List conqueredStructures = new ArrayList<>(); - public TFMagicMapData(int x, int z, byte scale, boolean trackpos, boolean unlimited, boolean locked, ResourceKey dim) { - super(x, z, scale, trackpos, unlimited, locked, dim); + // [VanillaCopy] from MapItemSavedData but with our own fields and constructor + public static final Codec CODEC = RecordCodecBuilder.create(i -> + i.group( + Level.RESOURCE_KEY_CODEC + .fieldOf("dimension") + .forGetter(m -> m.dimension), + Codec.INT + .fieldOf("xCenter") + .forGetter(m -> m.centerX), + Codec.INT + .fieldOf("zCenter") + .forGetter(m -> m.centerZ), + Codec.BYTE + .optionalFieldOf("scale", (byte) 0) + .forGetter(m -> m.scale), + Codec.BYTE_BUFFER + .fieldOf("colors") + .forGetter(m -> ByteBuffer.wrap(m.colors)), + Codec.BOOL + .optionalFieldOf("trackingPosition", true) + .forGetter(m -> m.trackingPosition), + Codec.BOOL + .optionalFieldOf("unlimitedTracking", false) + .forGetter(m -> m.unlimitedTracking), + Codec.BOOL + .optionalFieldOf("locked", false) + .forGetter(m -> m.locked), + MapBanner.CODEC + .listOf() + .optionalFieldOf("banners", List.of()) + .forGetter(m -> List.copyOf(m.bannerMarkers.values())), + MapFrame.CODEC + .listOf() + .optionalFieldOf("frames", List.of()) + .forGetter(m -> List.copyOf(m.frameMarkers.values())), + DecorationHolder.CODEC + .listOf() + .optionalFieldOf("decorations", List.of()) + .forGetter(m -> { + List holders = new ArrayList<>(); + m.decorations.forEach((id, decoration) -> { + if (decoration.type().value().showOnItemFrame()) { + holders.add(new DecorationHolder(id, decoration)); + } + }); + return holders; + }), + Codec.STRING + .listOf() + .optionalFieldOf("conquered_structures", List.of()) + .forGetter(m -> List.copyOf(m.conqueredStructures)) + ).apply(i, TFMagicMapData::new) + ); + + // [VanillaCopy] from MapItemSavedData but changed to use our Codec and namespace + public static SavedDataType magicMapType(MapId id) { + return new SavedDataType<>(TwilightForestMod.prefix(id.key()), () -> { + throw new IllegalStateException("Should never create an empty map saved data"); + }, CODEC, DataFixTypes.SAVED_DATA_MAP_DATA); } - public static TFMagicMapData load(CompoundTag nbt, HolderLookup.Provider provider) { - MapItemSavedData data = MapItemSavedData.load(nbt, provider); - final boolean trackingPosition = !nbt.contains("trackingPosition", 1) || nbt.getBoolean("trackingPosition"); - final boolean unlimitedTracking = nbt.getBoolean("unlimitedTracking"); - final boolean locked = nbt.getBoolean("locked"); - TFMagicMapData tfdata = new TFMagicMapData(data.centerX, data.centerZ, data.scale, trackingPosition, unlimitedTracking, locked, data.dimension); - - tfdata.colors = data.colors; - tfdata.bannerMarkers.putAll(data.bannerMarkers); - tfdata.frameMarkers.putAll(data.frameMarkers); - - for (DecorationHolder decoration : DecorationHolder.CODEC.listOf() - .parse(provider.createSerializationContext(NbtOps.INSTANCE), nbt.get("decorations")) - .resultOrPartial(error -> TwilightForestMod.LOGGER.warn("Failed to parse map decoration: '{}'", error)) - .orElse(List.of())) { - MapDecoration mapdecoration1 = decoration.decoration(); - MapDecoration mapdecoration = tfdata.decorations.put(decoration.id(), mapdecoration1); - if (!mapdecoration1.equals(mapdecoration)) { - if (mapdecoration != null && mapdecoration.type().value().trackCount()) { - tfdata.trackedDecorationCount--; - } + // [VanillaCopy] from MapItemSavedData + public TFMagicMapData(int centerX, int centerZ, byte scale, boolean trackingPosition, boolean unlimitedTracking, boolean locked, ResourceKey dimension) { + super(centerX, centerZ, scale, trackingPosition, unlimitedTracking, locked, dimension); + } - if (decoration.decoration().type().value().trackCount()) { - tfdata.trackedDecorationCount++; - } - tfdata.setDecorationsDirty(); - } + // [VanillaCopy] from MapItemSavedData but with our own fields + private TFMagicMapData(ResourceKey dimension, int centerX, int centerZ, byte scale, ByteBuffer colors, boolean trackingPosition, boolean unlimitedTracking, boolean locked, List banners, List frames, List decorations, List conqueredStructures) { + super(centerX, centerZ, scale, trackingPosition, unlimitedTracking, locked, dimension); + + if (colors.array().length == 16384) { + this.colors = colors.array(); } - if (nbt.contains("conquered_structures", Tag.TAG_LIST)) { - tfdata.conqueredStructures.clear(); - ListTag tag = nbt.getList("conquered_structures", Tag.TAG_STRING); - tag.forEach(tag1 -> tfdata.conqueredStructures.add(tag1.getAsString())); + for(MapBanner banner : banners) { + this.bannerMarkers.put(banner.getId(), banner); + this.addDecoration(banner.getDecoration(), null, banner.getId(), banner.pos().getX(), banner.pos().getZ(), 180.0F, banner.name().orElse(null)); } - return tfdata; - } + for(MapFrame frame : frames) { + this.frameMarkers.put(frame.getId(), frame); + this.addDecoration(MapDecorationTypes.FRAME, null, getFrameKey(frame.entityId()), frame.pos().getX(), frame.pos().getZ(), frame.rotation(), null); // getFrameKey(...) needs an AT entry or VanillaCopy + } - @Override - public CompoundTag save(CompoundTag tag, HolderLookup.Provider provider) { - tag = super.save(tag, provider); - List holders = new ArrayList<>(); - this.decorations.forEach((s, decoration) -> { - if (decoration.type().value().showOnItemFrame()) { - holders.add(new DecorationHolder(s, decoration)); - } - }); - tag.put("decorations", DecorationHolder.CODEC.listOf().encodeStart(NbtOps.INSTANCE, holders).getOrThrow()); + for (DecorationHolder holder : decorations) { + MapDecoration newDecoration = holder.decoration(); + MapDecoration oldDecoration = this.decorations.put(holder.id(), newDecoration); + + if (!newDecoration.equals(oldDecoration)) { + if (oldDecoration != null && oldDecoration.type().value().trackCount()) { + this.trackedDecorationCount--; + } - if (!this.conqueredStructures.isEmpty()) { - ListTag conqueredTag = new ListTag(); - for (String structure : this.conqueredStructures) { - conqueredTag.add(StringTag.valueOf(structure)); + if (newDecoration.type().value().trackCount()) { + this.trackedDecorationCount++; + } } - tag.put("conquered_structures", conqueredTag); } - return tag; + this.conqueredStructures.addAll(conqueredStructures); } - // [VanillaCopy] Adapted from World.getMapData - @Nullable - public static TFMagicMapData getMagicMapData(Level level, String name) { - if (level instanceof ServerLevel serverLevel) return (TFMagicMapData) serverLevel.getServer().overworld().getDataStorage().get(TFMagicMapData.factory(), name); - else return CLIENT_DATA.get(name); + // [VanillaCopy] Adapted from ServerLevel.getMapData(...) + public static @Nullable TFMagicMapData getServerMagicMapData(ServerLevel serverLevel, MapId id) { + return serverLevel.getServer().getDataStorage().get(magicMapType(id)); } - // Like the method above, but if we know we're on client - @Nullable - public static TFMagicMapData getClientMagicMapData(String name) { - return CLIENT_DATA.get(name); + // [VanillaCopy] Adapted from ClientLevel.getMapData(...) + public static @Nullable TFMagicMapData getClientMagicMapData(MapId id) { + return CLIENT_DATA.get(id); } - // [VanillaCopy] Adapted from World.registerMapData - public static void registerMagicMapData(Level level, TFMagicMapData data, String id) { - if (level instanceof ServerLevel serverLevel) serverLevel.getServer().overworld().getDataStorage().set(id, data); - else CLIENT_DATA.put(id, data); + // [VanillaCopy] Adapted from ServerLevel.setMapData(...) + public static void setServerMagicMapData(ServerLevel serverLevel, MapId id, TFMagicMapData data) { + serverLevel.getServer().getDataStorage().set(magicMapType(id), data); } - public static Factory factory() { - return new SavedData.Factory<>(() -> { - throw new IllegalStateException("Should never create an empty map saved data"); - }, TFMagicMapData::load, DataFixTypes.SAVED_DATA_MAP_DATA); + public static void setClientMagicMapData(MapId id, TFMagicMapData data) { + CLIENT_DATA.put(id, data); } @Nullable @@ -149,4 +177,4 @@ public record DecorationHolder(String id, MapDecoration decoration) { Codecs.DECORATION_CODEC.fieldOf("decoration").forGetter(DecorationHolder::decoration) ).apply(instance, DecorationHolder::new)); } -} +} \ No newline at end of file diff --git a/src/main/java/twilightforest/item/mapdata/TFMazeMapData.java b/src/main/java/twilightforest/item/mapdata/TFMazeMapData.java index 5c40cbf91a..83e04686a3 100644 --- a/src/main/java/twilightforest/item/mapdata/TFMazeMapData.java +++ b/src/main/java/twilightforest/item/mapdata/TFMazeMapData.java @@ -1,8 +1,8 @@ package twilightforest.item.mapdata; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.core.BlockPos; -import net.minecraft.core.HolderLookup; -import net.minecraft.nbt.CompoundTag; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientboundMapItemDataPacket; import net.minecraft.resources.ResourceKey; @@ -10,52 +10,101 @@ import net.minecraft.util.datafix.DataFixTypes; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; -import net.minecraft.world.level.saveddata.SavedData; -import net.minecraft.world.level.saveddata.maps.MapId; -import net.minecraft.world.level.saveddata.maps.MapItemSavedData; -import org.jetbrains.annotations.Nullable; +import net.minecraft.world.level.saveddata.SavedDataType; +import net.minecraft.world.level.saveddata.maps.*; +import org.jspecify.annotations.Nullable; +import twilightforest.TwilightForestMod; import twilightforest.init.TFStructures; import twilightforest.network.MazeMapPacket; import twilightforest.util.landmarks.LegacyLandmarkPlacements; +import java.nio.ByteBuffer; import java.util.HashMap; +import java.util.List; import java.util.Map; public class TFMazeMapData extends MapItemSavedData { - private static final Map CLIENT_DATA = new HashMap<>(); + private static final Map CLIENT_DATA = new HashMap<>(); public int yCenter; public boolean ore; - public TFMazeMapData(int x, int z, byte scale, boolean trackpos, boolean unlimited, boolean locked, ResourceKey dim) { - super(x, z, scale, trackpos, unlimited, locked, dim); + // [VanillaCopy] from MapItemSavedData but with our own fields and constructor + public static final Codec CODEC = RecordCodecBuilder.create(i -> + i.group( + Level.RESOURCE_KEY_CODEC + .fieldOf("dimension") + .forGetter(m -> m.dimension), + Codec.INT + .fieldOf("xCenter") + .forGetter(m -> m.centerX), + Codec.INT + .fieldOf("zCenter") + .forGetter(m -> m.centerZ), + Codec.BYTE + .optionalFieldOf("scale", (byte) 0) + .forGetter(m -> m.scale), + Codec.BYTE_BUFFER + .fieldOf("colors") + .forGetter(m -> ByteBuffer.wrap(m.colors)), + Codec.BOOL + .optionalFieldOf("trackingPosition", true) + .forGetter(m -> m.trackingPosition), + Codec.BOOL + .optionalFieldOf("unlimitedTracking", false) + .forGetter(m -> m.unlimitedTracking), + Codec.BOOL + .optionalFieldOf("locked", false) + .forGetter(m -> m.locked), + MapBanner.CODEC + .listOf() + .optionalFieldOf("banners", List.of()) + .forGetter(m -> List.copyOf(m.bannerMarkers.values())), + MapFrame.CODEC + .listOf() + .optionalFieldOf("frames", List.of()) + .forGetter(m -> List.copyOf(m.frameMarkers.values())), + Codec.INT + .optionalFieldOf("yCenter", 0) + .forGetter(m -> m.yCenter), + Codec.BOOL + .optionalFieldOf("mapOres", false) + .forGetter(m -> m.ore) + ).apply(i, TFMazeMapData::new) + ); + + // [VanillaCopy] from MapItemSavedData but changed to use our Codec and namespace + public static SavedDataType mazeMapType(MapId id) { + return new SavedDataType<>(TwilightForestMod.prefix(id.key()), () -> { + throw new IllegalStateException("Should never create an empty map saved data"); + }, CODEC, DataFixTypes.SAVED_DATA_MAP_DATA); } - public static TFMazeMapData load(CompoundTag nbt, HolderLookup.Provider provider) { - MapItemSavedData data = MapItemSavedData.load(nbt, provider); - final boolean trackingPosition = !nbt.contains("trackingPosition", 1) || nbt.getBoolean("trackingPosition"); - final boolean unlimitedTracking = nbt.getBoolean("unlimitedTracking"); - final boolean locked = nbt.getBoolean("locked"); - TFMazeMapData tfdata = new TFMazeMapData(data.centerX, data.centerZ, data.scale, trackingPosition, unlimitedTracking, locked, data.dimension); + // [VanillaCopy] from MapItemSavedData + public TFMazeMapData(int centerX, int centerZ, byte scale, boolean trackingPosition, boolean unlimitedTracking, boolean locked, ResourceKey dimension) { + super(centerX, centerZ, scale, trackingPosition, unlimitedTracking, locked, dimension); + } - tfdata.colors = data.colors; - tfdata.bannerMarkers.putAll(data.bannerMarkers); - tfdata.decorations.putAll(data.decorations); - tfdata.frameMarkers.putAll(data.frameMarkers); - tfdata.trackedDecorationCount = data.trackedDecorationCount; + // [VanillaCopy] from MapItemSavedData but with our own fields + private TFMazeMapData(ResourceKey dimension, int centerX, int centerZ, byte scale, ByteBuffer colors, boolean trackingPosition, boolean unlimitedTracking, boolean locked, List banners, List frames, int yCenter, boolean ore) { + super(centerX, centerZ, scale, trackingPosition, unlimitedTracking, locked, dimension); - tfdata.yCenter = nbt.getInt("yCenter"); - tfdata.ore = nbt.getBoolean("mapOres"); + if (colors.array().length == 16384) { + this.colors = colors.array(); + } - return tfdata; - } + for(MapBanner banner : banners) { + this.bannerMarkers.put(banner.getId(), banner); + this.addDecoration(banner.getDecoration(), null, banner.getId(), banner.pos().getX(), banner.pos().getZ(), 180.0F, banner.name().orElse(null)); + } - @Override - public CompoundTag save(CompoundTag nbt, HolderLookup.Provider provider) { - CompoundTag ret = super.save(nbt, provider); - ret.putInt("yCenter", this.yCenter); - ret.putBoolean("mapOres", this.ore); - return ret; + for(MapFrame frame : frames) { + this.frameMarkers.put(frame.getId(), frame); + this.addDecoration(MapDecorationTypes.FRAME, null, getFrameKey(frame.entityId()), frame.pos().getX(), frame.pos().getZ(), frame.rotation(), null); // getFrameKey(...) needs an AT entry or VanillaCopy + } + + this.yCenter = yCenter; + this.ore = ore; } public void calculateMapCenter(Level world, int x, int y, int z) { @@ -71,29 +120,23 @@ public void calculateMapCenter(Level world, int x, int y, int z) { } } - // [VanillaCopy] Adapted from World.getMapData - @Nullable - public static TFMazeMapData getMazeMapData(Level level, String name) { - if (level.isClientSide()) return CLIENT_DATA.get(name); - else return (TFMazeMapData) ((ServerLevel) level).getServer().overworld().getDataStorage().get(TFMazeMapData.factory(), name); + // [VanillaCopy] Adapted from ServerLevel.getMapData(...) + public static @Nullable TFMazeMapData getServerMazeMapData(ServerLevel serverLevel, MapId id) { + return serverLevel.getServer().getDataStorage().get(mazeMapType(id)); } - // Like the method above, but if we know we're on client - @Nullable - public static TFMazeMapData getClientMagicMapData(String name) { - return CLIENT_DATA.get(name); + // [VanillaCopy] Adapted from ClientLevel.getMapData(...) + public static @Nullable TFMazeMapData getClientMazeMapData(MapId id) { + return CLIENT_DATA.get(id); } - public static SavedData.Factory factory() { - return new SavedData.Factory<>(() -> { - throw new IllegalStateException("Should never create an empty map saved data"); - }, TFMazeMapData::load, DataFixTypes.SAVED_DATA_MAP_DATA); + // [VanillaCopy] Adapted from ServerLevel.setMapData(...) + public static void setServerMazeMapData(ServerLevel serverLevel, MapId id, TFMazeMapData data) { + serverLevel.getServer().getDataStorage().set(mazeMapType(id), data); } - // [VanillaCopy] Adapted from World.registerMapData - public static void registerMazeMapData(Level level, TFMazeMapData data, String id) { - if (level.isClientSide()) CLIENT_DATA.put(id, data); - else ((ServerLevel) level).getServer().overworld().getDataStorage().set(id, data); + public static void setClientMazeMapData(MapId id, TFMazeMapData data) { + CLIENT_DATA.put(id, data); } @Nullable diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 5d6951b947..bb15a7b38a 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -276,3 +276,6 @@ protected net.minecraft.world.level.block.entity.SkullBlockEntity owner # ClientLevel (Used in MagicPaintingRenderer) public net.minecraft.client.multiplayer.ClientLevel getSkyFlashTime()I + +# TFMagicMapData & TFMazeMapData (avoids a VanillaCopy for a helper method) +public net.minecraft.world.level.saveddata.maps.MapItemSavedData getFrameKey(I)Ljava/lang/String; From 8f594a8e21f58df7b6b2623fb457fc091860103b Mon Sep 17 00:00:00 2001 From: a6tumn Date: Tue, 21 Jul 2026 02:33:44 -0400 Subject: [PATCH 2/7] Manager implementation --- .../item/mapdata/MapDataManager.java | 48 +++++++++++++++++++ .../item/mapdata/TFMagicMapData.java | 23 --------- .../item/mapdata/TFMazeMapData.java | 25 +--------- 3 files changed, 49 insertions(+), 47 deletions(-) create mode 100644 src/main/java/twilightforest/item/mapdata/MapDataManager.java diff --git a/src/main/java/twilightforest/item/mapdata/MapDataManager.java b/src/main/java/twilightforest/item/mapdata/MapDataManager.java new file mode 100644 index 0000000000..291a288c5b --- /dev/null +++ b/src/main/java/twilightforest/item/mapdata/MapDataManager.java @@ -0,0 +1,48 @@ +package twilightforest.item.mapdata; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.saveddata.maps.MapId; +import org.jspecify.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; + +/* +* Most of the content in this class is adapted from implementations in ServerLevel and ClientLevel. +*/ +public final class MapDataManager { + private static final Map MAGIC_MAP_CLIENT_DATA = new HashMap<>(); + private static final Map MAZE_MAP_CLIENT_DATA = new HashMap<>(); + + public static @Nullable TFMagicMapData getServerMagicMapData(ServerLevel serverLevel, MapId id) { + return serverLevel.getServer().getDataStorage().get(TFMagicMapData.magicMapType(id)); + } + + public static @Nullable TFMazeMapData getServerMazeMapData(ServerLevel serverLevel, MapId id) { + return serverLevel.getServer().getDataStorage().get(TFMazeMapData.mazeMapType(id)); + } + + public static @Nullable TFMagicMapData getClientMagicMapData(MapId id) { + return MAGIC_MAP_CLIENT_DATA.get(id); + } + + public static @Nullable TFMazeMapData getClientMazeMapData(MapId id) { + return MAZE_MAP_CLIENT_DATA.get(id); + } + + public static void saveServerMagicMapData(ServerLevel serverLevel, MapId id, TFMagicMapData data) { + serverLevel.getServer().getDataStorage().set(TFMagicMapData.magicMapType(id), data); + } + + public static void saveServerMazeMapData(ServerLevel serverLevel, MapId id, TFMazeMapData data) { + serverLevel.getServer().getDataStorage().set(TFMazeMapData.mazeMapType(id), data); + } + + public static void saveClientMagicMapData(MapId id, TFMagicMapData data) { + MAGIC_MAP_CLIENT_DATA.put(id, data); + } + + public static void saveClientMazeMapData(MapId id, TFMazeMapData data) { + MAZE_MAP_CLIENT_DATA.put(id, data); + } +} \ No newline at end of file diff --git a/src/main/java/twilightforest/item/mapdata/TFMagicMapData.java b/src/main/java/twilightforest/item/mapdata/TFMagicMapData.java index b3cf7bdfa3..3e864f70e5 100644 --- a/src/main/java/twilightforest/item/mapdata/TFMagicMapData.java +++ b/src/main/java/twilightforest/item/mapdata/TFMagicMapData.java @@ -6,7 +6,6 @@ import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientboundMapItemDataPacket; import net.minecraft.resources.ResourceKey; -import net.minecraft.server.level.ServerLevel; import net.minecraft.util.datafix.DataFixTypes; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; @@ -21,12 +20,9 @@ import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; public class TFMagicMapData extends MapItemSavedData { - private static final Map CLIENT_DATA = new HashMap<>(); public final List conqueredStructures = new ArrayList<>(); // [VanillaCopy] from MapItemSavedData but with our own fields and constructor @@ -132,25 +128,6 @@ private TFMagicMapData(ResourceKey dimension, int centerX, int centerZ, b this.conqueredStructures.addAll(conqueredStructures); } - // [VanillaCopy] Adapted from ServerLevel.getMapData(...) - public static @Nullable TFMagicMapData getServerMagicMapData(ServerLevel serverLevel, MapId id) { - return serverLevel.getServer().getDataStorage().get(magicMapType(id)); - } - - // [VanillaCopy] Adapted from ClientLevel.getMapData(...) - public static @Nullable TFMagicMapData getClientMagicMapData(MapId id) { - return CLIENT_DATA.get(id); - } - - // [VanillaCopy] Adapted from ServerLevel.setMapData(...) - public static void setServerMagicMapData(ServerLevel serverLevel, MapId id, TFMagicMapData data) { - serverLevel.getServer().getDataStorage().set(magicMapType(id), data); - } - - public static void setClientMagicMapData(MapId id, TFMagicMapData data) { - CLIENT_DATA.put(id, data); - } - @Nullable @Override public Packet getUpdatePacket(MapId mapId, Player player) { diff --git a/src/main/java/twilightforest/item/mapdata/TFMazeMapData.java b/src/main/java/twilightforest/item/mapdata/TFMazeMapData.java index 83e04686a3..755a743354 100644 --- a/src/main/java/twilightforest/item/mapdata/TFMazeMapData.java +++ b/src/main/java/twilightforest/item/mapdata/TFMazeMapData.java @@ -19,13 +19,9 @@ import twilightforest.util.landmarks.LegacyLandmarkPlacements; import java.nio.ByteBuffer; -import java.util.HashMap; import java.util.List; -import java.util.Map; public class TFMazeMapData extends MapItemSavedData { - private static final Map CLIENT_DATA = new HashMap<>(); - public int yCenter; public boolean ore; @@ -120,29 +116,10 @@ public void calculateMapCenter(Level world, int x, int y, int z) { } } - // [VanillaCopy] Adapted from ServerLevel.getMapData(...) - public static @Nullable TFMazeMapData getServerMazeMapData(ServerLevel serverLevel, MapId id) { - return serverLevel.getServer().getDataStorage().get(mazeMapType(id)); - } - - // [VanillaCopy] Adapted from ClientLevel.getMapData(...) - public static @Nullable TFMazeMapData getClientMazeMapData(MapId id) { - return CLIENT_DATA.get(id); - } - - // [VanillaCopy] Adapted from ServerLevel.setMapData(...) - public static void setServerMazeMapData(ServerLevel serverLevel, MapId id, TFMazeMapData data) { - serverLevel.getServer().getDataStorage().set(mazeMapType(id), data); - } - - public static void setClientMazeMapData(MapId id, TFMazeMapData data) { - CLIENT_DATA.put(id, data); - } - @Nullable @Override public Packet getUpdatePacket(MapId mapId, Player player) { Packet packet = super.getUpdatePacket(mapId, player); return packet instanceof ClientboundMapItemDataPacket mapItemDataPacket ? new MazeMapPacket(mapItemDataPacket, this.ore, this.yCenter).toVanillaClientbound() : packet; } -} +} \ No newline at end of file From 146e2579ba2e8bbb776c9e8bcaf83d9378b9c880 Mon Sep 17 00:00:00 2001 From: a6tumn Date: Tue, 21 Jul 2026 02:46:51 -0400 Subject: [PATCH 3/7] Update map items --- .../twilightforest/item/MagicMapItem.java | 14 ++++++++++-- .../java/twilightforest/item/MazeMapItem.java | 22 ++++++++++++++----- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/main/java/twilightforest/item/MagicMapItem.java b/src/main/java/twilightforest/item/MagicMapItem.java index f54218a59b..2a637e2337 100644 --- a/src/main/java/twilightforest/item/MagicMapItem.java +++ b/src/main/java/twilightforest/item/MagicMapItem.java @@ -25,6 +25,7 @@ import twilightforest.init.TFBiomes; import twilightforest.init.TFDataMaps; import twilightforest.init.TFItems; +import twilightforest.item.mapdata.MapDataManager; import twilightforest.item.mapdata.TFMagicMapData; import twilightforest.tags.TFStructureTags; import twilightforest.util.datamaps.MagicMapBiomeColor; @@ -53,7 +54,16 @@ public static ItemStack setupNewMap(ServerLevel level, int worldX, int worldZ, b @Nullable public static TFMagicMapData getData(ItemStack stack, Level level) { MapId mapid = stack.get(DataComponents.MAP_ID); - return mapid == null ? null : TFMagicMapData.getMagicMapData(level, getMapName(mapid.id())); + + if (mapid == null) { + return null; + } + + if (level instanceof ServerLevel serverLevel) { + return MapDataManager.getServerMagicMapData(serverLevel, mapid); + } + + return MapDataManager.getClientMagicMapData(mapid); } @Nullable @@ -89,7 +99,7 @@ private static TFMagicMapData createMapData(ItemStack stack, ServerLevel level, ColumnPos pos = getMagicMapCenter(x, z); TFMagicMapData mapdata = new TFMagicMapData(pos.x(), pos.z(), (byte) scale, trackingPosition, unlimitedTracking, false, dimension); - TFMagicMapData.registerMagicMapData(level, mapdata, getMapName(freeMapId.id())); // call our own register method + MapDataManager.saveServerMagicMapData(level, freeMapId, mapdata); // call our own save method stack.set(DataComponents.MAP_ID, freeMapId); return mapdata; } diff --git a/src/main/java/twilightforest/item/MazeMapItem.java b/src/main/java/twilightforest/item/MazeMapItem.java index d23a3a21e3..f0f2d81259 100644 --- a/src/main/java/twilightforest/item/MazeMapItem.java +++ b/src/main/java/twilightforest/item/MazeMapItem.java @@ -27,6 +27,7 @@ import org.jspecify.annotations.Nullable; import twilightforest.init.TFDataMaps; import twilightforest.init.TFItems; +import twilightforest.item.mapdata.MapDataManager; import twilightforest.item.mapdata.TFMazeMapData; import twilightforest.util.datamaps.OreMapOreColor; @@ -53,8 +54,17 @@ public static ItemStack setupNewMap(ServerLevel level, int worldX, int worldZ, b @Nullable public static TFMazeMapData getData(ItemStack stack, Level level) { - MapId id = stack.get(DataComponents.MAP_ID); - return id == null ? null : TFMazeMapData.getMazeMapData(level, getMapName(id.id())); + MapId mapId = stack.get(DataComponents.MAP_ID); + + if (mapId == null) { + return null; + } + + if (level instanceof ServerLevel serverLevel) { + return MapDataManager.getServerMazeMapData(serverLevel, mapId); + } + + return MapDataManager.getClientMazeMapData(mapId); } @Nullable @@ -70,7 +80,7 @@ protected TFMazeMapData getCustomMapData(ItemStack stack, Level level) { } private static TFMazeMapData createMapData(ItemStack stack, ServerLevel level, int x, int z, int scale, boolean trackingPosition, boolean unlimitedTracking, ResourceKey dimension, int y, boolean ore) { - MapId i = level.getFreeMapId(); + MapId freeMapId = level.getFreeMapId(); int mapSize = 128 * (1 << scale); int roundX = Mth.floor((x + 64.0D) / (double) mapSize); @@ -81,8 +91,8 @@ private static TFMazeMapData createMapData(ItemStack stack, ServerLevel level, i TFMazeMapData mapdata = new TFMazeMapData(scaledX, scaledZ, (byte) scale, trackingPosition, unlimitedTracking, false, dimension); mapdata.calculateMapCenter(level, x, y, z); // call our own map center calculation mapdata.ore = ore; - TFMazeMapData.registerMazeMapData(level, mapdata, getMapName(i.id())); // call our own register method - stack.set(DataComponents.MAP_ID, i); + MapDataManager.saveServerMazeMapData(level, freeMapId, mapdata); // call our own save method + stack.set(DataComponents.MAP_ID, freeMapId); return mapdata; } @@ -166,7 +176,7 @@ public void update(Level level, Entity viewer, MapItemSavedData data) { if (this.mapOres) { // recolor ores - OreMapOreColor color = state.getBlock().builtInRegistryHolder().getData(TFDataMaps.ORE_MAP_ORE_COLOR); + OreMapOreColor color = state.typeHolder().getData(TFDataMaps.ORE_MAP_ORE_COLOR); if (color != null) { multiset.add(color.color(), 1000); } else if (!state.isAir() && state.is(Tags.Blocks.ORES)) { From 51f91116f2f4549eb68197fd6928b713416a8686 Mon Sep 17 00:00:00 2001 From: a6tumn Date: Tue, 21 Jul 2026 02:52:49 -0400 Subject: [PATCH 4/7] Update network packets --- .../twilightforest/network/MagicMapPacket.java | 17 +++++++++-------- .../twilightforest/network/MazeMapPacket.java | 17 +++++++++-------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/main/java/twilightforest/network/MagicMapPacket.java b/src/main/java/twilightforest/network/MagicMapPacket.java index d4ea0f60f5..b677deb720 100644 --- a/src/main/java/twilightforest/network/MagicMapPacket.java +++ b/src/main/java/twilightforest/network/MagicMapPacket.java @@ -1,15 +1,16 @@ package twilightforest.network; +import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.network.protocol.game.ClientboundMapItemDataPacket; -import net.minecraft.world.level.Level; +import net.minecraft.world.level.saveddata.maps.MapId; import net.minecraft.world.level.saveddata.maps.MapItemSavedData; import net.neoforged.neoforge.network.handling.IPayloadContext; import twilightforest.TwilightForestMod; -import twilightforest.item.MagicMapItem; +import twilightforest.item.mapdata.MapDataManager; import twilightforest.item.mapdata.TFMagicMapData; import java.util.List; @@ -36,13 +37,13 @@ public static void handle(MagicMapPacket message, IPayloadContext ctx) { ctx.enqueueWork(new Runnable() { @Override public void run() { - Level level = ctx.player().level(); + if (!(ctx.player().level() instanceof ClientLevel clientLevel)) return; - String s = MagicMapItem.getMapName(message.inner.mapId().id()); - TFMagicMapData mapdata = TFMagicMapData.getMagicMapData(level, s); + MapId mapId = message.inner.mapId(); + TFMagicMapData mapdata = MapDataManager.getClientMagicMapData(mapId); if (mapdata == null) { - mapdata = new TFMagicMapData(0, 0, message.inner.scale(), false, false, message.inner.locked(), level.dimension()); - TFMagicMapData.registerMagicMapData(level, mapdata, s); + mapdata = new TFMagicMapData(0, 0, message.inner.scale(), false, false, message.inner.locked(), clientLevel.dimension()); + MapDataManager.saveClientMagicMapData(mapId, mapdata); } message.inner.applyToMap(mapdata); @@ -50,7 +51,7 @@ public void run() { mapdata.conqueredStructures.clear(); mapdata.conqueredStructures.addAll(message.conqueredStructures()); - MapItemSavedData saved = level.getMapData(message.inner.mapId()); + MapItemSavedData saved = clientLevel.getMapData(message.inner.mapId()); if (saved != null) { saved.addClientSideDecorations( diff --git a/src/main/java/twilightforest/network/MazeMapPacket.java b/src/main/java/twilightforest/network/MazeMapPacket.java index 61a325b3c1..a4b7e8c4d8 100644 --- a/src/main/java/twilightforest/network/MazeMapPacket.java +++ b/src/main/java/twilightforest/network/MazeMapPacket.java @@ -1,15 +1,16 @@ package twilightforest.network; +import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.network.protocol.game.ClientboundMapItemDataPacket; -import net.minecraft.world.level.Level; +import net.minecraft.world.level.saveddata.maps.MapId; import net.minecraft.world.level.saveddata.maps.MapItemSavedData; import net.neoforged.neoforge.network.handling.IPayloadContext; import twilightforest.TwilightForestMod; -import twilightforest.item.MazeMapItem; +import twilightforest.item.mapdata.MapDataManager; import twilightforest.item.mapdata.TFMazeMapData; import java.util.stream.StreamSupport; @@ -38,10 +39,10 @@ public static void handle(MazeMapPacket message, IPayloadContext ctx) { ctx.enqueueWork(new Runnable() { @Override public void run() { - Level level = ctx.player().level(); + if (!(ctx.player().level() instanceof ClientLevel clientLevel)) return; - String s = MazeMapItem.getMapName(message.inner().mapId().id()); - TFMazeMapData mapdata = TFMazeMapData.getMazeMapData(level, s); + MapId mapId = message.inner.mapId(); + TFMazeMapData mapdata = MapDataManager.getClientMazeMapData(mapId); if (mapdata == null) { mapdata = new TFMazeMapData( 0, 0, @@ -49,16 +50,16 @@ public void run() { false, false, message.inner().locked(), - level.dimension() + clientLevel.dimension() ); - TFMazeMapData.registerMazeMapData(level, mapdata, s); + MapDataManager.saveClientMazeMapData(mapId, mapdata); } mapdata.ore = message.ore(); mapdata.yCenter = message.yCenter(); message.inner().applyToMap(mapdata); - MapItemSavedData saved = level.getMapData(message.inner().mapId()); + MapItemSavedData saved = clientLevel.getMapData(message.inner().mapId()); if (saved != null) { saved.addClientSideDecorations( From 9fdc0a7ed4ce72cb6809517abafa97df33872abe Mon Sep 17 00:00:00 2001 From: a6tumn Date: Thu, 23 Jul 2026 15:01:33 -0400 Subject: [PATCH 5/7] Small fixes for constructors --- src/main/java/twilightforest/item/mapdata/TFMagicMapData.java | 3 ++- src/main/java/twilightforest/item/mapdata/TFMazeMapData.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/twilightforest/item/mapdata/TFMagicMapData.java b/src/main/java/twilightforest/item/mapdata/TFMagicMapData.java index 3e864f70e5..524347730a 100644 --- a/src/main/java/twilightforest/item/mapdata/TFMagicMapData.java +++ b/src/main/java/twilightforest/item/mapdata/TFMagicMapData.java @@ -6,6 +6,7 @@ import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientboundMapItemDataPacket; import net.minecraft.resources.ResourceKey; +import net.minecraft.util.Mth; import net.minecraft.util.datafix.DataFixTypes; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; @@ -93,7 +94,7 @@ public TFMagicMapData(int centerX, int centerZ, byte scale, boolean trackingPosi // [VanillaCopy] from MapItemSavedData but with our own fields private TFMagicMapData(ResourceKey dimension, int centerX, int centerZ, byte scale, ByteBuffer colors, boolean trackingPosition, boolean unlimitedTracking, boolean locked, List banners, List frames, List decorations, List conqueredStructures) { - super(centerX, centerZ, scale, trackingPosition, unlimitedTracking, locked, dimension); + this(centerX, centerZ, (byte) Mth.clamp(scale, 0, 4), trackingPosition, unlimitedTracking, locked, dimension); if (colors.array().length == 16384) { this.colors = colors.array(); diff --git a/src/main/java/twilightforest/item/mapdata/TFMazeMapData.java b/src/main/java/twilightforest/item/mapdata/TFMazeMapData.java index 755a743354..767aae07dd 100644 --- a/src/main/java/twilightforest/item/mapdata/TFMazeMapData.java +++ b/src/main/java/twilightforest/item/mapdata/TFMazeMapData.java @@ -7,6 +7,7 @@ import net.minecraft.network.protocol.game.ClientboundMapItemDataPacket; import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.Mth; import net.minecraft.util.datafix.DataFixTypes; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; @@ -83,7 +84,7 @@ public TFMazeMapData(int centerX, int centerZ, byte scale, boolean trackingPosit // [VanillaCopy] from MapItemSavedData but with our own fields private TFMazeMapData(ResourceKey dimension, int centerX, int centerZ, byte scale, ByteBuffer colors, boolean trackingPosition, boolean unlimitedTracking, boolean locked, List banners, List frames, int yCenter, boolean ore) { - super(centerX, centerZ, scale, trackingPosition, unlimitedTracking, locked, dimension); + this(centerX, centerZ, (byte) Mth.clamp(scale, 0, 4), trackingPosition, unlimitedTracking, locked, dimension); if (colors.array().length == 16384) { this.colors = colors.array(); From c309fe30910203dc7302a0b0a032ca80169bec9c Mon Sep 17 00:00:00 2001 From: a6tumn Date: Thu, 23 Jul 2026 15:02:25 -0400 Subject: [PATCH 6/7] Fix format issue in TFMagicMapData --- src/main/java/twilightforest/item/mapdata/TFMagicMapData.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/twilightforest/item/mapdata/TFMagicMapData.java b/src/main/java/twilightforest/item/mapdata/TFMagicMapData.java index 524347730a..fb08294919 100644 --- a/src/main/java/twilightforest/item/mapdata/TFMagicMapData.java +++ b/src/main/java/twilightforest/item/mapdata/TFMagicMapData.java @@ -110,7 +110,6 @@ private TFMagicMapData(ResourceKey dimension, int centerX, int centerZ, b this.addDecoration(MapDecorationTypes.FRAME, null, getFrameKey(frame.entityId()), frame.pos().getX(), frame.pos().getZ(), frame.rotation(), null); // getFrameKey(...) needs an AT entry or VanillaCopy } - for (DecorationHolder holder : decorations) { MapDecoration newDecoration = holder.decoration(); MapDecoration oldDecoration = this.decorations.put(holder.id(), newDecoration); From c31fa4a9cce5a84903c3e55b99562e8ce3257869 Mon Sep 17 00:00:00 2001 From: a6tumn Date: Thu, 23 Jul 2026 15:04:06 -0400 Subject: [PATCH 7/7] Remove AT comments in mapdata --- src/main/java/twilightforest/item/mapdata/TFMagicMapData.java | 2 +- src/main/java/twilightforest/item/mapdata/TFMazeMapData.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/twilightforest/item/mapdata/TFMagicMapData.java b/src/main/java/twilightforest/item/mapdata/TFMagicMapData.java index fb08294919..c958541b7e 100644 --- a/src/main/java/twilightforest/item/mapdata/TFMagicMapData.java +++ b/src/main/java/twilightforest/item/mapdata/TFMagicMapData.java @@ -107,7 +107,7 @@ private TFMagicMapData(ResourceKey dimension, int centerX, int centerZ, b for(MapFrame frame : frames) { this.frameMarkers.put(frame.getId(), frame); - this.addDecoration(MapDecorationTypes.FRAME, null, getFrameKey(frame.entityId()), frame.pos().getX(), frame.pos().getZ(), frame.rotation(), null); // getFrameKey(...) needs an AT entry or VanillaCopy + this.addDecoration(MapDecorationTypes.FRAME, null, getFrameKey(frame.entityId()), frame.pos().getX(), frame.pos().getZ(), frame.rotation(), null); } for (DecorationHolder holder : decorations) { diff --git a/src/main/java/twilightforest/item/mapdata/TFMazeMapData.java b/src/main/java/twilightforest/item/mapdata/TFMazeMapData.java index 767aae07dd..18cbf2b1ed 100644 --- a/src/main/java/twilightforest/item/mapdata/TFMazeMapData.java +++ b/src/main/java/twilightforest/item/mapdata/TFMazeMapData.java @@ -97,7 +97,7 @@ private TFMazeMapData(ResourceKey dimension, int centerX, int centerZ, by for(MapFrame frame : frames) { this.frameMarkers.put(frame.getId(), frame); - this.addDecoration(MapDecorationTypes.FRAME, null, getFrameKey(frame.entityId()), frame.pos().getX(), frame.pos().getZ(), frame.rotation(), null); // getFrameKey(...) needs an AT entry or VanillaCopy + this.addDecoration(MapDecorationTypes.FRAME, null, getFrameKey(frame.entityId()), frame.pos().getX(), frame.pos().getZ(), frame.rotation(), null); } this.yCenter = yCenter;