diff --git a/bukkit/src/main/java/net/william278/husksync/listener/BukkitEventListener.java b/bukkit/src/main/java/net/william278/husksync/listener/BukkitEventListener.java index 432a1b67..5ec10546 100644 --- a/bukkit/src/main/java/net/william278/husksync/listener/BukkitEventListener.java +++ b/bukkit/src/main/java/net/william278/husksync/listener/BukkitEventListener.java @@ -43,6 +43,7 @@ import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.server.MapInitializeEvent; import org.bukkit.event.world.WorldSaveEvent; import org.jetbrains.annotations.NotNull; @@ -115,6 +116,13 @@ public class BukkitEventListener extends EventListener implements BukkitJoinEven .collect(Collectors.toList()))); } + @EventHandler(ignoreCancelled = true) + public void onMapInitialize(@NotNull MapInitializeEvent event) { + if (plugin.getSettings().doPersistLockedMaps() && event.getMap().isLocked()) { + getPlugin().runAsync(() -> ((BukkitHuskSync) plugin).renderMapFromFile(event.getMap())); + } + } + /* * Events to cancel if the player has not been set yet diff --git a/bukkit/src/main/java/net/william278/husksync/util/BukkitMapPersister.java b/bukkit/src/main/java/net/william278/husksync/util/BukkitMapPersister.java index 73e6fcde..60463fcc 100644 --- a/bukkit/src/main/java/net/william278/husksync/util/BukkitMapPersister.java +++ b/bukkit/src/main/java/net/william278/husksync/util/BukkitMapPersister.java @@ -22,6 +22,8 @@ package net.william278.husksync.util; import de.tr7zw.changeme.nbtapi.NBT; import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT; import de.tr7zw.changeme.nbtapi.iface.ReadableNBT; +import net.querz.nbt.io.NBTUtil; +import net.querz.nbt.tag.CompoundTag; import net.william278.husksync.HuskSync; import net.william278.mapdataapi.MapBanner; import net.william278.mapdataapi.MapData; @@ -36,6 +38,7 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import java.awt.*; +import java.io.File; import java.util.List; import java.util.*; import java.util.function.Function; @@ -175,11 +178,12 @@ public interface BukkitMapPersister { return; } - // Add a renderer to the map with the data + // Add a renderer to the map with the data and save to file final MapView view = generateRenderedMap(canvasData); final String worldUid = getDefaultMapWorld().getUID().toString(); meta.setMapView(view); map.setItemMeta(meta); + saveMapToFile(canvasData, view.getId()); // Set the map view ID in NBT NBT.modify(map, editable -> { @@ -192,6 +196,58 @@ public interface BukkitMapPersister { return map; } + default void renderMapFromFile(@NotNull MapView view) { + final File mapFile = new File(getMapCacheFolder(), view.getId() + ".dat"); + if (!mapFile.exists()) { + return; + } + + final MapData canvasData; + try { + canvasData = MapData.fromNbt(mapFile); + } catch (Throwable e) { + getPlugin().log(Level.WARNING, "Failed to deserialize map data from file", e); + return; + } + + // Create a new map view renderer with the map data color at each pixel + view.getRenderers().clear(); + view.addRenderer(new PersistentMapRenderer(canvasData)); + view.setLocked(true); + view.setScale(MapView.Scale.NORMAL); + view.setTrackingPosition(false); + view.setUnlimitedTracking(false); + + // Set the view to the map + setMapView(view); + } + + default void saveMapToFile(@NotNull MapData data, int id) { + getPlugin().runAsync(() -> { + final File mapFile = new File(getMapCacheFolder(), id + ".dat"); + if (mapFile.exists()) { + return; + } + + try { + final CompoundTag rootTag = new CompoundTag(); + rootTag.put("data", data.toNBT().getTag()); + NBTUtil.write(rootTag, mapFile); + } catch (Throwable e) { + getPlugin().log(Level.WARNING, "Failed to serialize map data to file", e); + } + }); + } + + @NotNull + private File getMapCacheFolder() { + final File mapCache = new File(getPlugin().getDataFolder(), "maps"); + if (!mapCache.exists() && !mapCache.mkdirs()) { + getPlugin().log(Level.WARNING, "Failed to create maps folder"); + } + return mapCache; + } + // Sets the renderer of a map, and returns the generated MapView @NotNull private MapView generateRenderedMap(@NotNull MapData canvasData) {