diff --git a/src/main/java/fr/moribus/imageonmap/ImageOnMap.java b/src/main/java/fr/moribus/imageonmap/ImageOnMap.java index 32a4b2d..bc3a0de 100644 --- a/src/main/java/fr/moribus/imageonmap/ImageOnMap.java +++ b/src/main/java/fr/moribus/imageonmap/ImageOnMap.java @@ -29,13 +29,16 @@ import org.bukkit.plugin.java.JavaPlugin; public final class ImageOnMap extends JavaPlugin { static private final String IMAGES_DIRECTORY_NAME = "images"; + static private final String MAPS_DIRECTORY_NAME = "maps"; static private ImageOnMap plugin; private final File imagesDirectory; + private final File mapsDirectory; public ImageOnMap() { imagesDirectory = new File(this.getDataFolder(), IMAGES_DIRECTORY_NAME); + mapsDirectory = new File(this.getDataFolder(), MAPS_DIRECTORY_NAME); plugin = this; } @@ -45,6 +48,7 @@ public final class ImageOnMap extends JavaPlugin } public File getImagesDirectory() {return imagesDirectory;} + public File getMapsDirectory() {return mapsDirectory;} public File getImageFile(short mapID) { return new File(imagesDirectory, "map"+mapID+".png"); @@ -63,6 +67,16 @@ public final class ImageOnMap extends JavaPlugin return; } } + + if(!mapsDirectory.exists()) + { + if(!mapsDirectory.mkdirs()) + { + PluginLogger.LogError("FATAL : Could not create the images directory.", null); + this.setEnabled(false); + return; + } + } //Init all the things ! MetricsLite.startMetrics(); diff --git a/src/main/java/fr/moribus/imageonmap/map/ImageMap.java b/src/main/java/fr/moribus/imageonmap/map/ImageMap.java index d75a5c0..000346f 100644 --- a/src/main/java/fr/moribus/imageonmap/map/ImageMap.java +++ b/src/main/java/fr/moribus/imageonmap/map/ImageMap.java @@ -21,19 +21,27 @@ package fr.moribus.imageonmap.map; import java.util.HashMap; import java.util.Map; import java.util.UUID; +import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.serialization.ConfigurationSerializable; public abstract class ImageMap implements ConfigurationSerializable { + static public enum Type + { + SINGLE, POSTER; + }; + static public final int WIDTH = 128; static public final int HEIGHT = 128; private final UUID userUUID; + private final Type mapType; private String imageName; - protected ImageMap(UUID userUUID) + protected ImageMap(UUID userUUID, Type mapType) { this.userUUID = userUUID; + this.mapType = mapType; } @@ -42,17 +50,30 @@ public abstract class ImageMap implements ConfigurationSerializable /* ====== Serialization methods ====== */ - protected ImageMap(Map map, UUID userUUID) throws IllegalArgumentException + static public ImageMap fromConfig(Map map, UUID userUUID) throws InvalidConfigurationException { + Type mapType; try { - this.userUUID = userUUID; - this.imageName = (String) map.get("name"); + mapType = Type.valueOf((String) map.get("type")); } catch(ClassCastException ex) { - throw new IllegalArgumentException(ex); + throw new InvalidConfigurationException(ex); } + + switch(mapType) + { + case SINGLE: return new SingleMap(map, userUUID); + case POSTER: return new PosterMap(map, userUUID); + default: throw new IllegalArgumentException("Unhandled map type given"); + } + } + + protected ImageMap(Map map, UUID userUUID, Type mapType) throws InvalidConfigurationException + { + this(userUUID, mapType); + this.imageName = getFieldValue(map, "name"); } protected abstract void postSerialize(Map map); @@ -61,9 +82,22 @@ public abstract class ImageMap implements ConfigurationSerializable public Map serialize() { Map map = new HashMap(); + map.put("type", mapType.toString()); map.put("name", imageName); return map; } + + static protected T getFieldValue(Map map, String fieldName) throws InvalidConfigurationException + { + try + { + return (T)map.get(fieldName); + } + catch(ClassCastException ex) + { + throw new InvalidConfigurationException("Invalid field \"" + fieldName + "\"", ex); + } + } /* ====== Getters & Setters ====== */ diff --git a/src/main/java/fr/moribus/imageonmap/map/MapManager.java b/src/main/java/fr/moribus/imageonmap/map/MapManager.java index ed7284e..2f5128d 100644 --- a/src/main/java/fr/moribus/imageonmap/map/MapManager.java +++ b/src/main/java/fr/moribus/imageonmap/map/MapManager.java @@ -18,12 +18,17 @@ package fr.moribus.imageonmap.map; +import fr.moribus.imageonmap.ImageOnMap; import java.util.ArrayList; import java.util.UUID; +import org.bukkit.Bukkit; +import org.bukkit.scheduler.BukkitTask; abstract public class MapManager { - static private final ArrayList playerMaps = new ArrayList();; + static private final long SAVE_DELAY = 200; + static private final ArrayList playerMaps = new ArrayList(); + static private BukkitTask autosaveTask; static public void init() { @@ -33,6 +38,8 @@ abstract public class MapManager static public void exit() { playerMaps.clear(); + save(); + if(autosaveTask != null) autosaveTask.cancel(); } static public boolean managesMap(short mapID) @@ -47,6 +54,24 @@ abstract public class MapManager return false; } + static public void notifyModification(UUID playerUUID) + { + getPlayerMapStore(playerUUID).notifyModification(); + if(autosaveTask == null) + Bukkit.getScheduler().runTaskLater(ImageOnMap.getPlugin(), new AutosaveRunnable(), SAVE_DELAY); + } + + static public void save() + { + synchronized(playerMaps) + { + for(PlayerMapStore tStore : playerMaps) + { + tStore.saveMapsFile(); + } + } + } + static private PlayerMapStore getPlayerMapStore(UUID playerUUID) { PlayerMapStore store = getExistingPlayerMapStore(playerUUID); @@ -69,4 +94,21 @@ abstract public class MapManager } return null; } + + static private class AutosaveRunnable implements Runnable + { + @Override + public void run() + { + synchronized(playerMaps) + { + for(PlayerMapStore toolStore : playerMaps) + { + if(toolStore.isModified()) toolStore.saveMapsFile(); + } + autosaveTask = null; + } + } + + } } diff --git a/src/main/java/fr/moribus/imageonmap/map/PlayerMapStore.java b/src/main/java/fr/moribus/imageonmap/map/PlayerMapStore.java index 74da0aa..5ccad9e 100644 --- a/src/main/java/fr/moribus/imageonmap/map/PlayerMapStore.java +++ b/src/main/java/fr/moribus/imageonmap/map/PlayerMapStore.java @@ -18,17 +18,31 @@ package fr.moribus.imageonmap.map; +import fr.moribus.imageonmap.ImageOnMap; +import fr.moribus.imageonmap.PluginLogger; +import java.io.File; +import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.UUID; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.configuration.serialization.ConfigurationSerializable; -public class PlayerMapStore +public class PlayerMapStore implements ConfigurationSerializable { private final UUID playerUUID; private final ArrayList mapList = new ArrayList(); + private boolean modified = false; public PlayerMapStore(UUID playerUUID) { this.playerUUID = playerUUID; + loadMapsFile(); } public boolean managesMap(short mapID) @@ -46,4 +60,91 @@ public class PlayerMapStore { return playerUUID; } + + public boolean isModified() + { + return modified; + } + + public void notifyModification() + { + this.modified = true; + } + + /* ****** Serializing ***** */ + + @Override + public Map serialize() + { + Map map = new HashMap(); + ArrayList list = new ArrayList(); + synchronized(mapList) + { + for(ImageMap tMap : mapList) + { + list.add(tMap.serialize()); + } + } + map.put("mapList", list); + return map; + } + + private void loadFromConfig(ConfigurationSection section) + { + if(section == null) return; + List> list = (List>) section.getList("mapList"); + if(list == null) return; + synchronized(mapList) + { + for(Map tMap : list) + { + try + { + mapList.add(ImageMap.fromConfig(tMap, playerUUID)); + } + catch(InvalidConfigurationException ex) + { + PluginLogger.LogWarning("Could not load map data", ex); + } + } + } + } + + /* ****** Configuration Files management ***** */ + + private FileConfiguration mapConfig = null; + private File mapsFile = null; + + private FileConfiguration getToolConfig() + { + if(mapConfig == null) loadMapsFile(); + + return mapConfig; + } + + private void loadMapsFile() + { + if(mapsFile == null) + { + mapsFile = new File(ImageOnMap.getPlugin().getMapsDirectory(), playerUUID.toString() + ".yml"); + if(!mapsFile.exists()) saveMapsFile(); + } + mapConfig = YamlConfiguration.loadConfiguration(mapsFile); + loadFromConfig(getToolConfig().getConfigurationSection("PlayerMapStore")); + } + + public void saveMapsFile() + { + if(mapsFile == null || mapConfig == null) return; + getToolConfig().set("PlayerMapStore", this.serialize()); + try + { + getToolConfig().save(mapsFile); + } + catch (IOException ex) + { + PluginLogger.LogError("Could not save maps file for player " + playerUUID.toString(), ex); + } + modified = false; + } } diff --git a/src/main/java/fr/moribus/imageonmap/map/PosterMap.java b/src/main/java/fr/moribus/imageonmap/map/PosterMap.java index abfd432..2627bee 100644 --- a/src/main/java/fr/moribus/imageonmap/map/PosterMap.java +++ b/src/main/java/fr/moribus/imageonmap/map/PosterMap.java @@ -20,6 +20,7 @@ package fr.moribus.imageonmap.map; import java.util.Map; import java.util.UUID; +import org.bukkit.configuration.InvalidConfigurationException; public class PosterMap extends ImageMap { @@ -29,7 +30,7 @@ public class PosterMap extends ImageMap public PosterMap(UUID userUUID, short[] mapsIDs, int columnCount, int rowCount) { - super(userUUID); + super(userUUID, Type.POSTER); this.mapsIDs = mapsIDs; this.columnCount = columnCount; this.rowCount = rowCount; @@ -52,6 +53,17 @@ public class PosterMap extends ImageMap return false; } + /* ====== Serialization methods ====== */ + + public PosterMap(Map map, UUID userUUID) throws InvalidConfigurationException + { + super(map, userUUID, Type.POSTER); + + columnCount = getFieldValue(map, "columns"); + rowCount = getFieldValue(map, "rows"); + mapsIDs = getFieldValue(map, "mapIDs"); + } + @Override protected void postSerialize(Map map) { diff --git a/src/main/java/fr/moribus/imageonmap/map/SingleMap.java b/src/main/java/fr/moribus/imageonmap/map/SingleMap.java index 5410115..648279b 100644 --- a/src/main/java/fr/moribus/imageonmap/map/SingleMap.java +++ b/src/main/java/fr/moribus/imageonmap/map/SingleMap.java @@ -20,6 +20,7 @@ package fr.moribus.imageonmap.map; import java.util.Map; import java.util.UUID; +import org.bukkit.configuration.InvalidConfigurationException; public class SingleMap extends ImageMap { @@ -27,7 +28,7 @@ public class SingleMap extends ImageMap public SingleMap(UUID ownerUUID, short mapID) { - super(ownerUUID); + super(ownerUUID, Type.SINGLE); this.mapID = mapID; } @@ -42,7 +43,15 @@ public class SingleMap extends ImageMap { return this.mapID == mapID; } - + + /* ====== Serialization methods ====== */ + + public SingleMap(Map map, UUID userUUID) throws InvalidConfigurationException + { + super(map, userUUID, Type.SINGLE); + mapID = getFieldValue(map, "mapID"); + } + @Override protected void postSerialize(Map map) {