diff --git a/src/main/java/fr/moribus/imageonmap/ImageOnMap.java b/src/main/java/fr/moribus/imageonmap/ImageOnMap.java index 1bcfad8..31aaff4 100644 --- a/src/main/java/fr/moribus/imageonmap/ImageOnMap.java +++ b/src/main/java/fr/moribus/imageonmap/ImageOnMap.java @@ -23,7 +23,7 @@ import fr.moribus.imageonmap.image.ImageIOExecutor; import fr.moribus.imageonmap.image.ImageRendererExecutor; import fr.moribus.imageonmap.image.MapInitEvent; import fr.moribus.imageonmap.map.MapManager; -import fr.moribus.imageonmap.migration.Migrator; +import fr.moribus.imageonmap.migration.MigratorExecutor; import fr.moribus.imageonmap.migration.V3Migrator; import fr.moribus.imageonmap.ui.MapItemManager; import java.io.File; @@ -61,6 +61,7 @@ public final class ImageOnMap extends JavaPlugin @Override public void onEnable() { + PluginLogger.init(this); // Creating the images and maps directories if necessary try { @@ -69,7 +70,7 @@ public final class ImageOnMap extends JavaPlugin } catch(IOException ex) { - PluginLogger.LogError("FATAL : " + ex.getMessage(), null); + PluginLogger.error("FATAL : " + ex.getMessage(), null); this.setEnabled(false); return; } @@ -83,7 +84,6 @@ public final class ImageOnMap extends JavaPlugin Commands.init(this); MapInitEvent.init(this); MapItemManager.init(); - Migrator.startWorker(); } @Override @@ -93,7 +93,8 @@ public final class ImageOnMap extends JavaPlugin ImageRendererExecutor.stop(); MapManager.exit(); MapItemManager.exit(); - Migrator.stopWorker(); + MigratorExecutor.waitForMigration(); + PluginLogger.exit(); } private File checkPluginDirectory(File primaryFile, File... alternateFiles) throws IOException diff --git a/src/main/java/fr/moribus/imageonmap/MetricsLite.java b/src/main/java/fr/moribus/imageonmap/MetricsLite.java index a44bd41..e2e418e 100644 --- a/src/main/java/fr/moribus/imageonmap/MetricsLite.java +++ b/src/main/java/fr/moribus/imageonmap/MetricsLite.java @@ -65,7 +65,7 @@ public class MetricsLite } catch (IOException e) { - PluginLogger.LogError("Failed to start MetricsLite", e); + PluginLogger.error("Failed to start MetricsLite", e); } } @@ -197,7 +197,7 @@ public class MetricsLite firstPost = false; } catch (IOException e) { if (debug) { - PluginLogger.LogWarning("[Metrics] ", e); + PluginLogger.warning("[Metrics] ", e); } } } @@ -219,7 +219,7 @@ public class MetricsLite configuration.load(getConfigFile()); } catch (IOException | InvalidConfigurationException ex) { if (debug) { - PluginLogger.LogInfo("[Metrics] " + ex.getMessage()); + PluginLogger.info("[Metrics] " + ex.getMessage()); } return true; } @@ -408,7 +408,7 @@ public class MetricsLite gzos = new GZIPOutputStream(baos); gzos.write(input.getBytes("UTF-8")); } catch (IOException e) { - PluginLogger.LogError("MetricsLite GZIP error : ", e); + PluginLogger.error("MetricsLite GZIP error : ", e); } finally { if (gzos != null) try { gzos.close(); diff --git a/src/main/java/fr/moribus/imageonmap/PluginLogger.java b/src/main/java/fr/moribus/imageonmap/PluginLogger.java index ae03c14..e3a38bd 100644 --- a/src/main/java/fr/moribus/imageonmap/PluginLogger.java +++ b/src/main/java/fr/moribus/imageonmap/PluginLogger.java @@ -18,33 +18,112 @@ package fr.moribus.imageonmap; +import java.text.MessageFormat; +import java.util.HashMap; import java.util.logging.Level; +import java.util.logging.LogRecord; import java.util.logging.Logger; +import org.bukkit.plugin.Plugin; abstract public class PluginLogger { + static private Plugin plugin; + static private Thread mainThread; + static private HashMap loggers; + + static public void init(Plugin plugin) + { + PluginLogger.plugin = plugin; + mainThread = Thread.currentThread(); + loggers = new HashMap<>(); + } + + static public void exit() + { + plugin = null; + mainThread = null; + loggers = null; + } + + static public void log(Level level, String message, Throwable ex) + { + getLogger().log(level, message, ex); + } + + static public void log(Level level, String message, Object...args) + { + getLogger().log(level, message, args); + } + + static public void log(Level level, String message, Throwable ex, Object... args) + { + log(level, message + " : " + ex.getMessage(), args); + } + + static public void info(String message, Object...args) + { + log(Level.INFO, message, args); + } + + static public void warning(String message, Object... args) + { + log(Level.WARNING, message, args); + } + + static public void warning(String message, Throwable ex) + { + warning(message + " : " + ex.getMessage()); + } + + static public void error(String message) + { + log(Level.SEVERE, message); + } + + static public void error(String message, Throwable ex) + { + log(Level.SEVERE, message, ex); + } + + static public void error(String message, Throwable ex, Object... args) + { + log(Level.SEVERE, message, ex, args); + } + static private Logger getLogger() { - return ImageOnMap.getPlugin().getLogger(); + Thread currentThread = Thread.currentThread(); + if(currentThread.equals(mainThread)) return plugin.getLogger(); + return getLogger(currentThread); } - static public void LogInfo(String message) + static private Logger getLogger(Thread thread) { - getLogger().log(Level.INFO, message); + PluginThreadLogger logger = loggers.get(thread); + if(logger == null) + { + logger = new PluginThreadLogger(thread); + loggers.put(thread, logger); + } + return logger; } - static public void LogWarning(String message) + static private class PluginThreadLogger extends Logger { - getLogger().log(Level.WARNING, message); - } - - static public void LogWarning(String message, Throwable ex) - { - getLogger().log(Level.WARNING, message, ex); - } - - static public void LogError(String message, Throwable ex) - { - getLogger().log(Level.SEVERE, message, ex); + private final String loggerName; + public PluginThreadLogger(Thread thread) + { + super(plugin.getClass().getCanonicalName(), null); + setParent(plugin.getLogger()); + setLevel(Level.ALL); + loggerName = "[" + thread.getName() + "] "; + } + + @Override + public void log(LogRecord logRecord) + { + logRecord.setMessage(loggerName + logRecord.getMessage()); + super.log(logRecord); + } } } diff --git a/src/main/java/fr/moribus/imageonmap/commands/Command.java b/src/main/java/fr/moribus/imageonmap/commands/Command.java index 1b629b0..c771e99 100644 --- a/src/main/java/fr/moribus/imageonmap/commands/Command.java +++ b/src/main/java/fr/moribus/imageonmap/commands/Command.java @@ -65,18 +65,12 @@ abstract public class Command return null; } - public boolean hasPermission(CommandSender sender) - { - if(!commandGroup.getPermission().hasPermission(sender)) return false; - return canExecute(sender); - } - public void execute(CommandSender sender, String[] args) { this.sender = sender; this.args = args; try { - if(!hasPermission(sender)) + if(!canExecute(sender)) throw new CommandException(this, Reason.SENDER_NOT_AUTHORIZED); run(); } diff --git a/src/main/java/fr/moribus/imageonmap/commands/CommandException.java b/src/main/java/fr/moribus/imageonmap/commands/CommandException.java index 2be9800..5f0afb6 100644 --- a/src/main/java/fr/moribus/imageonmap/commands/CommandException.java +++ b/src/main/java/fr/moribus/imageonmap/commands/CommandException.java @@ -65,7 +65,7 @@ public class CommandException extends Exception case SENDER_NOT_AUTHORIZED: return "You do not have the permission to use this command."; default: - PluginLogger.LogWarning("Unknown CommandException caught", this); + PluginLogger.warning("Unknown CommandException caught", this); return "An unknown error suddenly happened."; } } diff --git a/src/main/java/fr/moribus/imageonmap/commands/CommandPermission.java b/src/main/java/fr/moribus/imageonmap/commands/CommandPermission.java deleted file mode 100644 index 3ba24a1..0000000 --- a/src/main/java/fr/moribus/imageonmap/commands/CommandPermission.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2013 Moribus - * Copyright (C) 2015 ProkopyL - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package fr.moribus.imageonmap.commands; - -import org.bukkit.command.CommandSender; -import org.bukkit.plugin.Plugin; - -public abstract class CommandPermission -{ - abstract public boolean hasPermission(CommandSender sender); - - static public final CommandPermission OP_ONLY = new CommandPermission() - { - @Override - public boolean hasPermission(CommandSender sender) - { - return sender.isOp(); - } - }; - - static public CommandPermission bukkitPermission(final String permission) - { - return new CommandPermission() - { - @Override - public boolean hasPermission(CommandSender sender) - { - return sender.hasPermission(permission); - } - }; - } - - static public CommandPermission bukkitPermission(Plugin plugin, String permission) - { - final String permissionName = plugin.getName().toLowerCase() - + "." + permission.toLowerCase(); - return bukkitPermission(permissionName); - } -} diff --git a/src/main/java/fr/moribus/imageonmap/commands/Commands.java b/src/main/java/fr/moribus/imageonmap/commands/Commands.java index 03bb4a2..c237c6c 100644 --- a/src/main/java/fr/moribus/imageonmap/commands/Commands.java +++ b/src/main/java/fr/moribus/imageonmap/commands/Commands.java @@ -18,10 +18,9 @@ package fr.moribus.imageonmap.commands; -import fr.moribus.imageonmap.ImageOnMap; +import fr.moribus.imageonmap.commands.maptool.MigrateCommand; import fr.moribus.imageonmap.PluginLogger; import fr.moribus.imageonmap.commands.maptool.*; -import fr.moribus.imageonmap.commands.migration.*; import java.io.InputStream; import java.lang.reflect.Constructor; import java.util.ArrayList; @@ -36,10 +35,7 @@ import org.bukkit.command.CommandSender; import org.bukkit.command.TabCompleter; import org.bukkit.plugin.java.JavaPlugin; -/** - * - * @author Prokopyl - */ + public enum Commands implements TabCompleter, CommandExecutor { MAPTOOL(new String[]{"maptool"}, @@ -48,22 +44,17 @@ public enum Commands implements TabCompleter, CommandExecutor GetCommand.class, DeleteConfirmCommand.class, DeleteNoConfirmCommand.class, - GetRemainingCommand.class + GetRemainingCommand.class, + MigrateCommand.class ), - TOMAP(MAPTOOL, NewCommand.class, "tomap"), - MAPTOOL_MIGRATION(new String[]{"maptool-migration"}, CommandPermission.OP_ONLY, - StartCommand.class - ); + TOMAP(MAPTOOL, NewCommand.class, "tomap"); - - static private JavaPlugin plugin; static private final Commands[] commandGroups = Commands.class.getEnumConstants(); private final Commands shortcutCommandGroup; private final String[] names; private final Class[] commandsClasses; private final ArrayList commands = new ArrayList<>(); private final HashMap commandsDescriptions = new HashMap<>(); - private final CommandPermission commandPermission; private String description = ""; private Commands(Commands shortcutCommandGroup, Class commandClass, String ... names) @@ -71,23 +62,16 @@ public enum Commands implements TabCompleter, CommandExecutor this.names = names; this.commandsClasses = new Class[]{commandClass}; this.shortcutCommandGroup = shortcutCommandGroup; - this.commandPermission = shortcutCommandGroup.getPermission(); - initCommands(); - } - - private Commands(String[] names, CommandPermission permission, Class ... commandsClasses) - { - this.names = names; - this.commandsClasses = commandsClasses; - this.shortcutCommandGroup = null; - this.commandPermission = permission; - initDescriptions(); initCommands(); } private Commands(String[] names, Class ... commandsClasses) { - this(names, CommandPermission.bukkitPermission(ImageOnMap.getPlugin(), names[0]), commandsClasses); + this.names = names; + this.commandsClasses = commandsClasses; + this.shortcutCommandGroup = null; + initDescriptions(); + initCommands(); } private void initDescriptions() @@ -96,7 +80,7 @@ public enum Commands implements TabCompleter, CommandExecutor InputStream stream = getClass().getClassLoader().getResourceAsStream(fileName); if(stream == null) { - PluginLogger.LogWarning("Could not load description file for the " + getUsualName() + " command"); + PluginLogger.warning("Could not load description file for the " + getUsualName() + " command"); return; } @@ -154,7 +138,7 @@ public enum Commands implements TabCompleter, CommandExecutor } catch (Exception ex) { - PluginLogger.LogWarning("Exception while initializing command", ex); + PluginLogger.warning("Exception while initializing command", ex); } } @@ -341,6 +325,5 @@ public enum Commands implements TabCompleter, CommandExecutor public String getDescription(String commandName) { return commandsDescriptions.get(commandName); } public boolean isShortcutCommand() { return shortcutCommandGroup != null; } public Commands getShortcutCommandGroup() { return shortcutCommandGroup; } - public CommandPermission getPermission() { return commandPermission; } } diff --git a/src/main/java/fr/moribus/imageonmap/commands/HelpCommand.java b/src/main/java/fr/moribus/imageonmap/commands/HelpCommand.java index e26294e..d62b5b1 100644 --- a/src/main/java/fr/moribus/imageonmap/commands/HelpCommand.java +++ b/src/main/java/fr/moribus/imageonmap/commands/HelpCommand.java @@ -73,25 +73,27 @@ public class HelpCommand extends Command if(!command.canExecute(sender)) warning("You do not have the permission to use this command."); - sender.sendMessage("§l§6 ||== ImageOnMap help ==||\n" + - "§l§6 |Usage : §r" + command.getUsageString()); + String message = "§l§6 ||== ImageOnMap help ==||\n" + + "§l§6 |Usage : §r" + command.getUsageString(); try { String help = getHelpText(command); if(help.isEmpty()) { + sender.sendMessage(message); warning("There is no help message for this command."); } else { - sender.sendMessage(help); + sender.sendMessage(message + "\n" + help); } } catch(IOException ex) { + sender.sendMessage(message); warning("Could not read help for this command."); - PluginLogger.LogWarning("Could not read help for the command : " + command.getName(), ex); + PluginLogger.warning("Could not read help for the command : " + command.getName(), ex); } } diff --git a/src/main/java/fr/moribus/imageonmap/commands/maptool/DeleteNoConfirmCommand.java b/src/main/java/fr/moribus/imageonmap/commands/maptool/DeleteNoConfirmCommand.java index 3a2cc6e..3b28fe5 100644 --- a/src/main/java/fr/moribus/imageonmap/commands/maptool/DeleteNoConfirmCommand.java +++ b/src/main/java/fr/moribus/imageonmap/commands/maptool/DeleteNoConfirmCommand.java @@ -48,7 +48,7 @@ public class DeleteNoConfirmCommand extends Command } catch (MapManagerException ex) { - PluginLogger.LogWarning("A non-existent map was requested to be deleted", ex); + PluginLogger.warning("A non-existent map was requested to be deleted", ex); warning("This map does not exist."); } } diff --git a/src/main/java/fr/moribus/imageonmap/commands/migration/StartCommand.java b/src/main/java/fr/moribus/imageonmap/commands/maptool/MigrateCommand.java similarity index 59% rename from src/main/java/fr/moribus/imageonmap/commands/migration/StartCommand.java rename to src/main/java/fr/moribus/imageonmap/commands/maptool/MigrateCommand.java index afa6c3a..8ab9adb 100644 --- a/src/main/java/fr/moribus/imageonmap/commands/migration/StartCommand.java +++ b/src/main/java/fr/moribus/imageonmap/commands/maptool/MigrateCommand.java @@ -16,17 +16,16 @@ * along with this program. If not, see . */ -package fr.moribus.imageonmap.commands.migration; +package fr.moribus.imageonmap.commands.maptool; import fr.moribus.imageonmap.commands.*; -import fr.moribus.imageonmap.migration.Migrator; -import fr.moribus.imageonmap.worker.WorkerCallback; +import fr.moribus.imageonmap.migration.MigratorExecutor; import org.bukkit.command.CommandSender; -@CommandInfo(name = "start") -public class StartCommand extends Command +@CommandInfo(name = "migrate") +public class MigrateCommand extends Command { - public StartCommand(Commands commandGroup) { + public MigrateCommand(Commands commandGroup) { super(commandGroup); } @@ -34,28 +33,20 @@ public class StartCommand extends Command protected void run() throws CommandException { final CommandSender cmdSender = sender; - if(Migrator.isMigrationRunning()) + if(MigratorExecutor.isRunning()) { error("A migration process is already running. Check console for details."); } else { - Migrator.runMigration(new WorkerCallback() - { - @Override - public void finished(Void result) - { - info(cmdSender, "Migration finished. See console for details."); - } - - @Override - public void errored(Throwable exception) - { - warning(cmdSender, "Migration ended unexpectedly. See console for details."); - } - }); - info("Migration started. See console for details."); + MigratorExecutor.migrate(); } } + + @Override + public boolean canExecute(CommandSender sender) + { + return sender.isOp(); + } } diff --git a/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java b/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java index d8e0c3d..2170f02 100644 --- a/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java +++ b/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java @@ -79,7 +79,7 @@ public class NewCommand extends Command public void errored(Throwable exception) { player.sendMessage("§cMap rendering failed : " + exception.getMessage()); - PluginLogger.LogWarning("Rendering from '" + player.getName() + "' failed", exception); + PluginLogger.warning("Rendering from '{0}' failed", exception, player.getName()); } }); } diff --git a/src/main/java/fr/moribus/imageonmap/image/ImageRendererExecutor.java b/src/main/java/fr/moribus/imageonmap/image/ImageRendererExecutor.java index 7245c7b..b1f2921 100644 --- a/src/main/java/fr/moribus/imageonmap/image/ImageRendererExecutor.java +++ b/src/main/java/fr/moribus/imageonmap/image/ImageRendererExecutor.java @@ -170,7 +170,6 @@ public class ImageRendererExecutor extends Worker int x, y; x = (destinationW - finalW) / 2; y = (destinationH - finalH) / 2; - PluginLogger.LogInfo(finalW + " " + finalH + " : " + x + " " + y); BufferedImage newImage = new BufferedImage(destinationW, destinationH, BufferedImage.TYPE_INT_ARGB); diff --git a/src/main/java/fr/moribus/imageonmap/map/MapManager.java b/src/main/java/fr/moribus/imageonmap/map/MapManager.java index 75320c1..0ecf22d 100644 --- a/src/main/java/fr/moribus/imageonmap/map/MapManager.java +++ b/src/main/java/fr/moribus/imageonmap/map/MapManager.java @@ -111,6 +111,11 @@ abstract public class MapManager getPlayerMapStore(map.getUserUUID()).addMap(map); } + static public void insertMap(ImageMap map) + { + getPlayerMapStore(map.getUserUUID()).insertMap(map); + } + static public void deleteMap(ImageMap map) throws MapManagerException { getPlayerMapStore(map.getUserUUID()).deleteMap(map); diff --git a/src/main/java/fr/moribus/imageonmap/map/PlayerMapStore.java b/src/main/java/fr/moribus/imageonmap/map/PlayerMapStore.java index 0a34084..804ef8e 100644 --- a/src/main/java/fr/moribus/imageonmap/map/PlayerMapStore.java +++ b/src/main/java/fr/moribus/imageonmap/map/PlayerMapStore.java @@ -69,6 +69,11 @@ public class PlayerMapStore implements ConfigurationSerializable public synchronized void addMap(ImageMap map) throws MapManagerException { checkMapLimit(map); + insertMap(map); + } + + public synchronized void insertMap(ImageMap map) + { _addMap(map); notifyModification(); } @@ -201,15 +206,15 @@ public class PlayerMapStore implements ConfigurationSerializable } catch(InvalidConfigurationException ex) { - PluginLogger.LogWarning("Could not load map data : " + ex.getMessage()); + PluginLogger.warning("Could not load map data : ", ex); } } try { checkMapLimit(0); } catch(MapManagerException ex) { - PluginLogger.LogWarning("Map limit exceeded for player " + playerUUID.toString() + - " (" + mapList.size() + " maps loaded)."); + PluginLogger.warning("Map limit exceeded for player '{0}' ({1} maps loaded)", + playerUUID.toString(),mapList.size()); } } @@ -246,9 +251,8 @@ public class PlayerMapStore implements ConfigurationSerializable } catch (IOException ex) { - PluginLogger.LogError("Could not save maps file for player " + playerUUID.toString(), ex); + PluginLogger.error("Could not save maps file for player '{0}'", ex, playerUUID.toString()); } - PluginLogger.LogInfo("Saving maps file for " + playerUUID.toString()); synchronized(this) {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 7c8d7bb..0139cdc 100644 --- a/src/main/java/fr/moribus/imageonmap/map/PosterMap.java +++ b/src/main/java/fr/moribus/imageonmap/map/PosterMap.java @@ -33,16 +33,13 @@ public class PosterMap extends ImageMap { super(userUUID, Type.POSTER, id, name); this.mapsIDs = mapsIDs; - this.columnCount = columnCount; - this.rowCount = rowCount; + this.columnCount = Math.max(columnCount, 0); + this.rowCount = Math.max(rowCount, 0); } public PosterMap(UUID userUUID, short[] mapsIDs, int columnCount, int rowCount) { - super(userUUID, Type.POSTER, null, null); - this.mapsIDs = mapsIDs; - this.columnCount = columnCount; - this.rowCount = rowCount; + this(userUUID, mapsIDs, null, null, columnCount, rowCount); } @Override @@ -89,11 +86,19 @@ public class PosterMap extends ImageMap /* ====== Getters & Setters ====== */ + /** + * Returns the amount of columns in the poster map + * @return The number of columns, or 0 if this data is missing + */ public int getColumnCount() { return columnCount; } + /** + * Returns the amount of rows in the poster map + * @return The number of rows, or 0 if this data is missing + */ public int getRowCount() { return rowCount; @@ -101,13 +106,20 @@ public class PosterMap extends ImageMap public int getColumnAt(int i) { + if(columnCount == 0) return 0; return (i % columnCount) + 1; } public int getRowAt(int i) { + if(columnCount == 0) return 0; return (i / columnCount) + 1; } + + public boolean hasColumnData() + { + return rowCount != 0 && columnCount != 0; + } @Override public int getMapCount() diff --git a/src/main/java/fr/moribus/imageonmap/map/SingleMap.java b/src/main/java/fr/moribus/imageonmap/map/SingleMap.java index 2385ca1..1695161 100644 --- a/src/main/java/fr/moribus/imageonmap/map/SingleMap.java +++ b/src/main/java/fr/moribus/imageonmap/map/SingleMap.java @@ -26,10 +26,15 @@ public class SingleMap extends ImageMap { protected final short mapID; + public SingleMap(UUID ownerUUID, short mapID, String id, String name) + { + super(ownerUUID, Type.SINGLE, id, name); + this.mapID = mapID; + } + public SingleMap(UUID ownerUUID, short mapID) { - super(ownerUUID, Type.SINGLE); - this.mapID = mapID; + this(ownerUUID, mapID, null, null); } @Override diff --git a/src/main/java/fr/moribus/imageonmap/migration/Migrator.java b/src/main/java/fr/moribus/imageonmap/migration/Migrator.java deleted file mode 100644 index d32a022..0000000 --- a/src/main/java/fr/moribus/imageonmap/migration/Migrator.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2013 Moribus - * Copyright (C) 2015 ProkopyL - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package fr.moribus.imageonmap.migration; - -import fr.moribus.imageonmap.ImageOnMap; -import fr.moribus.imageonmap.worker.Worker; -import fr.moribus.imageonmap.worker.WorkerCallback; -import fr.moribus.imageonmap.worker.WorkerRunnable; - -public class Migrator extends Worker -{ - static private Migrator instance; - static private V3Migrator migrator; - - static public void startWorker() - { - if(instance != null) stopWorker(); - instance = new Migrator(); - instance.init(); - } - - static public void stopWorker() - { - instance.exit(); - instance = null; - } - - private Migrator() - { - super("Migration"); - } - - static public boolean isMigrationStarted() - { - return migrator != null; - } - - static public boolean isMigrationRunning() - { - return migrator != null && migrator.isRunning(); - } - - static public boolean runMigration(WorkerCallback callback) - { - if(isMigrationRunning()) return false; - if(!isMigrationStarted()) migrator = new V3Migrator(ImageOnMap.getPlugin()); - instance.submitQuery(new WorkerRunnable() - { - @Override - public Void run() throws Throwable - { - migrator.run(); - return null; - } - }, callback); - return true; - } -} diff --git a/src/main/java/fr/moribus/imageonmap/migration/MigratorExecutor.java b/src/main/java/fr/moribus/imageonmap/migration/MigratorExecutor.java new file mode 100644 index 0000000..d8a75a2 --- /dev/null +++ b/src/main/java/fr/moribus/imageonmap/migration/MigratorExecutor.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2013 Moribus + * Copyright (C) 2015 ProkopyL + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package fr.moribus.imageonmap.migration; + +import fr.moribus.imageonmap.ImageOnMap; +import fr.moribus.imageonmap.PluginLogger; + +public class MigratorExecutor +{ + static private Thread migratorThread; + + static public void migrate() + { + if(isRunning()) + { + PluginLogger.error("Migration is already running."); + return; + } + migratorThread = new Thread(new V3Migrator(ImageOnMap.getPlugin()), "ImageOnMap-Migration"); + migratorThread.start(); + } + + static public boolean isRunning() + { + return migratorThread != null && migratorThread.isAlive(); + } + + static public void waitForMigration() + { + if(isRunning()) + { + PluginLogger.info("Waiting for migration to finish ..."); + try + { + migratorThread.join(); + } + catch(InterruptedException ex) + { + PluginLogger.error("Migration thread has been interrupted while wating to finish. It may not have ended correctly."); + } + } + } +} diff --git a/src/main/java/fr/moribus/imageonmap/migration/OldSavedMap.java b/src/main/java/fr/moribus/imageonmap/migration/OldSavedMap.java index a139731..39d99f3 100644 --- a/src/main/java/fr/moribus/imageonmap/migration/OldSavedMap.java +++ b/src/main/java/fr/moribus/imageonmap/migration/OldSavedMap.java @@ -18,7 +18,12 @@ package fr.moribus.imageonmap.migration; +import fr.moribus.imageonmap.map.ImageMap; +import fr.moribus.imageonmap.map.SingleMap; +import java.util.ArrayList; import java.util.List; +import java.util.UUID; +import org.bukkit.configuration.Configuration; import org.bukkit.configuration.InvalidConfigurationException; class OldSavedMap @@ -54,6 +59,20 @@ class OldSavedMap userName = data.get(2); } + public ImageMap toImageMap(UUID userUUID) + { + return new SingleMap(userUUID, mapId, null, mapName); + } + + public void serialize(Configuration configuration) + { + ArrayList data = new ArrayList(); + data.add(Short.toString(mapId)); + data.add(mapName); + data.add(userName); + configuration.set(mapName, data); + } + public short getMapId() {return mapId;} public String getUserName() {return userName;} } diff --git a/src/main/java/fr/moribus/imageonmap/migration/OldSavedPoster.java b/src/main/java/fr/moribus/imageonmap/migration/OldSavedPoster.java index 3aab471..df7b47c 100644 --- a/src/main/java/fr/moribus/imageonmap/migration/OldSavedPoster.java +++ b/src/main/java/fr/moribus/imageonmap/migration/OldSavedPoster.java @@ -18,16 +18,23 @@ package fr.moribus.imageonmap.migration; +import fr.moribus.imageonmap.map.ImageMap; +import fr.moribus.imageonmap.map.PosterMap; +import java.util.ArrayList; import java.util.List; +import java.util.UUID; +import org.bukkit.configuration.Configuration; import org.bukkit.configuration.InvalidConfigurationException; class OldSavedPoster { - private String userName; - private short[] mapsIds; + private final String userName; + private final String posterName; + private final short[] mapsIds; - public OldSavedPoster(Object rawData) throws InvalidConfigurationException + public OldSavedPoster(Object rawData, String key) throws InvalidConfigurationException { + posterName = key; List data; try { @@ -68,5 +75,24 @@ class OldSavedPoster return false; } + public ImageMap toImageMap(UUID userUUID) + { + return new PosterMap(userUUID, mapsIds, null, "poster", 0, 0); + } + + public void serialize(Configuration configuration) + { + ArrayList data = new ArrayList(); + data.add(userName); + + for(short mapId : mapsIds) + { + data.add(Short.toString(mapId)); + } + + configuration.set(posterName, data); + + } + public String getUserName() {return userName;} } diff --git a/src/main/java/fr/moribus/imageonmap/migration/UUIDFetcher.java b/src/main/java/fr/moribus/imageonmap/migration/UUIDFetcher.java index 65ee55c..bad9a75 100644 --- a/src/main/java/fr/moribus/imageonmap/migration/UUIDFetcher.java +++ b/src/main/java/fr/moribus/imageonmap/migration/UUIDFetcher.java @@ -142,7 +142,7 @@ abstract public class UUIDFetcher for(String name : remainingNames) { user = fetchOriginalUUID(name); - uuids.put(user.name, user.uuid); + uuids.put(name, user.uuid); Thread.sleep(timeBetweenRequests); } @@ -151,7 +151,6 @@ abstract public class UUIDFetcher static private User fetchOriginalUUID(String name) throws IOException { HttpURLConnection connection = getGETConnection(TIMED_PROFILE_URL + name + "?at=" + NAME_CHANGE_TIMESTAMP); - sendRequest(connection); JSONObject object; @@ -187,16 +186,11 @@ abstract public class UUIDFetcher connection.setRequestMethod("GET"); connection.setUseCaches(false); connection.setDoInput(true); + connection.setDoOutput(true); + return connection; } - static private void sendRequest(HttpURLConnection connection) throws IOException - { - OutputStream stream = connection.getOutputStream(); - stream.flush(); - stream.close(); - } - private static void writeBody(HttpURLConnection connection, List names) throws IOException { OutputStream stream = connection.getOutputStream(); @@ -208,9 +202,9 @@ abstract public class UUIDFetcher private static Object readResponse(HttpURLConnection connection) throws IOException, ParseException { - return new JSONParser().parse(new InputStreamReader(connection.getInputStream())); + return new JSONParser().parse(new InputStreamReader(connection.getInputStream())); } - + private static UUID fromMojangUUID(String id) //Mojang sends string UUIDs without dashes ... { return UUID.fromString(id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + diff --git a/src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java b/src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java index 930f163..7338b33 100644 --- a/src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java +++ b/src/main/java/fr/moribus/imageonmap/migration/V3Migrator.java @@ -19,6 +19,8 @@ package fr.moribus.imageonmap.migration; import fr.moribus.imageonmap.ImageOnMap; +import fr.moribus.imageonmap.PluginLogger; +import fr.moribus.imageonmap.map.MapManager; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -28,6 +30,7 @@ import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.HashSet; import java.util.Map; @@ -42,7 +45,7 @@ import org.bukkit.plugin.Plugin; /** * This class represents and executes the ImageOnMap v3.x migration process */ -public class V3Migrator +public class V3Migrator implements Runnable { /** * The name of the former images directory @@ -111,12 +114,12 @@ public class V3Migrator /** * The list of all the posters to migrate */ - private final ArrayList postersToMigrate; + private final ArrayDeque postersToMigrate; /** * The list of all the single maps to migrate */ - private final ArrayList mapsToMigrate; + private final ArrayDeque mapsToMigrate; /** * The set of all the user names to retreive the UUID from Mojang @@ -145,8 +148,8 @@ public class V3Migrator backupsPrev3Directory = new File(dataFolder, BACKUPS_PREV3_DIRECTORY_NAME); backupsPostv3Directory = new File(dataFolder, BACKUPS_POSTV3_DIRECTORY_NAME); - postersToMigrate = new ArrayList<>(); - mapsToMigrate = new ArrayList<>(); + postersToMigrate = new ArrayDeque<>(); + mapsToMigrate = new ArrayDeque<>(); userNamesToFetch = new HashSet<>(); } @@ -166,21 +169,22 @@ public class V3Migrator } catch(Exception ex) { - logError("Error while preparing migration", ex); - logError("Aborting migration. No change has been made."); - Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex); + PluginLogger.error("Error while preparing migration"); + PluginLogger.error("Aborting migration. No change has been made.", ex); return; } try { - + mergeMapData(); + saveChanges(); + cleanup(); } catch(Exception ex) { - logError("Error while migrating", ex); - logError("Aborting migration. Some changes may already have been made."); - logError("Before trying to migrate again, you must recover player files from the backups, and then move the backups away from the plugin directory to avoid overwriting them."); + PluginLogger.error("Error while migrating", ex); + PluginLogger.error("Aborting migration. Some changes may already have been made."); + PluginLogger.error("Before trying to migrate again, you must recover player files from the backups, and then move the backups away from the plugin directory to avoid overwriting them."); Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex); } @@ -194,22 +198,22 @@ public class V3Migrator */ private boolean spotFilesToMigrate() { - logInfo("Looking for configuration files to migrate ..."); + PluginLogger.info("Looking for configuration files to migrate ..."); if(!oldPostersFile.exists()) oldPostersFile = null; - else logInfo("Detected former posters file " + OLD_POSTERS_FILE_NAME); + else PluginLogger.info("Detected former posters file {0}", OLD_POSTERS_FILE_NAME); if(!oldMapsFile.exists()) oldMapsFile = null; - else logInfo("Detected former maps file " + OLD_POSTERS_FILE_NAME); + else PluginLogger.info("Detected former maps file {0}", OLD_MAPS_FILE_NAME); if(oldPostersFile == null && oldMapsFile == null) { - logInfo("There is nothing to migrate. Stopping."); + PluginLogger.info("There is nothing to migrate. Stopping."); return false; } else { - logInfo("Done."); + PluginLogger.info("Done."); return true; } } @@ -223,9 +227,9 @@ public class V3Migrator if((backupsPrev3Directory.exists() && backupsPrev3Directory.list().length == 0) || (backupsPostv3Directory.exists() && backupsPostv3Directory.list().length == 0)) { - logError("Backup directories already exists."); - logError("This means that a migration has already been done, or may not have ended well."); - logError("To start a new migration, you must move away the backup directories so they are not overwritten."); + PluginLogger.error("Backup directories already exists."); + PluginLogger.error("This means that a migration has already been done, or may not have ended well."); + PluginLogger.error("To start a new migration, you must move away the backup directories so they are not overwritten."); return true; } @@ -238,18 +242,18 @@ public class V3Migrator */ private void backupMapData() throws IOException { - logInfo("Backing up map data before migrating ..."); + PluginLogger.info("Backing up map data before migrating ..."); if(!backupsPrev3Directory.exists()) backupsPrev3Directory.mkdirs(); if(!backupsPostv3Directory.exists()) backupsPostv3Directory.mkdirs(); - if(oldMapsFile.exists()) + if(oldMapsFile != null && oldMapsFile.exists()) { File oldMapsFileBackup = new File(backupsPrev3Directory, oldMapsFile.getName()); verifiedBackupCopy(oldMapsFile, oldMapsFileBackup); } - if(oldPostersFile.exists()) + if(oldPostersFile != null && oldPostersFile.exists()) { File oldPostersFileBackup = new File(backupsPrev3Directory, oldPostersFile.getName()); verifiedBackupCopy(oldPostersFile, oldPostersFileBackup); @@ -262,7 +266,7 @@ public class V3Migrator verifiedBackupCopy(mapFile, backupFile); } - logInfo("Backup complete."); + PluginLogger.info("Backup complete."); } /** @@ -287,37 +291,45 @@ public class V3Migrator */ private boolean loadOldFiles() { - FileConfiguration oldPosters = YamlConfiguration.loadConfiguration(oldPostersFile); - - OldSavedPoster oldPoster; - for(String key : oldPosters.getKeys(false)) + if(oldPostersFile != null) { - try + FileConfiguration oldPosters = YamlConfiguration.loadConfiguration(oldPostersFile); + + OldSavedPoster oldPoster; + for(String key : oldPosters.getKeys(false)) { - oldPoster = new OldSavedPoster(oldPosters.get(key)); - userNamesToFetch.add(oldPoster.getUserName()); - postersToMigrate.add(oldPoster); - } - catch(InvalidConfigurationException ex) - { - logWarning("Could not read poster data for key " + key, ex); + if("IdCount".equals(key)) continue; + try + { + oldPoster = new OldSavedPoster(oldPosters.get(key), key); + userNamesToFetch.add(oldPoster.getUserName()); + postersToMigrate.add(oldPoster); + } + catch(InvalidConfigurationException ex) + { + PluginLogger.warning("Could not read poster data for key '{0}'", ex, key); + } } } - FileConfiguration oldMaps = YamlConfiguration.loadConfiguration(oldMapsFile); - OldSavedMap oldMap; - - for(String key : oldMaps.getKeys(false)) + if(oldMapsFile != null) { - try + FileConfiguration oldMaps = YamlConfiguration.loadConfiguration(oldMapsFile); + OldSavedMap oldMap; + + for(String key : oldMaps.getKeys(false)) { - oldMap = new OldSavedMap(oldMaps.get(key)); - - if(!posterContains(oldMap)) mapsToMigrate.add(oldMap); - } - catch(InvalidConfigurationException ex) - { - logWarning("Could not read poster data for key " + key, ex); + try + { + if("IdCount".equals(key)) continue; + oldMap = new OldSavedMap(oldMaps.get(key)); + + if(!posterContains(oldMap)) mapsToMigrate.add(oldMap); + } + catch(InvalidConfigurationException ex) + { + PluginLogger.warning("Could not read poster data for key '{0}'", ex, key); + } } } @@ -331,22 +343,22 @@ public class V3Migrator */ private void fetchUUIDs() throws IOException, InterruptedException { - logInfo("Fetching UUIDs from Mojang ..."); + PluginLogger.info("Fetching UUIDs from Mojang ..."); try { usersUUIDs = UUIDFetcher.fetch(new ArrayList(userNamesToFetch)); } catch(IOException ex) { - logError("An error occured while fetching the UUIDs from Mojang", ex); + PluginLogger.error("An error occured while fetching the UUIDs from Mojang", ex); throw ex; } catch(InterruptedException ex) { - logError("The migration worker has been interrupted", ex); + PluginLogger.error("The migration worker has been interrupted", ex); throw ex; } - logInfo("Fetching done. " + usersUUIDs.size() + " UUIDs have been retreived."); + PluginLogger.info("Fetching done. {0} UUIDs have been retreived.", usersUUIDs.size()); } /** @@ -357,8 +369,8 @@ public class V3Migrator { if(usersUUIDs.size() == userNamesToFetch.size()) return true; int remainingUsersCount = userNamesToFetch.size() - usersUUIDs.size(); - logInfo("Mojang did not find UUIDs for "+remainingUsersCount+" players."); - logInfo("The Mojang servers limit requests rate at one per second, this may take some time..."); + PluginLogger.info("Mojang did not find UUIDs for {0} players at the current time.", remainingUsersCount); + PluginLogger.info("The Mojang servers limit requests rate at one per second, this may take some time..."); try { @@ -366,51 +378,143 @@ public class V3Migrator } catch(IOException ex) { - logError("An error occured while fetching the UUIDs from Mojang", ex); + PluginLogger.error("An error occured while fetching the UUIDs from Mojang"); throw ex; } catch(InterruptedException ex) { - logError("The migration worker has been interrupted", ex); + PluginLogger.error("The migration worker has been interrupted"); throw ex; } + if(usersUUIDs.size() != userNamesToFetch.size()) + { + PluginLogger.warning("Mojang did not find player data for {0} players", + userNamesToFetch.size() - usersUUIDs.size()); + PluginLogger.warning("The following players do not exist or do not have paid accounts :"); + + String missingUsersList = ""; + + for(String user : userNamesToFetch) + { + if(!usersUUIDs.containsKey(user)) missingUsersList += user + ","; + } + missingUsersList = missingUsersList.substring(0, missingUsersList.length()); + + PluginLogger.info(missingUsersList); + } if(usersUUIDs.size() <= 0) { - logInfo("Mojang could not find any of the registered players."); - logInfo("There is nothing to migrate. Stopping."); + PluginLogger.info("Mojang could not find any of the registered players."); + PluginLogger.info("There is nothing to migrate. Stopping."); return false; } return true; } + private void mergeMapData() + { + PluginLogger.info("Merging map data ..."); + + ArrayDeque remainingMaps = new ArrayDeque<>(); + ArrayDeque remainingPosters = new ArrayDeque<>(); + + UUID playerUUID; + OldSavedMap map; + while(!mapsToMigrate.isEmpty()) + { + map = mapsToMigrate.pop(); + playerUUID = usersUUIDs.get(map.getUserName()); + if(playerUUID == null) + { + remainingMaps.add(map); + } + else + { + MapManager.insertMap(map.toImageMap(playerUUID)); + } + } + mapsToMigrate.addAll(remainingMaps); + + OldSavedPoster poster; + while(!postersToMigrate.isEmpty()) + { + poster = postersToMigrate.pop(); + playerUUID = usersUUIDs.get(poster.getUserName()); + if(playerUUID == null) + { + remainingPosters.add(poster); + } + else + { + MapManager.insertMap(poster.toImageMap(playerUUID)); + } + } + postersToMigrate.addAll(remainingPosters); + } + + private void saveChanges() + { + PluginLogger.info("Saving changes ..."); + MapManager.save(); + } + + private void cleanup() throws IOException + { + PluginLogger.info("Cleaning up old data files ..."); + + //Cleaning maps file + if(oldMapsFile != null) + { + if(mapsToMigrate.isEmpty()) + { + PluginLogger.info("Deleting old map data file ..."); + oldMapsFile.delete(); + } + else + { + PluginLogger.info("{0} maps could not be migrated.", mapsToMigrate.size()); + YamlConfiguration mapConfig = new YamlConfiguration(); + mapConfig.set("IdCount", mapsToMigrate.size()); + + for(OldSavedMap map : mapsToMigrate) + { + map.serialize(mapConfig); + } + + mapConfig.save(oldMapsFile); + } + } + + //Cleaning posters file + if(oldPostersFile != null) + { + if(postersToMigrate.isEmpty()) + { + PluginLogger.info("Deleting old poster data file ..."); + oldPostersFile.delete(); + } + else + { + PluginLogger.info("{0} posters could not be migrated.", postersToMigrate.size()); + YamlConfiguration posterConfig = new YamlConfiguration(); + posterConfig.set("IdCount", postersToMigrate.size()); + + for(OldSavedPoster poster : postersToMigrate) + { + poster.serialize(posterConfig); + } + + posterConfig.save(oldPostersFile); + } + } + + PluginLogger.info("Data that has not been migrated will be kept in the old data files."); + } + /* ****** Utils ***** */ - static public void logInfo(String message) - { - System.out.println("[ImageOnMap-Migration][INFO] " + message); - } - - static public void logWarning(String message) - { - System.err.println("[ImageOnMap-Migration][WARN] " + message); - } - - static public void logWarning(String message, Exception ex) - { - logWarning(message + " : " + ex.getMessage()); - } - - static public void logError(String message) - { - System.err.println("[ImageOnMap-Migration][ERROR] " + message); - } - - static public void logError(String message, Exception ex) - { - logError(message + " : " + ex.getMessage()); - } - + public synchronized boolean isRunning() { return isRunning; @@ -424,6 +528,7 @@ public class V3Migrator /** * Executes the full migration, and defines the running status of the migration */ + @Override public void run() { setRunning(true); diff --git a/src/main/java/fr/moribus/imageonmap/ui/MapItemManager.java b/src/main/java/fr/moribus/imageonmap/ui/MapItemManager.java index e1a171b..9559ef4 100644 --- a/src/main/java/fr/moribus/imageonmap/ui/MapItemManager.java +++ b/src/main/java/fr/moribus/imageonmap/ui/MapItemManager.java @@ -64,12 +64,20 @@ public class MapItemManager implements Listener short[] mapsIDs = map.getMapsIDs(); boolean inventoryFull = false; + String mapName; for(int i = 0, c = mapsIDs.length; i < c; i++) { - inventoryFull = give(player, - createMapItem(mapsIDs[i], map.getName() + + if(map.hasColumnData()) + { + mapName = map.getName() + " (row " + map.getRowAt(i) + - ", column " + map.getColumnAt(i) + ")")) || inventoryFull; + ", column " + map.getColumnAt(i) + ")"; + } + else + { + mapName = map.getName(); + } + inventoryFull = give(player, createMapItem(mapsIDs[i], mapName)) || inventoryFull; } return inventoryFull; diff --git a/src/main/java/fr/moribus/imageonmap/worker/Worker.java b/src/main/java/fr/moribus/imageonmap/worker/Worker.java index 12dd741..9cae0ac 100644 --- a/src/main/java/fr/moribus/imageonmap/worker/Worker.java +++ b/src/main/java/fr/moribus/imageonmap/worker/Worker.java @@ -48,7 +48,7 @@ public abstract class Worker { if(thread != null && thread.isAlive()) { - PluginLogger.LogWarning("Restarting " + name + " thread."); + PluginLogger.warning("Restarting '{0}' thread.", name); exit(); } callbackManager.init(); @@ -118,7 +118,7 @@ public abstract class Worker private Thread createThread() { - return new Thread("ImageOnMap " + name) + return new Thread("ImageOnMap-" + name) { @Override public void run() diff --git a/src/main/resources/help/maptool/migrate.txt b/src/main/resources/help/maptool/migrate.txt new file mode 100644 index 0000000..6d14df3 --- /dev/null +++ b/src/main/resources/help/maptool/migrate.txt @@ -0,0 +1,36 @@ +Migrates the Map database to the new V3.x format, that uses UUIDs +instead of player names to designate players (among other improvements). +Migration runs in a separate thread, therefore its progress can only be +watched from the server console. + +The migration will run the following steps : + - Checking if there are files to migrate. If not, the migration stops. + - Checking if there are backups from a previous migration. + If there are, the migration stops. + - Loading the old map and poster data to memory. + - Backing up old files and new files, to the backups_pre-v3 and + backups_post-v3 subdirectories respectively. + Backup's integrity are chacked using file size and SHA1 checksum. + If integrity could not be proved, the migration stops. + - Retreiving the UUIDs of the players from Mojang's servers. + - Checking if some UUIDs could not be retreived. + If there are, this means some of your players may have changed names + before the migration started. The plugin will therefore try to retreive + them specifying a time, back when usernames could not be changed. + If some names could still not be matched to their UUIDs, then these are + probably non-paid accounts. + If no UUID has been retreived at all, the migration stops. + §c--- From this step, changes to disk will be made, and you will have to use§r + §c--- backups if you want to revert back from before the migration started.§r + - Merging the old map data with the new one, if there is any + (which can be the case if your player started to use newer + versions of ImageOnMap before the migration started). + - Saving all this merged map data to disk. + - Removing the old map data from their former files, leaving only the data + that could not be migrated due to usernames that could not be matched to + their UUIDs. + Original data is still present in the appropriate backup directory, + just in case. + +Note that this plugin will NEVER delete nor overwrite any backup directory. +Moving or deleting these backups is left to the administrator's responsibility. \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 510f807..49c9253 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -8,9 +8,6 @@ commands: usage: / [URL] maptool: description: manage maps - maptool-migration: - description: Manages the ImageOnMap migrations - permission: op permissions: imageonmap.userender: description: Allows you to use /tomap