This commit is contained in:
Vlammar 2023-07-30 21:56:31 +00:00 committed by GitHub
commit a6e1d71f79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 1837 additions and 1756 deletions

View File

@ -134,7 +134,7 @@
<dependency>
<groupId>fr.zcraft</groupId>
<artifactId>quartzlib</artifactId>
<version>0.0.6</version>
<version>0.0.7-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.bstats</groupId>

View File

@ -0,0 +1,319 @@
/*
* 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 <anais.jabre@gmail.com> (2019 2023)
*
* 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;
import fr.zcraft.quartzlib.tools.PluginLogger;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
public class Argument {
//<TODO special case with the --cancel -c type arguments
private final String name;
private final Type type;
private final Status status;
private String content;
private String defaultValue;
public Argument(String name, Type type, Status status) {
this.name = name;
this.type = type;
this.status = status;
}
public Argument(String name, Type type, Status status, String defaultValue) {
this.name = name;
this.type = type;
this.status = status;
this.defaultValue = defaultValue;
}
public static Argument findArgument(String argumentName, List<Argument> args) {
for (Argument a : args) {
if (a.getName().equalsIgnoreCase(argumentName)) {
return a;
}
}
PluginLogger.error("Can't find argument");
return null;
}
//TODO add error message for the console and/or player
public String getName() {
return name;
}
public Type getType() {
return type;
}
public Status getStatus() {
return status;
}
public static <T extends Object> T findContent(String argumentName, List<Argument> args) {
Argument argument = Argument.findArgument(argumentName, args);
if (argument != null) {
return argument.getContent();
}
PluginLogger.error("Error: argument {0} was not found", argumentName);
for (Argument a : args) {
PluginLogger.info("argument disponible {0}", a.getName());
}
return argument.getDefault();
}
public <T extends Object> T getDefault() {
if (defaultValue == null) {
return null;
}
switch (type) {
case BOOLEAN:
return (T) Boolean.valueOf(defaultValue);
case INT:
return (T) Integer.getInteger(defaultValue);
case UUID:
return (T) UUID.fromString(defaultValue);
case DOUBLE:
return (T) Double.valueOf(defaultValue);
case STRING:
return (T) defaultValue;
case ONLINE_PLAYER:
return (T) Bukkit.getPlayer(toUUID(defaultValue));
case OFFLINE_PLAYER:
return (T) Bukkit.getOfflinePlayer(toUUID(defaultValue));
default:
PluginLogger.info("To be implemented");
return null;
}
}
public <T extends Object> T getContent() {
switch (type) {
case BOOLEAN:
return (T) Boolean.valueOf(content);
case INT:
return (T) Integer.getInteger(content);
case UUID:
return (T) UUID.fromString(content);
case DOUBLE:
return (T) Double.valueOf(content);
case STRING:
return (T) content;
case ONLINE_PLAYER:
return (T) Bukkit.getPlayer(toUUID(content));
case OFFLINE_PLAYER:
return (T) Bukkit.getOfflinePlayer(toUUID(content));
default:
PluginLogger.info("To be implemented");
return null;
}
}
private void setEmpty() {
this.content = "";
}
private void setDefault(String defaultValue) {
this.defaultValue = defaultValue;
}
private void setContent(String content) {
//check if added content is type compatible
String msg = "Content wasn't parsable to type '{0}', got the following string {1}";
switch (type) {
case BOOLEAN:
case ONLINE_PLAYER:
case OFFLINE_PLAYER:
case STRING:
this.content = content;
break;
case DOUBLE:
try {
Double.valueOf(content);
} catch (NumberFormatException e) {
PluginLogger.warning(msg,
"double", content);
throw e;
}
this.content = content;
break;
case UUID:
try {
UUID.fromString(content);
} catch (IllegalArgumentException e) {
PluginLogger.warning(msg,
"UUID", content);
throw e;
}
this.content = content;
break;
case INT:
try {
Integer.parseInt(content);
} catch (NumberFormatException e) {
PluginLogger.warning(msg,
"integer", content);
throw e;
}
this.content = content;
break;
default:
}
}
private UUID toUUID(String content) {
try {
return UUID.fromString(content);
} catch (IllegalArgumentException e) {
return Bukkit.getOfflinePlayer(content).getUniqueId();
}
}
public static boolean isAmbiguous(List<Argument> prototype, boolean isPlayer) {
//TODO add check on the possible type
for (int i = 1; i < prototype.size(); i++) {
Argument arg = prototype.get(i);
Argument previous = prototype.get(i - 1);
if ((arg.getStatus() == Status.OPTIONAL && previous.getStatus() == Status.OPTIONAL)
|| (isPlayer
&& ((arg.getStatus() == Status.OPTIONAL_FOR_PLAYER_ONLY
&& previous.getStatus() == Status.OPTIONAL)
|| (arg.getStatus() == Status.OPTIONAL
&& previous.getStatus() == Status.OPTIONAL_FOR_PLAYER_ONLY)
|| (arg.getStatus() == Status.OPTIONAL_FOR_PLAYER_ONLY
&& previous.getStatus() == Status.OPTIONAL_FOR_PLAYER_ONLY)))) {
return true;
}
}
return false;
}
public static List<Argument> parseArguments(List<Argument> prototype, ArrayList<String> args, boolean isPlayer)
throws Exception {
//check if the command is not ambiguous
if (isAmbiguous(prototype, isPlayer)) {
throw new Exception("Parsing error, ambiguous command prototype");
}
// givemap Vlammar Vlammar:"carte 1" 10
// string |string| string <int>
List<Argument> list = new ArrayList<>();
List<Argument> uncertain = new ArrayList<>();
for (int i = 0; i < args.size(); i++) {
boolean next = false;
String arg = args.get(i);
PluginLogger.info("Argument: {0}", arg);
for (int j = i; j < prototype.size(); j++) {
PluginLogger.info("j = {0}", j);
Argument a = prototype.get(j);
PluginLogger.info("argument name: \n{0}", a.toString());
switch (a.status) {
case OBLIGATORY:
PluginLogger.info("OBLIGATORY");
if (uncertain.isEmpty()) {
PluginLogger.info(a.getName());
list.add(a);
a.setContent(arg);
PluginLogger.info("argument : \n{0}", a.toString());
next = true;
} else {
for (Argument l : uncertain) {
//if size doesnt match or
try {
PluginLogger.info("test pour l'erreur");
PluginLogger.info(a.getContent());
a.setContent(a.content); //todo erreur ?
PluginLogger.info("argument : \n{0}", a.toString());
} catch (Exception e) {
//shift to the right
}
}
PluginLogger.info(a.getName());
list.add(a);
uncertain = new ArrayList<>();
}
break;
case OPTIONAL:
PluginLogger.info("OPTIONAL");
PluginLogger.info(a.getName());
uncertain.add(a);
PluginLogger.info("argument : \n{0}", a.toString());
break;
case OPTIONAL_FOR_PLAYER_ONLY:
PluginLogger.info("OPTIONAL_FOR_PLAYER_ONLY");
if (!isPlayer) {
PluginLogger.info(a.getName());
list.add(a);
a.setContent(arg);
PluginLogger.info("argument : \n{0}", a.toString());
next = true;
} else {
PluginLogger.info(a.getName());
uncertain.add(a);
PluginLogger.info("argument : \n{0}", a.toString());
break;
//Str Str Str Int
//<player name> [playerFrom] [playerFrom]:<map name> <quantity >
}
break;
default:
throw new Exception("Status does not exist");
}
if (next) {
break;
}
}
}
return list;
}
@Override
public String toString() {
return "{ name: " + name + ";\ntype: " + type + ";\nstatus: " + status + ";\ncontent: " + content + " }";
}
}

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -44,6 +44,7 @@ import fr.moribus.imageonmap.commands.maptool.GetRemainingCommand;
import fr.moribus.imageonmap.commands.maptool.GiveCommand;
import fr.moribus.imageonmap.commands.maptool.ListCommand;
import fr.moribus.imageonmap.commands.maptool.NewCommand;
import fr.moribus.imageonmap.commands.maptool.RemotePlacingCommand;
import fr.moribus.imageonmap.commands.maptool.RenameCommand;
import fr.moribus.imageonmap.commands.maptool.UpdateCommand;
import fr.moribus.imageonmap.image.ImageIOExecutor;
@ -60,18 +61,24 @@ import fr.zcraft.quartzlib.tools.PluginLogger;
import fr.zcraft.quartzlib.tools.UpdateChecker;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.bstats.bukkit.Metrics;
public final class ImageOnMap extends QuartzPlugin {
private static final String IMAGES_DIRECTORY_NAME = "images";
private static final String RENDERS_DIRECTORY_NAME = "renders";
private static final String MAPS_DIRECTORY_NAME = "maps";
private static ImageOnMap plugin;
private final File mapsDirectory;
private File imagesDirectory;
private File rendersDirectory;
private File mapsDirectory;
private CommandWorkers commandWorker;
public ImageOnMap() {
imagesDirectory = new File(this.getDataFolder(), IMAGES_DIRECTORY_NAME);
rendersDirectory = new File(this.getDataFolder(), RENDERS_DIRECTORY_NAME);
mapsDirectory = new File(this.getDataFolder(), MAPS_DIRECTORY_NAME);
plugin = this;
}
@ -84,6 +91,10 @@ public final class ImageOnMap extends QuartzPlugin {
return imagesDirectory;
}
public File getRendersDirectory() {
return rendersDirectory;
}
public File getMapsDirectory() {
return mapsDirectory;
}
@ -92,20 +103,33 @@ public final class ImageOnMap extends QuartzPlugin {
return new File(imagesDirectory, "map" + mapID + ".png");
}
public File getRenderFile(int mapID) {
return new File(rendersDirectory, "render" + mapID + ".png");
}
public CommandWorkers getCommandWorker() {
return commandWorker;
}
@SuppressWarnings("unchecked")
private Map<String,File> checkDirs() throws IOException {
Map<String, File> dirs = new HashMap<>();
dirs.put("mapsDirectory", checkPluginDirectory(mapsDirectory));
dirs.put("rendersDirectory", checkPluginDirectory(rendersDirectory));
dirs.put("imagesDirectory", checkPluginDirectory(imagesDirectory));
return dirs;
}
@Override
public void onEnable() {
// Creating the images and maps directories if necessary
try {
//imagesDirectory = checkPluginDirectory(imagesDirectory, V3Migrator.getOldImagesDirectory(this));
checkPluginDirectory(mapsDirectory);
checkPluginDirectory(imagesDirectory);
Map<String, File> directories = checkDirs();
mapsDirectory = directories.get("mapsDirectory");
rendersDirectory = directories.get("rendersDirectory");
imagesDirectory = directories.get("imagesDirectory");
} catch (final IOException ex) {
PluginLogger.error("FATAL: " + ex.getMessage());
//disable the plugin
this.setEnabled(false);
return;
}
@ -123,9 +147,9 @@ public final class ImageOnMap extends QuartzPlugin {
MapInitEvent.init();
MapItemManager.init();
String commandGroupName = "maptool";
Commands.register(
"maptool",
commandGroupName,
NewCommand.class,
ListCommand.class,
GetCommand.class,
@ -135,19 +159,21 @@ public final class ImageOnMap extends QuartzPlugin {
GetRemainingCommand.class,
ExploreCommand.class,
//MigrateCommand.class,//Removed for now doesn't work nor is useful, maybe useful later on
UpdateCommand.class
UpdateCommand.class,
RemotePlacingCommand.class
);
Commands.registerShortcut("maptool", NewCommand.class, "tomap");
Commands.registerShortcut("maptool", ExploreCommand.class, "maps");
Commands.registerShortcut("maptool", GiveCommand.class, "givemap");
Commands.registerShortcut(commandGroupName, NewCommand.class, "tomap");
Commands.registerShortcut(commandGroupName, ExploreCommand.class, "maps");
Commands.registerShortcut(commandGroupName, GiveCommand.class, "givemap");
Commands.registerShortcut(commandGroupName, RemotePlacingCommand.class, "placemap");
if (PluginConfiguration.CHECK_FOR_UPDATES.get()) {
UpdateChecker.boot("imageonmap.26585");
}
if (PluginConfiguration.COLLECT_DATA.get()) {
final Metrics metrics = new Metrics(this,5920);
final Metrics metrics = new Metrics(this, 5920);
metrics.addCustomChart(new Metrics.SingleLineChart("rendered-images", MapManager::getImagesCount));
metrics.addCustomChart(new Metrics.SingleLineChart("used-minecraft-maps", MapManager::getMapCount));
} else {

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -62,7 +62,8 @@ public enum Permissions {
BYPASS_IMAGE_LIMIT("imageonmap.bypassimagelimit"),
BYPASS_MAP_LIMIT("imageonmap.bypassmaplimit"),
GIVE("imageonmap.give"),
BYPASS_WHITELIST("imageonmap.bypasswhitelist");
BYPASS_WHITELIST("imageonmap.bypasswhitelist"),
REMOTE_PLACING("imageonmap.remoteplacing");
private final String permission;
private final String[] aliases;
@ -79,6 +80,12 @@ public enum Permissions {
* @return {@code true} if this permission is granted to the permissible.
*/
public boolean grantedTo(Permissible permissible) {
//true only if not a player. If the console or a command block as send the command we can assume that it has
//enough privilege
if (permissible == null || permissible.isOp()) {
return true;
}
if (permissible.hasPermission(permission)) {
return true;
}
@ -103,17 +110,13 @@ public enum Permissions {
String prefix = String.format("imageonmap.%slimit.", type.name());
for (PermissionAttachmentInfo pai : perms) {
String permString = pai.getPermission().toLowerCase();
if (permString.startsWith(prefix)) {
if (pai.getValue()) {
try {
int limit = Integer.parseInt(permString.split(prefix)[1].trim());
return limit;
} catch (Exception e) {
PluginLogger.warning(
I.t("The correct syntax for setting map limit node is: ImageOnMap.mapLimit.X "
+ "where you can replace X with the limit of map a player is allowed to have"));
}
if (permString.startsWith(prefix) && pai.getValue()) {
try {
return Integer.parseInt(permString.split(prefix)[1].trim());
} catch (Exception e) {
PluginLogger.warning(
I.t("The correct syntax for setting map limit node is: ImageOnMap.mapLimit.X "
+ "where you can replace X with the limit of map a player is allowed to have"));
}
}
}

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -46,22 +46,24 @@ import java.util.Locale;
public final class PluginConfiguration extends Configuration {
public static ConfigurationItem<Locale> LANG = item("lang", Locale.class);
public static final ConfigurationItem<Locale> LANG = item("lang", Locale.class);
public static ConfigurationItem<Boolean> COLLECT_DATA = item("collect-data", true);
public static final ConfigurationItem<Boolean> COLLECT_DATA = item("collect-data", true);
public static ConfigurationItem<Boolean> CHECK_FOR_UPDATES = item("check-for-updates", true);
public static final ConfigurationItem<Boolean> CHECK_FOR_UPDATES = item("check-for-updates", true);
public static ConfigurationItem<Integer> MAP_GLOBAL_LIMIT = item("map-global-limit", 0, "Limit-map-by-server");
public static ConfigurationItem<Integer> MAP_PLAYER_LIMIT = item("map-player-limit", 0, "Limit-map-by-player");
public static final ConfigurationItem<Integer> MAP_GLOBAL_LIMIT =
item("map-global-limit", 0, "Limit-map-by-server");
public static final ConfigurationItem<Integer> MAP_PLAYER_LIMIT =
item("map-player-limit", 0, "Limit-map-by-player");
public static ConfigurationItem<Boolean> SAVE_FULL_IMAGE = item("save-full-image", true);
public static final ConfigurationItem<Boolean> SAVE_FULL_IMAGE = item("save-full-image", true);
public static ConfigurationItem<Integer> LIMIT_SIZE_X = item("limit-map-size-x", 0);
public static ConfigurationItem<Integer> LIMIT_SIZE_Y = item("limit-map-size-y", 0);
public static final ConfigurationItem<Integer> LIMIT_SIZE_X = item("limit-map-size-x", 0);
public static final ConfigurationItem<Integer> LIMIT_SIZE_Y = item("limit-map-size-y", 0);
public static ConfigurationList<String> IMAGES_HOSTNAMES_WHITELIST =
public static final ConfigurationList<String> IMAGES_HOSTNAMES_WHITELIST =
list("images-hostnames-whitelist", String.class);
}

View File

@ -0,0 +1,41 @@
/*
* 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 <anais.jabre@gmail.com> (2019 2023)
*
* 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;
public enum Status {
OBLIGATORY, OPTIONAL, OPTIONAL_FOR_PLAYER_ONLY
}

View File

@ -0,0 +1,41 @@
/*
* 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 <anais.jabre@gmail.com> (2019 2023)
*
* 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;
public enum Type {
STRING, INT, DOUBLE, BOOLEAN, UUID, ONLINE_PLAYER,OFFLINE_PLAYER
}

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -46,14 +46,34 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
public abstract class IoMCommand extends Command {
protected UUID getPlayerUUID(String playerName) {
return Bukkit.getOfflinePlayer(playerName).getUniqueId();
}
private boolean checkTooArguments(boolean bool, String msg) throws CommandException {
if (bool) {
throwInvalidArgument(msg);
}
return bool;
}
protected boolean checkTooManyArguments(boolean bool) throws CommandException {
return checkTooArguments(bool, I.t("Too many parameters!"));
}
protected boolean checkTooFewArguments(boolean bool) throws CommandException {
return checkTooArguments(bool, I.t("Too few parameters!"));
}
protected boolean checkArguments(boolean bool1, boolean bool2) throws CommandException {
return !(checkTooManyArguments(bool1) || checkTooFewArguments(bool2));
}
protected boolean checkHostnameWhitelist(final URL url) {
final List<String> hostnames = PluginConfiguration.IMAGES_HOSTNAMES_WHITELIST.get()
@ -72,39 +92,6 @@ public abstract class IoMCommand extends Command {
.anyMatch(h -> h.equalsIgnoreCase(url.getHost()));
}
protected void retrieveUUID(final String arg, final Consumer<UUID> consumer) {
// If it is being removed we may have to use Mojang services
consumer.accept(Bukkit.getOfflinePlayer(arg).getUniqueId());
}
protected ImageMap getMapFromArgs() throws CommandException {
return getMapFromArgs(playerSender(), 0, true);
}
protected ImageMap getMapFromArgs(final Player player, final int index, boolean expand) throws CommandException {
if (args.length <= index) {
throwInvalidArgument(I.t("You need to give a map name."));
}
ImageMap map;
String mapName = args[index];
if (expand) {
for (int i = index + 1, c = args.length; i < c; i++) {
mapName += " " + args[i];
}
}
mapName = mapName.trim();
map = MapManager.getMap(player.getUniqueId(), mapName);
if (map == null) {
error(I.t("This map does not exist."));
}
return map;
}
protected ArrayList<String> getArgs() {
ArrayList<String> arguments = new ArrayList<>();
@ -175,4 +162,5 @@ public abstract class IoMCommand extends Command {
return matches;
}
}

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -50,6 +50,7 @@ import fr.zcraft.quartzlib.tools.PluginLogger;
import fr.zcraft.quartzlib.tools.text.RawMessage;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -76,56 +77,76 @@ public class DeleteCommand extends IoMCommand {
ArrayList<String> arguments = getArgs();
final boolean confirm = hasFlag("confirm");
if (arguments.size() > 3 || (arguments.size() > 2 && !confirm)) {
throwInvalidArgument(I.t("Too many parameters!"));
return;
}
if (arguments.size() < 1) {
throwInvalidArgument(I.t("Too few parameters!"));
boolean isTooMany = arguments.size() > 3 || (arguments.size() > 2 && !confirm);
boolean isTooFew = arguments.isEmpty();
if (!checkArguments(isTooMany, isTooFew)) {
return;
}
final String playerName;
final String mapName;
final Player sender = playerSender();
final Player sender;
Player playerSender;
try {
playerSender = playerSender();
} catch (CommandException ignored) {
if (arguments.size() != 2) {
throwInvalidArgument(I.t("Player name is required from the console"));
}
playerSender = null;
}
sender = playerSender;
boolean notPlayer = sender == null;
if (arguments.size() == 2 || arguments.size() == 3) {
if (!Permissions.DELETEOTHER.grantedTo(sender)) {
throwNotAuthorized();
return;
}
playerName = arguments.get(0);
mapName = arguments.get(1);
} else {
playerName = sender.getName();
mapName = arguments.get(0);
}
retrieveUUID(playerName, uuid -> {
ImageMap map = MapManager.getMap(uuid, mapName);
if (map == null) {
warning(sender, I.t("This map does not exist."));
return;
}
if (!confirm) {
RawText msg = deleteMsg(getClass(), playerName, map);
RawMessage.send(sender, msg);
UUID uuid = getPlayerUUID(playerName);
ImageMap map = MapManager.getMap(uuid, mapName);
if (map == null) {
final String msg = "This map does not exist.";
if (notPlayer) {
PluginLogger.warning("" + msg);
} else {
if (sender != null && sender.isOnline() && sender.getInventory() != null) {
MapManager.clear(sender.getInventory(), map);
}
try {
MapManager.deleteMap(map);
success(sender, I.t("Map successfully deleted."));
} catch (MapManagerException ex) {
PluginLogger.warning(I.t("A non-existent map was requested to be deleted", ex));
warning(sender, I.t("This map does not exist."));
}
warning(sender, I.t(msg));
}
});
return;
}
if (!confirm && !notPlayer) {
RawText msg = deleteMsg(getClass(), playerName, map);
if (notPlayer) {
PluginLogger.info("" + msg.toFormattedText());
} else {
RawMessage.send(sender, msg);
}
} else {
if (sender != null && sender.isOnline()) {
MapManager.clear(sender.getInventory(), map);
}
try {
MapManager.deleteMap(map);
String msg = I.t("Map successfully deleted.");
if (sender != null) {
success(sender, msg);
} else {
PluginLogger.info(msg);
}
} catch (MapManagerException ex) {
PluginLogger.warning(I.t("A non-existent map was requested to be deleted", ex));
warning(sender, I.t("This map does not exist."));
}
}
}

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -43,8 +43,6 @@ import fr.moribus.imageonmap.gui.MapListGui;
import fr.zcraft.quartzlib.components.commands.CommandException;
import fr.zcraft.quartzlib.components.commands.CommandInfo;
import fr.zcraft.quartzlib.components.gui.Gui;
import fr.zcraft.quartzlib.components.i18n.I;
import fr.zcraft.quartzlib.tools.PluginLogger;
import java.util.ArrayList;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
@ -57,13 +55,14 @@ public class ExploreCommand extends IoMCommand {
@Override
protected void run() throws CommandException {
ArrayList<String> arguments = getArgs();
if (arguments.size() > 1) {
throwInvalidArgument(I.t("Too many parameters!"));
boolean isTooMany = arguments.size() > 1;
boolean isTooFew = false;
if (!checkArguments(isTooMany, isTooFew)) {
return;
}
final String playerName;
final Player sender = playerSender();
if (arguments.size() == 1) {
if (!Permissions.LISTOTHER.grantedTo(sender)) {
throwNotAuthorized();
@ -74,14 +73,10 @@ public class ExploreCommand extends IoMCommand {
playerName = sender.getName();
}
retrieveUUID(playerName, uuid -> {
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid);
if (sender.isOnline()) {
Gui.open(sender, new MapListGui(offlinePlayer, playerName));
}
});
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(playerName);
if (sender.isOnline()) {
Gui.open(sender, new MapListGui(offlinePlayer, playerName));
}
}

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -36,7 +36,6 @@
package fr.moribus.imageonmap.commands.maptool;
import fr.moribus.imageonmap.ImageOnMap;
import fr.moribus.imageonmap.Permissions;
import fr.moribus.imageonmap.commands.IoMCommand;
import fr.moribus.imageonmap.map.ImageMap;
@ -46,23 +45,22 @@ import fr.zcraft.quartzlib.components.commands.CommandInfo;
import fr.zcraft.quartzlib.components.i18n.I;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandInfo(name = "get",usageParameters = "[player name]:<map name>")
@CommandInfo(name = "get", usageParameters = "[player name]:<map name>")
public class GetCommand extends IoMCommand {
@Override
protected void run() throws CommandException {
ArrayList<String> arguments = getArgs();
if (arguments.size() > 2) {
throwInvalidArgument(I.t("Too many parameters!"));
return;
}
if (arguments.size() < 1) {
throwInvalidArgument(I.t("Too few parameters!"));
boolean isTooMany = arguments.size() > 2;
boolean isTooFew = arguments.isEmpty();
if (!checkArguments(isTooMany, isTooFew)) {
return;
}
final String playerName;
final String mapName;
final Player sender = playerSender();
@ -79,28 +77,23 @@ public class GetCommand extends IoMCommand {
mapName = arguments.get(1);
}
UUID uuid = getPlayerUUID(playerName);
if (!sender.isOnline()) {
return;
}
ImageMap map = MapManager.getMap(uuid, mapName);
if (map == null) {
warning(sender, I.t("This map does not exist."));
return;
}
if (map.give(sender)) {
info(I.t("The requested map was too big to fit in your inventory."));
info(I.t("Use '/maptool getremaining' to get the remaining maps."));
}
retrieveUUID(playerName, uuid -> {
if (!sender.isOnline()) {
return;
}
ImageMap map = MapManager.getMap(uuid, mapName);
if (map == null) {
warning(sender, I.t("This map does not exist."));
return;
}
if (map.give(sender)) {
info(I.t("The requested map was too big to fit in your inventory."));
info(I.t("Use '/maptool getremaining' to get the remaining maps."));
}
});
}
@Override

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -36,55 +36,87 @@
package fr.moribus.imageonmap.commands.maptool;
import fr.moribus.imageonmap.Argument;
import fr.moribus.imageonmap.Permissions;
import fr.moribus.imageonmap.Status;
import fr.moribus.imageonmap.Type;
import fr.moribus.imageonmap.commands.IoMCommand;
import fr.moribus.imageonmap.map.ImageMap;
import fr.moribus.imageonmap.map.MapManager;
import fr.zcraft.quartzlib.components.commands.CommandException;
import fr.zcraft.quartzlib.components.commands.CommandInfo;
import fr.zcraft.quartzlib.components.i18n.I;
import fr.zcraft.quartzlib.tools.PluginLogger;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandInfo(name = "give", usageParameters = "<player name> [playerFrom]:<map name>")
@CommandInfo(name = "give", usageParameters = "<player name> [playerFrom]:<map name> [quantity]")
public class GiveCommand extends IoMCommand {
protected List<Argument> commandPrototype() {
Argument target = new Argument("target", Type.STRING, Status.OBLIGATORY);
Argument from = new Argument("from", Type.STRING, Status.OPTIONAL_FOR_PLAYER_ONLY);
Argument mapName = new Argument("mapName", Type.STRING, Status.OBLIGATORY);
Argument quantity = new Argument("quantity", Type.INT, Status.OPTIONAL, "1");
List<Argument> list = new ArrayList<>();
list.add(target);
list.add(from);
list.add(mapName);
list.add(quantity);
return list;
}
// /givemap Vlammar "Carte 1" 10
// /maptool give Vlammar Vlammar:"Carte"
@Override
protected void run() throws CommandException {
if (args.length < 2) {
throwInvalidArgument(I.t("You must give a valid player name and a map name."));
return;
}
List<Argument> cmdProto = commandPrototype();
ArrayList<String> arguments = getArgs();
Boolean isPlayer = sender != null;
List<Argument> args;
try {
args = Argument.parseArguments(cmdProto, arguments, isPlayer);
} catch (Exception e) {
PluginLogger.error("Error while parsing command");
return;
}
if (arguments.size() > 3) {
throwInvalidArgument(I.t("Too many parameters!"));
boolean isTooMany = arguments.size() > 4;
boolean isTooFew = arguments.size() < 2;
if (!checkArguments(isTooMany, isTooFew)) {
return;
}
if (arguments.size() < 1) {
throwInvalidArgument(I.t("Too few parameters!"));
final String mapName = Argument.findContent("mapName", args);
final String from = Argument.findContent("from", args);
final String playerName = Argument.findContent("target", args);
final int quantity = Argument.findContent("quantity", args);
PluginLogger.info("quantity {0}", quantity);
if (mapName == null || from == null || playerName == null) {
PluginLogger.error("Error one argument is null, check argument names");
return;
}
final String mapName;
final String from;
final String playerName;
final Player playerSender;
Player playerSender1;
try {
playerSender1 = playerSender();
} catch (CommandException ignored) {
if (arguments.size() == 2) {
throwInvalidArgument(I.t("Player name is required from the console"));
throwInvalidArgument(I.t("Player name is required for the console"));
}
playerSender1 = null;
}
playerSender = playerSender1;
if (arguments.size() == 2) {
/*if (arguments.size() == 2) {
from = playerSender.getName();
playerName = arguments.get(0);
mapName = arguments.get(1);
@ -98,26 +130,25 @@ public class GiveCommand extends IoMCommand {
playerName = "";
mapName = "";
}
}
}*/
final Player sender = playerSender();
UUID uuid = getPlayerUUID(from);
UUID uuid2 = getPlayerUUID(playerName);
retrieveUUID(from, uuid -> {
final ImageMap map = MapManager.getMap(uuid, mapName);
final ImageMap map = MapManager.getMap(uuid, mapName);
if (map == null) {
warning(sender, I.t("This map does not exist."));
return;
}
if (map == null) {
warning(sender, I.t("This map does not exist."));
return;
}
retrieveUUID(playerName, uuid2 -> {
if (Bukkit.getPlayer((uuid2)) != null && Bukkit.getPlayer((uuid2)).isOnline()
&& map.give(Bukkit.getPlayer(uuid2))) {
info(I.t("The requested map was too big to fit in your inventory."));
info(I.t("Use '/maptool getremaining' to get the remaining maps."));
}
});
});
if (Bukkit.getPlayer((uuid2)) != null && Bukkit.getPlayer((uuid2)).isOnline()
&& map.give(Bukkit.getPlayer(uuid2), quantity)) {
info(I.t("The requested map was too big to fit in your inventory."));
info(I.t("Use '/maptool getremaining' to get the remaining maps."));
}
}

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -46,9 +46,11 @@ import fr.zcraft.quartzlib.components.commands.CommandInfo;
import fr.zcraft.quartzlib.components.i18n.I;
import fr.zcraft.quartzlib.components.rawtext.RawText;
import fr.zcraft.quartzlib.components.rawtext.RawTextPart;
import fr.zcraft.quartzlib.tools.PluginLogger;
import fr.zcraft.quartzlib.tools.text.RawMessage;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -58,49 +60,73 @@ public class ListCommand extends IoMCommand {
@Override
protected void run() throws CommandException {
ArrayList<String> arguments = getArgs();
if (arguments.size() > 1) {
throwInvalidArgument(I.t("Too many parameters!"));
boolean isTooMany = arguments.size() > 1;
boolean isTooFew = false;
if (!checkArguments(isTooMany, isTooFew)) {
return;
}
String playerName;
final boolean isHuman = (sender instanceof Player);
if (arguments.size() == 1) {
if (!Permissions.LISTOTHER.grantedTo(sender)) {
if (!Permissions.LISTOTHER.grantedTo(sender) && isHuman) {
throwNotAuthorized();
return;
}
playerName = arguments.get(0);
} else {
playerName = playerSender().getName();
}
final Player sender = playerSender();
retrieveUUID(playerName, uuid -> {
List<ImageMap> mapList = MapManager.getMapList(uuid);
if (mapList.isEmpty()) {
info(sender, I.t("No map found."));
if (isHuman) {
playerName = playerSender().getName();
} else {
PluginLogger.warning(I.t("You must give a player name"));
return;
}
String message = I.tn("{white}{bold}{0} map found.",
"{white}{bold}{0} maps found.",
mapList.size());
info(sender, I.tn("{white}{bold}{0} map found.", "{white}{bold}{0} maps found.", mapList.size()));
RawTextPart rawText = new RawText("");
rawText = addMap(rawText, mapList.get(0));
//TODO pagination chat
for (int i = 1, c = mapList.size(); i < c; i++) {
rawText = rawText.then(", ").color(ChatColor.GRAY);
rawText = addMap(rawText, mapList.get(i));
}
final Player playerSender;
if (isHuman) {
playerSender = playerSender();
} else {
playerSender = null;
}
UUID uuid = getPlayerUUID(playerName);
List<ImageMap> mapList = MapManager.getMapList(uuid);
if (mapList.isEmpty()) {
String msg = I.t("No map found.");
if (isHuman) {
info(playerSender, msg);
} else {
PluginLogger.info(msg);
}
RawMessage.send(sender, rawText.build());
return;
}
String msg = I.tn("{white}{bold}{0} map found.",
"{white}{bold}{0} maps found.",
mapList.size());
if (isHuman) {
info(playerSender,
msg); //TODO merge those into a common info(isHuman,msg) that print to a sender or the console
} else {
PluginLogger.info(msg);
}
RawTextPart rawText = new RawText("");
rawText = addMap(rawText, mapList.get(0));
//TODO pagination chat
for (int i = 1, c = mapList.size(); i < c; i++) {
rawText = rawText.then(", ").color(ChatColor.GRAY);
rawText = addMap(rawText, mapList.get(i));
}
if (isHuman) {
RawMessage.send(playerSender, rawText.build());
} else {
PluginLogger.info(rawText.build().toPlainText());
}
});
}
private RawTextPart<?> addMap(RawTextPart<?> rawText, ImageMap map) {

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -38,6 +38,7 @@ package fr.moribus.imageonmap.commands.maptool;
import fr.moribus.imageonmap.Permissions;
import fr.moribus.imageonmap.commands.IoMCommand;
import fr.moribus.imageonmap.gui.RenderGui;
import fr.moribus.imageonmap.image.ImageRendererExecutor;
import fr.moribus.imageonmap.image.ImageUtils;
import fr.moribus.imageonmap.map.ImageMap;
@ -45,6 +46,7 @@ import fr.moribus.imageonmap.map.MapManager;
import fr.moribus.imageonmap.map.PosterMap;
import fr.zcraft.quartzlib.components.commands.CommandException;
import fr.zcraft.quartzlib.components.commands.CommandInfo;
import fr.zcraft.quartzlib.components.gui.Gui;
import fr.zcraft.quartzlib.components.i18n.I;
import fr.zcraft.quartzlib.components.worker.WorkerCallback;
import fr.zcraft.quartzlib.tools.PluginLogger;
@ -79,6 +81,7 @@ public class NewCommand extends IoMCommand {
@Override
protected void run() throws CommandException {
//TODO check if not too many args
final Player player = playerSender();
ImageUtils.ScalingType scaling = ImageUtils.ScalingType.NONE;
URL url;
@ -121,66 +124,73 @@ public class NewCommand extends IoMCommand {
throwInvalidArgument(I.t("Invalid URL."));
return;
}
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."));
boolean isPlayer = sender != null;
// TODO Add a per-player toggle for the GUI.
if (args.length < 2 && isPlayer) {
Gui.open(player, new RenderGui(url));
} 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);
}
}
}

View File

@ -0,0 +1,57 @@
/*
* 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 <anais.jabre@gmail.com> (2019 2023)
*
* 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.commands.maptool;
import fr.moribus.imageonmap.Permissions;
import fr.moribus.imageonmap.commands.IoMCommand;
import fr.zcraft.quartzlib.components.commands.CommandException;
import fr.zcraft.quartzlib.components.commands.CommandInfo;
import org.bukkit.command.CommandSender;
@CommandInfo(name = "RemotePlacing", usageParameters = "[player name]:map name position rotation")
public class RemotePlacingCommand extends IoMCommand {
@Override
protected void run() throws CommandException {
//if wall => need position and direction N/S/E/W
//else if floor or ceiling => same + rotation
}
@Override
public boolean canExecute(CommandSender sender) {
return Permissions.REMOTE_PLACING.grantedTo(sender);
}
}

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -34,24 +34,6 @@
* knowledge of the CeCILL license and that you accept its terms.
*/
/*
* Copyright (C) 2013 Moribus
* Copyright (C) 2015 ProkopyL <prokopylmc@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package fr.moribus.imageonmap.commands.maptool;
import fr.moribus.imageonmap.Permissions;
@ -70,25 +52,25 @@ public class RenameCommand extends IoMCommand {
@Override
protected void run() throws CommandException {
ArrayList<String> arguments = getArgs();
ArrayList<String> argList = getArgs();
if (argList.size() != 2) {
warning(I.t("Not enough or too many arguments! Usage: /maptool rename <map name> <new map name>"));
boolean isTooMany = arguments.size() > 2;
boolean isTooFew = arguments.size() < 2;
if (!checkArguments(isTooMany, isTooFew)) {
return;
}
ImageMap map = MapManager.getMap(playerSender().getUniqueId(), argList.get(0));
String oldName = arguments.get(0);
ImageMap map = MapManager.getMap(playerSender().getUniqueId(), oldName);
if (map == null) {
error(I.t("This map does not exist."));
return;
}
map.rename(argList.get(1));
String newName = arguments.get(1);
map.rename(newName);
}
@Override
protected List<String> complete() throws CommandException {
if (args.length == 1) {
return getMatchingMapNames(playerSender(), args[0]);
}

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -52,6 +52,7 @@ import fr.zcraft.quartzlib.tools.text.MessageSender;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.UUID;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -62,17 +63,10 @@ public class UpdateCommand extends IoMCommand {
protected void run() throws CommandException {
//TODO fix the issue where to many quick usage of offlineNameFetch will return null
ArrayList<String> arguments = getArgs();
String warningMsg;
if (arguments.size() > 4) {
warningMsg = "Too many parameters!"
+ " Usage: /maptool update [player name]:<map name> <new url> [stretched|covered]";
warning(I.t(warningMsg));
return;
}
if (arguments.size() < 2) {
warningMsg =
"Too few parameters! Usage: /maptool update [player name]:<map name> <new url> [stretched|covered]";
warning(I.t(warningMsg));
boolean isTooMany = arguments.size() > 4;
boolean isTooFew = arguments.size() < 2;
if (!checkArguments(isTooMany, isTooFew)) {
return;
}
final String playerName;
@ -139,87 +133,83 @@ public class UpdateCommand extends IoMCommand {
}
}
final ImageUtils.ScalingType scaling;
final ImageUtils.ScalingType scaling = ImageUtils.scalingTypeFromName(resize);//TODO test if nothing broke
// because I went from 3 to 4 by adding the none as default instead of the contained one.
switch (resize) {
UUID uuid = getPlayerUUID(playerName);
ImageMap map = MapManager.getMap(uuid, mapName);
case "stretched":
scaling = ImageUtils.ScalingType.STRETCHED;
break;
case "covered":
scaling = ImageUtils.ScalingType.COVERED;
break;
default:
scaling = ImageUtils.ScalingType.CONTAINED;
if (map == null) {
warning(sender, I.t("This map does not exist."));
return;
}
//TODO passer en static
//ImageOnMap.getPlugin().getCommandWorker().offlineNameFetch(playerName, uuid -> {
retrieveUUID(playerName, uuid -> {
ImageMap map = MapManager.getMap(uuid, mapName);
if (map == null) {
warning(sender, I.t("This map does not exist."));
URL url1;
try {
url1 = new URL(url);
if (!Permissions.BYPASS_WHITELIST.grantedTo(playerSender) && !checkHostnameWhitelist(url1)) {
throwInvalidArgument(I.t("This hosting website is not trusted, if you think that this is an error "
+ " contact your server administrator"));
return;
}
URL url1;
try {
url1 = new URL(url);
if (!Permissions.BYPASS_WHITELIST.grantedTo(playerSender) && !checkHostnameWhitelist(url1)) {
throwInvalidArgument(I.t("This hosting website is not trusted, if you think that this is an error "
+ " contact your server administrator"));
return;
}
//TODO replace by a check of the load status.(if not loaded load the mapmanager)
MapManager.load(false);//we don't want to spam the console each time we reload the mapManager
//TODO replace by a check of the load status.(if not loaded load the mapmanager)
MapManager.load(false);//we don't want to spam the console each time we reload the mapManager
Integer[] size = {1, 1};
if (map.getType() == ImageMap.Type.POSTER) {
size = map.getSize(map.getUserUUID(), map.getId());
}
int width = size[0];
int height = size[1];
try {
if (playerSender != null) {
ActionBar.sendPermanentMessage(playerSender, ChatColor.DARK_GREEN + I.t("Updating..."));
}
ImageRendererExecutor
.update(url1, scaling, uuid, map, width, height, new WorkerCallback<ImageMap>() {
@Override
public void finished(ImageMap result) {
if (playerSender != null) {
ActionBar.removeMessage(playerSender);
MessageSender.sendActionBarMessage(playerSender,
ChatColor.DARK_GREEN + I.t("The map was updated using the new image!"));
}
}
@Override
public void errored(Throwable exception) {
if (playerSender != null) {
playerSender
.sendMessage(
I.t("{ce}Map rendering failed: {0}", exception.getMessage()));
}
PluginLogger.warning("Rendering from {0} failed: {1}: {2}",
playerSender.getName(),
exception.getClass().getCanonicalName(),
exception.getMessage());
}
});
} finally {
if (playerSender != null) {
ActionBar.removeMessage(playerSender);
}
}
} catch (MalformedURLException | CommandException ex) {
warning(sender, I.t("Invalid URL."));
Integer[] size = {1, 1};
if (map.getType() == ImageMap.Type.POSTER) {
size = map.getSize(map.getUserUUID(), map.getId());
}
});
if (size.length == 0) {
size = new Integer[] {1, 1};
}
int width = size[0];
int height = size[1];
try {
String msg = I.t("Updating...");
if (playerSender != null) {
//TODO tester si player humain
ActionBar.sendPermanentMessage(playerSender, ChatColor.DARK_GREEN + msg);
} else {
PluginLogger.info(msg);
}
ImageRendererExecutor
.update(url1, scaling, uuid, map, width, height, new WorkerCallback<ImageMap>() {
@Override
public void finished(ImageMap result) {
String msg = I.t("The map was updated using the new image!");
if (playerSender != null) {
//TODO tester si player humain
ActionBar.removeMessage(playerSender);
MessageSender.sendActionBarMessage(playerSender,
ChatColor.DARK_GREEN + msg);
} else {
PluginLogger.info(msg);
}
}
@Override
public void errored(Throwable exception) {
if (playerSender != null) {
playerSender
.sendMessage(
I.t("{ce}Map rendering failed: {0}", exception.getMessage()));
}
PluginLogger.warning("Rendering from {0} failed: {1}: {2}",
playerSender.getName(),
exception.getClass().getCanonicalName(),
exception.getMessage());
}
});
} finally {
if (playerSender != null) {
ActionBar.removeMessage(playerSender);
}
}
} catch (MalformedURLException | CommandException ex) {
warning(sender, I.t("Invalid URL."));
}
}

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -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;
@ -57,8 +56,8 @@ import org.bukkit.inventory.ItemStack;
public class MapDetailGui extends ExplorerGui<Integer> {
private final ImageMap map;
private OfflinePlayer offplayer;
private String name;
private final OfflinePlayer offplayer;
private final String name;
public MapDetailGui(ImageMap map, OfflinePlayer p, String name) {
super();
@ -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

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -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()) {

View File

@ -0,0 +1,183 @@
/*
* 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 <anais.jabre@gmail.com> (2019 2023)
*
* 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.gui;
import fr.moribus.imageonmap.image.ImageUtils;
import fr.zcraft.quartzlib.components.gui.ActionGui;
import fr.zcraft.quartzlib.components.i18n.I;
import fr.zcraft.quartzlib.tools.items.ItemStackBuilder;
import fr.zcraft.quartzlib.tools.items.TextualBanners;
import java.net.URL;
import org.bukkit.ChatColor;
import org.bukkit.DyeColor;
import org.bukkit.Material;
public class RenderGui extends ActionGui {
final URL url;
boolean resize = false;
int width = 0;
int height = 0;
boolean originalSizeLoaded = false;
int originalWidth = 0;
int originalHeight = 0;
ImageUtils.ScalingType scaling = ImageUtils.ScalingType.NONE;
public RenderGui(URL url) {
this.url = url;
}
@Override
protected void onUpdate() {
setTitle(I.t("Image Editor"));
setHeight(6);
action("toggle_resize", 0, new ItemStackBuilder(Material.PAINTING)
.title(ChatColor.LIGHT_PURPLE, ChatColor.BOLD + I.t("Resize image"))
.loreLine(ChatColor.DARK_GRAY, resize ? I.t("Enabled") : I.t("Disabled"))
.loreSeparator()
.longLore(ChatColor.GRAY,
I.t("You can automatically resize the image to a certain number of blocks (or item frames)."))
.loreSeparator()
.loreLine(ChatColor.BLUE, I.t("Original size (in blocks)"))
.loreLine(ChatColor.GRAY,
originalSizeLoaded ? I.t("{0} × {1}", originalWidth, originalHeight) : I.t("Loading..."))
.loreSeparator()
.longLore(resize ? I.t("{gray}» {white}Click{gray} to disable resize") :
I.t("{gray}» {white}Click{gray} to enable resize"))
);
injectSizeEditor(2, true);
injectSizeEditor(11, false);
}
/**
* Injects the size editor in the GUI.
*
* @param slot The slot where the editor must start.
* @param isWidth True to inject a width-size editor; false to inject a height-editor.
*/
private void injectSizeEditor(int slot, final boolean isWidth) {
final String action_key = isWidth ? "width_" : "height_";
final String currentSize = ChatColor.DARK_GRAY + I.t("Current size: {0} × {1}", width, height);
action(action_key + "_decrement_10", slot++, getBannerButton(false, true, resize)
.title(ChatColor.RED, I.t("- 10"))
.loreLine(currentSize)
.loreSeparator()
.longLore(isWidth
? I.t("{gray}» {white}Click{gray} to decrease the image's width by 10 blocks")
: I.t("{gray}» {white}Click{gray} to decrease the image's height by 10 blocks")
)
);
action(action_key + "_decrement_1", slot++, getBannerButton(false, false, resize)
.title(ChatColor.RED, I.t("- 1"))
.loreLine(currentSize)
.loreSeparator()
.longLore(isWidth
? I.t("{gray}» {white}Click{gray} to decrease the image's width by one block")
: I.t("{gray}» {white}Click{gray} to decrease the image's height by one block")
)
);
action(action_key + "_increment_1", slot++, getBannerButton(true, false, resize)
.title(ChatColor.GREEN, I.t("+ 1"))
.loreLine(currentSize)
.loreSeparator()
.longLore(isWidth
? I.t("{gray}» {white}Click{gray} to increase the image's width by one block")
: I.t("{gray}» {white}Click{gray} to increase the image's height by one block")
)
);
action(action_key + "_increment_10", slot++, getBannerButton(true, true, resize)
.title(ChatColor.GREEN, I.t("+ 10"))
.loreLine(currentSize)
.loreSeparator()
.longLore(isWidth
? I.t("{gray}» {white}Click{gray} to increase the image's width by 10 blocks")
: I.t("{gray}» {white}Click{gray} to increase the image's height by 10 blocks")
)
);
/*(action_key + "_set_values", slot++, getBannerButton(false, false, resize)
.title(ChatColor.BLUE, I.t("set the size"))
.loreLine(currentSize)
.loreSeparator()
.longLore(isWidth
? I.t("{gray}» {white}Click{gray} to set the image's width")
: I.t("{gray}» {white}Click{gray} to set the image's height")
)
);*/
slot++;
}
/**
* Creates a banner for the +/- buttons.
* + are green, - are red
* short steps are light, long steps are dark
* disabled banners are in grayscale
*
* @param positive true for a + banner
* @param longStep true for a darker banner
* @param disabled true for a grayscale banner
* @return The banner in a builder.
*/
private ItemStackBuilder getBannerButton(boolean positive, boolean longStep, boolean disabled) {
//final char symbol = positive ? '+' : '-'; //TODO this need rework have something that work but need QL update
final char symbol = positive ? '*' : '-';
final DyeColor background;
if (disabled) {
background = longStep ? DyeColor.BLACK : DyeColor.GRAY;
} else {
if (positive) {
background = longStep ? DyeColor.GREEN : DyeColor.LIME;
} else {
background = longStep ? DyeColor.RED : DyeColor.PINK;
}
}
return new ItemStackBuilder(TextualBanners.getCharBanner(symbol, background, DyeColor.BLACK));
}
}

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -36,15 +36,20 @@
package fr.moribus.imageonmap.image;
import fr.moribus.imageonmap.Permissions;
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.zcraft.quartzlib.components.i18n.I;
import fr.zcraft.quartzlib.components.worker.Worker;
import fr.zcraft.quartzlib.components.worker.WorkerAttributes;
import fr.zcraft.quartzlib.components.worker.WorkerCallback;
import fr.zcraft.quartzlib.components.worker.WorkerRunnable;
import fr.zcraft.quartzlib.tools.PluginLogger;
import fr.zcraft.quartzlib.tools.text.ActionBar;
import fr.zcraft.quartzlib.tools.text.MessageSender;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
@ -56,9 +61,46 @@ import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import javax.imageio.ImageIO;
import org.bukkit.Bukkit;
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,
final int width, final int height) {
final Player player = Bukkit.getPlayer(playerUUID);
if (player == null) {
return;
}
ActionBar.sendPermanentMessage(player, ChatColor.DARK_GREEN + I.t("Rendering..."));
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())) {
player.sendMessage(ChatColor.GRAY + I.t("The rendered map was too big to fit in your inventory."));
player.sendMessage(ChatColor.GRAY + I.t("Use '/maptool getremaining' to get the remaining maps."));
}
}
@Override
public void errored(Throwable exception) {
ActionBar.removeMessage(player);
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());
}
});
}
private static URLConnection connecting(URL url) throws IOException {
final URLConnection connection = url.openConnection();
connection.addRequestProperty("User-Agent",
@ -94,6 +136,7 @@ public class ImageRendererExecutor extends Worker {
public static void render(final URL url, final ImageUtils.ScalingType scaling, final UUID playerUUID,
final int width, final int height, WorkerCallback<ImageMap> callback) {
submitQuery(new WorkerRunnable<ImageMap>() {
@Override
public ImageMap run() throws Throwable {
@ -144,14 +187,11 @@ public class ImageRendererExecutor extends Worker {
}
// Limits are in place and the player does NOT have rights to avoid them.
checkSizeLimit(playerUUID, image);
if (scaling != ImageUtils.ScalingType.NONE && height <= 1 && width <= 1) {
ImageMap ret = renderSingle(scaling.resize(image, ImageMap.WIDTH, ImageMap.HEIGHT), playerUUID);
image.flush();//Safe to free
return ret;
}
final BufferedImage resizedImage =
scaling.resize(image, ImageMap.WIDTH * width, ImageMap.HEIGHT * height);
final BufferedImage resizedImage;
resizedImage = scaling.resize(image, ImageMap.WIDTH * width, ImageMap.HEIGHT * height);
image.flush();//Safe to free
return renderPoster(resizedImage, playerUUID);
}
}, callback);
@ -204,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();

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -125,6 +125,29 @@ public class ImageUtils {
}
public static ScalingType scalingTypeFromName(String resize) {
switch (resize) {
case "stretch":
case "stretched":
case "resize-stretched":
return ScalingType.STRETCHED;
case "cover":
case "covered":
case "resize-covered":
return ScalingType.COVERED;
case "contain":
case "contained":
case "resize-contained":
case "resize":
return ScalingType.CONTAINED;
default:
return ScalingType.NONE;
}
}
public enum ScalingType {
NONE,
CONTAINED,

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.

View File

@ -0,0 +1,224 @@
/*
* 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 <anais.jabre@gmail.com> (2019 2023)
*
* 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 fr.zcraft.quartzlib.tools.PluginLogger;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import javax.xml.crypto.Data;
import org.bukkit.util.io.BukkitObjectInputStream;
import org.bukkit.util.io.BukkitObjectOutputStream;
public class DATReader {
public boolean saveData(String filePath) {
try {
BukkitObjectOutputStream out =
new BukkitObjectOutputStream(new GZIPOutputStream(new FileOutputStream(filePath)));
out.writeObject(this);
out.close();
return true;
} catch (IOException e) {
// TODO Auto-generated catch block
PluginLogger.error("" + e.getMessage());
return false;
}
}
public boolean loadData(String filePath) {
try {
BukkitObjectInputStream in =
new BukkitObjectInputStream(new GZIPInputStream(new FileInputStream(filePath)));
Data data = (Data) in.readObject();
PluginLogger.info("loaded data" + data);
in.close();
return true;
} catch (ClassNotFoundException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
}
/*
package tutorial;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.UUID;
import java.util.logging.Level;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.util.io.BukkitObjectInputStream;
import org.bukkit.util.io.BukkitObjectOutputStream;
public class Data implements Serializable {
private static transient final long serialVersionUID = -1681012206529286330L;
public final HashMap<Location, String> blockSnapShot;
public final HashSet<UUID> previouslyOnlinePlayers;
// Can be used for saving
public Data(HashMap<Location, String> blockSnapShot, HashSet<UUID> previouslyOnlinePlayers) {
this.blockSnapShot = blockSnapShot;
this.previouslyOnlinePlayers = previouslyOnlinePlayers;
}
// Can be used for loading
public Data(Data loadedData) {
this.blockSnapShot = loadedData.blockSnapShot;
this.previouslyOnlinePlayers = loadedData.previouslyOnlinePlayers;
}
public boolean saveData(String filePath) {
try {
BukkitObjectOutputStream out =
new BukkitObjectOutputStream(new GZIPOutputStream(new FileOutputStream(filePath)));
out.writeObject(this);
out.close();
return true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
public static Data loadData(String filePath) {
try {
BukkitObjectInputStream in =
new BukkitObjectInputStream(new GZIPInputStream(new FileInputStream(filePath)));
Data data = (Data) in.readObject();
in.close();
return data;
} catch (ClassNotFoundException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
public static void getBlocksPlayersAndSave() {
// HashMap used for storing blocks
HashMap<Location, String> blockSnapShot = new HashMap<Location, String>();
// HashSet used for storing the online players
HashSet<UUID> previouslyOnlinePlayers = new HashSet<UUID>();
// Grabs the spawn location of the first world the server finds
Location spawnLocation = Bukkit.getServer().getWorlds().iterator().next().getSpawnLocation();
// One variable to store our blockLocation
Location blockLocation;
// Variables to store our x y z coordinates
int x, y, z;
// We will first retrieve all the currently online players
Bukkit.getServer().getOnlinePlayers().forEach(player -> previouslyOnlinePlayers.add(player.getUniqueId()));
// Next we will retrieve all block data in a 64 by 64 radius around the spawn.
// While looping, using the new keyword and making declarations like "int x = 0;"
// will create garbage, and that garbage will start to pile up if the loop is
// extensive. We will take as much of a load off of the garbage collector as we
// can here by re-assigning x,y,z not re-declaring, and re-assigning the declared
// blockLocation to retrieve the block data. (we are going to store 262,144 blocks...)
for (x = 0; x <= 32; x++) {
for (y = 0; y <= 32; y++) {
for(z = 0; z <= 32; z++) {
blockSnapShot.put(blockLocation = new Location(spawnLocation.getWorld(),
spawnLocation.getX() - x,
spawnLocation.getY() - y,
spawnLocation.getZ() - z), blockLocation.getBlock().getBlockData().getAsString());
blockSnapShot.put(blockLocation = new Location(spawnLocation.getWorld(),
spawnLocation.getX() + x,
spawnLocation.getY() - y,
spawnLocation.getZ() - z), blockLocation.getBlock().getBlockData().getAsString());
blockSnapShot.put(blockLocation = new Location(spawnLocation.getWorld(),
spawnLocation.getX() - x,
spawnLocation.getY() + y,
spawnLocation.getZ() - z), blockLocation.getBlock().getBlockData().getAsString());
blockSnapShot.put(blockLocation = new Location(spawnLocation.getWorld(),
spawnLocation.getX() - x,
spawnLocation.getY() - y,
spawnLocation.getZ() + z), blockLocation.getBlock().getBlockData().getAsString());
blockSnapShot.put(blockLocation = new Location(spawnLocation.getWorld(),
spawnLocation.getX() + x,
spawnLocation.getY() + y,
spawnLocation.getZ() + z), blockLocation.getBlock().getBlockData().getAsString());
blockSnapShot.put(blockLocation = new Location(spawnLocation.getWorld(),
spawnLocation.getX() - x,
spawnLocation.getY() + y,
spawnLocation.getZ() + z), blockLocation.getBlock().getBlockData().getAsString());
blockSnapShot.put(blockLocation = new Location(spawnLocation.getWorld(),
spawnLocation.getX() + x,
spawnLocation.getY() - y,
spawnLocation.getZ() + z), blockLocation.getBlock().getBlockData().getAsString());
blockSnapShot.put(blockLocation = new Location(spawnLocation.getWorld(),
spawnLocation.getX() + x,
spawnLocation.getY() + y,
spawnLocation.getZ() - z), blockLocation.getBlock().getBlockData().getAsString());
}
}
}
// Finally we save the retrieved data to a file
// You will most likely want to change the file location to your some other directory,
// like your plugin's data directory, instead of the Tutorial's.
new Data(blockSnapShot, previouslyOnlinePlayers).saveData("Tutorial.data");
Bukkit.getServer().getLogger().log(Level.INFO, "Data Saved");
}
public static void welcomePlayersAndResetBlocks() {
// Load the data from disc using our loadData method.
Data data = new Data(Data.loadData("Tutorial.data"));
// For each player that is current online send them a message
data.previouslyOnlinePlayers.forEach(playerId -> {
if (Bukkit.getServer().getPlayer(playerId).isOnline()) {
Bukkit.getServer().getPlayer(playerId).
sendMessage("Thanks for coming back after downtime. Hope you see the spawn blocks change!");
}
});
// Change all of the blocks around the spawn to what we have saved in our file.
data.blockSnapShot.keySet().forEach(location ->
location.getBlock().setBlockData(Bukkit.getServer().createBlockData(data.blockSnapShot.get(location))));
Bukkit.getServer().getLogger().log(Level.INFO, "Data loaded");
}
}*/

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -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:
@ -114,11 +113,11 @@ public abstract class ImageMap implements ConfigurationSerializable {
MapManager.getPlayerMapStore(playerUUID).getToolConfig().getConfigurationSection("PlayerMapStore");
if (section == null) {
return null;
return new Integer[0];
}
List<Map<String, Object>> list = (List<Map<String, Object>>) section.getList("mapList");
if (list == null) {
return null;
return new Integer[0];
}
for (Map<String, Object> tmpMap : list) {
@ -126,7 +125,7 @@ public abstract class ImageMap implements ConfigurationSerializable {
return new Integer[] {(Integer) tmpMap.get("columns"), (Integer) tmpMap.get("rows")};
}
}
return null;
return new Integer[0];
}
protected static <T> T getFieldValue(Map<String, Object> map, String fieldName)
@ -149,6 +148,7 @@ public abstract class ImageMap implements ConfigurationSerializable {
public abstract int[] getMapsIDs();
public abstract int getFirstMapID();
/* ====== Serialization methods ====== */
public abstract boolean managesMap(int mapID);
@ -172,6 +172,14 @@ public abstract class ImageMap implements ConfigurationSerializable {
return MapItemManager.give(player, this);
}
public boolean give(Player player, int quantity) {
boolean bool = true;
for (int i = 0; i < quantity; i++) {
bool = bool && MapItemManager.give(player, this);
}
return bool;
}
protected abstract void postSerialize(Map<String, Object> map);
@Override

View File

@ -1,82 +1,56 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
*
* 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);
}
}
/*
* 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 <anais.jabre@gmail.com> (2019 2023)
*
* 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;
public class MapIndexes {
private final int columnIndex;
private final int rowIndex;
public MapIndexes(int rowIndex, int columnIndex) {
this.rowIndex = rowIndex;
this.columnIndex = columnIndex;
}
public int getColumnIndex() {
return columnIndex;
}
public int getRowIndex() {
return rowIndex;
}
}

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -45,6 +45,7 @@ import fr.zcraft.quartzlib.tools.PluginLogger;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Material;
@ -101,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;
}
@ -110,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());
}
@ -157,7 +161,7 @@ public abstract class MapManager {
public static void notifyModification(UUID playerUUID) {
getPlayerMapStore(playerUUID).notifyModification();
if (autosaveTask == null) {
Bukkit.getScheduler().runTaskLater(ImageOnMap.getPlugin(), new AutosaveRunnable(), SAVE_DELAY);
Bukkit.getScheduler().runTaskLater(ImageOnMap.getPlugin(), new AutoSaveRunnable(), SAVE_DELAY);
}
}
@ -268,7 +272,7 @@ public abstract class MapManager {
//Loading
public static void load(boolean verbose) {
int loadedFilesCount = 0;
for (File file : ImageOnMap.getPlugin().getMapsDirectory().listFiles()) {
for (File file : Objects.requireNonNull(ImageOnMap.getPlugin().getMapsDirectory().listFiles())) {
UUID uuid = getUUIDFromFile(file);
if (uuid == null) {
continue;
@ -373,7 +377,7 @@ public abstract class MapManager {
return null;
}
private static class AutosaveRunnable implements Runnable {
private static class AutoSaveRunnable implements Runnable {
@Override
public void run() {
synchronized (playerMaps) {

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -54,10 +54,11 @@ import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
public class PlayerMapStore implements ConfigurationSerializable {
private final UUID playerUUID;
private final ArrayList<ImageMap> mapList = new ArrayList<ImageMap>();
private final ArrayList<ImageMap> mapList = new ArrayList<>();
private boolean modified = false;
private int mapCount = 0;
private FileConfiguration mapConfig = null;
@ -67,6 +68,7 @@ public class PlayerMapStore implements ConfigurationSerializable {
this.playerUUID = playerUUID;
}
//TODO maybe usefull to merge with the other manages map
public synchronized boolean managesMap(int mapID) {
for (ImageMap map : mapList) {
if (map.managesMap(mapID)) {
@ -83,13 +85,7 @@ public class PlayerMapStore implements ConfigurationSerializable {
if (item.getType() != Material.FILLED_MAP) {
return false;
}
for (ImageMap map : mapList) {
if (map.managesMap(item)) {
return true;
}
}
return false;
return managesMap(MapManager.getMapIdFromItemStack(item));
}
public synchronized void addMap(ImageMap map) throws MapManagerException {
@ -108,33 +104,27 @@ public class PlayerMapStore implements ConfigurationSerializable {
}
public synchronized void deleteMap(ImageMap map) throws MapManagerException {
remove_Map(map);
delete_Map(map);
notifyModification();
}
private void remove_Map(ImageMap map) throws MapManagerException {
private void delete_Map(ImageMap map) throws MapManagerException {
if (!mapList.remove(map)) {
throw new MapManagerException(Reason.IMAGEMAP_DOES_NOT_EXIST);
}
mapCount -= map.getMapCount();
}
public synchronized boolean mapExists(String id) {
for (ImageMap map : mapList) {
if (map.getId().equals(id)) {
return true;
}
}
return false;
public synchronized boolean mapExists(String mapId) {
return getMap(mapId) != null;
}
public String getNextAvailableMapID(String mapId) {
//TODO check if the value is always greater than the id count
if (!mapExists(mapId)) {
return mapId;
}
int id = 0;
do {
id++;
} while (mapExists(mapId + "-" + id));
@ -143,11 +133,12 @@ public class PlayerMapStore implements ConfigurationSerializable {
}
public synchronized List<ImageMap> getMapList() {
return new ArrayList(mapList);
return new ArrayList<>(mapList);
}
//TODO refactor to arraylist instead of an array
public synchronized ImageMap[] getMaps() {
return mapList.toArray(new ImageMap[mapList.size()]);
return mapList.toArray(new ImageMap[0]);
}
public synchronized ImageMap getMap(String mapId) {
@ -156,7 +147,6 @@ public class PlayerMapStore implements ConfigurationSerializable {
return map;
}
}
return null;
}
@ -202,9 +192,9 @@ public class PlayerMapStore implements ConfigurationSerializable {
/* ****** Configuration Files management ***** */
@Override
public Map<String, Object> serialize() {
Map<String, Object> map = new HashMap<String, Object>();
ArrayList<Map> list = new ArrayList<Map>();
public @NotNull Map<String, Object> serialize() {
Map<String, Object> map = new HashMap<>();
ArrayList<Map> list = new ArrayList<>();
synchronized (this) {
for (ImageMap tmpMap : mapList) {
list.add(tmpMap.serialize());

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -36,11 +36,17 @@
package fr.moribus.imageonmap.map;
import fr.zcraft.quartzlib.tools.PluginLogger;
import fr.zcraft.quartzlib.tools.world.WorldUtils;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.bukkit.Location;
import org.bukkit.block.BlockFace;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.Player;
public class PosterMap extends ImageMap {
protected final int[] mapsIDs;
@ -76,6 +82,16 @@ public class PosterMap extends ImageMap {
return mapsIDs;
}
@Override
public int getFirstMapID() {
int first = -1;
for (int id : mapsIDs) {
if (first == -1 || first > id) {
first = id;
}
}
return first;
}
/* ====== Serialization methods ====== */
@Override
@ -158,6 +174,7 @@ public class PosterMap extends ImageMap {
public int getMapIdAtReverseZ(int index, BlockFace orientation, BlockFace bf) {
//TODO maybe a bug there why don't use orientation?
int x = 0;
int y = 0;
switch (bf) {
@ -177,7 +194,6 @@ public class PosterMap extends ImageMap {
}
public boolean hasColumnData() {
return rowCount != 0 && columnCount != 0;
}
@ -193,8 +209,87 @@ public class PosterMap extends ImageMap {
return i;
}
}
throw new IllegalArgumentException("Invalid map ID");
}
public int getSortedIndex(int mapID) {
int[] ids = mapsIDs.clone();
Arrays.sort(ids);
for (int i : ids) {
PluginLogger.info("" + i);
}
for (int i = 0; i < mapsIDs.length; i++) {
if (ids[i] == mapID) {
return i;
}
}
throw new IllegalArgumentException("Invalid map ID");
}
public MapIndexes getIndexes(int mapID) {
int index = getSortedIndex(mapID);
PluginLogger.info(rowCount + " " + columnCount + " " + index);
return new MapIndexes(index / columnCount, index % columnCount);
}
public Location findLocationFirstFrame(ItemFrame frame, Player player) {
final ImageMap map = MapManager.getMap(frame.getItem());
if (!(map instanceof PosterMap)) {
return null;
}
PosterMap poster = (PosterMap) map;
if (!poster.hasColumnData()) {
return null;
}
int mapID = MapManager.getMapIdFromItemStack(frame.getItem());
BlockFace bf = WorldUtils.get4thOrientation(player.getLocation());
MapIndexes mapindexes = getIndexes(mapID);
int row = mapindexes.getRowIndex();
int column = mapindexes.getColumnIndex();
Location loc = frame.getLocation();
PluginLogger.info("\n\nlocalization of the initial clicked frame " + loc);
PluginLogger.info("row " + row + " col " + column);
switch (frame.getFacing().getOppositeFace()) {
case UP:
case DOWN:
switch (bf) {
case NORTH:
loc.add(-row, 0, column);
break;
case SOUTH:
loc.add(row, 0, -column);
break;
case WEST:
loc.add(row, 0, column);
break;
case EAST:
loc.add(-row, 0, -column);
break;
default:
throw new IllegalStateException("Unexpected value: " + bf);
}
break;
case EAST:
loc.add(0, row, -column);
break;
case WEST:
loc.add(0, row, column);
break;
case NORTH:
loc.add(-column, row, 0);
break;
case SOUTH:
loc.add(column, row, 0);
break;
default:
throw new IllegalStateException("Unexpected value: " + bf);
}
PluginLogger.info("\n\nlocalization of the first frame " + loc);
return loc;
}
}

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -36,11 +36,10 @@
package fr.moribus.imageonmap.migration;
import fr.moribus.imageonmap.ImageOnMap;
import fr.zcraft.quartzlib.components.i18n.I;
import fr.zcraft.quartzlib.tools.PluginLogger;
//TODO need to support new render folder and write on maps automatically
public class MigratorExecutor {
private static Thread migratorThread;
@ -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();
}

View File

@ -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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
*
* 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<String>();
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;
}
}

View File

@ -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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
*
* 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<String>();
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;
}
}

View File

@ -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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
*
* 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);
}
}

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -40,10 +40,8 @@ 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.PluginLogger;
import fr.zcraft.quartzlib.tools.items.ItemStackBuilder;
import fr.zcraft.quartzlib.tools.items.ItemUtils;
import fr.zcraft.quartzlib.tools.runners.RunTask;
@ -89,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()) {
@ -142,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);
}
@ -164,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);
@ -194,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);
//}
}
//
@ -297,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())) {

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -36,9 +36,13 @@
package fr.moribus.imageonmap.ui;
import fr.moribus.imageonmap.map.PosterMap;
import fr.moribus.imageonmap.map.ImageMap;
import fr.moribus.imageonmap.map.MapManager;
import fr.zcraft.quartzlib.tools.PluginLogger;
import fr.zcraft.quartzlib.tools.world.FlatLocation;
import fr.zcraft.quartzlib.tools.world.WorldUtils;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
@ -48,121 +52,22 @@ import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
public class PosterOnASurface {
public FlatLocation loc1;
public FlatLocation loc2;
public ItemFrame[] frames;
/**
* Return the list of map Frames associated with a specific map
*/
public static ItemFrame[] getMatchingMapFrames(PosterMap map, FlatLocation location, int mapId, BlockFace bf) {
int mapIndex = map.getIndex(mapId);
//int x = map.getColumnAt(mapIndex), y = map.getRowAt(mapIndex);
int x = 0;
int y = 0;
switch (bf) {
case EAST:
case WEST:
y = map.getColumnCount() - 1;
break;
case NORTH:
case SOUTH:
y = map.getRowCount() - 1;
break;
default:
throw new IllegalStateException("Unexpected value: " + bf);
}
return getMatchingMapFrames(map, location.clone().addH(x, y, bf), bf).clone();
}
public static ItemFrame[] getMatchingMapFrames(PosterMap map, FlatLocation location, BlockFace bf) {
ItemFrame[] frames = new ItemFrame[map.getMapCount()];
FlatLocation loc = location.clone();
int x = 0;
int y = 0;
switch (bf) {
case EAST:
case WEST:
//X=map.getRowCount();
//Y=map.getColumnCount();
//break;
case NORTH:
case SOUTH:
y = map.getRowCount();
x = map.getColumnCount();
break;
default:
throw new IllegalStateException("Unexpected value: " + bf);
}
for (int j = 0; j < y; ++j) {
for (int i = 0; i < x; ++i) {
int mapIndex = map.getIndexAt(i, j);
ItemFrame frame = getMapFrameAt(loc, map);
if (frame != null) {
frames[mapIndex] = frame;
}
switch (bf) {
case EAST:
case WEST:
loc.addH(0, -1, bf);
break;
case NORTH:
case SOUTH:
loc.addH(1, 0, bf);
break;
default:
throw new IllegalStateException("Unexpected value: " + bf);
}
}
switch (bf) {
case EAST:
case WEST:
loc.addH(1, map.getColumnCount(), bf);//test
break;
case NORTH:
case SOUTH:
loc.addH(-map.getColumnCount(), -1, bf);
break;
default:
throw new IllegalStateException("Unexpected value: " + bf);
}
}
return frames;
}
public static ItemFrame getMapFrameAt(FlatLocation location, PosterMap map) {
public static ItemFrame getEmptyFrameAt(Location location, BlockFace facing) {
Entity[] entities = location.getChunk().getEntities();
for (Entity entity : entities) {
if (!(entity instanceof ItemFrame)) {
continue;
}
if (!WorldUtils.blockEquals(location, entity.getLocation())) {
boolean notItemFrame = !(entity instanceof ItemFrame);
if (notItemFrame || !WorldUtils.blockEquals(location, entity.getLocation())) {
continue;
}
ItemFrame frame = (ItemFrame) entity;
if (frame.getFacing() != location.getFacing()) {
continue;
}
ItemStack item = frame.getItem();
if (item.getType() != Material.FILLED_MAP) {
continue;
}
if (!map.managesMap(item)) {
if (frame.getFacing() != facing || item.getType() != Material.AIR) {
continue;
}
return frame;
@ -171,22 +76,17 @@ public class PosterOnASurface {
return null;
}
public static ItemFrame getEmptyFrameAt(Location location, BlockFace facing) {
public static ItemFrame getFrameAt(Location location, BlockFace facing) {
Entity[] entities = location.getChunk().getEntities();
for (Entity entity : entities) {
if (!(entity instanceof ItemFrame)) {
continue;
}
if (!WorldUtils.blockEquals(location, entity.getLocation())) {
boolean notItemFrame = !(entity instanceof ItemFrame);
if (notItemFrame || !WorldUtils.blockEquals(location, entity.getLocation())) {
continue;
}
ItemFrame frame = (ItemFrame) entity;
if (frame.getFacing() != facing) {
continue;
}
ItemStack item = frame.getItem();
if (item.getType() != Material.AIR) {
if (frame.getFacing() != facing) {
continue;
}
return frame;
@ -253,6 +153,116 @@ public class PosterOnASurface {
return true;
}
public static Map<Location, ItemFrame> getItemFramesLocation(Player p, Location startingLocation,
Location selectedLocation, BlockFace facing,
int rows,
int columns) {
Map<Location, ItemFrame> itemFramesLocationMap = new HashMap();
BlockFace bf = WorldUtils.get4thOrientation(p.getLocation());
boolean isWall =
facing.equals(BlockFace.WEST) || facing.equals(BlockFace.EAST) || facing.equals(BlockFace.NORTH)
|| facing.equals(BlockFace.SOUTH);
boolean isFloor = facing.equals(BlockFace.DOWN);
boolean isCeiling = facing.equals(BlockFace.UP);
Location loc = startingLocation;
ItemFrame selectedFrame = getFrameAt(selectedLocation, facing);
int x = 0;
int z = 0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
PluginLogger.info("column " + c);
PluginLogger.info("row " + r);
if (test(selectedFrame, loc, facing)) {
itemFramesLocationMap.put(loc.clone(), getFrameAt(loc, facing));
}
//do a row
if (isWall || isFloor) {
switch (bf) {
case NORTH:
x++;
loc = loc.add(1, 0, 0);
break;
case SOUTH:
x--;
loc = loc.add(-1, 0, 0);
break;
case EAST:
z++;
loc = loc.add(0, 0, 1);
break;
case WEST:
z--;
loc = loc.add(0, 0, -1);
break;
default:
throw new IllegalStateException("Unexpected value: " + bf);
}
} else if (isCeiling) {
switch (bf) {
case NORTH:
x--;
loc = loc.add(-1, 0, 0);
break;
case SOUTH:
x++;
loc = loc.add(1, 0, 0);
break;
case EAST:
z--;
loc = loc.add(0, 0, -1);
break;
case WEST:
z++;
loc = loc.add(0, 0, 1);
break;
default:
throw new IllegalStateException("Unexpected value: " + bf);
}
}
}
if (isWall) {
loc = loc.add(-x, -1, -z);
} else if (isFloor || isCeiling) {
switch (bf) {
case NORTH:
case SOUTH:
loc = loc.add(-x, 0, 1);
break;
case EAST:
case WEST:
loc = loc.add(1, 0, -z);
break;
default:
throw new IllegalStateException("Unexpected value: " + bf);
}
x = 0;
z = 0;
}
}
return itemFramesLocationMap;
}
//TODO add descr and move to correct class and rename
private static boolean test(ItemFrame selectedFrame, Location loc, BlockFace facing) {
ImageMap firstMap = MapManager.getMap(selectedFrame.getItem());
MapManager.getMap(getFrameAt(loc, facing).getItem());
for (int id : firstMap.getMapsIDs()) {
if (id == MapManager.getMapIdFromItemStack(getFrameAt(loc, facing).getItem())) {
return true;
}
//TODO refactor with lambda
}
return false;
}
public void expand() {
}

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -36,15 +36,10 @@
package fr.moribus.imageonmap.ui;
import fr.moribus.imageonmap.map.PosterMap;
import fr.zcraft.quartzlib.tools.world.FlatLocation;
import fr.zcraft.quartzlib.tools.world.WorldUtils;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ItemFrame;
import org.bukkit.inventory.ItemStack;
public class PosterWall {
@ -53,84 +48,8 @@ public class PosterWall {
public ItemFrame[] frames;
public static ItemFrame[] getMatchingMapFrames(PosterMap map, FlatLocation location, int mapId) {
int mapIndex = map.getIndex(mapId);
int x = map.getColumnAt(mapIndex);
int y = map.getRowAt(mapIndex);
return getMatchingMapFrames(map, location.clone().add(-x, y));
}
public static ItemFrame[] getMatchingMapFrames(PosterMap map, FlatLocation location) {
ItemFrame[] frames = new ItemFrame[map.getMapCount()];
FlatLocation loc = location.clone();
for (int y = 0; y < map.getRowCount(); ++y) {
for (int x = 0; x < map.getColumnCount(); ++x) {
int mapIndex = map.getIndexAt(x, y);
ItemFrame frame = getMapFrameAt(loc, map);
if (frame != null) {
frames[mapIndex] = frame;
}
loc.add(1, 0);
}
loc.setX(location.getX());
loc.setZ(location.getZ());
loc.add(0, -1);
}
return frames;
}
public static ItemFrame getMapFrameAt(FlatLocation location, PosterMap map) {
Entity[] entities = location.getChunk().getEntities();
for (Entity entity : entities) {
if (!(entity instanceof ItemFrame)) {
continue;
}
if (!WorldUtils.blockEquals(location, entity.getLocation())) {
continue;
}
ItemFrame frame = (ItemFrame) entity;
if (frame.getFacing() != location.getFacing()) {
continue;
}
ItemStack item = frame.getItem();
if (item.getType() != Material.FILLED_MAP) {
continue;
}
if (!map.managesMap(item)) {
continue;
}
return frame;
}
return null;
}
public static ItemFrame getEmptyFrameAt(Location location, BlockFace facing) {
Entity[] entities = location.getChunk().getEntities();
for (Entity entity : entities) {
if (!(entity instanceof ItemFrame)) {
continue;
}
if (!WorldUtils.blockEquals(location, entity.getLocation())) {
continue;
}
ItemFrame frame = (ItemFrame) entity;
if (frame.getFacing() != facing) {
continue;
}
ItemStack item = frame.getItem();
if (item.getType() != Material.AIR) {
continue;
}
return frame;
}
return null;
return PosterOnASurface.getEmptyFrameAt(location, facing);
}
public boolean isValid() {
@ -159,7 +78,4 @@ public class PosterWall {
return true;
}
public void expand() {
}
}

View File

@ -1,8 +1,8 @@
/*
* 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 2021)
* Copyright or © or Copr. Vlammar <valentin.jabre@gmail.com> (2019 2021)
* Copyright or © or Copr. Amaury Carrade <amaury@carrade.eu> (2016 2022)
* Copyright or © or Copr. Vlammar <anais.jabre@gmail.com> (2019 2023)
*
* This software is a computer program whose purpose is to allow insertion of
* custom images in a Minecraft world.
@ -36,39 +36,37 @@
package fr.moribus.imageonmap.ui;
import com.google.common.collect.ImmutableMap;
import fr.moribus.imageonmap.Permissions;
import fr.moribus.imageonmap.image.MapInitEvent;
import fr.moribus.imageonmap.map.ImageMap;
import fr.moribus.imageonmap.map.MapManager;
import fr.moribus.imageonmap.map.PosterMap;
import fr.zcraft.quartzlib.components.i18n.I;
import fr.zcraft.quartzlib.components.nbt.NBT;
import fr.zcraft.quartzlib.components.nbt.NBTCompound;
import fr.zcraft.quartzlib.components.nbt.NBTList;
import fr.zcraft.quartzlib.tools.PluginLogger;
import fr.zcraft.quartzlib.tools.items.GlowEffect;
import fr.zcraft.quartzlib.tools.items.ItemStackBuilder;
import fr.zcraft.quartzlib.tools.reflection.NMSException;
import fr.zcraft.quartzlib.tools.runners.RunTask;
import fr.zcraft.quartzlib.tools.text.MessageSender;
import fr.zcraft.quartzlib.tools.world.FlatLocation;
import fr.zcraft.quartzlib.tools.world.WorldUtils;
import java.lang.reflect.Method;
import java.util.Map;
import org.bukkit.ChatColor;
import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Rotation;
import org.bukkit.block.BlockFace;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
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() {
}
@ -128,7 +126,8 @@ public abstract class SplatterMapManager {
* @return The modified item stack. The instance may be different if the passed item stack is not a craft itemstack.
*/
public static ItemStack addSplatterAttribute(final ItemStack itemStack) {
GlowEffect.addGlow(itemStack);
itemStack.addUnsafeEnchantment(Enchantment.LURE, 1);
//TODO check if safe guard for duplication XP still works
return itemStack;
}
@ -140,21 +139,7 @@ public abstract class SplatterMapManager {
* @return True if the attribute was detected.
*/
public static boolean hasSplatterAttributes(ItemStack itemStack) {
try {
final NBTCompound nbt = NBT.fromItemStack(itemStack);
if (!nbt.containsKey("Enchantments")) {
return false;
}
final Object enchantments = nbt.get("Enchantments");
if (!(enchantments instanceof NBTList)) {
return false;
}
return !((NBTList) enchantments).isEmpty();
} catch (NMSException e) {
PluginLogger.error("Unable to get Splatter Map attribute on item", e);
return false;
}
return MapManager.managesMap(itemStack);
}
/**
@ -198,6 +183,7 @@ public abstract class SplatterMapManager {
* @param player Player placing map
* @return true if the map was correctly placed
*/
@SuppressWarnings("checkstyle:VariableDeclarationUsageDistance")
public static boolean placeSplatterMap(ItemFrame startFrame, Player player, PlayerInteractEntityEvent event) {
ImageMap map = MapManager.getMap(player.getInventory().getItemInMainHand());
@ -229,8 +215,6 @@ public abstract class SplatterMapManager {
int i = 0;
for (ItemFrame frame : surface.frames) {
BlockFace bf = WorldUtils.get4thOrientation(player.getLocation());
int id = poster.getMapIdAtReverseZ(i, bf, startFrame.getFacing());
Rotation rot = Rotation.NONE;
switch (frame.getFacing()) {
case UP:
@ -241,13 +225,12 @@ public abstract class SplatterMapManager {
default:
//throw new IllegalStateException("Unexpected value: " + frame.getFacing());
}
BlockFace bf = WorldUtils.get4thOrientation(player.getLocation());
int id = poster.getMapIdAtReverseZ(i, bf, startFrame.getFacing());
//Rotation management relative to player rotation the default position is North,
// when on ceiling we flipped the rotation
RunTask.later(() -> {
addPropertiesToFrames(player, frame);
frame.setItem(
new ItemStackBuilder(Material.FILLED_MAP).nbt(ImmutableMap.of("map", id)).craftItem());
}, 5L);
setupMap(player, frame, id);
if (i == 0) {
//First map need to be rotate one time CounterClockwise
@ -281,7 +264,6 @@ public abstract class SplatterMapManager {
throw new IllegalStateException("Unexpected value: " + bf);
}
MapInitEvent.initMap(id);
i++;
}
@ -305,11 +287,8 @@ public abstract class SplatterMapManager {
int id = poster.getMapIdAtReverseY(i);
RunTask.later(() -> {
addPropertiesToFrames(player, frame);
frame.setItem(
new ItemStackBuilder(Material.FILLED_MAP).nbt(ImmutableMap.of("map", id)).craftItem());
}, 5L);
setupMap(player, frame, id);
//Force reset of rotation
@ -321,6 +300,14 @@ public abstract class SplatterMapManager {
return true;
}
private static void setupMap(Player player, ItemFrame frame, int id) {
RunTask.later(() -> {
addPropertiesToFrames(player, frame);
ItemStack item = MapItemManager.createMapItem(id, "", true, false);
frame.setItem(item);
}, 5L);
}
/**
* Remove splattermap
*
@ -337,33 +324,18 @@ public abstract class SplatterMapManager {
if (!poster.hasColumnData()) {
return null;
}
FlatLocation loc = new FlatLocation(startFrame.getLocation(), startFrame.getFacing());
ItemFrame[] matchingFrames = null;
//We search for the map on the top left corner
Location startingLocation = poster.findLocationFirstFrame(startFrame, player);
switch (startFrame.getFacing()) {
case UP:
case DOWN:
matchingFrames = PosterOnASurface.getMatchingMapFrames(poster, loc,
MapManager.getMapIdFromItemStack(startFrame.getItem()),
WorldUtils.get4thOrientation(player.getLocation()));//startFrame.getFacing());
break;
case NORTH:
case SOUTH:
case EAST:
case WEST:
matchingFrames = PosterWall.getMatchingMapFrames(poster, loc,
MapManager.getMapIdFromItemStack(startFrame.getItem()));
break;
default:
throw new IllegalStateException("Unexpected value: " + startFrame.getFacing());
}
if (matchingFrames == null) {
return null;
}
for (ItemFrame frame : matchingFrames) {
Map<Location, ItemFrame>
itemFrameLocations =
PosterOnASurface.getItemFramesLocation(player, startingLocation, startFrame.getLocation(),
startFrame.getFacing(),
poster.getRowCount(), poster.getColumnCount());
//TODO check if it is the correct map id and check the why it delete more than it should and out of place
for (Map.Entry<Location, ItemFrame> entry : itemFrameLocations.entrySet()) {
ItemFrame frame = itemFrameLocations.get(entry.getKey());
PluginLogger.info("Frame to delete " + frame);
if (frame != null) {
removePropertiesFromFrames(player, frame);
frame.setItem(null);

View File

@ -1,20 +1,23 @@
name: ImageOnMap
main: fr.moribus.imageonmap.ImageOnMap
version: "4.2.2"
version: "5.0.0"
api-version: "1.13"
commands:
tomap:
description: render an image in a map
description: Render an image in a map
usage: /<command> [URL]
maptool:
description: Manage maps
maps:
description: Manage maps through a GUI
givemap:
description: give a map to a player from a player map store, by default take from the player that make the command
description: Give a map to a player from a playerMapStore, by default take from the player that make the command
usage: /<command> [player_from] player_to map_name
placemap:
description: Place a map remotely and deploy it
usage: /<command> [player_from]:<map_name> <N/S/E/W> <UP/DOWN/WALL> x y z
permissions:
imageonmap.*:
@ -42,6 +45,7 @@ permissions:
imageonmap.bypassimagelimit: false
imageonmap.bypasswhitelist: true
imageonmap.placeinvisiblesplattermap: true
imageonmap.remoteplacing: false
imageonmap.userender:
description: "Allows you to use /tomap and related commands (/maptool getremaining). Alias of imageonmap.new."
@ -130,3 +134,7 @@ permissions:
imageonmap.placeinvisiblesplattermap:
description: "Allows you to make the item frame on which you placed your splatter map invisible."
default: true
imageonmap.remoteplacing:
description: "Allows you to remotly place a map from a playerMapStore to a specific position."
default: op