mirror of
https://github.com/zDevelopers/ImageOnMap.git
synced 2024-09-28 22:47:45 +02:00
refactor of single map and poster map => poster map
This commit is contained in:
parent
c18ca1448d
commit
fccdf4e5de
@ -123,79 +123,74 @@ public class NewCommand extends IoMCommand {
|
||||
throwInvalidArgument(I.t("Invalid URL."));
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isPlayer = sender != null;
|
||||
// TODO Add a per-player toggle for the GUI.
|
||||
if (args.length >= 2) {
|
||||
ImageRendererExecutor.renderAndNotify(url, scaling, player.getUniqueId(), width, height);
|
||||
} else {
|
||||
if (args.length < 2 && isPlayer) {
|
||||
Gui.open(player, new RenderGui(url));
|
||||
}
|
||||
//I try to test if the gui is run correctly
|
||||
//keep the following as a fallback and for cmd made by console
|
||||
|
||||
/*
|
||||
if (args.length >= 2) {
|
||||
if (args.length >= 3) {
|
||||
try {
|
||||
if (args.length >= 4) {
|
||||
width = Integer.parseInt(args[2]);
|
||||
height = Integer.parseInt(args[3]);
|
||||
} else {
|
||||
String[] size;
|
||||
if (args[2].contains("*") && !args[2].contains("x")) {
|
||||
size = args[2].split("\\*");
|
||||
width = Integer.parseInt(size[0]);
|
||||
height = Integer.parseInt(size[1]);
|
||||
}
|
||||
if (!args[2].contains("*") && args[2].contains("x")) {
|
||||
size = args[2].split("x");
|
||||
width = Integer.parseInt(size[0]);
|
||||
height = Integer.parseInt(size[1]);
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
|
||||
throwInvalidArgument(I.t("resize dimension as to be in format <n m> or <nxm> or <n*m>."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
scaling = resizeMode();
|
||||
}
|
||||
if (width < 0 || height < 0) {
|
||||
throwInvalidArgument(I.t("You need to specify a valid size. e.g. resize 4 5"));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ActionBar.sendPermanentMessage(player, ChatColor.DARK_GREEN + I.t("Rendering..."));
|
||||
ImageRendererExecutor
|
||||
.render(url, scaling, player.getUniqueId(), width, height, new WorkerCallback<ImageMap>() {
|
||||
@Override
|
||||
public void finished(ImageMap result) {
|
||||
ActionBar.removeMessage(player);
|
||||
MessageSender
|
||||
.sendActionBarMessage(player, ChatColor.DARK_GREEN + I.t("Rendering finished!"));
|
||||
|
||||
if (result.give(player)
|
||||
&& (result instanceof PosterMap && !((PosterMap) result).hasColumnData())) {
|
||||
info(I.t("The rendered map was too big to fit in your inventory."));
|
||||
info(I.t("Use '/maptool getremaining' to get the remaining maps."));
|
||||
} else {
|
||||
//ImageRendererExecutor.renderAndNotify(url, scaling, player.getUniqueId(), width, height);
|
||||
if (args.length >= 2) {
|
||||
if (args.length >= 3) {
|
||||
try {
|
||||
if (args.length >= 4) {
|
||||
width = Integer.parseInt(args[2]);
|
||||
height = Integer.parseInt(args[3]);
|
||||
} else {
|
||||
String[] size;
|
||||
if (args[2].contains("*") && !args[2].contains("x")) {
|
||||
size = args[2].split("\\*");
|
||||
width = Integer.parseInt(size[0]);
|
||||
height = Integer.parseInt(size[1]);
|
||||
}
|
||||
if (!args[2].contains("*") && args[2].contains("x")) {
|
||||
size = args[2].split("x");
|
||||
width = Integer.parseInt(size[0]);
|
||||
height = Integer.parseInt(size[1]);
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
|
||||
throwInvalidArgument(I.t("resize dimension as to be in format <n m> or <nxm> or <n*m>."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
scaling = resizeMode();
|
||||
}
|
||||
if (width < 0 || height < 0) {
|
||||
throwInvalidArgument(I.t("You need to specify a valid size. e.g. resize 4 5"));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ActionBar.sendPermanentMessage(player, ChatColor.DARK_GREEN + I.t("Rendering..."));
|
||||
ImageRendererExecutor
|
||||
.render(url, scaling, player.getUniqueId(), width, height, new WorkerCallback<ImageMap>() {
|
||||
@Override
|
||||
public void finished(ImageMap result) {
|
||||
ActionBar.removeMessage(player);
|
||||
MessageSender
|
||||
.sendActionBarMessage(player,
|
||||
ChatColor.DARK_GREEN + I.t("Rendering finished!"));
|
||||
|
||||
@Override
|
||||
public void errored(Throwable exception) {
|
||||
player.sendMessage(I.t("{ce}Map rendering failed: {0}", exception.getMessage()));
|
||||
if (result.give(player)
|
||||
&& (result instanceof PosterMap && !((PosterMap) result).hasColumnData())) {
|
||||
info(I.t("The rendered map was too big to fit in your inventory."));
|
||||
info(I.t("Use '/maptool getremaining' to get the remaining maps."));
|
||||
}
|
||||
}
|
||||
|
||||
PluginLogger.warning("Rendering from {0} failed: {1}: {2}",
|
||||
player.getName(),
|
||||
exception.getClass().getCanonicalName(),
|
||||
exception.getMessage());
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
ActionBar.removeMessage(player);
|
||||
@Override
|
||||
public void errored(Throwable exception) {
|
||||
player.sendMessage(I.t("{ce}Map rendering failed: {0}", exception.getMessage()));
|
||||
|
||||
PluginLogger.warning("Rendering from {0} failed: {1}: {2}",
|
||||
player.getName(),
|
||||
exception.getClass().getCanonicalName(),
|
||||
exception.getMessage());
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
ActionBar.removeMessage(player);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -39,7 +39,6 @@ package fr.moribus.imageonmap.gui;
|
||||
import fr.moribus.imageonmap.Permissions;
|
||||
import fr.moribus.imageonmap.map.ImageMap;
|
||||
import fr.moribus.imageonmap.map.PosterMap;
|
||||
import fr.moribus.imageonmap.map.SingleMap;
|
||||
import fr.moribus.imageonmap.ui.MapItemManager;
|
||||
import fr.zcraft.quartzlib.components.gui.ExplorerGui;
|
||||
import fr.zcraft.quartzlib.components.gui.Gui;
|
||||
@ -105,9 +104,7 @@ public class MapDetailGui extends ExplorerGui<Integer> {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (map instanceof SingleMap) {
|
||||
return MapItemManager.createMapItem((SingleMap) map, true);
|
||||
} else if (map instanceof PosterMap) {
|
||||
if (map instanceof PosterMap) {
|
||||
return MapItemManager.createMapItem((PosterMap) map, x, y);
|
||||
}
|
||||
|
||||
@ -124,15 +121,11 @@ public class MapDetailGui extends ExplorerGui<Integer> {
|
||||
return MapItemManager.createMapItem(poster, poster.getIndex(mapId));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStack getEmptyViewItem() {
|
||||
if (map instanceof SingleMap) {
|
||||
return getViewItem(0, 0);
|
||||
} else {
|
||||
/* @Override
|
||||
protected ItemStack getEmptyViewItem() {
|
||||
return super.getEmptyViewItem();
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
@Override
|
||||
protected void onUpdate() {
|
||||
/// Title of the map details GUI
|
||||
|
@ -41,7 +41,6 @@ import fr.moribus.imageonmap.PluginConfiguration;
|
||||
import fr.moribus.imageonmap.map.ImageMap;
|
||||
import fr.moribus.imageonmap.map.MapManager;
|
||||
import fr.moribus.imageonmap.map.PosterMap;
|
||||
import fr.moribus.imageonmap.map.SingleMap;
|
||||
import fr.moribus.imageonmap.ui.MapItemManager;
|
||||
import fr.moribus.imageonmap.ui.SplatterMapManager;
|
||||
import fr.zcraft.quartzlib.components.gui.ExplorerGui;
|
||||
@ -72,19 +71,14 @@ public class MapListGui extends ExplorerGui<ImageMap> {
|
||||
@Override
|
||||
protected ItemStack getViewItem(ImageMap map) {
|
||||
String mapDescription;
|
||||
if (map instanceof SingleMap) {
|
||||
/// Displayed subtitle description of a single map on the list GUI
|
||||
mapDescription = I.tl(getPlayerLocale(), "{white}Single map");
|
||||
PosterMap poster = (PosterMap) map;
|
||||
if (poster.hasColumnData()) {
|
||||
/// Displayed subtitle description of a poster map on the list GUI (columns × rows in english)
|
||||
mapDescription = I.tl(getPlayerLocale(), "{white}Poster map ({0} × {1})", poster.getColumnCount(),
|
||||
poster.getRowCount());
|
||||
} else {
|
||||
PosterMap poster = (PosterMap) map;
|
||||
if (poster.hasColumnData()) {
|
||||
/// Displayed subtitle description of a poster map on the list GUI (columns × rows in english)
|
||||
mapDescription = I.tl(getPlayerLocale(), "{white}Poster map ({0} × {1})", poster.getColumnCount(),
|
||||
poster.getRowCount());
|
||||
} else {
|
||||
/// Displayed subtitle description of a poster map without column data on the list GUI
|
||||
mapDescription = I.tl(getPlayerLocale(), "{white}Poster map ({0} parts)", poster.getMapCount());
|
||||
}
|
||||
/// Displayed subtitle description of a poster map without column data on the list GUI
|
||||
mapDescription = I.tl(getPlayerLocale(), "{white}Poster map ({0} parts)", poster.getMapCount());
|
||||
}
|
||||
|
||||
ItemStackBuilder builder = new ItemStackBuilder(Material.FILLED_MAP)
|
||||
@ -147,9 +141,7 @@ public class MapListGui extends ExplorerGui<ImageMap> {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (map instanceof SingleMap) {
|
||||
return MapItemManager.createMapItem(map.getMapsIDs()[0], map.getName(), false, true);
|
||||
} else if (map instanceof PosterMap) {
|
||||
if (map instanceof PosterMap) {
|
||||
PosterMap poster = (PosterMap) map;
|
||||
|
||||
if (poster.hasColumnData()) {
|
||||
|
@ -65,7 +65,6 @@ import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
|
||||
|
||||
@WorkerAttributes(name = "Image Renderer", queriesMainThread = true)
|
||||
public class ImageRendererExecutor extends Worker {
|
||||
public static void renderAndNotify(final URL url, final ImageUtils.ScalingType scaling, final UUID playerUUID,
|
||||
@ -189,14 +188,10 @@ public class ImageRendererExecutor extends Worker {
|
||||
// Limits are in place and the player does NOT have rights to avoid them.
|
||||
checkSizeLimit(playerUUID, image);
|
||||
final BufferedImage resizedImage;
|
||||
if (scaling != ImageUtils.ScalingType.NONE && height <= 1 && width <= 1) {
|
||||
resizedImage = scaling.resize(image, ImageMap.WIDTH * width, ImageMap.HEIGHT * height);
|
||||
image.flush();//Safe to free
|
||||
return renderSingle(resizedImage, playerUUID);
|
||||
}
|
||||
resizedImage =
|
||||
scaling.resize(image, ImageMap.WIDTH * width, ImageMap.HEIGHT * height);
|
||||
|
||||
resizedImage = scaling.resize(image, ImageMap.WIDTH * width, ImageMap.HEIGHT * height);
|
||||
image.flush();//Safe to free
|
||||
|
||||
return renderPoster(resizedImage, playerUUID);
|
||||
}
|
||||
}, callback);
|
||||
@ -249,27 +244,6 @@ public class ImageRendererExecutor extends Worker {
|
||||
});
|
||||
}
|
||||
|
||||
private static ImageMap renderSingle(final BufferedImage image, final UUID playerUUID) throws Throwable {
|
||||
MapManager.checkMapLimit(1, playerUUID);
|
||||
final Future<Integer> futureMapID = submitToMainThread(new Callable<Integer>() {
|
||||
@Override
|
||||
public Integer call() throws Exception {
|
||||
return MapManager.getNewMapsIds(1)[0];
|
||||
}
|
||||
});
|
||||
|
||||
final int mapID = futureMapID.get();
|
||||
ImageIOExecutor.saveImage(mapID, image);
|
||||
submitToMainThread(new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
Renderer.installRenderer(image, mapID);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
return MapManager.createMap(playerUUID, mapID);
|
||||
}
|
||||
|
||||
private static ImageMap renderPoster(final BufferedImage image, final UUID playerUUID) throws Throwable {
|
||||
final PosterImage poster = new PosterImage(image);
|
||||
final int mapCount = poster.getImagesCount();
|
||||
|
@ -91,7 +91,7 @@ public abstract class ImageMap implements ConfigurationSerializable {
|
||||
}
|
||||
|
||||
public static ImageMap fromConfig(Map<String, Object> map, UUID userUUID) throws InvalidConfigurationException {
|
||||
Type mapType;
|
||||
Type mapType;//TODO refactor this
|
||||
try {
|
||||
mapType = Type.valueOf((String) map.get("type"));
|
||||
} catch (ClassCastException ex) {
|
||||
@ -100,7 +100,6 @@ public abstract class ImageMap implements ConfigurationSerializable {
|
||||
|
||||
switch (mapType) {
|
||||
case SINGLE:
|
||||
return new SingleMap(map, userUUID);
|
||||
case POSTER:
|
||||
return new PosterMap(map, userUUID);
|
||||
default:
|
||||
|
@ -102,8 +102,10 @@ public abstract class MapManager {
|
||||
}
|
||||
|
||||
public static ImageMap createMap(UUID playerUUID, int mapID) throws MapManagerException {
|
||||
ImageMap newMap = new SingleMap(playerUUID, mapID);
|
||||
addMap(newMap);
|
||||
//ImageMap newMap = new SingleMap(playerUUID, mapID);
|
||||
int[] ids = new int[] {mapID};
|
||||
ImageMap newMap = new PosterMap(playerUUID, ids, 1, 1);
|
||||
addMap(newMap);//TODO refactor this
|
||||
return newMap;
|
||||
}
|
||||
|
||||
@ -111,7 +113,8 @@ public abstract class MapManager {
|
||||
ImageMap newMap;
|
||||
|
||||
if (image.getImagesCount() == 1) {
|
||||
newMap = new SingleMap(playerUUID, mapsIDs[0]);
|
||||
newMap = new PosterMap(playerUUID, mapsIDs, 1, 1);//TODO refactor this
|
||||
//newMap = new SingleMap(playerUUID, mapsIDs[0]);
|
||||
} else {
|
||||
newMap = new PosterMap(playerUUID, mapsIDs, image.getColumns(), image.getLines());
|
||||
}
|
||||
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright or © or Copr. Moribus (2013)
|
||||
* Copyright or © or Copr. ProkopyL <prokopylmc@gmail.com> (2015)
|
||||
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 – 2022)
|
||||
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 – 2022)
|
||||
*
|
||||
* This software is a computer program whose purpose is to allow insertion of
|
||||
* custom images in a Minecraft world.
|
||||
*
|
||||
* This software is governed by the CeCILL license under French law and
|
||||
* abiding by the rules of distribution of free software. You can use,
|
||||
* modify and/ or redistribute the software under the terms of the CeCILL
|
||||
* license as circulated by CEA, CNRS and INRIA at the following URL
|
||||
* "http://www.cecill.info".
|
||||
*
|
||||
* As a counterpart to the access to the source code and rights to copy,
|
||||
* modify and redistribute granted by the license, users are provided only
|
||||
* with a limited warranty and the software's author, the holder of the
|
||||
* economic rights, and the successive licensors have only limited
|
||||
* liability.
|
||||
*
|
||||
* In this respect, the user's attention is drawn to the risks associated
|
||||
* with loading, using, modifying and/or developing or reproducing the
|
||||
* software by the user in light of its specific status of free software,
|
||||
* that may mean that it is complicated to manipulate, and that also
|
||||
* therefore means that it is reserved for developers and experienced
|
||||
* professionals having in-depth computer knowledge. Users are therefore
|
||||
* encouraged to load and test the software's suitability as regards their
|
||||
* requirements in conditions enabling the security of their systems and/or
|
||||
* data to be ensured and, more generally, to use and operate it in the
|
||||
* same conditions as regards security.
|
||||
*
|
||||
* The fact that you are presently reading this means that you have had
|
||||
* knowledge of the CeCILL license and that you accept its terms.
|
||||
*/
|
||||
|
||||
package fr.moribus.imageonmap.map;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
|
||||
public class SingleMap extends ImageMap {
|
||||
protected final int mapID;
|
||||
|
||||
public SingleMap(UUID ownerUUID, int mapID, String id, String name) {
|
||||
super(ownerUUID, Type.SINGLE, id, name);
|
||||
this.mapID = mapID;
|
||||
}
|
||||
|
||||
public SingleMap(UUID ownerUUID, int mapID) {
|
||||
this(ownerUUID, mapID, null, null);
|
||||
}
|
||||
|
||||
public SingleMap(Map<String, Object> map, UUID userUUID) throws InvalidConfigurationException {
|
||||
super(map, userUUID, Type.SINGLE);
|
||||
mapID = getFieldValue(map, "mapID");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getMapsIDs() {
|
||||
return new int[] {mapID};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean managesMap(int mapID) {
|
||||
return this.mapID == mapID;
|
||||
}
|
||||
|
||||
/* ====== Serialization methods ====== */
|
||||
|
||||
@Override
|
||||
public int getMapCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postSerialize(Map<String, Object> map) {
|
||||
map.put("mapID", mapID);
|
||||
}
|
||||
|
||||
}
|
@ -36,7 +36,6 @@
|
||||
|
||||
package fr.moribus.imageonmap.migration;
|
||||
|
||||
import fr.moribus.imageonmap.ImageOnMap;
|
||||
import fr.zcraft.quartzlib.components.i18n.I;
|
||||
import fr.zcraft.quartzlib.tools.PluginLogger;
|
||||
|
||||
@ -49,7 +48,7 @@ public class MigratorExecutor {
|
||||
PluginLogger.error(I.t("Migration is already running."));
|
||||
return;
|
||||
}
|
||||
migratorThread = new Thread(new V3Migrator(ImageOnMap.getPlugin()), "ImageOnMap-Migration");
|
||||
//migratorThread = new Thread(new V3Migrator(ImageOnMap.getPlugin()), "ImageOnMap-Migration");
|
||||
migratorThread.start();
|
||||
}
|
||||
|
||||
|
@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright or © or Copr. Moribus (2013)
|
||||
* Copyright or © or Copr. ProkopyL <prokopylmc@gmail.com> (2015)
|
||||
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 – 2022)
|
||||
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 – 2022)
|
||||
*
|
||||
* This software is a computer program whose purpose is to allow insertion of
|
||||
* custom images in a Minecraft world.
|
||||
*
|
||||
* This software is governed by the CeCILL license under French law and
|
||||
* abiding by the rules of distribution of free software. You can use,
|
||||
* modify and/ or redistribute the software under the terms of the CeCILL
|
||||
* license as circulated by CEA, CNRS and INRIA at the following URL
|
||||
* "http://www.cecill.info".
|
||||
*
|
||||
* As a counterpart to the access to the source code and rights to copy,
|
||||
* modify and redistribute granted by the license, users are provided only
|
||||
* with a limited warranty and the software's author, the holder of the
|
||||
* economic rights, and the successive licensors have only limited
|
||||
* liability.
|
||||
*
|
||||
* In this respect, the user's attention is drawn to the risks associated
|
||||
* with loading, using, modifying and/or developing or reproducing the
|
||||
* software by the user in light of its specific status of free software,
|
||||
* that may mean that it is complicated to manipulate, and that also
|
||||
* therefore means that it is reserved for developers and experienced
|
||||
* professionals having in-depth computer knowledge. Users are therefore
|
||||
* encouraged to load and test the software's suitability as regards their
|
||||
* requirements in conditions enabling the security of their systems and/or
|
||||
* data to be ensured and, more generally, to use and operate it in the
|
||||
* same conditions as regards security.
|
||||
*
|
||||
* The fact that you are presently reading this means that you have had
|
||||
* knowledge of the CeCILL license and that you accept its terms.
|
||||
*/
|
||||
|
||||
package fr.moribus.imageonmap.migration;
|
||||
|
||||
import fr.moribus.imageonmap.map.ImageMap;
|
||||
import fr.moribus.imageonmap.map.MapManager;
|
||||
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 {
|
||||
private final short mapId;
|
||||
private final String mapName;
|
||||
private final String userName;
|
||||
|
||||
public OldSavedMap(Object rawData) throws InvalidConfigurationException {
|
||||
List<String> data;
|
||||
try {
|
||||
data = (List<String>) rawData;
|
||||
} catch (ClassCastException ex) {
|
||||
throw new InvalidConfigurationException("Invalid map data : " + ex.getMessage());
|
||||
}
|
||||
|
||||
if (data.size() < 3) {
|
||||
throw new InvalidConfigurationException("Map data too short (given : " + data.size() + ", expected 3)");
|
||||
}
|
||||
try {
|
||||
mapId = Short.parseShort(data.get(0));
|
||||
} catch (NumberFormatException ex) {
|
||||
throw new InvalidConfigurationException("Invalid map ID : " + ex.getMessage());
|
||||
}
|
||||
|
||||
mapName = data.get(1);
|
||||
userName = data.get(2);
|
||||
}
|
||||
|
||||
public ImageMap toImageMap(UUID userUUID) {
|
||||
return new SingleMap(userUUID, mapId, null, mapName);
|
||||
}
|
||||
|
||||
public void serialize(Configuration configuration) {
|
||||
ArrayList<String> data = new ArrayList<>();
|
||||
data.add(Short.toString(mapId));
|
||||
data.add(mapName);
|
||||
data.add(userName);
|
||||
configuration.set(mapName, data);
|
||||
}
|
||||
|
||||
public boolean isMapValid() {
|
||||
return MapManager.mapIdExists(mapId);
|
||||
}
|
||||
|
||||
public short getMapId() {
|
||||
return mapId;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Copyright or © or Copr. Moribus (2013)
|
||||
* Copyright or © or Copr. ProkopyL <prokopylmc@gmail.com> (2015)
|
||||
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 – 2022)
|
||||
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 – 2022)
|
||||
*
|
||||
* This software is a computer program whose purpose is to allow insertion of
|
||||
* custom images in a Minecraft world.
|
||||
*
|
||||
* This software is governed by the CeCILL license under French law and
|
||||
* abiding by the rules of distribution of free software. You can use,
|
||||
* modify and/ or redistribute the software under the terms of the CeCILL
|
||||
* license as circulated by CEA, CNRS and INRIA at the following URL
|
||||
* "http://www.cecill.info".
|
||||
*
|
||||
* As a counterpart to the access to the source code and rights to copy,
|
||||
* modify and redistribute granted by the license, users are provided only
|
||||
* with a limited warranty and the software's author, the holder of the
|
||||
* economic rights, and the successive licensors have only limited
|
||||
* liability.
|
||||
*
|
||||
* In this respect, the user's attention is drawn to the risks associated
|
||||
* with loading, using, modifying and/or developing or reproducing the
|
||||
* software by the user in light of its specific status of free software,
|
||||
* that may mean that it is complicated to manipulate, and that also
|
||||
* therefore means that it is reserved for developers and experienced
|
||||
* professionals having in-depth computer knowledge. Users are therefore
|
||||
* encouraged to load and test the software's suitability as regards their
|
||||
* requirements in conditions enabling the security of their systems and/or
|
||||
* data to be ensured and, more generally, to use and operate it in the
|
||||
* same conditions as regards security.
|
||||
*
|
||||
* The fact that you are presently reading this means that you have had
|
||||
* knowledge of the CeCILL license and that you accept its terms.
|
||||
*/
|
||||
|
||||
package fr.moribus.imageonmap.migration;
|
||||
|
||||
import fr.moribus.imageonmap.map.ImageMap;
|
||||
import fr.moribus.imageonmap.map.MapManager;
|
||||
import fr.moribus.imageonmap.map.PosterMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.configuration.Configuration;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
|
||||
class OldSavedPoster {
|
||||
private final String userName;
|
||||
private final String posterName;
|
||||
private final short[] mapsIds;
|
||||
|
||||
public OldSavedPoster(Object rawData, String key) throws InvalidConfigurationException {
|
||||
posterName = key;
|
||||
List<String> data;
|
||||
try {
|
||||
data = (List<String>) rawData;
|
||||
} catch (ClassCastException ex) {
|
||||
throw new InvalidConfigurationException("Invalid map data : " + ex.getMessage());
|
||||
}
|
||||
|
||||
if (data.size() < 2) {
|
||||
throw new InvalidConfigurationException(
|
||||
"Poster data too short (given : " + data.size() + ", expected at least 2)");
|
||||
}
|
||||
userName = data.get(0);
|
||||
mapsIds = new short[data.size() - 1];
|
||||
|
||||
for (int i = 1, c = data.size(); i < c; i++) {
|
||||
try {
|
||||
mapsIds[i - 1] = Short.parseShort(data.get(i));
|
||||
} catch (NumberFormatException ex) {
|
||||
throw new InvalidConfigurationException("Invalid map ID : " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(OldSavedMap map) {
|
||||
short mapId = map.getMapId();
|
||||
|
||||
for (short mapsId : mapsIds) {
|
||||
if (mapsId == mapId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public ImageMap toImageMap(UUID userUUID) {
|
||||
// Converts the maps IDs to int as MC 1.13.2+ uses integer ids
|
||||
final int[] mapsIdsInt = new int[mapsIds.length];
|
||||
Arrays.setAll(mapsIdsInt, i -> mapsIds[i]);
|
||||
|
||||
return new PosterMap(userUUID, mapsIdsInt, null, "poster", 0, 0);
|
||||
}
|
||||
|
||||
public void serialize(Configuration configuration) {
|
||||
ArrayList<String> data = new ArrayList<>();
|
||||
data.add(userName);
|
||||
|
||||
for (short mapId : mapsIds) {
|
||||
data.add(Short.toString(mapId));
|
||||
}
|
||||
|
||||
configuration.set(posterName, data);
|
||||
|
||||
}
|
||||
|
||||
public boolean isMapValid() {
|
||||
for (short mapId : mapsIds) {
|
||||
if (!MapManager.mapIdExists(mapId)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public short[] getMapsIds() {
|
||||
return mapsIds;
|
||||
}
|
||||
}
|
@ -1,619 +0,0 @@
|
||||
/*
|
||||
* Copyright or © or Copr. Moribus (2013)
|
||||
* Copyright or © or Copr. ProkopyL <prokopylmc@gmail.com> (2015)
|
||||
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 – 2022)
|
||||
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 – 2022)
|
||||
*
|
||||
* This software is a computer program whose purpose is to allow insertion of
|
||||
* custom images in a Minecraft world.
|
||||
*
|
||||
* This software is governed by the CeCILL license under French law and
|
||||
* abiding by the rules of distribution of free software. You can use,
|
||||
* modify and/ or redistribute the software under the terms of the CeCILL
|
||||
* license as circulated by CEA, CNRS and INRIA at the following URL
|
||||
* "http://www.cecill.info".
|
||||
*
|
||||
* As a counterpart to the access to the source code and rights to copy,
|
||||
* modify and redistribute granted by the license, users are provided only
|
||||
* with a limited warranty and the software's author, the holder of the
|
||||
* economic rights, and the successive licensors have only limited
|
||||
* liability.
|
||||
*
|
||||
* In this respect, the user's attention is drawn to the risks associated
|
||||
* with loading, using, modifying and/or developing or reproducing the
|
||||
* software by the user in light of its specific status of free software,
|
||||
* that may mean that it is complicated to manipulate, and that also
|
||||
* therefore means that it is reserved for developers and experienced
|
||||
* professionals having in-depth computer knowledge. Users are therefore
|
||||
* encouraged to load and test the software's suitability as regards their
|
||||
* requirements in conditions enabling the security of their systems and/or
|
||||
* data to be ensured and, more generally, to use and operate it in the
|
||||
* same conditions as regards security.
|
||||
*
|
||||
* The fact that you are presently reading this means that you have had
|
||||
* knowledge of the CeCILL license and that you accept its terms.
|
||||
*/
|
||||
|
||||
package fr.moribus.imageonmap.migration;
|
||||
|
||||
import fr.moribus.imageonmap.ImageOnMap;
|
||||
import fr.moribus.imageonmap.map.MapManager;
|
||||
import fr.zcraft.quartzlib.components.i18n.I;
|
||||
import fr.zcraft.quartzlib.tools.PluginLogger;
|
||||
import fr.zcraft.quartzlib.tools.mojang.UUIDFetcher;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
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.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
/**
|
||||
* This class represents and executes the ImageOnMap v3.x migration process
|
||||
*/
|
||||
public class V3Migrator implements Runnable {
|
||||
/**
|
||||
* The name of the former images directory
|
||||
*/
|
||||
private static final String OLD_IMAGES_DIRECTORY_NAME = "Image";
|
||||
|
||||
/**
|
||||
* The name of the former file that contained all the maps definitions (including posters)
|
||||
*/
|
||||
private static final String OLD_MAPS_FILE_NAME = "map.yml";
|
||||
|
||||
/**
|
||||
* The name of the former file that contained all the posters definitions
|
||||
*/
|
||||
private static final String OLD_POSTERS_FILE_NAME = "poster.yml";
|
||||
|
||||
/**
|
||||
* The name of the backup directory that will contain the pre-v3 files that
|
||||
* were present before the migration started
|
||||
*/
|
||||
private static final String BACKUPS_PREV3_DIRECTORY_NAME = "backups_pre-v3";
|
||||
|
||||
/**
|
||||
* The name of the backup directory that will contain the post-v3 files that
|
||||
* were present before the migration started
|
||||
*/
|
||||
private static final String BACKUPS_POSTV3_DIRECTORY_NAME = "backups_post-v3";
|
||||
/**
|
||||
* The plugin that is running the migration
|
||||
*/
|
||||
private final ImageOnMap plugin;
|
||||
/**
|
||||
* The backup directory that will contain the pre-v3 files that
|
||||
* were present before the migration started
|
||||
*/
|
||||
private final File backupsPrev3Directory;
|
||||
/**
|
||||
* The backup directory that will contain the post-v3 files that
|
||||
* were present before the migration started
|
||||
*/
|
||||
private final File backupsPostv3Directory;
|
||||
/**
|
||||
* The list of all the posters to migrate
|
||||
*/
|
||||
private final ArrayDeque<OldSavedPoster> postersToMigrate;
|
||||
/**
|
||||
* The list of all the single maps to migrate
|
||||
*/
|
||||
private final ArrayDeque<OldSavedMap> mapsToMigrate;
|
||||
/**
|
||||
* The set of all the user names to retreive the UUID from Mojang
|
||||
*/
|
||||
private final HashSet<String> userNamesToFetch;
|
||||
/**
|
||||
* The former file that contained all the posters definitions
|
||||
*/
|
||||
private File oldPostersFile;
|
||||
/**
|
||||
* The former file that contained all the maps definitions (including posters)
|
||||
*/
|
||||
private File oldMapsFile;
|
||||
/**
|
||||
* The map of all the usernames and their corresponding UUIDs
|
||||
*/
|
||||
private Map<String, UUID> usersUUIDs;
|
||||
/**
|
||||
* Defines if the migration process is currently running
|
||||
*/
|
||||
private boolean isRunning = false;
|
||||
|
||||
public V3Migrator(ImageOnMap plugin) {
|
||||
this.plugin = plugin;
|
||||
|
||||
File dataFolder = plugin.getDataFolder();
|
||||
|
||||
oldPostersFile = new File(dataFolder, OLD_POSTERS_FILE_NAME);
|
||||
oldMapsFile = new File(dataFolder, OLD_MAPS_FILE_NAME);
|
||||
|
||||
backupsPrev3Directory = new File(dataFolder, BACKUPS_PREV3_DIRECTORY_NAME);
|
||||
backupsPostv3Directory = new File(dataFolder, BACKUPS_POSTV3_DIRECTORY_NAME);
|
||||
|
||||
postersToMigrate = new ArrayDeque<>();
|
||||
mapsToMigrate = new ArrayDeque<>();
|
||||
userNamesToFetch = new HashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the former images directory of a given plugin
|
||||
*
|
||||
* @param plugin The plugin.
|
||||
* @return the corresponding 'Image' directory
|
||||
*/
|
||||
public static File getOldImagesDirectory(Plugin plugin) {
|
||||
return new File(plugin.getDataFolder(), OLD_IMAGES_DIRECTORY_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a standard file copy, and checks the integrity of the destination
|
||||
* file after the copy
|
||||
*
|
||||
* @param sourceFile The file to copy
|
||||
* @param destinationFile The destination file
|
||||
* @throws IOException If the copy failed, if the integrity check failed, or if the destination file already exists
|
||||
*/
|
||||
private static void verifiedBackupCopy(File sourceFile, File destinationFile) throws IOException {
|
||||
if (destinationFile.exists()) {
|
||||
throw new IOException(
|
||||
"Backup copy failed : destination file (" + destinationFile.getName() + ") already exists.");
|
||||
}
|
||||
|
||||
long sourceSize = sourceFile.length();
|
||||
String sourceCheckSum = fileCheckSum(sourceFile, "SHA1");
|
||||
|
||||
Path sourcePath = Paths.get(sourceFile.getAbsolutePath());
|
||||
Path destinationPath = Paths.get(destinationFile.getAbsolutePath());
|
||||
Files.copy(sourcePath, destinationPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
long destinationSize = destinationFile.length();
|
||||
String destinationCheckSum = fileCheckSum(destinationFile, "SHA1");
|
||||
|
||||
if (sourceSize != destinationSize || !sourceCheckSum.equals(destinationCheckSum)) {
|
||||
throw new IOException("Backup copy failed : source and destination files ("
|
||||
+ sourceFile.getName()
|
||||
+ ") differ after copy.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ****** Actions ***** */
|
||||
|
||||
/**
|
||||
* Calculates the checksum of a given file
|
||||
*
|
||||
* @param file The file to calculate the checksum of
|
||||
* @param algorithmName The name of the algorithm to use
|
||||
* @return The resulting checksum in hexadecimal format
|
||||
* @throws IOException
|
||||
**/
|
||||
private static String fileCheckSum(File file, String algorithmName) throws IOException {
|
||||
MessageDigest instance;
|
||||
try {
|
||||
instance = MessageDigest.getInstance(algorithmName);
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
throw new IOException(
|
||||
"Could not check file integrity because of NoSuchAlgorithmException : " + ex.getMessage());
|
||||
}
|
||||
|
||||
FileInputStream inputStream = new FileInputStream(file);
|
||||
|
||||
byte[] data = new byte[1024];
|
||||
int read = 0;
|
||||
|
||||
while ((read = inputStream.read(data)) != -1) {
|
||||
instance.update(data);
|
||||
}
|
||||
|
||||
byte[] hashBytes = instance.digest();
|
||||
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
char hexChar;
|
||||
for (int i = 0; i < hashBytes.length; i++) {
|
||||
hexChar = Integer.toHexString((hashBytes[i] & 0xff) + 0x100).charAt(0);
|
||||
buffer.append(hexChar);
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the full migration
|
||||
*/
|
||||
private void migrate() {
|
||||
try {
|
||||
if (!spotFilesToMigrate()) {
|
||||
return;
|
||||
}
|
||||
if (checkForExistingBackups()) {
|
||||
return;
|
||||
}
|
||||
if (!loadOldFiles()) {
|
||||
return;
|
||||
}
|
||||
backupMapData();
|
||||
fetchUUIDs();
|
||||
if (!fetchMissingUUIDs()) {
|
||||
return;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
PluginLogger.error(I.t("Error while preparing migration"));
|
||||
PluginLogger.error(I.t("Aborting migration. No change has been made."), ex);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
mergeMapData();
|
||||
saveChanges();
|
||||
cleanup();
|
||||
} catch (Exception ex) {
|
||||
PluginLogger.error(I.t("Error while migrating"), ex);
|
||||
PluginLogger.error(I.t("Aborting migration. Some changes may already have been made."));
|
||||
PluginLogger.error(I.t(
|
||||
"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."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there is any of the former files to be migrated
|
||||
*
|
||||
* @return true if any former map or poster file exists, false otherwise
|
||||
*/
|
||||
private boolean spotFilesToMigrate() {
|
||||
PluginLogger.info(I.t("Looking for configuration files to migrate..."));
|
||||
|
||||
if (!oldPostersFile.exists()) {
|
||||
oldPostersFile = null;
|
||||
} else {
|
||||
PluginLogger.info(I.t("Detected former posters file {0}", OLD_POSTERS_FILE_NAME));
|
||||
}
|
||||
|
||||
if (!oldMapsFile.exists()) {
|
||||
oldMapsFile = null;
|
||||
} else {
|
||||
PluginLogger.info(I.t("Detected former maps file {0}", OLD_MAPS_FILE_NAME));
|
||||
}
|
||||
|
||||
if (oldPostersFile == null && oldMapsFile == null) {
|
||||
PluginLogger.info(I.t("There is nothing to migrate. Stopping."));
|
||||
return false;
|
||||
} else {
|
||||
PluginLogger.info(I.t("Done."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if any existing backup directories exists
|
||||
*
|
||||
* @return true if a non-empty backup directory exists, false otherwise
|
||||
*/
|
||||
private boolean checkForExistingBackups() {
|
||||
if ((backupsPrev3Directory.exists() && backupsPrev3Directory.list().length == 0)
|
||||
|| (backupsPostv3Directory.exists() && backupsPostv3Directory.list().length == 0)) {
|
||||
PluginLogger.error(I.t("Backup directories already exists."));
|
||||
PluginLogger.error(I.t("This means that a migration has already been done,"
|
||||
+ " or may not have ended well."));
|
||||
PluginLogger.error(I.t(
|
||||
"To start a new migration,"
|
||||
+ " you must move away the backup directories so they are not overwritten."));
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates backups of the former map files, and of the existing map stores
|
||||
*
|
||||
* @throws IOException
|
||||
**/
|
||||
private void backupMapData() throws IOException {
|
||||
PluginLogger.info(I.t("Backing up map data before migrating..."));
|
||||
|
||||
if (!backupsPrev3Directory.exists()) {
|
||||
backupsPrev3Directory.mkdirs();
|
||||
}
|
||||
if (!backupsPostv3Directory.exists()) {
|
||||
backupsPostv3Directory.mkdirs();
|
||||
}
|
||||
|
||||
if (oldMapsFile != null && oldMapsFile.exists()) {
|
||||
File oldMapsFileBackup = new File(backupsPrev3Directory, oldMapsFile.getName());
|
||||
verifiedBackupCopy(oldMapsFile, oldMapsFileBackup);
|
||||
}
|
||||
|
||||
if (oldPostersFile != null && oldPostersFile.exists()) {
|
||||
File oldPostersFileBackup = new File(backupsPrev3Directory, oldPostersFile.getName());
|
||||
verifiedBackupCopy(oldPostersFile, oldPostersFileBackup);
|
||||
}
|
||||
|
||||
File backupFile;
|
||||
for (File mapFile : plugin.getMapsDirectory().listFiles()) {
|
||||
backupFile = new File(backupsPostv3Directory, mapFile.getName());
|
||||
verifiedBackupCopy(mapFile, backupFile);
|
||||
}
|
||||
|
||||
PluginLogger.info(I.t("Backup complete."));
|
||||
}
|
||||
|
||||
/**
|
||||
* An utility function to check if a map is actually part of a loaded poster
|
||||
*
|
||||
* @param map The single map.
|
||||
* @return true if the map is part of a poster, false otherwise
|
||||
*/
|
||||
private boolean posterContains(OldSavedMap map) {
|
||||
for (OldSavedPoster poster : postersToMigrate) {
|
||||
if (poster.contains(map)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the former files into the corresponding arrays
|
||||
* Also fetches the names of all the users that have maps
|
||||
*
|
||||
* @return true if any of the files contained readable map data, false otherwise
|
||||
*/
|
||||
private boolean loadOldFiles() {
|
||||
if (oldPostersFile != null) {
|
||||
FileConfiguration oldPosters = YamlConfiguration.loadConfiguration(oldPostersFile);
|
||||
|
||||
OldSavedPoster oldPoster;
|
||||
for (String key : oldPosters.getKeys(false)) {
|
||||
if ("IdCount".equals(key)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
oldPoster = new OldSavedPoster(oldPosters.get(key), key);
|
||||
postersToMigrate.add(oldPoster);
|
||||
if (!userNamesToFetch.contains(oldPoster.getUserName())) {
|
||||
userNamesToFetch.add(oldPoster.getUserName());
|
||||
}
|
||||
} catch (InvalidConfigurationException ex) {
|
||||
PluginLogger.warning("Could not read poster data for key {0}", ex, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (oldMapsFile != null) {
|
||||
FileConfiguration oldMaps = YamlConfiguration.loadConfiguration(oldMapsFile);
|
||||
OldSavedMap oldMap;
|
||||
|
||||
for (String key : oldMaps.getKeys(false)) {
|
||||
try {
|
||||
if ("IdCount".equals(key)) {
|
||||
continue;
|
||||
}
|
||||
oldMap = new OldSavedMap(oldMaps.get(key));
|
||||
|
||||
if (!posterContains(oldMap)) {
|
||||
mapsToMigrate.add(oldMap);
|
||||
}
|
||||
|
||||
if (!userNamesToFetch.contains(oldMap.getUserName())) {
|
||||
userNamesToFetch.add(oldMap.getUserName());
|
||||
}
|
||||
} catch (InvalidConfigurationException ex) {
|
||||
PluginLogger.warning("Could not read poster data for key '{0}'", ex, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (postersToMigrate.size() > 0) || (mapsToMigrate.size() > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all the needed UUIDs from Mojang's UUID conversion service
|
||||
*
|
||||
* @throws IOException if the fetcher could not connect to Mojang's servers
|
||||
* @throws InterruptedException if the thread was interrupted while fetching UUIDs
|
||||
*/
|
||||
private void fetchUUIDs() throws IOException, InterruptedException {
|
||||
PluginLogger.info(I.t("Fetching UUIDs from Mojang..."));
|
||||
try {
|
||||
usersUUIDs = UUIDFetcher.fetch(new ArrayList<String>(userNamesToFetch));
|
||||
} catch (IOException ex) {
|
||||
PluginLogger.error(I.t("An error occurred while fetching the UUIDs from Mojang"), ex);
|
||||
throw ex;
|
||||
} catch (InterruptedException ex) {
|
||||
PluginLogger.error(I.t("The migration worker has been interrupted"), ex);
|
||||
throw ex;
|
||||
}
|
||||
PluginLogger.info(I.tn("Fetching done. {0} UUID have been retrieved.",
|
||||
"Fetching done. {0} UUIDs have been retrieved.", usersUUIDs.size()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the UUIDs that could not be retrieved via Mojang's standard API
|
||||
*
|
||||
* @return true if at least one UUID has been retrieved, false otherwise
|
||||
*/
|
||||
private boolean fetchMissingUUIDs() throws IOException, InterruptedException {
|
||||
if (usersUUIDs.size() == userNamesToFetch.size()) {
|
||||
return true;
|
||||
}
|
||||
int remainingUsersCount = userNamesToFetch.size() - usersUUIDs.size();
|
||||
PluginLogger.info(I.tn("Mojang did not find UUIDs for {0} player at the current time.",
|
||||
"Mojang did not find UUIDs for {0} players at the current time.", remainingUsersCount));
|
||||
PluginLogger.info(I.t("The Mojang servers limit requests rate at one per second, this may take some time..."));
|
||||
|
||||
try {
|
||||
UUIDFetcher.fetchRemaining(userNamesToFetch, usersUUIDs);
|
||||
} catch (IOException ex) {
|
||||
PluginLogger.error(I.t("An error occurred while fetching the UUIDs from Mojang"));
|
||||
throw ex;
|
||||
} catch (InterruptedException ex) {
|
||||
PluginLogger.error(I.t("The migration worker has been interrupted"));
|
||||
throw ex;
|
||||
}
|
||||
|
||||
if (usersUUIDs.size() != userNamesToFetch.size()) {
|
||||
PluginLogger.warning(I.tn("Mojang did not find player data for {0} player",
|
||||
"Mojang did not find player data for {0} players",
|
||||
userNamesToFetch.size() - usersUUIDs.size()));
|
||||
PluginLogger.warning(I.t("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) {
|
||||
PluginLogger.info(I.t("Mojang could not find any of the registered players."));
|
||||
PluginLogger.info(I.t("There is nothing to migrate. Stopping."));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void mergeMapData() {
|
||||
PluginLogger.info(I.t("Merging map data..."));
|
||||
|
||||
ArrayDeque<OldSavedMap> remainingMaps = new ArrayDeque<>();
|
||||
ArrayDeque<OldSavedPoster> remainingPosters = new ArrayDeque<>();
|
||||
|
||||
ArrayDeque<Integer> missingMapIds = new ArrayDeque<>();
|
||||
|
||||
UUID playerUUID;
|
||||
OldSavedMap map;
|
||||
while (!mapsToMigrate.isEmpty()) {
|
||||
map = mapsToMigrate.pop();
|
||||
playerUUID = usersUUIDs.get(map.getUserName());
|
||||
if (playerUUID == null) {
|
||||
remainingMaps.add(map);
|
||||
} else if (!map.isMapValid()) {
|
||||
missingMapIds.add((int) map.getMapId());
|
||||
} 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 if (!poster.isMapValid()) {
|
||||
missingMapIds.addAll(Arrays.stream(ArrayUtils.toObject(poster.getMapsIds())).map(id -> (int) id)
|
||||
.collect(Collectors.toList()));
|
||||
} else {
|
||||
MapManager.insertMap(poster.toImageMap(playerUUID));
|
||||
}
|
||||
}
|
||||
postersToMigrate.addAll(remainingPosters);
|
||||
|
||||
if (!missingMapIds.isEmpty()) {
|
||||
PluginLogger.warning(I.tn("{0} registered minecraft map is missing from the save.",
|
||||
"{0} registered minecraft maps are missing from the save.", missingMapIds.size()));
|
||||
PluginLogger.warning(
|
||||
I.t("These maps will not be migrated,"
|
||||
+ " but this could mean the save has been altered or corrupted."));
|
||||
PluginLogger.warning(I.t("The following maps are missing : {0} ",
|
||||
StringUtils.join(missingMapIds, ',')));
|
||||
}
|
||||
}
|
||||
|
||||
/* ****** Utils ***** */
|
||||
|
||||
private void saveChanges() {
|
||||
PluginLogger.info(I.t("Saving changes..."));
|
||||
MapManager.save();
|
||||
}
|
||||
|
||||
private void cleanup() throws IOException {
|
||||
PluginLogger.info(I.t("Cleaning up old data files..."));
|
||||
|
||||
//Cleaning maps file
|
||||
if (oldMapsFile != null) {
|
||||
if (mapsToMigrate.isEmpty()) {
|
||||
PluginLogger.info(I.t("Deleting old map data file..."));
|
||||
oldMapsFile.delete();
|
||||
} else {
|
||||
PluginLogger.info(I.tn("{0} map could not be migrated.", "{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(I.t("Deleting old poster data file..."));
|
||||
oldPostersFile.delete();
|
||||
} else {
|
||||
PluginLogger.info(I.tn("{0} poster could not be migrated.", "{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(I.t("Data that has not been migrated will be kept in the old data files."));
|
||||
}
|
||||
|
||||
public synchronized boolean isRunning() {
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
private synchronized void setRunning(boolean running) {
|
||||
this.isRunning = running;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the full migration, and defines the running status of the migration
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
setRunning(true);
|
||||
migrate();
|
||||
setRunning(false);
|
||||
}
|
||||
|
||||
}
|
@ -40,7 +40,6 @@ import fr.moribus.imageonmap.Permissions;
|
||||
import fr.moribus.imageonmap.map.ImageMap;
|
||||
import fr.moribus.imageonmap.map.MapManager;
|
||||
import fr.moribus.imageonmap.map.PosterMap;
|
||||
import fr.moribus.imageonmap.map.SingleMap;
|
||||
import fr.zcraft.quartzlib.components.i18n.I;
|
||||
import fr.zcraft.quartzlib.core.QuartzLib;
|
||||
import fr.zcraft.quartzlib.tools.items.ItemStackBuilder;
|
||||
@ -88,15 +87,10 @@ public class MapItemManager implements Listener {
|
||||
public static boolean give(Player player, ImageMap map) {
|
||||
if (map instanceof PosterMap) {
|
||||
return give(player, (PosterMap) map);
|
||||
} else if (map instanceof SingleMap) {
|
||||
return give(player, (SingleMap) map);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean give(Player player, SingleMap map) {
|
||||
return give(player, createMapItem(map, true));
|
||||
}
|
||||
|
||||
public static boolean give(Player player, PosterMap map) {
|
||||
if (!map.hasColumnData()) {
|
||||
@ -141,14 +135,6 @@ public class MapItemManager implements Listener {
|
||||
return givenItemsCount;
|
||||
}
|
||||
|
||||
public static ItemStack createMapItem(SingleMap map) {
|
||||
return createMapItem(map.getMapsIDs()[0], map.getName(), false);
|
||||
}
|
||||
|
||||
public static ItemStack createMapItem(SingleMap map, boolean goldTitle) {
|
||||
return createMapItem(map.getMapsIDs()[0], map.getName(), false, goldTitle);
|
||||
}
|
||||
|
||||
public static ItemStack createMapItem(PosterMap map, int index) {
|
||||
return createMapItem(map.getMapIdAt(index), getMapTitle(map, index), true);
|
||||
}
|
||||
@ -163,17 +149,24 @@ public class MapItemManager implements Listener {
|
||||
|
||||
public static ItemStack createMapItem(int mapID, String text, boolean isMapPart, boolean goldTitle) {
|
||||
ItemStack mapItem;
|
||||
if (goldTitle) {
|
||||
if (text == "") {
|
||||
mapItem = new ItemStackBuilder(Material.FILLED_MAP)
|
||||
.title(ChatColor.GOLD, text)
|
||||
.hideAllAttributes()
|
||||
.item();
|
||||
} else {
|
||||
mapItem = new ItemStackBuilder(Material.FILLED_MAP)
|
||||
.title(text)
|
||||
.hideAllAttributes()
|
||||
.item();
|
||||
if (goldTitle) {
|
||||
mapItem = new ItemStackBuilder(Material.FILLED_MAP)
|
||||
.title(ChatColor.GOLD, text)
|
||||
.hideAllAttributes()
|
||||
.item();
|
||||
} else {
|
||||
mapItem = new ItemStackBuilder(Material.FILLED_MAP)
|
||||
.title(text)
|
||||
.hideAllAttributes()
|
||||
.item();
|
||||
}
|
||||
}
|
||||
|
||||
final MapMeta meta = (MapMeta) mapItem.getItemMeta();
|
||||
meta.setMapId(mapID);
|
||||
meta.setColor(isMapPart ? Color.LIME : Color.GREEN);
|
||||
@ -193,17 +186,14 @@ public class MapItemManager implements Listener {
|
||||
|
||||
private static String getMapTitle(ItemStack item) {
|
||||
ImageMap map = MapManager.getMap(item);
|
||||
if (map instanceof SingleMap) {
|
||||
return map.getName();
|
||||
} else {
|
||||
PosterMap poster = (PosterMap) map;
|
||||
int index = poster.getIndex(MapManager.getMapIdFromItemStack(item));
|
||||
if (poster.hasColumnData()) {
|
||||
return getMapTitle(poster, poster.getRowAt(index), poster.getColumnAt(index));
|
||||
}
|
||||
|
||||
return getMapTitle(poster, index);
|
||||
PosterMap poster = (PosterMap) map;
|
||||
int index = poster.getIndex(MapManager.getMapIdFromItemStack(item));
|
||||
if (poster.hasColumnData()) {
|
||||
return getMapTitle(poster, poster.getRowAt(index), poster.getColumnAt(index));
|
||||
}
|
||||
|
||||
return getMapTitle(poster, index);
|
||||
//}
|
||||
}
|
||||
|
||||
//
|
||||
@ -296,19 +286,19 @@ public class MapItemManager implements Listener {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Permissions.REMOVE_SPLATTER_MAP.grantedTo(player)) {
|
||||
if (player.isSneaking()) {
|
||||
PosterMap poster = SplatterMapManager.removeSplatterMap(frame, player);
|
||||
if (poster != null) {
|
||||
event.setCancelled(true);
|
||||
if (Permissions.REMOVE_SPLATTER_MAP.grantedTo(player) && player.isSneaking()) {
|
||||
|
||||
if (player.getGameMode() != GameMode.CREATIVE
|
||||
|| !SplatterMapManager.hasSplatterMap(player, poster)) {
|
||||
poster.give(player);
|
||||
}
|
||||
return;
|
||||
PosterMap poster = SplatterMapManager.removeSplatterMap(frame, player);
|
||||
if (poster != null) {
|
||||
event.setCancelled(true);
|
||||
|
||||
if (player.getGameMode() != GameMode.CREATIVE
|
||||
|| !SplatterMapManager.hasSplatterMap(player, poster)) {
|
||||
poster.give(player);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!MapManager.managesMap(frame.getItem())) {
|
||||
|
@ -57,6 +57,7 @@ import org.bukkit.Material;
|
||||
import org.bukkit.Rotation;
|
||||
import org.bukkit.attribute.AttributeModifier;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.entity.ItemFrame;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||
@ -66,7 +67,7 @@ import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.MapMeta;
|
||||
|
||||
//TODO rework splatter effect, using ID is far more stable than nbt tags.
|
||||
// To update when adding small picture previsualization.
|
||||
// To update when adding small picture snapshot.
|
||||
public abstract class SplatterMapManager {
|
||||
private SplatterMapManager() {
|
||||
}
|
||||
@ -318,8 +319,9 @@ public abstract class SplatterMapManager {
|
||||
|
||||
RunTask.later(() -> {
|
||||
addPropertiesToFrames(player, frame);
|
||||
frame.setItem(
|
||||
new ItemStackBuilder(Material.FILLED_MAP).nbt(ImmutableMap.of("map", id)).craftItem());
|
||||
|
||||
ItemStack item = MapItemManager.createMapItem(id, "", true, false);
|
||||
frame.setItem(item);
|
||||
}, 5L);
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user