Add the ability to synchronise/persist locked maps cross-server, close #14

feat/data-edit-commands
William278 2 years ago
parent 945b65e1bc
commit c0709f82bd

@ -3,6 +3,7 @@ dependencies {
implementation 'org.bstats:bstats-bukkit:3.0.0' implementation 'org.bstats:bstats-bukkit:3.0.0'
implementation 'net.william278:mpdbdataconverter:1.0.1' implementation 'net.william278:mpdbdataconverter:1.0.1'
implementation 'net.william278:hsldataconverter:1.0' implementation 'net.william278:hsldataconverter:1.0'
implementation 'net.william278:MapDataAPI:1.0'
implementation 'me.lucko:commodore:2.2' implementation 'me.lucko:commodore:2.2'
implementation 'net.kyori:adventure-platform-bukkit:4.1.2' implementation 'net.kyori:adventure-platform-bukkit:4.1.2'
implementation 'dev.triumphteam:triumph-gui:3.1.3' implementation 'dev.triumphteam:triumph-gui:3.1.3'
@ -31,6 +32,8 @@ shadowJar {
relocate 'dev.dejvokep', 'net.william278.husksync.libraries' relocate 'dev.dejvokep', 'net.william278.husksync.libraries'
relocate 'net.william278.desertwell', 'net.william278.husksync.libraries.desertwell' relocate 'net.william278.desertwell', 'net.william278.husksync.libraries.desertwell'
relocate 'net.william278.paginedown', 'net.william278.husksync.libraries.paginedown' relocate 'net.william278.paginedown', 'net.william278.husksync.libraries.paginedown'
relocate 'net.william278.mapdataapi', 'net.william278.husksync.libraries.mapdataapi'
relocate 'net.querz', 'net.william278.husksync.libraries.nbt'
relocate 'me.lucko.commodore', 'net.william278.husksync.libraries.commodore' relocate 'me.lucko.commodore', 'net.william278.husksync.libraries.commodore'
relocate 'net.byteflux.libby', 'net.william278.husksync.libraries.libby' relocate 'net.byteflux.libby', 'net.william278.husksync.libraries.libby'

@ -0,0 +1,121 @@
package net.william278.husksync.data;
import net.william278.husksync.BukkitHuskSync;
import net.william278.mapdataapi.MapData;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.MapMeta;
import org.bukkit.map.MapCanvas;
import org.bukkit.map.MapRenderer;
import org.bukkit.map.MapView;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.util.Objects;
import java.util.logging.Level;
/**
* Handles the persistence of {@link MapData} into {@link ItemStack}s.
*/
public class BukkitMapHandler {
private static final BukkitHuskSync plugin = BukkitHuskSync.getInstance();
private static final NamespacedKey MAP_DATA_KEY = new NamespacedKey(plugin, "map_data");
/**
* Get the {@link MapData} from the given {@link ItemStack} and persist it in its' data container
*
* @param itemStack the {@link ItemStack} to get the {@link MapData} from
*/
public static void persistMapData(@NotNull ItemStack itemStack) {
if (itemStack.getType() != Material.FILLED_MAP) {
return;
}
final MapMeta mapMeta = (MapMeta) itemStack.getItemMeta();
if (mapMeta == null || !mapMeta.hasMapView()) {
return;
}
// Get the map view
final MapView mapView = mapMeta.getMapView();
if (mapView == null || !mapView.isLocked() || mapView.isVirtual()) {
return;
}
final int mapId = mapView.getId();
if (mapId < 0) {
return;
}
// Get the map data
try {
if (!itemStack.getItemMeta().getPersistentDataContainer().has(MAP_DATA_KEY, PersistentDataType.STRING)) {
itemStack.getItemMeta().getPersistentDataContainer().set(MAP_DATA_KEY, PersistentDataType.STRING,
MapData.getFromFile(Bukkit.getWorlds().get(0).getWorldFolder(), mapId).toString());
}
} catch (IOException e) {
plugin.getLogger().log(Level.WARNING, "Failed to serialize map data for map " + mapId + ")");
}
}
/**
* Set the map data of the given {@link ItemStack} to the given {@link MapData}, applying a map view to the item stack
*
* @param itemStack the {@link ItemStack} to set the map data of
*/
public static void setMapRenderer(@NotNull ItemStack itemStack) {
if (itemStack.getType() != Material.FILLED_MAP) {
return;
}
final MapMeta mapMeta = (MapMeta) itemStack.getItemMeta();
if (mapMeta == null) {
return;
}
if (!itemStack.getItemMeta().getPersistentDataContainer().has(MAP_DATA_KEY, PersistentDataType.STRING)) {
return;
}
try {
final String serializedData = Objects.requireNonNull(itemStack
.getItemMeta().getPersistentDataContainer().get(MAP_DATA_KEY, PersistentDataType.STRING));
final MapData mapData = MapData.fromString(serializedData);
// Create a new map view renderer with the map data color at each pixel
final MapView mapView = mapMeta.getMapView();
if (mapView == null) {
return;
}
mapView.getRenderers().forEach(mapView::removeRenderer);
mapView.addRenderer(new BukkitMapDataRenderer(mapData));
} catch (IOException e) {
plugin.getLogger().log(Level.WARNING, "Failed to deserialize map data for a player");
}
}
/**
* Renders {@link MapData} to a bukkit {@link MapView}.
*/
public static class BukkitMapDataRenderer extends MapRenderer {
private final MapData mapData;
protected BukkitMapDataRenderer(@NotNull MapData mapData) {
this.mapData = mapData;
}
@Override
public void render(@NotNull MapView map, @NotNull MapCanvas canvas, @NotNull Player player) {
for (int i = 0; i < 128; i++) {
for (int j = 0; j < 128; j++) {
canvas.setPixel(i, j, (byte) mapData.getColorAt(i, j).intValue());
}
}
map.setLocked(true);
}
}
}

@ -1,6 +1,7 @@
package net.william278.husksync.data; package net.william278.husksync.data;
import net.william278.husksync.BukkitHuskSync; import net.william278.husksync.BukkitHuskSync;
import net.william278.husksync.config.Settings;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffect;
import org.bukkit.util.io.BukkitObjectInputStream; import org.bukkit.util.io.BukkitObjectInputStream;
@ -40,7 +41,11 @@ public class BukkitSerializer {
bukkitOutputStream.writeInt(inventoryContents.length); bukkitOutputStream.writeInt(inventoryContents.length);
// Write each serialize each ItemStack to the output stream // Write each serialize each ItemStack to the output stream
final boolean persistLockedMaps = BukkitHuskSync.getInstance().getSettings().getSynchronizationFeature(Settings.SynchronizationFeature.LOCKED_MAPS);
for (ItemStack inventoryItem : inventoryContents) { for (ItemStack inventoryItem : inventoryContents) {
if (persistLockedMaps) {
BukkitMapHandler.persistMapData(inventoryItem);
}
bukkitOutputStream.writeObject(serializeItemStack(inventoryItem)); bukkitOutputStream.writeObject(serializeItemStack(inventoryItem));
} }
@ -89,8 +94,13 @@ public class BukkitSerializer {
// Set the ItemStacks in the array from deserialized ItemStack data // Set the ItemStacks in the array from deserialized ItemStack data
int slotIndex = 0; int slotIndex = 0;
final boolean persistLockedMaps = BukkitHuskSync.getInstance().getSettings().getSynchronizationFeature(Settings.SynchronizationFeature.LOCKED_MAPS);
for (ItemStack ignored : inventoryContents) { for (ItemStack ignored : inventoryContents) {
inventoryContents[slotIndex] = deserializeItemStack(bukkitInputStream.readObject()); final ItemStack deserialized = deserializeItemStack(bukkitInputStream.readObject());
if (persistLockedMaps) {
BukkitMapHandler.setMapRenderer(deserialized);
}
inventoryContents[slotIndex] = deserialized;
slotIndex++; slotIndex++;
} }

@ -180,7 +180,8 @@ public class Settings {
GAME_MODE(true), GAME_MODE(true),
STATISTICS(true), STATISTICS(true),
PERSISTENT_DATA_CONTAINER(false), PERSISTENT_DATA_CONTAINER(false),
LOCATION(false); LOCATION(false),
LOCKED_MAPS(true);
private final boolean enabledByDefault; private final boolean enabledByDefault;

Loading…
Cancel
Save