mirror of
https://github.com/zDevelopers/ImageOnMap.git
synced 2024-11-25 11:35:35 +01:00
Merge pull request #19 from AmauryCarrade/feature-explorer-gui-13
This commit is contained in:
commit
a2cdb02834
49
pom.xml
49
pom.xml
@ -5,24 +5,65 @@
|
||||
<artifactId>ImageOnMap</artifactId>
|
||||
<version>2.99</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.7</maven.compiler.source>
|
||||
<maven.compiler.target>1.7</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.3</version>
|
||||
<configuration>
|
||||
<artifactSet>
|
||||
<includes>
|
||||
<include>fr.zcraft:zlib</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>fr.zcraft.zlib</pattern>
|
||||
<shadedPattern>fr.moribus.imageonmap</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>zDevelopers</id>
|
||||
<url>http://maven.carrade.eu/artifactory/snapshots</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<!-- Dependency information -->
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
<version>1.8-R0.1-SNAPSHOT</version>
|
||||
<version>1.8.3-R0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>fr.zcraft</groupId>
|
||||
<artifactId>zlib</artifactId>
|
||||
<version>0.99-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
||||
|
@ -18,7 +18,14 @@
|
||||
|
||||
package fr.moribus.imageonmap;
|
||||
|
||||
import fr.moribus.imageonmap.commands.Commands;
|
||||
import fr.moribus.imageonmap.commands.maptool.DeleteConfirmCommand;
|
||||
import fr.moribus.imageonmap.commands.maptool.DeleteNoConfirmCommand;
|
||||
import fr.moribus.imageonmap.commands.maptool.ExploreCommand;
|
||||
import fr.moribus.imageonmap.commands.maptool.GetCommand;
|
||||
import fr.moribus.imageonmap.commands.maptool.GetRemainingCommand;
|
||||
import fr.moribus.imageonmap.commands.maptool.ListCommand;
|
||||
import fr.moribus.imageonmap.commands.maptool.MigrateCommand;
|
||||
import fr.moribus.imageonmap.commands.maptool.NewCommand;
|
||||
import fr.moribus.imageonmap.image.ImageIOExecutor;
|
||||
import fr.moribus.imageonmap.image.ImageRendererExecutor;
|
||||
import fr.moribus.imageonmap.image.MapInitEvent;
|
||||
@ -26,11 +33,15 @@ import fr.moribus.imageonmap.map.MapManager;
|
||||
import fr.moribus.imageonmap.migration.MigratorExecutor;
|
||||
import fr.moribus.imageonmap.migration.V3Migrator;
|
||||
import fr.moribus.imageonmap.ui.MapItemManager;
|
||||
import fr.zcraft.zlib.components.commands.Commands;
|
||||
import fr.zcraft.zlib.components.gui.Gui;
|
||||
import fr.zcraft.zlib.core.ZPlugin;
|
||||
import fr.zcraft.zlib.tools.PluginLogger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public final class ImageOnMap extends JavaPlugin
|
||||
public final class ImageOnMap extends ZPlugin
|
||||
{
|
||||
static private final String IMAGES_DIRECTORY_NAME = "images";
|
||||
static private final String MAPS_DIRECTORY_NAME = "maps";
|
||||
@ -58,10 +69,10 @@ public final class ImageOnMap extends JavaPlugin
|
||||
return new File(imagesDirectory, "map"+mapID+".png");
|
||||
}
|
||||
|
||||
@SuppressWarnings ("unchecked")
|
||||
@Override
|
||||
public void onEnable()
|
||||
{
|
||||
PluginLogger.init(this);
|
||||
// Creating the images and maps directories if necessary
|
||||
try
|
||||
{
|
||||
@ -70,31 +81,44 @@ public final class ImageOnMap extends JavaPlugin
|
||||
}
|
||||
catch(IOException ex)
|
||||
{
|
||||
PluginLogger.error("FATAL : " + ex.getMessage(), null);
|
||||
PluginLogger.error("FATAL : " + ex.getMessage());
|
||||
this.setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
loadComponents(Gui.class, Commands.class, ImageIOExecutor.class, ImageRendererExecutor.class);
|
||||
|
||||
//Init all the things !
|
||||
PluginConfiguration.init(this);
|
||||
MetricsLite.startMetrics();
|
||||
ImageIOExecutor.start();
|
||||
ImageRendererExecutor.start();
|
||||
MapManager.init();
|
||||
Commands.init(this);
|
||||
MapInitEvent.init(this);
|
||||
MapItemManager.init();
|
||||
|
||||
Commands.register(
|
||||
"maptool",
|
||||
NewCommand.class,
|
||||
ListCommand.class,
|
||||
GetCommand.class,
|
||||
DeleteConfirmCommand.class,
|
||||
DeleteNoConfirmCommand.class,
|
||||
GetRemainingCommand.class,
|
||||
ExploreCommand.class,
|
||||
MigrateCommand.class
|
||||
);
|
||||
|
||||
Commands.registerShortcut("maptool", NewCommand.class, "tomap");
|
||||
Commands.registerShortcut("maptool", ExploreCommand.class, "maps");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable()
|
||||
{
|
||||
ImageIOExecutor.stop();
|
||||
ImageRendererExecutor.stop();
|
||||
MapManager.exit();
|
||||
MapItemManager.exit();
|
||||
MigratorExecutor.waitForMigration();
|
||||
PluginLogger.exit();
|
||||
|
||||
super.onDisable();
|
||||
}
|
||||
|
||||
private File checkPluginDirectory(File primaryFile, File... alternateFiles) throws IOException
|
||||
@ -108,5 +132,4 @@ public final class ImageOnMap extends JavaPlugin
|
||||
throw new IOException("Could not create '" + primaryFile.getName() + "' plugin directory.");
|
||||
return primaryFile;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ package fr.moribus.imageonmap;
|
||||
* either expressed or implied, of anybody else.
|
||||
*/
|
||||
|
||||
import fr.zcraft.zlib.tools.PluginLogger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
@ -1,129 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Logger;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
abstract public class PluginLogger
|
||||
{
|
||||
static private Plugin plugin;
|
||||
static private Thread mainThread;
|
||||
static private HashMap<Thread, PluginThreadLogger> loggers;
|
||||
|
||||
static public void init(Plugin plugin)
|
||||
{
|
||||
PluginLogger.plugin = plugin;
|
||||
mainThread = Thread.currentThread();
|
||||
loggers = new HashMap<>();
|
||||
}
|
||||
|
||||
static public void exit()
|
||||
{
|
||||
plugin = null;
|
||||
mainThread = null;
|
||||
loggers = null;
|
||||
}
|
||||
|
||||
static public void log(Level level, String message, Throwable ex)
|
||||
{
|
||||
getLogger().log(level, message, ex);
|
||||
}
|
||||
|
||||
static public void log(Level level, String message, Object...args)
|
||||
{
|
||||
getLogger().log(level, message, args);
|
||||
}
|
||||
|
||||
static public void log(Level level, String message, Throwable ex, Object... args)
|
||||
{
|
||||
log(level, message + " : " + ex.getMessage(), args);
|
||||
}
|
||||
|
||||
static public void info(String message, Object...args)
|
||||
{
|
||||
log(Level.INFO, message, args);
|
||||
}
|
||||
|
||||
static public void warning(String message, Object... args)
|
||||
{
|
||||
log(Level.WARNING, message, args);
|
||||
}
|
||||
|
||||
static public void warning(String message, Throwable ex)
|
||||
{
|
||||
warning(message + " : " + ex.getMessage());
|
||||
}
|
||||
|
||||
static public void error(String message)
|
||||
{
|
||||
log(Level.SEVERE, message);
|
||||
}
|
||||
|
||||
static public void error(String message, Throwable ex)
|
||||
{
|
||||
log(Level.SEVERE, message, ex);
|
||||
}
|
||||
|
||||
static public void error(String message, Throwable ex, Object... args)
|
||||
{
|
||||
log(Level.SEVERE, message, ex, args);
|
||||
}
|
||||
|
||||
static private Logger getLogger()
|
||||
{
|
||||
Thread currentThread = Thread.currentThread();
|
||||
if(currentThread.equals(mainThread)) return plugin.getLogger();
|
||||
return getLogger(currentThread);
|
||||
}
|
||||
|
||||
static private Logger getLogger(Thread thread)
|
||||
{
|
||||
PluginThreadLogger logger = loggers.get(thread);
|
||||
if(logger == null)
|
||||
{
|
||||
logger = new PluginThreadLogger(thread);
|
||||
loggers.put(thread, logger);
|
||||
}
|
||||
return logger;
|
||||
}
|
||||
|
||||
static private class PluginThreadLogger extends Logger
|
||||
{
|
||||
private final String loggerName;
|
||||
public PluginThreadLogger(Thread thread)
|
||||
{
|
||||
super(plugin.getClass().getCanonicalName(), null);
|
||||
setParent(plugin.getLogger());
|
||||
setLevel(Level.ALL);
|
||||
loggerName = "[" + thread.getName() + "] ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(LogRecord logRecord)
|
||||
{
|
||||
logRecord.setMessage(loggerName + logRecord.getMessage());
|
||||
super.log(logRecord);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,268 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import fr.moribus.imageonmap.commands.CommandException.Reason;
|
||||
import fr.moribus.imageonmap.map.ImageMap;
|
||||
import fr.moribus.imageonmap.map.MapManager;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
abstract public class Command
|
||||
{
|
||||
static private final String IMAGEONMAP_GLOBAL_PERMISSION = "imageonmap.userender";
|
||||
|
||||
protected final Commands commandGroup;
|
||||
protected final String commandName;
|
||||
protected final String usageParameters;
|
||||
protected final String commandDescription;
|
||||
protected final String[] aliases;
|
||||
|
||||
protected CommandSender sender;
|
||||
protected String[] args;
|
||||
|
||||
abstract protected void run() throws CommandException;
|
||||
|
||||
public Command(Commands commandGroup)
|
||||
{
|
||||
this.commandGroup = commandGroup;
|
||||
|
||||
CommandInfo commandInfo = this.getClass().getAnnotation(CommandInfo.class);
|
||||
if(commandInfo == null)
|
||||
throw new IllegalArgumentException("Command has no CommandInfo annotation");
|
||||
|
||||
commandName = commandInfo.name().toLowerCase();
|
||||
usageParameters = commandInfo.usageParameters();
|
||||
commandDescription = commandGroup.getDescription(commandName);
|
||||
aliases = commandInfo.aliases();
|
||||
}
|
||||
|
||||
public boolean canExecute(CommandSender sender)
|
||||
{
|
||||
return sender.hasPermission("imageonmap." + commandGroup.getUsualName())
|
||||
|| sender.hasPermission(IMAGEONMAP_GLOBAL_PERMISSION);
|
||||
}
|
||||
|
||||
protected List<String> complete() throws CommandException
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void execute(CommandSender sender, String[] args)
|
||||
{
|
||||
this.sender = sender; this.args = args;
|
||||
try
|
||||
{
|
||||
if(!canExecute(sender))
|
||||
throw new CommandException(this, Reason.SENDER_NOT_AUTHORIZED);
|
||||
run();
|
||||
}
|
||||
catch(CommandException ex)
|
||||
{
|
||||
warning(ex.getReasonString());
|
||||
}
|
||||
this.sender = null; this.args = null;
|
||||
}
|
||||
|
||||
public List<String> tabComplete(CommandSender sender, String[] args)
|
||||
{
|
||||
List<String> result = null;
|
||||
this.sender = sender; this.args = args;
|
||||
try
|
||||
{
|
||||
if(canExecute(sender))
|
||||
result = complete();
|
||||
}
|
||||
catch(CommandException ex){}
|
||||
|
||||
this.sender = null; this.args = null;
|
||||
if(result == null) result = new ArrayList<String>();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public String getUsageString()
|
||||
{
|
||||
return "/" + commandGroup.getUsualName() + " " + commandName + " " + usageParameters;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return commandName;
|
||||
}
|
||||
|
||||
public Commands getCommandGroup()
|
||||
{
|
||||
return commandGroup;
|
||||
}
|
||||
|
||||
public String[] getAliases()
|
||||
{
|
||||
return aliases;
|
||||
}
|
||||
|
||||
public boolean matches(String name)
|
||||
{
|
||||
if(commandName.equals(name.toLowerCase())) return true;
|
||||
|
||||
for(String alias : aliases)
|
||||
{
|
||||
if(alias.equals(name)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
///////////// Common methods for commands /////////////
|
||||
|
||||
protected void throwInvalidArgument(String reason) throws CommandException
|
||||
{
|
||||
throw new CommandException(this, Reason.INVALID_PARAMETERS, reason);
|
||||
}
|
||||
|
||||
protected Player playerSender() throws CommandException
|
||||
{
|
||||
if(!(sender instanceof Player))
|
||||
throw new CommandException(this, Reason.COMMANDSENDER_EXPECTED_PLAYER);
|
||||
return (Player)sender;
|
||||
}
|
||||
|
||||
protected ImageMap getMapFromArgs() throws CommandException
|
||||
{
|
||||
return getMapFromArgs(playerSender(), 0, true);
|
||||
}
|
||||
|
||||
protected ImageMap getMapFromArgs(Player player, int index, boolean expand) throws CommandException
|
||||
{
|
||||
if(args.length <= index) throwInvalidArgument("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("This map does not exist.");
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
///////////// Methods for command execution /////////////
|
||||
|
||||
static protected void info(CommandSender sender, String message)
|
||||
{
|
||||
sender.sendMessage("§7" + message);
|
||||
}
|
||||
|
||||
protected void info(String message)
|
||||
{
|
||||
info(sender, message);
|
||||
}
|
||||
|
||||
static protected void warning(CommandSender sender, String message)
|
||||
{
|
||||
sender.sendMessage("§c" + message);
|
||||
}
|
||||
|
||||
protected void warning(String message)
|
||||
{
|
||||
info(sender, message);
|
||||
}
|
||||
|
||||
protected void error(String message) throws CommandException
|
||||
{
|
||||
throw new CommandException(this, Reason.COMMAND_ERROR, message);
|
||||
}
|
||||
|
||||
protected void tellRaw(String rawMessage) throws CommandException
|
||||
{
|
||||
Player player = playerSender();
|
||||
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(),
|
||||
"tellraw " + player.getName() + " " + rawMessage);
|
||||
}
|
||||
|
||||
///////////// Methods for autocompletion /////////////
|
||||
|
||||
protected List<String> getMatchingSubset(String prefix, String... list)
|
||||
{
|
||||
return getMatchingSubset(Arrays.asList(list), prefix);
|
||||
}
|
||||
|
||||
protected List<String> getMatchingSubset(Iterable<? extends String> list, String prefix)
|
||||
{
|
||||
List<String> matches = new ArrayList<String>();
|
||||
|
||||
for(String item : list)
|
||||
{
|
||||
if(item.startsWith(prefix)) matches.add(item);
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
protected List<String> getMatchingPlayerNames(String prefix)
|
||||
{
|
||||
return getMatchingPlayerNames(Bukkit.getOnlinePlayers(), prefix);
|
||||
}
|
||||
|
||||
protected List<String> getMatchingPlayerNames(Iterable<? extends Player> players, String prefix)
|
||||
{
|
||||
List<String> matches = new ArrayList<String>();
|
||||
|
||||
for(Player player : players)
|
||||
{
|
||||
if(player.getName().startsWith(prefix)) matches.add(player.getName());
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
protected List<String> getMatchingMapNames(Player player, String prefix)
|
||||
{
|
||||
return getMatchingToolNames(MapManager.getMapList(player.getUniqueId()), prefix);
|
||||
}
|
||||
|
||||
protected List<String> getMatchingToolNames(Iterable<? extends ImageMap> maps, String prefix)
|
||||
{
|
||||
List<String> matches = new ArrayList<String>();
|
||||
|
||||
for(ImageMap map : maps)
|
||||
{
|
||||
if(map.getId().startsWith(prefix)) matches.add(map.getId());
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import fr.moribus.imageonmap.PluginLogger;
|
||||
|
||||
public class CommandException extends Exception
|
||||
{
|
||||
public enum Reason
|
||||
{
|
||||
COMMANDSENDER_EXPECTED_PLAYER,
|
||||
INVALID_PARAMETERS,
|
||||
COMMAND_ERROR,
|
||||
SENDER_NOT_AUTHORIZED
|
||||
}
|
||||
|
||||
private final Reason reason;
|
||||
private final Command command;
|
||||
private final String extra;
|
||||
|
||||
public CommandException(Command command, Reason reason, String extra)
|
||||
{
|
||||
this.command = command;
|
||||
this.reason = reason;
|
||||
this.extra = extra;
|
||||
}
|
||||
|
||||
public CommandException(Command command, Reason reason)
|
||||
{
|
||||
this(command, reason, "");
|
||||
}
|
||||
|
||||
public Reason getReason() { return reason; }
|
||||
|
||||
public String getReasonString()
|
||||
{
|
||||
switch(reason)
|
||||
{
|
||||
case COMMANDSENDER_EXPECTED_PLAYER:
|
||||
return "You must be a player to use this command.";
|
||||
case INVALID_PARAMETERS:
|
||||
return "Invalid arguments : " + extra +"\n§r" +
|
||||
"Usage : " + command.getUsageString() + "\n" +
|
||||
"For more information, use /" +
|
||||
command.getCommandGroup().getUsualName() + " help " +
|
||||
command.getName();
|
||||
case COMMAND_ERROR:
|
||||
return extra.isEmpty() ? "An unknown error suddenly happened." : extra;
|
||||
case SENDER_NOT_AUTHORIZED:
|
||||
return "You do not have the permission to use this command.";
|
||||
default:
|
||||
PluginLogger.warning("Unknown CommandException caught", this);
|
||||
return "An unknown error suddenly happened.";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,329 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import fr.moribus.imageonmap.commands.maptool.MigrateCommand;
|
||||
import fr.moribus.imageonmap.PluginLogger;
|
||||
import fr.moribus.imageonmap.commands.maptool.*;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
|
||||
public enum Commands implements TabCompleter, CommandExecutor
|
||||
{
|
||||
MAPTOOL(new String[]{"maptool"},
|
||||
NewCommand.class,
|
||||
ListCommand.class,
|
||||
GetCommand.class,
|
||||
DeleteConfirmCommand.class,
|
||||
DeleteNoConfirmCommand.class,
|
||||
GetRemainingCommand.class,
|
||||
MigrateCommand.class
|
||||
),
|
||||
TOMAP(MAPTOOL, NewCommand.class, "tomap");
|
||||
|
||||
static private final Commands[] commandGroups = Commands.class.getEnumConstants();
|
||||
private final Commands shortcutCommandGroup;
|
||||
private final String[] names;
|
||||
private final Class<? extends Command>[] commandsClasses;
|
||||
private final ArrayList<Command> commands = new ArrayList<>();
|
||||
private final HashMap<String, String> commandsDescriptions = new HashMap<>();
|
||||
private String description = "";
|
||||
|
||||
private Commands(Commands shortcutCommandGroup, Class<? extends Command> commandClass, String ... names)
|
||||
{
|
||||
this.names = names;
|
||||
this.commandsClasses = new Class[]{commandClass};
|
||||
this.shortcutCommandGroup = shortcutCommandGroup;
|
||||
initCommands();
|
||||
}
|
||||
|
||||
private Commands(String[] names, Class<? extends Command> ... commandsClasses)
|
||||
{
|
||||
this.names = names;
|
||||
this.commandsClasses = commandsClasses;
|
||||
this.shortcutCommandGroup = null;
|
||||
initDescriptions();
|
||||
initCommands();
|
||||
}
|
||||
|
||||
private void initDescriptions()
|
||||
{
|
||||
String fileName = "help/" + getUsualName() + ".txt";
|
||||
InputStream stream = getClass().getClassLoader().getResourceAsStream(fileName);
|
||||
if(stream == null)
|
||||
{
|
||||
PluginLogger.warning("Could not load description file for the " + getUsualName() + " command");
|
||||
return;
|
||||
}
|
||||
|
||||
Scanner scanner = new Scanner(stream);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
//Getting the group's description
|
||||
//And then each command's description
|
||||
int colonIndex, firstSpaceIndex;
|
||||
boolean isGroupDescription = true;
|
||||
while (scanner.hasNextLine())
|
||||
{
|
||||
String line = scanner.nextLine();
|
||||
colonIndex = line.indexOf(':');
|
||||
if(isGroupDescription)
|
||||
{
|
||||
firstSpaceIndex = line.indexOf(' ');
|
||||
if(colonIndex > 0 && firstSpaceIndex > colonIndex)
|
||||
isGroupDescription = false;
|
||||
}
|
||||
|
||||
if(isGroupDescription)
|
||||
{
|
||||
builder.append(line).append('\n');
|
||||
}
|
||||
else
|
||||
{
|
||||
commandsDescriptions.put(line.substring(0, colonIndex).trim(),
|
||||
line.substring(colonIndex + 1).trim());
|
||||
}
|
||||
}
|
||||
|
||||
scanner.close();
|
||||
description = builder.toString().trim();
|
||||
|
||||
}
|
||||
|
||||
private void initCommands()
|
||||
{
|
||||
for (Class<? extends Command> commandClass : commandsClasses)
|
||||
{
|
||||
addCommand(commandClass);
|
||||
}
|
||||
|
||||
if(!isShortcutCommand()) addCommand(HelpCommand.class);
|
||||
}
|
||||
|
||||
private void addCommand(Class<? extends Command> commandClass)
|
||||
{
|
||||
Constructor<? extends Command> constructor;
|
||||
try
|
||||
{
|
||||
constructor = commandClass.getConstructor(Commands.class);
|
||||
commands.add(constructor.newInstance(isShortcutCommand() ? shortcutCommandGroup : this));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginLogger.warning("Exception while initializing command", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean executeMatchingCommand(CommandSender sender, String[] args)
|
||||
{
|
||||
if(isShortcutCommand())
|
||||
{
|
||||
commands.get(0).execute(sender, args);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(args.length <= 0)
|
||||
{
|
||||
sender.sendMessage(getUsage()); return false;
|
||||
}
|
||||
|
||||
String commandName = args[0];
|
||||
String[] commandArgs = getCommandArgsFromGroupArgs(args);
|
||||
|
||||
return executeMatchingCommand(sender, commandName, commandArgs);
|
||||
}
|
||||
|
||||
private boolean executeMatchingCommand(CommandSender sender, String commandName, String[] args)
|
||||
{
|
||||
Command command = getMatchingCommand(commandName);
|
||||
if(command != null)
|
||||
{
|
||||
command.execute(sender, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
sender.sendMessage(getUsage());
|
||||
}
|
||||
return command != null;
|
||||
}
|
||||
|
||||
static public void init(JavaPlugin plugin)
|
||||
{
|
||||
org.bukkit.command.PluginCommand bukkitCommand;
|
||||
for(Commands commandGroup : commandGroups)
|
||||
{
|
||||
bukkitCommand = plugin.getCommand(commandGroup.getUsualName());
|
||||
bukkitCommand.setAliases(commandGroup.getAliases());
|
||||
bukkitCommand.setExecutor(commandGroup);
|
||||
bukkitCommand.setTabCompleter(commandGroup);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(CommandSender sender, org.bukkit.command.Command cmd, String label, String[] args)
|
||||
{
|
||||
return tabComplete(sender, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, org.bukkit.command.Command cmd, String label, String[] args)
|
||||
{
|
||||
return executeMatchingCommand(sender, args);
|
||||
}
|
||||
|
||||
public List<String> tabComplete(CommandSender sender, String[] args)
|
||||
{
|
||||
if(isShortcutCommand()) return commands.get(0).tabComplete(sender, args);
|
||||
if(args.length <= 1) return tabComplete(sender, args.length == 1 ? args[0] : null);
|
||||
String commandName = args[0];
|
||||
String[] commandArgs = getCommandArgsFromGroupArgs(args);
|
||||
return tabCompleteMatching(sender, commandName, commandArgs);
|
||||
}
|
||||
|
||||
public List<String> tabComplete(CommandSender sender, String commandName)
|
||||
{
|
||||
ArrayList<String> matchingCommands = new ArrayList<String>();
|
||||
for(Command command : commands)
|
||||
{
|
||||
if(!command.canExecute(sender)) continue;
|
||||
if(commandName == null || command.getName().startsWith(commandName.toLowerCase()))
|
||||
{
|
||||
matchingCommands.add(command.getName());
|
||||
}
|
||||
}
|
||||
return matchingCommands;
|
||||
}
|
||||
|
||||
private List<String> tabCompleteMatching(CommandSender sender, String commandName, String[] args)
|
||||
{
|
||||
Command command = getMatchingCommand(commandName);
|
||||
if(command != null)
|
||||
{
|
||||
return command.tabComplete(sender, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ArrayList<String>();
|
||||
}
|
||||
}
|
||||
|
||||
static public String[] getCommandArgsFromGroupArgs(String[] args)
|
||||
{
|
||||
String[] commandArgs = new String[args.length - 1];
|
||||
|
||||
for(int i = 0; i < commandArgs.length; i++)
|
||||
{
|
||||
commandArgs[i] = args[i + 1];
|
||||
}
|
||||
|
||||
return commandArgs;
|
||||
}
|
||||
|
||||
public Command getMatchingCommand(String commandName)
|
||||
{
|
||||
for(Command command : commands)
|
||||
{
|
||||
if(command.matches(commandName))
|
||||
{
|
||||
return command;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static public boolean execute(CommandSender sender, String commandName, String[] args)
|
||||
{
|
||||
Commands commandGroup = getMatchingCommandGroup(commandName);
|
||||
if(commandGroup == null) return false;
|
||||
commandGroup.executeMatchingCommand(sender, args);
|
||||
return true;
|
||||
}
|
||||
|
||||
static public List<String> tabComplete(CommandSender sender, String commandName, String[] args)
|
||||
{
|
||||
Commands commandGroup = getMatchingCommandGroup(commandName);
|
||||
if(commandGroup == null) return new ArrayList<String>();
|
||||
return commandGroup.tabComplete(sender, args);
|
||||
}
|
||||
|
||||
static private Commands getMatchingCommandGroup(String commandName)
|
||||
{
|
||||
Commands commandGroup = null;
|
||||
for(Commands tCommandGroup : commandGroups)
|
||||
{
|
||||
if(tCommandGroup.matches(commandName))
|
||||
{
|
||||
commandGroup = tCommandGroup;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return commandGroup;
|
||||
}
|
||||
|
||||
public boolean matches(String name)
|
||||
{
|
||||
name = name.toLowerCase();
|
||||
for(String commandName : names)
|
||||
{
|
||||
if(commandName.equals(name)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String[] getCommandsNames()
|
||||
{
|
||||
String[] commandsNames = new String[commands.size()];
|
||||
|
||||
for(int i = 0; i < commands.size(); i++)
|
||||
{
|
||||
commandsNames[i] = commands.get(i).getName();
|
||||
}
|
||||
|
||||
return commandsNames;
|
||||
}
|
||||
|
||||
protected String getUsage()
|
||||
{
|
||||
if(isShortcutCommand()) return "§cUsage : " + commands.get(0).getUsageString();
|
||||
return "§cUsage : /" + getUsualName() +
|
||||
" <" + StringUtils.join(getCommandsNames(), "|") + ">";
|
||||
}
|
||||
|
||||
public String getUsualName() { return names[0]; }
|
||||
public String[] getNames() { return names.clone(); }
|
||||
public List<String> getAliases() { return Arrays.asList(names).subList(1, names.length);}
|
||||
public Command[] getCommands() { return commands.toArray(new Command[commands.size()]);}
|
||||
public String getDescription() { return description; }
|
||||
public String getDescription(String commandName) { return commandsDescriptions.get(commandName); }
|
||||
public boolean isShortcutCommand() { return shortcutCommandGroup != null; }
|
||||
public Commands getShortcutCommandGroup() { return shortcutCommandGroup; }
|
||||
|
||||
}
|
@ -1,140 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import fr.moribus.imageonmap.PluginLogger;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
|
||||
@CommandInfo(name = "help", usageParameters = "<command name>")
|
||||
public class HelpCommand extends Command
|
||||
{
|
||||
|
||||
public HelpCommand(Commands commandGroup) {
|
||||
super(commandGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run() throws CommandException
|
||||
{
|
||||
if(args.length < 1)
|
||||
groupHelp();
|
||||
else
|
||||
commandHelp();
|
||||
}
|
||||
|
||||
private void groupHelp() throws CommandException
|
||||
{
|
||||
sender.sendMessage(commandGroup.getDescription());
|
||||
|
||||
String tCommandName;
|
||||
String tDescription;
|
||||
for(Command tCommand: commandGroup.getCommands())
|
||||
{
|
||||
if(!tCommand.canExecute(sender)) continue;
|
||||
tCommandName = tCommand.getName();
|
||||
tDescription = commandGroup.getDescription(tCommandName);
|
||||
tCommandName = commandGroup.getUsualName() + " " + tCommandName;
|
||||
if(tDescription == null)
|
||||
sender.sendMessage("§6/" + tCommandName + "§r");
|
||||
else
|
||||
sender.sendMessage("§6/" + tCommandName + " : §r" + tDescription);
|
||||
}
|
||||
}
|
||||
|
||||
private void commandHelp() throws CommandException
|
||||
{
|
||||
Command command = commandGroup.getMatchingCommand(args[0]);
|
||||
if(command == null)
|
||||
{
|
||||
error("The specified command does not exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!command.canExecute(sender))
|
||||
warning("You do not have the permission to use this command.");
|
||||
|
||||
String message = "§l§6 ||== ImageOnMap help ==||\n" +
|
||||
"§l§6 |Usage : §r" + command.getUsageString();
|
||||
|
||||
try
|
||||
{
|
||||
String help = getHelpText(command);
|
||||
if(help.isEmpty())
|
||||
{
|
||||
sender.sendMessage(message);
|
||||
warning("There is no help message for this command.");
|
||||
}
|
||||
else
|
||||
{
|
||||
sender.sendMessage(message + "\n" + help);
|
||||
}
|
||||
}
|
||||
catch(IOException ex)
|
||||
{
|
||||
sender.sendMessage(message);
|
||||
warning("Could not read help for this command.");
|
||||
PluginLogger.warning("Could not read help for the command : " + command.getName(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private String getHelpText(Command command) throws IOException
|
||||
{
|
||||
String fileName = "help/"+ commandGroup.getUsualName() +
|
||||
"/" + command.getName() + ".txt";
|
||||
|
||||
StringBuilder result = new StringBuilder("");
|
||||
|
||||
InputStream stream = getClass().getClassLoader().getResourceAsStream(fileName);
|
||||
if(stream == null) return "";
|
||||
|
||||
Scanner scanner = new Scanner(stream);
|
||||
|
||||
while (scanner.hasNextLine())
|
||||
{
|
||||
String line = scanner.nextLine();
|
||||
result.append("§l§9 |§r").append(line).append("\n");
|
||||
}
|
||||
|
||||
scanner.close();
|
||||
|
||||
return result.toString().trim();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected List<String> complete() throws CommandException
|
||||
{
|
||||
if(args.length != 1) return null;
|
||||
|
||||
ArrayList<String> matches = new ArrayList<String>();
|
||||
|
||||
for(Command command : commandGroup.getCommands())
|
||||
{
|
||||
if(command.getName().startsWith(args[0]))
|
||||
matches.add(command.getName());
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
}
|
77
src/main/java/fr/moribus/imageonmap/commands/IoMCommand.java
Normal file
77
src/main/java/fr/moribus/imageonmap/commands/IoMCommand.java
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import fr.moribus.imageonmap.map.ImageMap;
|
||||
import fr.moribus.imageonmap.map.MapManager;
|
||||
import fr.zcraft.zlib.components.commands.Command;
|
||||
import fr.zcraft.zlib.components.commands.CommandException;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public abstract class IoMCommand extends Command
|
||||
{
|
||||
protected ImageMap getMapFromArgs() throws CommandException
|
||||
{
|
||||
return getMapFromArgs(playerSender(), 0, true);
|
||||
}
|
||||
|
||||
protected ImageMap getMapFromArgs(Player player, int index, boolean expand) throws CommandException
|
||||
{
|
||||
if(args.length <= index) throwInvalidArgument("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("This map does not exist.");
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
protected List<String> getMatchingMapNames(Player player, String prefix)
|
||||
{
|
||||
return getMatchingMapNames(MapManager.getMapList(player.getUniqueId()), prefix);
|
||||
}
|
||||
|
||||
protected List<String> getMatchingMapNames(Iterable<? extends ImageMap> maps, String prefix)
|
||||
{
|
||||
List<String> matches = new ArrayList<>();
|
||||
|
||||
for(ImageMap map : maps)
|
||||
{
|
||||
if(map.getId().startsWith(prefix)) matches.add(map.getId());
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
}
|
@ -18,20 +18,18 @@
|
||||
|
||||
package fr.moribus.imageonmap.commands.maptool;
|
||||
|
||||
import fr.moribus.imageonmap.commands.*;
|
||||
import fr.moribus.imageonmap.commands.IoMCommand;
|
||||
import fr.moribus.imageonmap.map.ImageMap;
|
||||
import fr.zcraft.zlib.components.commands.CommandException;
|
||||
import fr.zcraft.zlib.components.commands.CommandInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@CommandInfo(name = "delete", usageParameters = "[tool name]")
|
||||
public class DeleteConfirmCommand extends Command
|
||||
@CommandInfo (name = "delete", usageParameters = "[tool name]")
|
||||
public class DeleteConfirmCommand extends IoMCommand
|
||||
{
|
||||
|
||||
public DeleteConfirmCommand(Commands commandGroup) {
|
||||
super(commandGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run() throws CommandException
|
||||
protected void run() throws CommandException
|
||||
{
|
||||
ImageMap map = getMapFromArgs();
|
||||
tellRaw("{text:\"You are going to delete \",extra:[{text:\""+ map.getId() +"\",color:gold},{text:\". Are you sure ? \",color:white}," +
|
||||
@ -45,8 +43,7 @@ public class DeleteConfirmCommand extends Command
|
||||
{
|
||||
if(args.length == 1)
|
||||
return getMatchingMapNames(playerSender(), args[0]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -18,25 +18,23 @@
|
||||
|
||||
package fr.moribus.imageonmap.commands.maptool;
|
||||
|
||||
import fr.moribus.imageonmap.PluginLogger;
|
||||
import fr.moribus.imageonmap.commands.*;
|
||||
import fr.moribus.imageonmap.commands.IoMCommand;
|
||||
import fr.moribus.imageonmap.map.ImageMap;
|
||||
import fr.moribus.imageonmap.map.MapManager;
|
||||
import fr.moribus.imageonmap.map.MapManagerException;
|
||||
import java.util.List;
|
||||
import fr.zcraft.zlib.components.commands.CommandException;
|
||||
import fr.zcraft.zlib.components.commands.CommandInfo;
|
||||
import fr.zcraft.zlib.tools.PluginLogger;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@CommandInfo(name = "delete-noconfirm", usageParameters = "[map name]")
|
||||
public class DeleteNoConfirmCommand extends Command
|
||||
|
||||
@CommandInfo (name = "delete-noconfirm", usageParameters = "[map name]")
|
||||
public class DeleteNoConfirmCommand extends IoMCommand
|
||||
{
|
||||
|
||||
public DeleteNoConfirmCommand(Commands commandGroup) {
|
||||
super(commandGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run() throws CommandException
|
||||
protected void run() throws CommandException
|
||||
{
|
||||
Player player = playerSender();
|
||||
ImageMap map = getMapFromArgs();
|
||||
|
@ -16,15 +16,22 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package fr.moribus.imageonmap.commands;
|
||||
package fr.moribus.imageonmap.commands.maptool;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE})
|
||||
public @interface CommandInfo
|
||||
import fr.moribus.imageonmap.commands.IoMCommand;
|
||||
import fr.moribus.imageonmap.gui.MapListGui;
|
||||
import fr.zcraft.zlib.components.commands.CommandException;
|
||||
import fr.zcraft.zlib.components.commands.CommandInfo;
|
||||
import fr.zcraft.zlib.components.gui.Gui;
|
||||
|
||||
|
||||
@CommandInfo (name = "explore")
|
||||
public class ExploreCommand extends IoMCommand
|
||||
{
|
||||
String name();
|
||||
String usageParameters() default "";
|
||||
String[] aliases() default {};
|
||||
@Override
|
||||
protected void run() throws CommandException
|
||||
{
|
||||
Gui.open(playerSender(), new MapListGui());
|
||||
}
|
||||
}
|
@ -18,17 +18,16 @@
|
||||
|
||||
package fr.moribus.imageonmap.commands.maptool;
|
||||
|
||||
import fr.moribus.imageonmap.commands.*;
|
||||
import java.util.List;
|
||||
import fr.moribus.imageonmap.commands.IoMCommand;
|
||||
import fr.zcraft.zlib.components.commands.CommandException;
|
||||
import fr.zcraft.zlib.components.commands.CommandInfo;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@CommandInfo(name = "get")
|
||||
public class GetCommand extends Command
|
||||
import java.util.List;
|
||||
|
||||
@CommandInfo (name = "get")
|
||||
public class GetCommand extends IoMCommand
|
||||
{
|
||||
public GetCommand(Commands commandGroup) {
|
||||
super(commandGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run() throws CommandException
|
||||
{
|
||||
|
@ -18,20 +18,15 @@
|
||||
|
||||
package fr.moribus.imageonmap.commands.maptool;
|
||||
|
||||
import fr.moribus.imageonmap.commands.Command;
|
||||
import fr.moribus.imageonmap.commands.CommandException;
|
||||
import fr.moribus.imageonmap.commands.CommandInfo;
|
||||
import fr.moribus.imageonmap.commands.Commands;
|
||||
import fr.moribus.imageonmap.commands.IoMCommand;
|
||||
import fr.moribus.imageonmap.ui.MapItemManager;
|
||||
import fr.zcraft.zlib.components.commands.CommandException;
|
||||
import fr.zcraft.zlib.components.commands.CommandInfo;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@CommandInfo(name = "getremaining", aliases = {"getrest"})
|
||||
public class GetRemainingCommand extends Command
|
||||
@CommandInfo (name = "getremaining", aliases = {"getrest"})
|
||||
public class GetRemainingCommand extends IoMCommand
|
||||
{
|
||||
public GetRemainingCommand(Commands commandGroup) {
|
||||
super(commandGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run() throws CommandException
|
||||
{
|
||||
|
@ -18,19 +18,18 @@
|
||||
|
||||
package fr.moribus.imageonmap.commands.maptool;
|
||||
|
||||
import fr.moribus.imageonmap.commands.*;
|
||||
import fr.moribus.imageonmap.commands.IoMCommand;
|
||||
import fr.moribus.imageonmap.map.ImageMap;
|
||||
import fr.moribus.imageonmap.map.MapManager;
|
||||
import java.util.List;
|
||||
import fr.zcraft.zlib.components.commands.CommandException;
|
||||
import fr.zcraft.zlib.components.commands.CommandInfo;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@CommandInfo(name = "list")
|
||||
public class ListCommand extends Command
|
||||
import java.util.List;
|
||||
|
||||
@CommandInfo (name = "list")
|
||||
public class ListCommand extends IoMCommand
|
||||
{
|
||||
public ListCommand(Commands commandGroup) {
|
||||
super(commandGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run() throws CommandException
|
||||
{
|
||||
@ -52,5 +51,4 @@ public class ListCommand extends Command
|
||||
}
|
||||
player.sendMessage(sMapList);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,21 +18,18 @@
|
||||
|
||||
package fr.moribus.imageonmap.commands.maptool;
|
||||
|
||||
import fr.moribus.imageonmap.commands.*;
|
||||
import fr.moribus.imageonmap.commands.IoMCommand;
|
||||
import fr.moribus.imageonmap.migration.MigratorExecutor;
|
||||
import fr.zcraft.zlib.components.commands.CommandException;
|
||||
import fr.zcraft.zlib.components.commands.CommandInfo;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
@CommandInfo(name = "migrate")
|
||||
public class MigrateCommand extends Command
|
||||
@CommandInfo (name = "migrate")
|
||||
public class MigrateCommand extends IoMCommand
|
||||
{
|
||||
public MigrateCommand(Commands commandGroup) {
|
||||
super(commandGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run() throws CommandException
|
||||
{
|
||||
final CommandSender cmdSender = sender;
|
||||
if(MigratorExecutor.isRunning())
|
||||
{
|
||||
error("A migration process is already running. Check console for details.");
|
||||
|
@ -18,25 +18,21 @@
|
||||
|
||||
package fr.moribus.imageonmap.commands.maptool;
|
||||
|
||||
import fr.moribus.imageonmap.PluginLogger;
|
||||
import fr.moribus.imageonmap.commands.Command;
|
||||
import fr.moribus.imageonmap.commands.CommandException;
|
||||
import fr.moribus.imageonmap.commands.CommandInfo;
|
||||
import fr.moribus.imageonmap.commands.Commands;
|
||||
import fr.moribus.imageonmap.commands.IoMCommand;
|
||||
import fr.moribus.imageonmap.image.ImageRendererExecutor;
|
||||
import fr.moribus.imageonmap.map.ImageMap;
|
||||
import fr.moribus.imageonmap.worker.WorkerCallback;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import fr.zcraft.zlib.components.commands.CommandException;
|
||||
import fr.zcraft.zlib.components.commands.CommandInfo;
|
||||
import fr.zcraft.zlib.components.worker.WorkerCallback;
|
||||
import fr.zcraft.zlib.tools.PluginLogger;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@CommandInfo(name = "new", usageParameters = "<URL> [resize]")
|
||||
public class NewCommand extends Command
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
@CommandInfo (name = "new", usageParameters = "<URL> [resize]")
|
||||
public class NewCommand extends IoMCommand
|
||||
{
|
||||
public NewCommand(Commands commandGroup) {
|
||||
super(commandGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run() throws CommandException
|
||||
{
|
||||
@ -83,5 +79,4 @@ public class NewCommand extends Command
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
194
src/main/java/fr/moribus/imageonmap/gui/ConfirmDeleteMapGui.java
Normal file
194
src/main/java/fr/moribus/imageonmap/gui/ConfirmDeleteMapGui.java
Normal file
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* 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.gui;
|
||||
|
||||
import fr.moribus.imageonmap.map.ImageMap;
|
||||
import fr.moribus.imageonmap.map.MapManager;
|
||||
import fr.moribus.imageonmap.map.MapManagerException;
|
||||
import fr.zcraft.zlib.components.gui.ActionGui;
|
||||
import fr.zcraft.zlib.components.gui.Gui;
|
||||
import fr.zcraft.zlib.components.gui.GuiAction;
|
||||
import fr.zcraft.zlib.tools.PluginLogger;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.DyeColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.material.Dye;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
|
||||
public class ConfirmDeleteMapGui extends ActionGui
|
||||
{
|
||||
static private final int BUTTONS_WIDTH = 4;
|
||||
|
||||
static private final int FIRST_SLOT_DELETE_BUTTON = 27;
|
||||
static private final int SHIFT_CANCEL_BUTTON = 5;
|
||||
|
||||
/**
|
||||
* The messages randomly displayed in the lore of the “delete” buttons.
|
||||
*/
|
||||
static private final String[] DELETE_MESSAGES = new String[]{
|
||||
"Please", "I'm still alive", "Don't do that", "I'm still loving you", "I want to live",
|
||||
"Please please", "Please please please", "What are you doing?!", "Nooooo!",
|
||||
"Click and I'll be dead", "Why?", "Please don't do that", "Think about my family",
|
||||
"Click, I don't like you anymore.", "I don't hate you.", "Click, I'm ready.",
|
||||
"I'm a green button.", "I'm different.", "Thanks anyway.", "Excuse me.", "Get mad.",
|
||||
"Sorry!", "My fault!", "I don't blame you.", "No hard feelings.",
|
||||
"But I need to protect the humans!", "Noooo!", "I'm scared!", "What are you doing?",
|
||||
"It burns.", "This is not good.", "Can't breathe.", "Thanks anyway.", "These things happen.",
|
||||
"That was nobody's fault.", "I probably deserved it.", "I blame myself."
|
||||
};
|
||||
|
||||
/**
|
||||
* The messages randomly displayed in the lore of the “cancel” buttons.
|
||||
*/
|
||||
static private final String[] CANCEL_MESSAGES = new String[] {
|
||||
"Yay!", "Still aliiiive!", "Click click click", "Yes do that", "I'm a red button.",
|
||||
"Please click here", "The other button is ugly", "Save me", "This is the good choice",
|
||||
"Click, I want to live!", "I'll be dead another day anyway", "Are you sure?",
|
||||
"So you're still loving me?", "Please save me", "Take me with you.",
|
||||
"Excuse me.", "Don't make lemonade.", "Sleep mode activated.", "Hybernating.",
|
||||
"Your business is appreciated.", "Hey! It's me! Don't shoot!", "Wheee!", "Hurray!",
|
||||
"You have excellent aim!", "Please please please"
|
||||
};
|
||||
|
||||
/**
|
||||
* The map being deleted.
|
||||
*/
|
||||
private final ImageMap mapToDelete;
|
||||
|
||||
/**
|
||||
* A source of randomness.
|
||||
*
|
||||
* Yes, this javadoc comment is REALLY useful. Trust me.
|
||||
*/
|
||||
private final Random random = new Random();
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mapToDelete The map being deleted.
|
||||
*/
|
||||
public ConfirmDeleteMapGui(ImageMap mapToDelete)
|
||||
{
|
||||
this.mapToDelete = mapToDelete;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUpdate()
|
||||
{
|
||||
setTitle(mapToDelete.getName() + " » " + ChatColor.BLACK + "Confirm deletion");
|
||||
setSize(6 * 9);
|
||||
|
||||
/* ** Item representation of the image being deleted ** */
|
||||
|
||||
ItemStack beingDeleted = new ItemStack(Material.EMPTY_MAP);
|
||||
ItemMeta meta = beingDeleted.getItemMeta();
|
||||
|
||||
meta.setDisplayName(ChatColor.RED + "You're about to destroy this map...");
|
||||
meta.setLore(Arrays.asList(
|
||||
ChatColor.RED + "..." + ChatColor.ITALIC + "forever" + ChatColor.RED + ".",
|
||||
"",
|
||||
ChatColor.GRAY + "Name: " + ChatColor.WHITE + mapToDelete.getName(),
|
||||
ChatColor.GRAY + "Map ID: " + ChatColor.WHITE + mapToDelete.getId(),
|
||||
ChatColor.GRAY + "Maps inside: " + ChatColor.WHITE + mapToDelete.getMapsIDs().length
|
||||
));
|
||||
|
||||
beingDeleted.setItemMeta(meta);
|
||||
|
||||
action("", 13, beingDeleted);
|
||||
|
||||
|
||||
/* ** Buttons ** */
|
||||
|
||||
int slot = FIRST_SLOT_DELETE_BUTTON;
|
||||
for(; slot < getSize() - (9 - BUTTONS_WIDTH); slot++)
|
||||
{
|
||||
action("delete", slot, createDeleteSubButton());
|
||||
action("cancel", slot + SHIFT_CANCEL_BUTTON, createCancelSubButton());
|
||||
|
||||
if((slot + 1) % 9 == (9 - BUTTONS_WIDTH - 1))
|
||||
slot += 5;
|
||||
}
|
||||
}
|
||||
|
||||
private ItemStack createDeleteSubButton()
|
||||
{
|
||||
// Orange? Nooo. In the real world this is red. True story.
|
||||
return createSubButton(DyeColor.ORANGE, ChatColor.RED + "Delete the map", DELETE_MESSAGES);
|
||||
}
|
||||
|
||||
private ItemStack createCancelSubButton()
|
||||
{
|
||||
// YES. Purple = lime. BECAUSE. Just accept it.
|
||||
return createSubButton(DyeColor.PURPLE, ChatColor.GREEN + "Cancel", CANCEL_MESSAGES);
|
||||
}
|
||||
|
||||
private ItemStack createSubButton(DyeColor color, String title, String[] messages)
|
||||
{
|
||||
Dye pane = new Dye(Material.STAINED_GLASS_PANE);
|
||||
pane.setColor(color);
|
||||
|
||||
ItemStack subButton = pane.toItemStack(1);
|
||||
ItemMeta meta = subButton.getItemMeta();
|
||||
|
||||
meta.setDisplayName(title);
|
||||
meta.setLore(Arrays.asList(
|
||||
"",
|
||||
ChatColor.GRAY + messages[random.nextInt(messages.length)]
|
||||
));
|
||||
|
||||
subButton.setItemMeta(meta);
|
||||
return subButton;
|
||||
}
|
||||
|
||||
@GuiAction ("cancel")
|
||||
protected void cancel()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
@GuiAction ("delete")
|
||||
protected void delete()
|
||||
{
|
||||
MapManager.clear(getPlayer().getInventory(), mapToDelete);
|
||||
|
||||
try
|
||||
{
|
||||
MapManager.deleteMap(mapToDelete);
|
||||
getPlayer().sendMessage(ChatColor.GRAY + "Map successfully deleted.");
|
||||
}
|
||||
catch (MapManagerException ex)
|
||||
{
|
||||
PluginLogger.warning("Error while deleting map", ex);
|
||||
getPlayer().sendMessage(ChatColor.RED + ex.getMessage());
|
||||
}
|
||||
|
||||
|
||||
// We try to open the map list GUI, if the map was deleted, before the details GUI
|
||||
// (so the grandparent GUI)..
|
||||
if (getParent() != null && getParent().getParent() != null)
|
||||
Gui.open(getPlayer(), getParent().getParent());
|
||||
else
|
||||
close();
|
||||
}
|
||||
}
|
166
src/main/java/fr/moribus/imageonmap/gui/MapDetailGui.java
Normal file
166
src/main/java/fr/moribus/imageonmap/gui/MapDetailGui.java
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* 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.gui;
|
||||
|
||||
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.zlib.components.gui.ExplorerGui;
|
||||
import fr.zcraft.zlib.components.gui.Gui;
|
||||
import fr.zcraft.zlib.components.gui.GuiAction;
|
||||
import fr.zcraft.zlib.components.gui.GuiUtils;
|
||||
import fr.zcraft.zlib.components.gui.PromptGui;
|
||||
import fr.zcraft.zlib.tools.Callback;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
|
||||
public class MapDetailGui extends ExplorerGui
|
||||
{
|
||||
private final ImageMap map;
|
||||
|
||||
public MapDetailGui(ImageMap map)
|
||||
{
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStack getViewItem(int x, int y)
|
||||
{
|
||||
Material partMaterial = Material.PAPER;
|
||||
if((y % 2 == 0 && x % 2 == 0) || (y % 2 == 1 && x % 2 == 1))
|
||||
partMaterial = Material.EMPTY_MAP;
|
||||
|
||||
ItemStack part = new ItemStack(partMaterial);
|
||||
ItemMeta meta = part.getItemMeta();
|
||||
|
||||
meta.setDisplayName(ChatColor.GREEN + "Map part");
|
||||
meta.setLore(Arrays.asList(
|
||||
ChatColor.GRAY + "Column: " + ChatColor.WHITE + (y + 1),
|
||||
ChatColor.GRAY + "Row: " + ChatColor.WHITE + (x + 1),
|
||||
"",
|
||||
ChatColor.GRAY + "» Click to get only this part"
|
||||
));
|
||||
|
||||
part.setItemMeta(meta);
|
||||
return part;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStack getPickedUpItem(int x, int y)
|
||||
{
|
||||
if(map instanceof SingleMap)
|
||||
{
|
||||
return MapItemManager.createMapItem((SingleMap)map);
|
||||
}
|
||||
else if(map instanceof PosterMap)
|
||||
{
|
||||
return MapItemManager.createMapItem((PosterMap)map, x, y);
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Unsupported map type : " + map.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStack getEmptyViewItem()
|
||||
{
|
||||
if(map instanceof SingleMap)
|
||||
{
|
||||
return getViewItem(0, 0);
|
||||
}
|
||||
else return super.getEmptyViewItem();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUpdate()
|
||||
{
|
||||
setTitle("Your maps » " + ChatColor.BLACK + map.getName());
|
||||
setKeepHorizontalScrollingSpace(true);
|
||||
|
||||
if(map instanceof PosterMap)
|
||||
setDataShape(((PosterMap) map).getColumnCount(), ((PosterMap) map).getRowCount());
|
||||
else
|
||||
setData(null); // Fallback to the empty view item.
|
||||
|
||||
|
||||
action("rename", getSize() - 7, GuiUtils.makeItem(Material.BOOK_AND_QUILL, ChatColor.BLUE + "Rename this image", Arrays.asList(
|
||||
ChatColor.GRAY + "Click here to rename this image;",
|
||||
ChatColor.GRAY + "this is used for your own organization."
|
||||
)));
|
||||
|
||||
action("delete", getSize() - 6, GuiUtils.makeItem(Material.BARRIER, ChatColor.RED + "Delete this image", Arrays.asList(
|
||||
ChatColor.GRAY + "Deletes this map " + ChatColor.WHITE + "forever" + ChatColor.GRAY + ".",
|
||||
ChatColor.GRAY + "This action cannot be undone!",
|
||||
"",
|
||||
ChatColor.GRAY + "You will be asked to confirm your",
|
||||
ChatColor.GRAY + "choice if you click here."
|
||||
)));
|
||||
|
||||
|
||||
// To keep the controls centered, the back button is shifted to the right when the
|
||||
// arrow isn't displayed, so when the map fit on the grid without sliders.
|
||||
int backSlot = getSize() - 4;
|
||||
|
||||
if(map instanceof PosterMap && ((PosterMap) map).getColumnCount() <= INVENTORY_ROW_SIZE)
|
||||
backSlot++;
|
||||
|
||||
action("back", backSlot, GuiUtils.makeItem(Material.EMERALD, ChatColor.GREEN + "« Back", Collections.singletonList(
|
||||
ChatColor.GRAY + "Go back to the list."
|
||||
)));
|
||||
}
|
||||
|
||||
|
||||
@GuiAction ("rename")
|
||||
public void rename()
|
||||
{
|
||||
PromptGui.prompt(getPlayer(), new Callback<String>()
|
||||
{
|
||||
@Override
|
||||
public void call(String newName)
|
||||
{
|
||||
if (newName == null || newName.isEmpty())
|
||||
{
|
||||
getPlayer().sendMessage(ChatColor.RED + "Map names can't be empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
map.rename(newName);
|
||||
getPlayer().sendMessage(ChatColor.GRAY + "Map successfully renamed.");
|
||||
}
|
||||
}, map.getName(), this);
|
||||
}
|
||||
|
||||
@GuiAction ("delete")
|
||||
public void delete()
|
||||
{
|
||||
Gui.open(getPlayer(), new ConfirmDeleteMapGui(map), this);
|
||||
}
|
||||
|
||||
@GuiAction ("back")
|
||||
public void back()
|
||||
{
|
||||
close();
|
||||
}
|
||||
}
|
185
src/main/java/fr/moribus/imageonmap/gui/MapListGui.java
Normal file
185
src/main/java/fr/moribus/imageonmap/gui/MapListGui.java
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* 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.gui;
|
||||
|
||||
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.zcraft.zlib.components.gui.ExplorerGui;
|
||||
import fr.zcraft.zlib.components.gui.Gui;
|
||||
import fr.zcraft.zlib.components.gui.GuiUtils;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
|
||||
public class MapListGui extends ExplorerGui<ImageMap>
|
||||
{
|
||||
private final NumberFormat bigNumbersFormatter = new DecimalFormat("###,###,###,###", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
|
||||
|
||||
|
||||
@Override
|
||||
protected ItemStack getViewItem(ImageMap map)
|
||||
{
|
||||
String mapDescription;
|
||||
if (map instanceof SingleMap)
|
||||
mapDescription = "Single map";
|
||||
else
|
||||
mapDescription = "Poster map (" + ((PosterMap) map).getColumnCount() + "×" + ((PosterMap) map).getRowCount() + ")";
|
||||
|
||||
ItemStack icon = GuiUtils.makeItem(Material.MAP, ChatColor.GREEN + "" + ChatColor.BOLD + map.getName(), Arrays.asList(
|
||||
ChatColor.WHITE + mapDescription,
|
||||
"",
|
||||
ChatColor.GRAY + "Map ID: " + map.getId(),
|
||||
"",
|
||||
ChatColor.GRAY + "» Left-click to get this map",
|
||||
ChatColor.GRAY + "» Right-click for details and options"
|
||||
));
|
||||
|
||||
return GuiUtils.hideItemAttributes(icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStack getEmptyViewItem()
|
||||
{
|
||||
ItemStack empty = new ItemStack(Material.BARRIER);
|
||||
ItemMeta meta = empty.getItemMeta();
|
||||
|
||||
meta.setDisplayName(ChatColor.RED + "You don't have any map.");
|
||||
meta.setLore(Arrays.asList(
|
||||
ChatColor.GRAY + "Get started by creating a new one",
|
||||
ChatColor.GRAY + "using " + ChatColor.WHITE + "/tomap <URL> [resize]" + ChatColor.GRAY + "!"
|
||||
));
|
||||
|
||||
empty.setItemMeta(meta);
|
||||
return empty;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRightClick(ImageMap data)
|
||||
{
|
||||
Gui.open(getPlayer(), new MapDetailGui(data), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStack getPickedUpItem(ImageMap map)
|
||||
{
|
||||
if (map instanceof SingleMap)
|
||||
{
|
||||
return MapItemManager.createMapItem(map.getMapsIDs()[0], map.getName());
|
||||
}
|
||||
|
||||
MapItemManager.give(getPlayer(), map);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUpdate()
|
||||
{
|
||||
ImageMap[] maps = MapManager.getMaps(getPlayer().getUniqueId());
|
||||
setData(maps);
|
||||
setTitle(ChatColor.BLACK + "Your maps " + ChatColor.RESET + "(" + maps.length + ")");
|
||||
|
||||
setKeepHorizontalScrollingSpace(true);
|
||||
|
||||
|
||||
/* ** Statistics ** */
|
||||
|
||||
int imagesCount = MapManager.getMapList(getPlayer().getUniqueId()).size();
|
||||
int mapPartCount = MapManager.getMapPartCount(getPlayer().getUniqueId());
|
||||
|
||||
int mapGlobalLimit = PluginConfiguration.MAP_GLOBAL_LIMIT.getInteger();
|
||||
int mapPersonalLimit = PluginConfiguration.MAP_PLAYER_LIMIT.getInteger();
|
||||
|
||||
int mapPartGloballyLeft = mapGlobalLimit - MapManager.getMapCount();
|
||||
int mapPartPersonallyLeft = mapPersonalLimit - mapPartCount;
|
||||
|
||||
int mapPartLeft;
|
||||
if (mapGlobalLimit <= 0 && mapPersonalLimit <= 0)
|
||||
mapPartLeft = -1;
|
||||
else if (mapGlobalLimit <= 0)
|
||||
mapPartLeft = mapPartPersonallyLeft;
|
||||
else if (mapPersonalLimit <= 0)
|
||||
mapPartLeft = mapPartGloballyLeft;
|
||||
else
|
||||
mapPartLeft = Math.min(mapPartGloballyLeft, mapPartPersonallyLeft);
|
||||
|
||||
double percentageUsed = mapPartLeft < 0 ? 0 : ((double) mapPartCount) / ((double) (mapPartCount + mapPartLeft)) * 100;
|
||||
|
||||
|
||||
ItemStack statistics = new ItemStack(Material.ENCHANTED_BOOK);
|
||||
ItemMeta meta = statistics.getItemMeta();
|
||||
|
||||
meta.setDisplayName(ChatColor.BLUE + "Usage statistics");
|
||||
meta.setLore(Arrays.asList(
|
||||
"",
|
||||
getStatisticText("Images rendered", imagesCount),
|
||||
getStatisticText("Minecraft maps used", mapPartCount)
|
||||
));
|
||||
|
||||
if (mapPartLeft >= 0)
|
||||
{
|
||||
List<String> lore = meta.getLore();
|
||||
|
||||
lore.add("");
|
||||
lore.add(ChatColor.BLUE + "Minecraft maps limits");
|
||||
|
||||
lore.add("");
|
||||
lore.add(getStatisticText("Server-wide limit", mapGlobalLimit, true));
|
||||
lore.add(getStatisticText("Per-player limit", mapPersonalLimit, true));
|
||||
|
||||
lore.add("");
|
||||
lore.add(getStatisticText("Current consumption", ((int) Math.rint(percentageUsed)) + " %"));
|
||||
lore.add(getStatisticText("Maps left", mapPartLeft));
|
||||
|
||||
meta.setLore(lore);
|
||||
}
|
||||
|
||||
GuiUtils.hideItemAttributes(meta);
|
||||
|
||||
statistics.setItemMeta(meta);
|
||||
action("", getSize() - 5, statistics);
|
||||
}
|
||||
|
||||
private String getStatisticText(String title, Integer value)
|
||||
{
|
||||
return getStatisticText(title, value, false);
|
||||
}
|
||||
|
||||
private String getStatisticText(String title, Integer value, boolean zeroIsUnlimited)
|
||||
{
|
||||
return getStatisticText(title, zeroIsUnlimited && value <= 0 ? "unlimited" : bigNumbersFormatter.format(value));
|
||||
}
|
||||
|
||||
private String getStatisticText(String title, String value)
|
||||
{
|
||||
return ChatColor.GRAY + title + ": " + ChatColor.WHITE + value;
|
||||
}
|
||||
}
|
@ -20,53 +20,36 @@ package fr.moribus.imageonmap.image;
|
||||
|
||||
import fr.moribus.imageonmap.ImageOnMap;
|
||||
import fr.moribus.imageonmap.map.ImageMap;
|
||||
import fr.moribus.imageonmap.worker.Worker;
|
||||
import fr.moribus.imageonmap.worker.WorkerCallback;
|
||||
import fr.moribus.imageonmap.worker.WorkerRunnable;
|
||||
import fr.zcraft.zlib.components.worker.Worker;
|
||||
import fr.zcraft.zlib.components.worker.WorkerAttributes;
|
||||
import fr.zcraft.zlib.components.worker.WorkerRunnable;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
|
||||
@WorkerAttributes (name = "Image IO")
|
||||
public class ImageIOExecutor extends Worker
|
||||
{
|
||||
static private ImageIOExecutor instance;
|
||||
|
||||
static public void start()
|
||||
{
|
||||
if(instance != null) stop();
|
||||
instance = new ImageIOExecutor();
|
||||
instance.init();
|
||||
}
|
||||
|
||||
static public void stop()
|
||||
{
|
||||
instance.exit();
|
||||
instance = null;
|
||||
}
|
||||
|
||||
private ImageIOExecutor()
|
||||
{
|
||||
super("Image IO");
|
||||
}
|
||||
|
||||
static public void loadImage(final File file, final Renderer mapRenderer)
|
||||
{
|
||||
instance.submitQuery(new WorkerRunnable<Void>()
|
||||
submitQuery(new WorkerRunnable<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void run() throws Exception
|
||||
{
|
||||
@Override
|
||||
public Void run() throws Exception
|
||||
{
|
||||
BufferedImage image = ImageIO.read(file);
|
||||
mapRenderer.setImage(image);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
BufferedImage image = ImageIO.read(file);
|
||||
mapRenderer.setImage(image);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static public void saveImage(final File file, final BufferedImage image)
|
||||
{
|
||||
instance.submitQuery(new WorkerRunnable<Void>()
|
||||
submitQuery(new WorkerRunnable<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void run() throws Throwable
|
||||
@ -101,7 +84,7 @@ public class ImageIOExecutor extends Worker
|
||||
|
||||
static public void deleteImage(final File file)
|
||||
{
|
||||
instance.submitQuery(new WorkerRunnable<Void>()
|
||||
submitQuery(new WorkerRunnable<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void run() throws Throwable
|
||||
@ -109,7 +92,6 @@ public class ImageIOExecutor extends Worker
|
||||
Files.delete(file.toPath());
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -18,46 +18,29 @@
|
||||
|
||||
package fr.moribus.imageonmap.image;
|
||||
|
||||
import fr.moribus.imageonmap.PluginLogger;
|
||||
import fr.moribus.imageonmap.map.ImageMap;
|
||||
import fr.moribus.imageonmap.map.MapManager;
|
||||
import fr.moribus.imageonmap.worker.Worker;
|
||||
import fr.moribus.imageonmap.worker.WorkerCallback;
|
||||
import fr.moribus.imageonmap.worker.WorkerRunnable;
|
||||
import java.awt.Graphics;
|
||||
import fr.zcraft.zlib.components.worker.Worker;
|
||||
import fr.zcraft.zlib.components.worker.WorkerAttributes;
|
||||
import fr.zcraft.zlib.components.worker.WorkerCallback;
|
||||
import fr.zcraft.zlib.components.worker.WorkerRunnable;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
|
||||
@WorkerAttributes (name = "Image Renderer", queriesMainThread = true)
|
||||
public class ImageRendererExecutor extends Worker
|
||||
{
|
||||
static private ImageRendererExecutor instance;
|
||||
|
||||
static public void start()
|
||||
{
|
||||
if(instance != null) stop();
|
||||
instance = new ImageRendererExecutor();
|
||||
instance.init();
|
||||
}
|
||||
|
||||
static public void stop()
|
||||
{
|
||||
instance.exit();
|
||||
instance = null;
|
||||
}
|
||||
|
||||
private ImageRendererExecutor()
|
||||
{
|
||||
super("Image IO", true);
|
||||
}
|
||||
|
||||
static public void Test(WorkerCallback callback)
|
||||
{
|
||||
instance.submitQuery(new WorkerRunnable<Void>()
|
||||
submitQuery(new WorkerRunnable<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void run() throws Throwable
|
||||
@ -70,15 +53,15 @@ public class ImageRendererExecutor extends Worker
|
||||
|
||||
static public void Render(final URL url, final boolean scaling, final UUID playerUUID, WorkerCallback<ImageMap> callback)
|
||||
{
|
||||
instance.submitQuery(new WorkerRunnable<ImageMap>()
|
||||
submitQuery(new WorkerRunnable<ImageMap>()
|
||||
{
|
||||
@Override
|
||||
public ImageMap run() throws Throwable
|
||||
{
|
||||
final BufferedImage image = ImageIO.read(url);
|
||||
if(image == null) throw new IOException("The given URL is not a valid image");
|
||||
|
||||
if(scaling) return RenderSingle(image, playerUUID);
|
||||
if (image == null) throw new IOException("The given URL is not a valid image");
|
||||
|
||||
if (scaling) return RenderSingle(image, playerUUID);
|
||||
else return RenderPoster(image, playerUUID);
|
||||
}
|
||||
}, callback);
|
||||
@ -87,7 +70,7 @@ public class ImageRendererExecutor extends Worker
|
||||
static private ImageMap RenderSingle(final BufferedImage image, final UUID playerUUID) throws Throwable
|
||||
{
|
||||
MapManager.checkMapLimit(1, playerUUID);
|
||||
Future<Short> futureMapID = instance.submitToMainThread(new Callable<Short>()
|
||||
Future<Short> futureMapID = submitToMainThread(new Callable<Short>()
|
||||
{
|
||||
@Override
|
||||
public Short call() throws Exception
|
||||
@ -101,7 +84,7 @@ public class ImageRendererExecutor extends Worker
|
||||
final short mapID = futureMapID.get();
|
||||
ImageIOExecutor.saveImage(mapID, finalImage);
|
||||
|
||||
instance.submitToMainThread(new Callable<Void>()
|
||||
submitToMainThread(new Callable<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void call() throws Exception
|
||||
@ -121,7 +104,7 @@ public class ImageRendererExecutor extends Worker
|
||||
final int mapCount = poster.getImagesCount();
|
||||
|
||||
MapManager.checkMapLimit(mapCount, playerUUID);
|
||||
final Future<short[]> futureMapsIds = instance.submitToMainThread(new Callable<short[]>()
|
||||
final Future<short[]> futureMapsIds = submitToMainThread(new Callable<short[]>()
|
||||
{
|
||||
@Override
|
||||
public short[] call() throws Exception
|
||||
@ -136,7 +119,7 @@ public class ImageRendererExecutor extends Worker
|
||||
|
||||
ImageIOExecutor.saveImage(mapsIDs, poster);
|
||||
|
||||
instance.submitToMainThread(new Callable<Void>()
|
||||
submitToMainThread(new Callable<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void call() throws Exception
|
||||
@ -178,5 +161,4 @@ public class ImageRendererExecutor extends Worker
|
||||
graphics.dispose();
|
||||
return newImage;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,7 +28,9 @@ import org.bukkit.entity.ItemFrame;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.player.PlayerItemHeldEvent;
|
||||
import org.bukkit.event.player.PlayerPickupItemEvent;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.map.MapView;
|
||||
@ -73,6 +75,26 @@ public class MapInitEvent implements Listener
|
||||
initMap(item);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerPickup(PlayerPickupItemEvent event)
|
||||
{
|
||||
ItemStack item = event.getItem().getItemStack();
|
||||
initMap(item);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerInventoryPlace(InventoryClickEvent event)
|
||||
{
|
||||
switch(event.getAction())
|
||||
{
|
||||
case PLACE_ALL:
|
||||
case PLACE_ONE:
|
||||
case PLACE_SOME:
|
||||
case SWAP_WITH_CURSOR:
|
||||
initMap(event.getCursor());
|
||||
}
|
||||
}
|
||||
|
||||
static protected void initMap(ItemStack item)
|
||||
{
|
||||
if (item != null && item.getType() == Material.MAP)
|
||||
|
@ -18,15 +18,14 @@
|
||||
|
||||
package fr.moribus.imageonmap.map;
|
||||
|
||||
import fr.moribus.imageonmap.ui.MapItemManager;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import fr.moribus.imageonmap.ui.*;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.configuration.*;
|
||||
import org.bukkit.configuration.serialization.*;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.inventory.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public abstract class ImageMap implements ConfigurationSerializable
|
||||
{
|
||||
@ -160,6 +159,11 @@ public abstract class ImageMap implements ConfigurationSerializable
|
||||
return id;
|
||||
}
|
||||
|
||||
public synchronized Type getType()
|
||||
{
|
||||
return mapType;
|
||||
}
|
||||
|
||||
public synchronized void rename(String id, String name)
|
||||
{
|
||||
this.id = id;
|
||||
|
@ -61,7 +61,7 @@ abstract public class MapManager
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static public boolean managesMap(ItemStack item)
|
||||
{
|
||||
synchronized(playerMaps)
|
||||
@ -73,7 +73,7 @@ abstract public class MapManager
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static public ImageMap createMap(UUID playerUUID, short mapID) throws MapManagerException
|
||||
{
|
||||
ImageMap newMap = new SingleMap(playerUUID, mapID);
|
||||
@ -139,10 +139,66 @@ abstract public class MapManager
|
||||
return getPlayerMapStore(playerUUID).getMapList();
|
||||
}
|
||||
|
||||
static public ImageMap[] getMaps(UUID playerUUID)
|
||||
{
|
||||
return getPlayerMapStore(playerUUID).getMaps();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of minecraft maps used by the images rendered by the given player.
|
||||
*
|
||||
* @param playerUUID The player's UUID.
|
||||
*
|
||||
* @return The count.
|
||||
*/
|
||||
static public int getMapPartCount(UUID playerUUID)
|
||||
{
|
||||
return getPlayerMapStore(playerUUID).getMapCount();
|
||||
}
|
||||
|
||||
static public ImageMap getMap(UUID playerUUID, String mapId)
|
||||
{
|
||||
return getPlayerMapStore(playerUUID).getMap(mapId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ImageMap} this map belongs to.
|
||||
*
|
||||
* @param mapId The ID of the Minecraft map.
|
||||
* @return The {@link ImageMap}.
|
||||
*/
|
||||
static public ImageMap getMap(short mapId)
|
||||
{
|
||||
synchronized(playerMaps)
|
||||
{
|
||||
for(PlayerMapStore mapStore : playerMaps)
|
||||
{
|
||||
if(mapStore.managesMap(mapId))
|
||||
{
|
||||
for(ImageMap map : mapStore.getMapList())
|
||||
{
|
||||
if(map.managesMap(mapId))
|
||||
{
|
||||
return map;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ImageMap} this map belongs to.
|
||||
*
|
||||
* @param item The map, as an {@link ItemStack}.
|
||||
* @return The {@link ImageMap}.
|
||||
*/
|
||||
static public ImageMap getMap(ItemStack item)
|
||||
{
|
||||
return getMap(item.getDurability());
|
||||
}
|
||||
|
||||
static public void clear(Inventory inventory)
|
||||
{
|
||||
@ -192,7 +248,12 @@ abstract public class MapManager
|
||||
}
|
||||
getPlayerMapStore(userUUID).checkMapLimit(newMapsCount);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the total number of minecraft maps used by ImageOnMap images.
|
||||
*
|
||||
* @return The count.
|
||||
*/
|
||||
static public int getMapCount()
|
||||
{
|
||||
int mapCount = 0;
|
||||
|
@ -20,8 +20,15 @@ package fr.moribus.imageonmap.map;
|
||||
|
||||
import fr.moribus.imageonmap.ImageOnMap;
|
||||
import fr.moribus.imageonmap.PluginConfiguration;
|
||||
import fr.moribus.imageonmap.PluginLogger;
|
||||
import fr.moribus.imageonmap.map.MapManagerException.Reason;
|
||||
import fr.zcraft.zlib.tools.PluginLogger;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@ -29,12 +36,6 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class PlayerMapStore implements ConfigurationSerializable
|
||||
{
|
||||
@ -127,6 +128,11 @@ public class PlayerMapStore implements ConfigurationSerializable
|
||||
return new ArrayList(mapList);
|
||||
}
|
||||
|
||||
public synchronized ImageMap[] getMaps()
|
||||
{
|
||||
return mapList.toArray(new ImageMap[mapList.size()]);
|
||||
}
|
||||
|
||||
public synchronized ImageMap getMap(String mapId)
|
||||
{
|
||||
for(ImageMap map : mapList)
|
||||
|
@ -18,10 +18,11 @@
|
||||
|
||||
package fr.moribus.imageonmap.map;
|
||||
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
|
||||
public class PosterMap extends ImageMap
|
||||
{
|
||||
@ -115,6 +116,20 @@ public class PosterMap extends ImageMap
|
||||
if(columnCount == 0) return 0;
|
||||
return (i / columnCount) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the map id at the given column and line.
|
||||
*
|
||||
* @param col The column. Starts at 0.
|
||||
* @param row The row. Starts at 0.
|
||||
* @return The Minecraft map ID.
|
||||
*
|
||||
* @throws ArrayIndexOutOfBoundsException if the given coordinates are too big (out of the poster).
|
||||
*/
|
||||
public short getMapIdAt(int col, int row)
|
||||
{
|
||||
return mapsIDs[getColumnCount() * col + row];
|
||||
}
|
||||
|
||||
public boolean hasColumnData()
|
||||
{
|
||||
|
@ -19,7 +19,8 @@
|
||||
package fr.moribus.imageonmap.migration;
|
||||
|
||||
import fr.moribus.imageonmap.ImageOnMap;
|
||||
import fr.moribus.imageonmap.PluginLogger;
|
||||
import fr.zcraft.zlib.tools.PluginLogger;
|
||||
|
||||
|
||||
public class MigratorExecutor
|
||||
{
|
||||
|
@ -1,222 +0,0 @@
|
||||
/*
|
||||
* 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.migration;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
abstract public class UUIDFetcher
|
||||
{
|
||||
/**
|
||||
* The maximal amount of usernames to send to mojang per request
|
||||
* This allows not to overload mojang's service with too many usernames at a time
|
||||
*/
|
||||
static private final int MOJANG_USERNAMES_PER_REQUEST = 100;
|
||||
|
||||
/**
|
||||
* The maximal amount of requests to send to Mojang
|
||||
* The time limit for this amount is MOJANG_MAX_REQUESTS_TIME
|
||||
* Read : You can only send MOJANG_MAX_REQUESTS in MOJANG_MAX_REQUESTS_TIME seconds
|
||||
*/
|
||||
static private final int MOJANG_MAX_REQUESTS = 600;
|
||||
|
||||
/**
|
||||
* The timeframe for the Mojang request limit (in seconds)
|
||||
*/
|
||||
static private final int MOJANG_MAX_REQUESTS_TIME = 600;
|
||||
|
||||
/**
|
||||
* The minimum time between two requests to mojang (in milliseconds)
|
||||
*/
|
||||
static private final int TIME_BETWEEN_REQUESTS = 200;
|
||||
|
||||
/**
|
||||
* The (approximative) timestamp of the date when Mojang name changing feature
|
||||
* was announced to be released
|
||||
*/
|
||||
static private final int NAME_CHANGE_TIMESTAMP = 1420844400;
|
||||
|
||||
static private final String PROFILE_URL = "https://api.mojang.com/profiles/minecraft";
|
||||
static private final String TIMED_PROFILE_URL = "https://api.mojang.com/users/profiles/minecraft/";
|
||||
|
||||
static public Map<String, UUID> fetch(List<String> names) throws IOException, InterruptedException
|
||||
{
|
||||
return fetch(names, MOJANG_USERNAMES_PER_REQUEST);
|
||||
}
|
||||
|
||||
static public Map<String, UUID> fetch(List<String> names, int limitByRequest) throws IOException, InterruptedException
|
||||
{
|
||||
Map<String, UUID> UUIDs = new HashMap<String, UUID>();
|
||||
int requests = (names.size() / limitByRequest) + 1;
|
||||
|
||||
List<String> tempNames;
|
||||
Map<String, UUID> tempUUIDs;
|
||||
|
||||
for(int i = 0; i < requests; i++)
|
||||
{
|
||||
tempNames = names.subList(limitByRequest * i, Math.min((limitByRequest * (i+1)) - 1, names.size()));
|
||||
tempUUIDs = rawFetch(tempNames);
|
||||
UUIDs.putAll(tempUUIDs);
|
||||
Thread.sleep(TIME_BETWEEN_REQUESTS);
|
||||
}
|
||||
|
||||
return UUIDs;
|
||||
}
|
||||
|
||||
static private Map<String, UUID> rawFetch(List<String> names) throws IOException
|
||||
{
|
||||
Map<String, UUID> uuidMap = new HashMap<String, UUID>();
|
||||
HttpURLConnection connection = getPOSTConnection(PROFILE_URL);
|
||||
|
||||
writeBody(connection, names);
|
||||
JSONArray array;
|
||||
try
|
||||
{
|
||||
array = (JSONArray) readResponse(connection);
|
||||
}
|
||||
catch(ParseException ex)
|
||||
{
|
||||
throw new IOException("Invalid response from server, unable to parse received JSON : " + ex.toString());
|
||||
}
|
||||
|
||||
for (Object profile : array)
|
||||
{
|
||||
JSONObject jsonProfile = (JSONObject) profile;
|
||||
String id = (String) jsonProfile.get("id");
|
||||
String name = (String) jsonProfile.get("name");
|
||||
uuidMap.put(name, fromMojangUUID(id));
|
||||
}
|
||||
|
||||
return uuidMap;
|
||||
}
|
||||
|
||||
static public void fetchRemaining(Collection<String> names, Map<String, UUID> uuids) throws IOException, InterruptedException
|
||||
{
|
||||
ArrayList<String> remainingNames = new ArrayList<>();
|
||||
|
||||
for(String name : names)
|
||||
{
|
||||
if(!uuids.containsKey(name)) remainingNames.add(name);
|
||||
}
|
||||
|
||||
int timeBetweenRequests;
|
||||
if(remainingNames.size() > MOJANG_MAX_REQUESTS)
|
||||
{
|
||||
timeBetweenRequests = (MOJANG_MAX_REQUESTS / MOJANG_MAX_REQUESTS_TIME) * 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
timeBetweenRequests = TIME_BETWEEN_REQUESTS;
|
||||
}
|
||||
|
||||
User user;
|
||||
for(String name : remainingNames)
|
||||
{
|
||||
user = fetchOriginalUUID(name);
|
||||
uuids.put(name, user.uuid);
|
||||
Thread.sleep(timeBetweenRequests);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static private User fetchOriginalUUID(String name) throws IOException
|
||||
{
|
||||
HttpURLConnection connection = getGETConnection(TIMED_PROFILE_URL + name + "?at=" + NAME_CHANGE_TIMESTAMP);
|
||||
|
||||
JSONObject object;
|
||||
|
||||
try
|
||||
{
|
||||
object = (JSONObject) readResponse(connection);
|
||||
}
|
||||
catch(ParseException ex)
|
||||
{
|
||||
throw new IOException("Invalid response from server, unable to parse received JSON : " + ex.toString());
|
||||
}
|
||||
|
||||
User user = new User();
|
||||
user.name = (String) object.get("name");
|
||||
user.uuid = fromMojangUUID((String)object.get("id"));
|
||||
return user;
|
||||
}
|
||||
|
||||
static private HttpURLConnection getPOSTConnection(String url) throws IOException
|
||||
{
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/json");
|
||||
connection.setUseCaches(false);
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(true);
|
||||
return connection;
|
||||
}
|
||||
|
||||
static private HttpURLConnection getGETConnection(String url) throws IOException
|
||||
{
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setUseCaches(false);
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(true);
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
private static void writeBody(HttpURLConnection connection, List<String> names) throws IOException
|
||||
{
|
||||
OutputStream stream = connection.getOutputStream();
|
||||
String body = JSONArray.toJSONString(names);
|
||||
stream.write(body.getBytes());
|
||||
stream.flush();
|
||||
stream.close();
|
||||
}
|
||||
|
||||
private static Object readResponse(HttpURLConnection connection) throws IOException, ParseException
|
||||
{
|
||||
return new JSONParser().parse(new InputStreamReader(connection.getInputStream()));
|
||||
}
|
||||
|
||||
private static UUID fromMojangUUID(String id) //Mojang sends string UUIDs without dashes ...
|
||||
{
|
||||
return UUID.fromString(id.substring(0, 8) + "-" + id.substring(8, 12) + "-" +
|
||||
id.substring(12, 16) + "-" + id.substring(16, 20) + "-" +
|
||||
id.substring(20, 32));
|
||||
}
|
||||
|
||||
static private class User
|
||||
{
|
||||
public String name;
|
||||
public UUID uuid;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,8 +19,14 @@
|
||||
package fr.moribus.imageonmap.migration;
|
||||
|
||||
import fr.moribus.imageonmap.ImageOnMap;
|
||||
import fr.moribus.imageonmap.PluginLogger;
|
||||
import fr.moribus.imageonmap.map.MapManager;
|
||||
import fr.zcraft.zlib.tools.PluginLogger;
|
||||
import fr.zcraft.zlib.tools.mojang.UUIDFetcher;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
@ -37,10 +43,6 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
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
|
||||
@ -350,7 +352,7 @@ public class V3Migrator implements Runnable
|
||||
}
|
||||
catch(IOException ex)
|
||||
{
|
||||
PluginLogger.error("An error occured while fetching the UUIDs from Mojang", ex);
|
||||
PluginLogger.error("An error occurred while fetching the UUIDs from Mojang", ex);
|
||||
throw ex;
|
||||
}
|
||||
catch(InterruptedException ex)
|
||||
@ -358,12 +360,12 @@ public class V3Migrator implements Runnable
|
||||
PluginLogger.error("The migration worker has been interrupted", ex);
|
||||
throw ex;
|
||||
}
|
||||
PluginLogger.info("Fetching done. {0} UUIDs have been retreived.", usersUUIDs.size());
|
||||
PluginLogger.info("Fetching done. {0} UUIDs have been retrieved.", usersUUIDs.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the UUIDs that could not be retreived via Mojang's standard API
|
||||
* @return true if at least one UUID has been retreived, false otherwise
|
||||
* 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
|
||||
{
|
||||
@ -378,7 +380,7 @@ public class V3Migrator implements Runnable
|
||||
}
|
||||
catch(IOException ex)
|
||||
{
|
||||
PluginLogger.error("An error occured while fetching the UUIDs from Mojang");
|
||||
PluginLogger.error("An error occurred while fetching the UUIDs from Mojang");
|
||||
throw ex;
|
||||
}
|
||||
catch(InterruptedException ex)
|
||||
|
@ -21,10 +21,8 @@ package fr.moribus.imageonmap.ui;
|
||||
import fr.moribus.imageonmap.map.ImageMap;
|
||||
import fr.moribus.imageonmap.map.PosterMap;
|
||||
import fr.moribus.imageonmap.map.SingleMap;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.HashMap;
|
||||
import java.util.Queue;
|
||||
import java.util.UUID;
|
||||
import fr.zcraft.zlib.components.gui.GuiUtils;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
@ -32,6 +30,11 @@ import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.HashMap;
|
||||
import java.util.Queue;
|
||||
import java.util.UUID;
|
||||
|
||||
public class MapItemManager implements Listener
|
||||
{
|
||||
static private HashMap<UUID, Queue<ItemStack>> mapItemCache;
|
||||
@ -56,7 +59,7 @@ public class MapItemManager implements Listener
|
||||
|
||||
static public boolean give(Player player, SingleMap map)
|
||||
{
|
||||
return give(player, createMapItem(map.getMapsIDs()[0], map.getName()));
|
||||
return give(player, createMapItem(map));
|
||||
}
|
||||
|
||||
static public boolean give(Player player, PosterMap map)
|
||||
@ -69,7 +72,7 @@ public class MapItemManager implements Listener
|
||||
{
|
||||
if(map.hasColumnData())
|
||||
{
|
||||
mapName = map.getName() +
|
||||
mapName = map.getName() +
|
||||
" (row " + map.getRowAt(i) +
|
||||
", column " + map.getColumnAt(i) + ")";
|
||||
}
|
||||
@ -112,16 +115,70 @@ public class MapItemManager implements Listener
|
||||
}
|
||||
}
|
||||
|
||||
static public ItemStack createMapItem(SingleMap map)
|
||||
{
|
||||
return createMapItem(map.getMapsIDs()[0], map.getName());
|
||||
}
|
||||
|
||||
static public ItemStack createMapItem(PosterMap map, int x, int y)
|
||||
{
|
||||
String mapName;
|
||||
if(map.hasColumnData())
|
||||
{
|
||||
mapName = map.getName() +
|
||||
" (row " + x +
|
||||
", column " + y + ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
mapName = map.getName();
|
||||
}
|
||||
return createMapItem(map.getMapIdAt(x, y), mapName);
|
||||
}
|
||||
|
||||
static public ItemStack createMapItem(short mapID, String text)
|
||||
{
|
||||
ItemStack itemMap = new ItemStack(Material.MAP, 1, mapID);
|
||||
|
||||
ItemMeta meta = itemMap.getItemMeta();
|
||||
meta.setDisplayName(text);
|
||||
meta.setDisplayName(ChatColor.RESET + text);
|
||||
GuiUtils.hideItemAttributes(meta);
|
||||
itemMap.setItemMeta(meta);
|
||||
|
||||
return itemMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the item to place to display the (col;row) part of the given poster.
|
||||
*
|
||||
* @param col The column to display. Starts at 0.
|
||||
* @param row The row to display. Starts at 0.
|
||||
*
|
||||
* @return The map.
|
||||
*
|
||||
* @throws ArrayIndexOutOfBoundsException If col;row is not inside the map.
|
||||
*/
|
||||
static public ItemStack createSubMapItem(ImageMap map, int col, int row)
|
||||
{
|
||||
if(map instanceof PosterMap && ((PosterMap) map).hasColumnData())
|
||||
{
|
||||
return MapItemManager.createMapItem(
|
||||
((PosterMap) map).getMapIdAt(row, col),
|
||||
map.getName() +
|
||||
" (row " + (row + 1) +
|
||||
", column " + (col + 1) + ")"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(row != 0 || col != 0)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException(); // Coherence
|
||||
}
|
||||
|
||||
return MapItemManager.createMapItem(map.getMapsIDs()[0], map.getName());
|
||||
}
|
||||
}
|
||||
|
||||
static public int getCacheSize(Player player)
|
||||
{
|
||||
|
@ -1,132 +0,0 @@
|
||||
/*
|
||||
* 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.worker;
|
||||
|
||||
import fr.moribus.imageonmap.PluginLogger;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public abstract class Worker
|
||||
{
|
||||
private final String name;
|
||||
private final ArrayDeque<WorkerRunnable> runQueue = new ArrayDeque<>();
|
||||
|
||||
private final WorkerCallbackManager callbackManager;
|
||||
private final WorkerMainThreadExecutor mainThreadExecutor;
|
||||
private Thread thread;
|
||||
|
||||
protected Worker(String name)
|
||||
{
|
||||
this(name, false);
|
||||
}
|
||||
|
||||
protected Worker(String name, boolean runMainThreadExecutor)
|
||||
{
|
||||
this.name = name;
|
||||
this.callbackManager = new WorkerCallbackManager(name);
|
||||
this.mainThreadExecutor = runMainThreadExecutor ? new WorkerMainThreadExecutor(name) : null;
|
||||
}
|
||||
|
||||
protected void init()
|
||||
{
|
||||
if(thread != null && thread.isAlive())
|
||||
{
|
||||
PluginLogger.warning("Restarting '{0}' thread.", name);
|
||||
exit();
|
||||
}
|
||||
callbackManager.init();
|
||||
if(mainThreadExecutor != null) mainThreadExecutor.init();
|
||||
thread = createThread();
|
||||
thread.start();
|
||||
}
|
||||
|
||||
protected void exit()
|
||||
{
|
||||
thread.interrupt();
|
||||
callbackManager.exit();
|
||||
if(mainThreadExecutor != null) mainThreadExecutor.exit();
|
||||
thread = null;
|
||||
}
|
||||
|
||||
private void run()
|
||||
{
|
||||
WorkerRunnable currentRunnable;
|
||||
|
||||
while(!Thread.interrupted())
|
||||
{
|
||||
synchronized(runQueue)
|
||||
{
|
||||
try
|
||||
{
|
||||
while(runQueue.isEmpty()) runQueue.wait();
|
||||
}
|
||||
catch(InterruptedException ex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
currentRunnable = runQueue.pop();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
callbackManager.callback(currentRunnable, currentRunnable.run());
|
||||
}
|
||||
catch(Throwable ex)
|
||||
{
|
||||
callbackManager.callback(currentRunnable, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void submitQuery(WorkerRunnable runnable)
|
||||
{
|
||||
synchronized(runQueue)
|
||||
{
|
||||
runQueue.add(runnable);
|
||||
runQueue.notify();
|
||||
}
|
||||
}
|
||||
|
||||
protected void submitQuery(WorkerRunnable runnable, WorkerCallback callback)
|
||||
{
|
||||
callbackManager.setupCallback(runnable, callback);
|
||||
submitQuery(runnable);
|
||||
}
|
||||
|
||||
protected <T> Future<T> submitToMainThread(Callable<T> callable)
|
||||
{
|
||||
if(mainThreadExecutor != null) return mainThreadExecutor.submit(callable);
|
||||
return null;
|
||||
}
|
||||
|
||||
private Thread createThread()
|
||||
{
|
||||
return new Thread("ImageOnMap-" + name)
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
Worker.this.run();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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.worker;
|
||||
|
||||
public interface WorkerCallback<T>
|
||||
{
|
||||
public void finished(T result);
|
||||
public void errored(Throwable exception);
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
/*
|
||||
* 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.worker;
|
||||
|
||||
import fr.moribus.imageonmap.ImageOnMap;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.HashMap;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
class WorkerCallbackManager implements Runnable
|
||||
{
|
||||
static private final int WATCH_LOOP_DELAY = 5;
|
||||
|
||||
private final HashMap<WorkerRunnable, WorkerRunnableInfo> callbacks;
|
||||
private final ArrayDeque<WorkerRunnableInfo> callbackQueue;
|
||||
|
||||
private final String name;
|
||||
|
||||
private BukkitTask selfTask;
|
||||
|
||||
public WorkerCallbackManager(String name)
|
||||
{
|
||||
callbacks = new HashMap<>();
|
||||
callbackQueue = new ArrayDeque<>();
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
selfTask = Bukkit.getScheduler().runTaskTimer(ImageOnMap.getPlugin(), this, 0, WATCH_LOOP_DELAY);
|
||||
}
|
||||
|
||||
public void setupCallback(WorkerRunnable runnable, WorkerCallback callback)
|
||||
{
|
||||
synchronized(callbacks)
|
||||
{
|
||||
callbacks.put(runnable, new WorkerRunnableInfo(callback));
|
||||
}
|
||||
}
|
||||
|
||||
public <T> void callback(WorkerRunnable<T> runnable, T result)
|
||||
{
|
||||
callback(runnable, result, null);
|
||||
}
|
||||
|
||||
public <T> void callback(WorkerRunnable<T> runnable, T result, Throwable exception)
|
||||
{
|
||||
WorkerRunnableInfo<T> runnableInfo;
|
||||
synchronized(callbacks)
|
||||
{
|
||||
runnableInfo = callbacks.get(runnable);
|
||||
}
|
||||
if(runnableInfo == null) return;
|
||||
runnableInfo.setRunnableException(exception);
|
||||
runnableInfo.setResult(result);
|
||||
|
||||
enqueueCallback(runnableInfo);
|
||||
}
|
||||
|
||||
public void exit()
|
||||
{
|
||||
if(selfTask != null) selfTask.cancel();
|
||||
}
|
||||
|
||||
private void enqueueCallback(WorkerRunnableInfo runnableInfo)
|
||||
{
|
||||
synchronized(callbackQueue)
|
||||
{
|
||||
callbackQueue.add(runnableInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
WorkerRunnableInfo currentRunnableInfo;
|
||||
synchronized(callbackQueue)
|
||||
{
|
||||
if(callbackQueue.isEmpty()) return;
|
||||
currentRunnableInfo = callbackQueue.pop();
|
||||
}
|
||||
|
||||
currentRunnableInfo.runCallback();
|
||||
}
|
||||
|
||||
private class WorkerRunnableInfo<T>
|
||||
{
|
||||
private final WorkerCallback<T> callback;
|
||||
private T result;
|
||||
private Throwable runnableException;
|
||||
|
||||
public WorkerRunnableInfo(WorkerCallback callback)
|
||||
{
|
||||
this.callback = callback;
|
||||
this.runnableException = null;
|
||||
}
|
||||
|
||||
public WorkerCallback getCallback()
|
||||
{
|
||||
return callback;
|
||||
}
|
||||
|
||||
public void runCallback()
|
||||
{
|
||||
if(runnableCrashed())
|
||||
{
|
||||
callback.errored(runnableException);
|
||||
}
|
||||
else
|
||||
{
|
||||
callback.finished(result);
|
||||
}
|
||||
}
|
||||
|
||||
public void setResult(T result)
|
||||
{
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public Throwable getRunnableException()
|
||||
{
|
||||
return runnableException;
|
||||
}
|
||||
|
||||
public void setRunnableException(Throwable runnableException)
|
||||
{
|
||||
this.runnableException = runnableException;
|
||||
}
|
||||
|
||||
public boolean runnableCrashed()
|
||||
{
|
||||
return this.runnableException != null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,199 +0,0 @@
|
||||
/*
|
||||
* 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.worker;
|
||||
|
||||
import fr.moribus.imageonmap.ImageOnMap;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
class WorkerMainThreadExecutor implements Runnable
|
||||
{
|
||||
static private final int WATCH_LOOP_DELAY = 1;
|
||||
|
||||
private final String name;
|
||||
private final ArrayDeque<WorkerFuture> mainThreadQueue = new ArrayDeque<>();
|
||||
private BukkitTask mainThreadTask;
|
||||
|
||||
public WorkerMainThreadExecutor(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
mainThreadTask = Bukkit.getScheduler().runTaskTimer(ImageOnMap.getPlugin(), this, 0, WATCH_LOOP_DELAY);
|
||||
}
|
||||
|
||||
public void exit()
|
||||
{
|
||||
mainThreadTask.cancel();
|
||||
mainThreadTask = null;
|
||||
}
|
||||
|
||||
public <T> Future<T> submit(Callable<T> callable)
|
||||
{
|
||||
WorkerFuture<T> future = new WorkerFuture<T>(callable);
|
||||
synchronized(mainThreadQueue)
|
||||
{
|
||||
mainThreadQueue.add(future);
|
||||
}
|
||||
return future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
WorkerFuture currentFuture;
|
||||
synchronized(mainThreadQueue)
|
||||
{
|
||||
if(mainThreadQueue.isEmpty()) return;
|
||||
currentFuture = mainThreadQueue.pop();
|
||||
}
|
||||
|
||||
currentFuture.runCallable();
|
||||
}
|
||||
|
||||
private class WorkerFuture<T> implements Future<T>
|
||||
{
|
||||
private final Callable<T> callable;
|
||||
private boolean isCancelled;
|
||||
private boolean isDone;
|
||||
private Exception executionException;
|
||||
private T value;
|
||||
|
||||
public WorkerFuture(Callable<T> callable)
|
||||
{
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
public void runCallable()
|
||||
{
|
||||
try
|
||||
{
|
||||
value = callable.call();
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
executionException = ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
isDone = true;
|
||||
synchronized(this){this.notifyAll();}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning)
|
||||
{
|
||||
if(this.isCancelled || this.isDone) return false;
|
||||
this.isCancelled = true;
|
||||
this.isDone = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled()
|
||||
{
|
||||
return this.isCancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone()
|
||||
{
|
||||
return this.isDone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() throws InterruptedException, ExecutionException
|
||||
{
|
||||
waitForCompletion();
|
||||
if(executionException != null) throw new ExecutionException(executionException);
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
|
||||
{
|
||||
waitForCompletion(timeout, unit);
|
||||
if(executionException != null) throw new ExecutionException(executionException);
|
||||
return value;
|
||||
}
|
||||
|
||||
private void waitForCompletion(long timeout) throws InterruptedException, TimeoutException
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
long remainingTime;
|
||||
long timeoutTime = System.currentTimeMillis() + timeout;
|
||||
while(!isDone)
|
||||
{
|
||||
remainingTime = timeoutTime - System.currentTimeMillis();
|
||||
if(remainingTime <= 0) throw new TimeoutException();
|
||||
this.wait(remainingTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void waitForCompletion() throws InterruptedException
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
while(!isDone) this.wait();
|
||||
}
|
||||
}
|
||||
|
||||
private void waitForCompletion(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException
|
||||
{
|
||||
long millis = 0;
|
||||
switch(unit)
|
||||
{
|
||||
case NANOSECONDS:
|
||||
millis = timeout / 10^6;
|
||||
break;
|
||||
case MICROSECONDS:
|
||||
millis = timeout / 10^3;
|
||||
break;
|
||||
case MILLISECONDS:
|
||||
millis = timeout;
|
||||
break;
|
||||
case SECONDS:
|
||||
millis = timeout * 10^3;
|
||||
break;
|
||||
case MINUTES:
|
||||
millis = timeout * 10^3 * 60;
|
||||
break;
|
||||
case HOURS:
|
||||
millis = timeout * 10^3 * 3600;
|
||||
break;
|
||||
case DAYS:
|
||||
millis = timeout * 10^3 * 3600 * 24;
|
||||
}
|
||||
waitForCompletion(millis);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
/*
|
||||
* 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.worker;
|
||||
|
||||
public interface WorkerRunnable<T>
|
||||
{
|
||||
public T run() throws Throwable;
|
||||
}
|
@ -8,6 +8,9 @@ commands:
|
||||
usage: /<command> [URL]
|
||||
maptool:
|
||||
description: manage maps
|
||||
maps:
|
||||
description: manage maps through a GUI
|
||||
|
||||
permissions:
|
||||
imageonmap.userender:
|
||||
description: Allows you to use /tomap
|
||||
|
Loading…
Reference in New Issue
Block a user