mirror of
https://github.com/zDevelopers/ImageOnMap.git
synced 2025-02-12 17:41:19 +01:00
ImageOnMap is now a zLib plugin.
* NEW: added zLib dependency. * NEW: removed all classes moved to the zLib, and updated the references to these classes to the zLib ones. * BUG: fixed some GUI navigation problems. * NEW: implemented the items renaming into the details GUI.
This commit is contained in:
parent
d25bf9bd0e
commit
2443574316
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,9 +18,14 @@
|
||||
|
||||
package fr.moribus.imageonmap;
|
||||
|
||||
import fr.moribus.imageonmap.commands.Commands;
|
||||
import fr.moribus.imageonmap.gui.core.*;
|
||||
import fr.moribus.imageonmap.guiproko.core.Gui;
|
||||
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;
|
||||
@ -28,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";
|
||||
@ -60,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
|
||||
{
|
||||
@ -76,30 +85,40 @@ public final class ImageOnMap extends JavaPlugin
|
||||
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();
|
||||
GuiManager.init(this);
|
||||
Gui.init(this);
|
||||
|
||||
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();
|
||||
Gui.exit();
|
||||
|
||||
super.onDisable();
|
||||
}
|
||||
|
||||
private File checkPluginDirectory(File primaryFile, File... alternateFiles) throws IOException
|
||||
@ -113,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,130 +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, args);
|
||||
log(level, "Exception : ", ex);
|
||||
}
|
||||
|
||||
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,30 +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 java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE})
|
||||
public @interface CommandInfo
|
||||
{
|
||||
String name();
|
||||
String usageParameters() default "";
|
||||
String[] aliases() default {};
|
||||
}
|
@ -1,324 +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.*;
|
||||
import fr.moribus.imageonmap.commands.maptool.*;
|
||||
import org.apache.commons.lang.*;
|
||||
import org.bukkit.command.*;
|
||||
import org.bukkit.plugin.java.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public enum Commands implements TabCompleter, CommandExecutor
|
||||
{
|
||||
MAPTOOL(new String[]{"maptool"},
|
||||
NewCommand.class,
|
||||
ListCommand.class,
|
||||
GetCommand.class,
|
||||
DeleteConfirmCommand.class,
|
||||
DeleteNoConfirmCommand.class,
|
||||
GetRemainingCommand.class,
|
||||
ExploreCommand.class,
|
||||
MigrateCommand.class
|
||||
),
|
||||
TOMAP(MAPTOOL, NewCommand.class, "tomap"),
|
||||
MAPS(MAPTOOL, ExploreCommand.class, "maps");
|
||||
|
||||
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();
|
||||
|
@ -19,19 +19,16 @@
|
||||
package fr.moribus.imageonmap.commands.maptool;
|
||||
|
||||
|
||||
import fr.moribus.imageonmap.commands.*;
|
||||
import fr.moribus.imageonmap.guiproko.list.MapListGui;
|
||||
import fr.moribus.imageonmap.guiproko.core.Gui;
|
||||
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 Command
|
||||
@CommandInfo (name = "explore")
|
||||
public class ExploreCommand extends IoMCommand
|
||||
{
|
||||
public ExploreCommand(Commands commandGroup)
|
||||
{
|
||||
super(commandGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run() throws CommandException
|
||||
{
|
||||
|
@ -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
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,17 +16,24 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package fr.moribus.imageonmap.guiproko.list;
|
||||
package fr.moribus.imageonmap.gui;
|
||||
|
||||
import fr.moribus.imageonmap.*;
|
||||
import fr.moribus.imageonmap.guiproko.core.*;
|
||||
import fr.moribus.imageonmap.map.*;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.inventory.*;
|
||||
import org.bukkit.inventory.meta.*;
|
||||
import org.bukkit.material.*;
|
||||
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.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
|
||||
public class ConfirmDeleteMapGui extends ActionGui
|
||||
@ -42,12 +49,6 @@ public class ConfirmDeleteMapGui extends ActionGui
|
||||
*/
|
||||
private ImageMap mapToDelete;
|
||||
|
||||
/**
|
||||
* The previously-viewed page of the list GUI.
|
||||
* Used to be able to bring the user back to the same page.
|
||||
*/
|
||||
private int currentPage;
|
||||
|
||||
/**
|
||||
* The messages randomly displayed in the lore of the “delete” buttons.
|
||||
*/
|
||||
@ -69,12 +70,10 @@ public class ConfirmDeleteMapGui extends ActionGui
|
||||
/**
|
||||
*
|
||||
* @param mapToDelete The map being deleted.
|
||||
* @param currentPage The previously-viewed page of the list GUI.
|
||||
*/
|
||||
public ConfirmDeleteMapGui(ImageMap mapToDelete, int currentPage)
|
||||
public ConfirmDeleteMapGui(ImageMap mapToDelete)
|
||||
{
|
||||
this.mapToDelete = mapToDelete;
|
||||
this.currentPage = currentPage;
|
||||
|
||||
deleteMessages = new String[]{
|
||||
"Please", "I'm still alive", "Don't do that", "I'm still loving you", "I want to live",
|
||||
@ -166,13 +165,15 @@ public class ConfirmDeleteMapGui extends ActionGui
|
||||
subButton.setItemMeta(meta);
|
||||
return subButton;
|
||||
}
|
||||
|
||||
protected void action_cancel()
|
||||
|
||||
@GuiAction ("cancel")
|
||||
protected void cancel()
|
||||
{
|
||||
Gui.open(getPlayer(), new MapDetailGui(null /*mapToDelete, currentPage */));
|
||||
close();
|
||||
}
|
||||
|
||||
protected void action_delete()
|
||||
|
||||
@GuiAction ("delete")
|
||||
protected void delete()
|
||||
{
|
||||
MapManager.clear(getPlayer().getInventory(), mapToDelete);
|
||||
|
||||
@ -187,6 +188,12 @@ public class ConfirmDeleteMapGui extends ActionGui
|
||||
getPlayer().sendMessage(ChatColor.RED + "This map does not exists.");
|
||||
}
|
||||
|
||||
Gui.open(getPlayer(), new MapListGui(/* currentPage */));
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
@ -16,15 +16,24 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package fr.moribus.imageonmap.guiproko.list;
|
||||
package fr.moribus.imageonmap.gui;
|
||||
|
||||
import fr.moribus.imageonmap.guiproko.core.*;
|
||||
import fr.moribus.imageonmap.map.*;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.inventory.*;
|
||||
import org.bukkit.inventory.meta.*;
|
||||
import fr.moribus.imageonmap.map.ImageMap;
|
||||
import fr.moribus.imageonmap.map.PosterMap;
|
||||
import fr.moribus.imageonmap.map.SingleMap;
|
||||
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.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
|
||||
public class MapDetailGui extends ExplorerGui<Void>
|
||||
@ -80,38 +89,18 @@ public class MapDetailGui extends ExplorerGui<Void>
|
||||
setData(null); // Fallback to the empty view item.
|
||||
|
||||
|
||||
ItemStack back = new ItemStack(Material.EMERALD);
|
||||
ItemMeta meta = back.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.GREEN + "« Back");
|
||||
meta.setLore(Collections.singletonList(
|
||||
ChatColor.GRAY + "Go back to the list."
|
||||
));
|
||||
back.setItemMeta(meta);
|
||||
|
||||
ItemStack rename = new ItemStack(Material.BOOK_AND_QUILL);
|
||||
meta = rename.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.BLUE + "Rename this image");
|
||||
meta.setLore(Arrays.asList(
|
||||
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."
|
||||
));
|
||||
rename.setItemMeta(meta);
|
||||
)));
|
||||
|
||||
ItemStack delete = new ItemStack(Material.BARRIER);
|
||||
meta = delete.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.RED + "Delete this image");
|
||||
meta.setLore(Arrays.asList(
|
||||
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."
|
||||
));
|
||||
delete.setItemMeta(meta);
|
||||
|
||||
|
||||
action("rename", getSize() - 7, rename);
|
||||
action("delete", getSize() - 6, delete);
|
||||
)));
|
||||
|
||||
|
||||
// To keep the controls centered, the back button is shifted to the right when the
|
||||
@ -121,6 +110,33 @@ public class MapDetailGui extends ExplorerGui<Void>
|
||||
if(map instanceof PosterMap && ((PosterMap) map).getColumnCount() <= INVENTORY_ROW_SIZE)
|
||||
backSlot++;
|
||||
|
||||
action("back", backSlot, back);
|
||||
action("back", backSlot, GuiUtils.makeItem(Material.EMERALD, ChatColor.GREEN + "« Back", Collections.singletonList(
|
||||
ChatColor.GRAY + "Go back to the list."
|
||||
)));
|
||||
}
|
||||
|
||||
|
||||
@GuiAction ("rename")
|
||||
public void rename()
|
||||
{
|
||||
Gui.open(getPlayer(), new PromptGui(new Callback<String>() {
|
||||
@Override
|
||||
public void call(String name)
|
||||
{
|
||||
map.rename(name);
|
||||
}
|
||||
}, 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;
|
||||
}
|
||||
}
|
@ -1,345 +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.gui.core;
|
||||
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.event.inventory.*;
|
||||
import org.bukkit.inventory.*;
|
||||
import org.bukkit.inventory.meta.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* @author IamBlueSlime, Amaury Carrade
|
||||
*/
|
||||
public abstract class AbstractGui {
|
||||
protected TreeMap<Integer, String> actions = new TreeMap<>();
|
||||
protected Inventory inventory;
|
||||
|
||||
/**
|
||||
* This method is called when the inventory is open through the
|
||||
* {@link GuiManager}. Use this to populate the GUI.
|
||||
*
|
||||
* You will have to store the inventory inside the {@link AbstractGui#inventory} protected attribute,
|
||||
* as this attribute will be used by all other methods.
|
||||
*
|
||||
* @param player The player this GUI will be displayed to.
|
||||
*/
|
||||
public abstract void display(Player player);
|
||||
|
||||
/**
|
||||
* A standard way to update the GUI when it is not closed. This method is
|
||||
* never called automatically, you have to call it when needed.
|
||||
*
|
||||
* @param player The player this GUI is displayed to.
|
||||
*/
|
||||
public void update(Player player)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this to open the GUI. The GUI is not automatically open, allowing you
|
||||
* to open it at the best moment (before or after populating it, as example).
|
||||
*
|
||||
* @param player The player this GUI will be displayed to.
|
||||
*/
|
||||
public void open(Player player)
|
||||
{
|
||||
player.openInventory(inventory);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called when the GUI is closed.
|
||||
*
|
||||
* @param player The player this GUI was displayed to.
|
||||
*/
|
||||
public void onClose(Player player)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called when the player clicks on the GUI.
|
||||
*
|
||||
* @param player The player who clicked on the GUI.
|
||||
* @param stack The clicked {@link ItemStack}.
|
||||
* @param action The action associated with this slot using {@link AbstractGui#setSlotData(ItemStack, int, String)}
|
||||
* or other similar methods.
|
||||
* @param clickType The click.
|
||||
* @param invAction The inventory action.
|
||||
* @param event The full {@link InventoryClickEvent} triggered by the player.
|
||||
*/
|
||||
public void onClick(Player player, ItemStack stack, String action, ClickType clickType, InventoryAction invAction, InventoryClickEvent event)
|
||||
{
|
||||
this.onClick(player, stack, action, clickType, invAction);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called when the player clicks on the GUI.
|
||||
*
|
||||
* @param player The player who clicked on the GUI.
|
||||
* @param stack The clicked {@link ItemStack}.
|
||||
* @param action The action associated with this slot using {@link AbstractGui#setSlotData(ItemStack, int, String)}
|
||||
* or other similar methods.
|
||||
* @param clickType The click.
|
||||
* @param invAction The inventory action.
|
||||
*/
|
||||
public void onClick(Player player, ItemStack stack, String action, ClickType clickType, InventoryAction invAction)
|
||||
{
|
||||
this.onClick(player, stack, action, clickType);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called when the player clicks on the GUI.
|
||||
*
|
||||
* @param player The player who clicked on the GUI.
|
||||
* @param stack The clicked {@link ItemStack}.
|
||||
* @param action The action associated with this slot using {@link AbstractGui#setSlotData(ItemStack, int, String)}
|
||||
* or other similar methods.
|
||||
* @param clickType The click.
|
||||
*/
|
||||
public void onClick(Player player, ItemStack stack, String action, ClickType clickType)
|
||||
{
|
||||
this.onClick(player, stack, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called when the player clicks on the GUI.
|
||||
*
|
||||
* @param player The player who clicked on the GUI.
|
||||
* @param stack The clicked {@link ItemStack}.
|
||||
* @param action The action associated with this slot using {@link AbstractGui#setSlotData(ItemStack, int, String)}
|
||||
* or other similar methods.
|
||||
*/
|
||||
public void onClick(Player player, ItemStack stack, String action) {}
|
||||
|
||||
|
||||
/**
|
||||
* This method will be called when the user places an item in the GUI, either by shift-click or directly.
|
||||
*
|
||||
* Use the {@link InventoryAction} to distinguish these cases.
|
||||
*
|
||||
* @param player The played who moved the stack to the GUI.
|
||||
* @param stack The moved {@link ItemStack}.
|
||||
* @param clickType The click.
|
||||
* @param invAction The inventory action.
|
||||
* @param event The full {@link InventoryClickEvent} triggered by the player.
|
||||
*/
|
||||
public void onItemDeposit(Player player, ItemStack stack, ClickType clickType, InventoryAction invAction, InventoryClickEvent event)
|
||||
{
|
||||
onItemDeposit(player, stack, clickType, invAction);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called when the user places an item in the GUI, either by shift-click or directly.
|
||||
*
|
||||
* Use the {@link InventoryAction} to distinguish these cases.
|
||||
*
|
||||
* @param player The played who moved the stack to the GUI.
|
||||
* @param stack The moved {@link ItemStack}.
|
||||
* @param clickType The click.
|
||||
* @param invAction The inventory action.
|
||||
*/
|
||||
public void onItemDeposit(Player player, ItemStack stack, ClickType clickType, InventoryAction invAction)
|
||||
{
|
||||
onItemDeposit(player, stack, clickType);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called when the user places an item in the GUI, either by shift-click or directly.
|
||||
*
|
||||
* Use the {@link InventoryAction} to distinguish these cases.
|
||||
*
|
||||
* @param player The played who moved the stack to the GUI.
|
||||
* @param stack The moved {@link ItemStack}.
|
||||
* @param clickType The click.
|
||||
*/
|
||||
public void onItemDeposit(Player player, ItemStack stack, ClickType clickType)
|
||||
{
|
||||
onItemDeposit(player, stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called when the user places an item in the GUI, either by shift-click or directly.
|
||||
*
|
||||
* Use the {@link InventoryAction} to distinguish these cases.
|
||||
*
|
||||
* @param player The played who moved the stack to the GUI.
|
||||
* @param stack The moved {@link ItemStack}.
|
||||
*/
|
||||
public void onItemDeposit(Player player, ItemStack stack)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a slot as a managed one.
|
||||
*
|
||||
* When such a slot is clicked by the player, the {@link #onClick(Player, ItemStack, String, ClickType, InventoryAction, InventoryClickEvent)}
|
||||
* method is called (and all methods with the same name and less arguments).
|
||||
*
|
||||
* @param inv The inventory the item will be added to.
|
||||
* @param name The display name of the item.
|
||||
* @param material The material of this item.
|
||||
* @param slot The slot this item will be added to.
|
||||
* @param description The description (lore) of the item (one line per {@link String} in the array).
|
||||
* @param action The action associated with this slot, retrieved with the {@link #onClick(Player, ItemStack, String)] methods.
|
||||
*/
|
||||
public void setSlotData(Inventory inv, String name, Material material, int slot, String[] description, String action)
|
||||
{
|
||||
this.setSlotData(inv, name, new ItemStack(material, 1), slot, description, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a slot as a managed one, using the default inventory.
|
||||
*
|
||||
* When such a slot is clicked by the player, the {@link #onClick(Player, ItemStack, String, ClickType, InventoryAction, InventoryClickEvent)}
|
||||
* method is called (and all methods with the same name and less arguments).
|
||||
*
|
||||
* @param name The display name of the item.
|
||||
* @param material The material of this item.
|
||||
* @param slot The slot this item will be added to.
|
||||
* @param description The description (lore) of the item (one line per {@link String} in the array).
|
||||
* @param action The action associated with this slot, retrieved with the {@link #onClick(Player, ItemStack, String)] methods.
|
||||
*/
|
||||
public void setSlotData(String name, Material material, int slot, String[] description, String action)
|
||||
{
|
||||
this.setSlotData(this.inventory, name, new ItemStack(material, 1), slot, description, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a slot as a managed one, using the default inventory.
|
||||
*
|
||||
* When such a slot is clicked by the player, the {@link #onClick(Player, ItemStack, String, ClickType, InventoryAction, InventoryClickEvent)}
|
||||
* method is called (and all methods with the same name and less arguments).
|
||||
*
|
||||
* @param name The display name of the item.
|
||||
* @param item The {@link ItemStack} displayed in this slot.
|
||||
* @param slot The slot this item will be added to.
|
||||
* @param description The description (lore) of the item (one line per {@link String} in the array).
|
||||
* @param action The action associated with this slot, retrieved with the {@link #onClick(Player, ItemStack, String)] methods.
|
||||
*/
|
||||
public void setSlotData(String name, ItemStack item, int slot, String[] description, String action)
|
||||
{
|
||||
this.setSlotData(this.inventory, name, item, slot, description, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a slot as a managed one.
|
||||
*
|
||||
* When such a slot is clicked by the player, the {@link #onClick(Player, ItemStack, String, ClickType, InventoryAction, InventoryClickEvent)}
|
||||
* method is called (and all methods with the same name and less arguments).
|
||||
*
|
||||
* @param inv The inventory the item will be added to.
|
||||
* @param name The display name of the item.
|
||||
* @param item The {@link ItemStack} displayed in this slot.
|
||||
* @param slot The slot this item will be added to.
|
||||
* @param description The description (lore) of the item (one line per {@link String} in the array).
|
||||
* @param action The action associated with this slot, retrieved with the {@link #onClick(Player, ItemStack, String)] methods.
|
||||
*/
|
||||
public void setSlotData(Inventory inv, String name, ItemStack item, int slot, String[] description, String action)
|
||||
{
|
||||
this.actions.put(slot, action);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
|
||||
meta.setDisplayName(name);
|
||||
|
||||
if (description != null)
|
||||
meta.setLore(Arrays.asList(description));
|
||||
|
||||
item.setItemMeta(meta);
|
||||
inv.setItem(slot, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a slot as a managed one.
|
||||
*
|
||||
* When such a slot is clicked by the player, the {@link #onClick(Player, ItemStack, String, ClickType, InventoryAction, InventoryClickEvent)}
|
||||
* method is called (and all methods with the same name and less arguments).
|
||||
*
|
||||
* @param inv The inventory the item will be added to.
|
||||
* @param item The {@link ItemStack} displayed in this slot.
|
||||
* @param slot The slot this item will be added to.
|
||||
* @param action The action associated with this slot, retrieved with the {@link #onClick(Player, ItemStack, String)] methods.
|
||||
*/
|
||||
public void setSlotData(Inventory inv, ItemStack item, int slot, String action)
|
||||
{
|
||||
this.actions.put(slot, action);
|
||||
inv.setItem(slot, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a slot as a managed one, using the default inventory.
|
||||
*
|
||||
* When such a slot is clicked by the player, the {@link #onClick(Player, ItemStack, String, ClickType, InventoryAction, InventoryClickEvent)}
|
||||
* method is called (and all methods with the same name and less arguments).
|
||||
*
|
||||
* @param item The {@link ItemStack} displayed in this slot.
|
||||
* @param slot The slot this item will be added to.
|
||||
* @param action The action associated with this slot, retrieved with the {@link #onClick(Player, ItemStack, String)] methods.
|
||||
*/
|
||||
public void setSlotData(ItemStack item, int slot, String action)
|
||||
{
|
||||
setSlotData(this.inventory, item, slot, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the registered action associated with the given slot.
|
||||
*
|
||||
* @param slot The slot.
|
||||
*
|
||||
* @return The action; {@code null} if there isn't any action registered to this slot.
|
||||
*/
|
||||
public String getAction(int slot)
|
||||
{
|
||||
if (!this.actions.containsKey(slot))
|
||||
return null;
|
||||
|
||||
return this.actions.get(slot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the slot registered to the given action.
|
||||
*
|
||||
* @param action The action.
|
||||
*
|
||||
* @return The slot; {@code -1} if this action is not registered.
|
||||
*/
|
||||
public int getSlot(String action)
|
||||
{
|
||||
for (int slot : this.actions.keySet())
|
||||
if (this.actions.get(slot).equals(action))
|
||||
return slot;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default inventory.
|
||||
*
|
||||
* @return The inventory.
|
||||
*/
|
||||
public Inventory getInventory()
|
||||
{
|
||||
return this.inventory;
|
||||
}
|
||||
}
|
@ -1,108 +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.gui.core;
|
||||
|
||||
import org.bukkit.Material;
|
||||
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.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
|
||||
/**
|
||||
* @author IamBlueSlime, Amaury Carrade
|
||||
*
|
||||
* Changes by Amaury Carrade to use statics (beh, code style, these things).
|
||||
*/
|
||||
public class GuiListener implements Listener {
|
||||
|
||||
public static void init(Plugin plugin)
|
||||
{
|
||||
plugin.getServer().getPluginManager().registerEvents(new GuiListener(), plugin);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClick(InventoryClickEvent event)
|
||||
{
|
||||
if (event.getWhoClicked() instanceof Player)
|
||||
{
|
||||
Player player = (Player) event.getWhoClicked();
|
||||
AbstractGui gui = GuiManager.getPlayerGui(player);
|
||||
|
||||
if(gui == null)
|
||||
return;
|
||||
|
||||
if (event.getInventory() instanceof PlayerInventory)
|
||||
return;
|
||||
|
||||
|
||||
/* *** Click from player inventory (with shift) *** */
|
||||
|
||||
if(event.getRawSlot() != event.getSlot())
|
||||
{
|
||||
if(event.isShiftClick())
|
||||
{
|
||||
gui.onItemDeposit(player, event.getCurrentItem(), event.getClick(), event.getAction(), event);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* *** Click on the GUI inventory *** */
|
||||
|
||||
if(event.getCursor() != null && event.getCursor().getType() != Material.AIR)
|
||||
{
|
||||
gui.onItemDeposit(player, event.getCursor(), event.getClick(), event.getAction(), event);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
String action = gui.getAction(event.getSlot());
|
||||
|
||||
if (action != null)
|
||||
gui.onClick(player, event.getCurrentItem(), action, event.getClick(), event.getAction(), event);
|
||||
}
|
||||
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryDrag(InventoryDragEvent event)
|
||||
{
|
||||
Player player = (Player) event.getWhoClicked();
|
||||
AbstractGui gui = GuiManager.getPlayerGui(player);
|
||||
|
||||
if (gui != null)
|
||||
{
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClose(InventoryCloseEvent event)
|
||||
{
|
||||
if (GuiManager.getPlayerGui(event.getPlayer()) != null)
|
||||
GuiManager.removeClosedGui((Player) event.getPlayer());
|
||||
}
|
||||
}
|
@ -1,120 +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.gui.core;
|
||||
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
||||
/**
|
||||
* A tool to easily manage GUIs.
|
||||
*
|
||||
* @author IamBlueSlime and Amaury Carrade.
|
||||
*/
|
||||
public class GuiManager {
|
||||
|
||||
protected static Map<UUID, AbstractGui> currentGUIs;
|
||||
|
||||
/**
|
||||
* Call this when the plugin is enabled.
|
||||
*
|
||||
* @param plugin The plugin using this.
|
||||
*/
|
||||
public static void init(Plugin plugin)
|
||||
{
|
||||
currentGUIs = new ConcurrentHashMap<>();
|
||||
|
||||
GuiListener.init(plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a GUI for the given player.
|
||||
*
|
||||
* Closes any GUI already open for this player.
|
||||
*
|
||||
* @param player The player this GUI will be open to.
|
||||
* @param gui The GUI to open.
|
||||
*/
|
||||
public static void openGui(Player player, AbstractGui gui)
|
||||
{
|
||||
if (currentGUIs.containsKey(player.getUniqueId()))
|
||||
closeGui(player);
|
||||
|
||||
currentGUIs.put(player.getUniqueId(), gui);
|
||||
gui.display(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the currently open GUI of this player, if it exists.
|
||||
*
|
||||
* Without any open GUI for this player, does nothing.
|
||||
*
|
||||
* @param player The player.
|
||||
*/
|
||||
public static void closeGui(Player player)
|
||||
{
|
||||
player.closeInventory();
|
||||
removeClosedGui(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the {@link AbstractGui#onClose(Player)} method of the currently open GUI of the
|
||||
* given {@link Player} and unregisters it as open.
|
||||
*
|
||||
* @param player The player
|
||||
*/
|
||||
public static void removeClosedGui(Player player)
|
||||
{
|
||||
if (currentGUIs.containsKey(player.getUniqueId()))
|
||||
{
|
||||
//noinspection ConstantConditions
|
||||
getPlayerGui(player).onClose(player);
|
||||
currentGUIs.remove(player.getUniqueId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently open {@link AbstractGui} of the given {@link HumanEntity}.
|
||||
*
|
||||
* @param player The HumanEntity.
|
||||
* @return The open GUI, or {@code null} if no GUI are open.
|
||||
*/
|
||||
public static AbstractGui getPlayerGui(HumanEntity player)
|
||||
{
|
||||
if (currentGUIs.containsKey(player.getUniqueId()))
|
||||
return currentGUIs.get(player.getUniqueId());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all open GUIs.
|
||||
*
|
||||
* @return The GUI (map: player's {@link UUID} → {@link AbstractGui}).
|
||||
*/
|
||||
public static Map<UUID, AbstractGui> getPlayersGui()
|
||||
{
|
||||
return currentGUIs;
|
||||
}
|
||||
}
|
@ -1,85 +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.gui.core;
|
||||
|
||||
import fr.moribus.imageonmap.PluginLogger;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
||||
public class GuiUtils {
|
||||
|
||||
private static boolean supported = true;
|
||||
|
||||
private static Object[] itemFlags;
|
||||
|
||||
static
|
||||
{
|
||||
try {
|
||||
Class<?> itemFlagEnumClass = Class.forName("org.bukkit.inventory.ItemFlag");
|
||||
|
||||
Method valuesMethod = itemFlagEnumClass.getDeclaredMethod("values");
|
||||
itemFlags = (Object[]) valuesMethod.invoke(null);
|
||||
|
||||
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e) {
|
||||
// Not supported :c
|
||||
supported = false;
|
||||
} catch (InvocationTargetException e) {
|
||||
PluginLogger.error("Exception occurred while loading the ItemFlags.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the vanilla informations displayed on the tooltips of the given item,
|
||||
* like enchantments, map infos, etc.
|
||||
*
|
||||
* @param stack The item.
|
||||
*/
|
||||
public static void removeVanillaInfos(ItemStack stack)
|
||||
{
|
||||
ItemMeta meta = stack.getItemMeta();
|
||||
removeVanillaInfos(meta);
|
||||
stack.setItemMeta(meta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the vanilla informations displayed on the tooltips of the given item,
|
||||
* like enchantments, map infos, etc.
|
||||
*
|
||||
* @param meta The item's metadata.
|
||||
*/
|
||||
public static void removeVanillaInfos(ItemMeta meta)
|
||||
{
|
||||
if(!supported) return;
|
||||
|
||||
try {
|
||||
Method addItemFlagsMethod = meta.getClass().getMethod("addItemFlags", itemFlags.getClass());
|
||||
addItemFlagsMethod.setAccessible(true);
|
||||
addItemFlagsMethod.invoke(meta, (Object) itemFlags);
|
||||
|
||||
} catch (NoSuchMethodException | IllegalAccessException ignored) {
|
||||
// Should never happens, or only with breaking changes in the Bukkit API.
|
||||
} catch (InvocationTargetException e) {
|
||||
PluginLogger.error("Exception occurred while invoking the ItemMeta.addItemFlags method.", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,206 +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.gui.list;
|
||||
|
||||
import fr.moribus.imageonmap.PluginLogger;
|
||||
import fr.moribus.imageonmap.gui.core.AbstractGui;
|
||||
import fr.moribus.imageonmap.gui.core.GuiManager;
|
||||
import fr.moribus.imageonmap.map.ImageMap;
|
||||
import fr.moribus.imageonmap.map.MapManager;
|
||||
import fr.moribus.imageonmap.map.MapManagerException;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.DyeColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
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 AbstractGui
|
||||
{
|
||||
|
||||
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 map being deleted.
|
||||
*/
|
||||
private ImageMap mapToDelete;
|
||||
|
||||
/**
|
||||
* The previously-viewed page of the list GUI.
|
||||
* Used to be able to bring the user back to the same page.
|
||||
*/
|
||||
private int currentPage;
|
||||
|
||||
/**
|
||||
* The messages randomly displayed in the lore of the “delete” buttons.
|
||||
*/
|
||||
private String[] deleteMessages;
|
||||
|
||||
/**
|
||||
* The messages randomly displayed in the lore of the “cancel” buttons.
|
||||
*/
|
||||
private String[] cancelMessages;
|
||||
|
||||
/**
|
||||
* A source of randomness.
|
||||
*
|
||||
* Yes, this javadoc comment is REALLY useful.
|
||||
*/
|
||||
private Random random = new Random();
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mapToDelete The map being deleted.
|
||||
* @param currentPage The previously-viewed page of the list GUI.
|
||||
*/
|
||||
public ConfirmDeleteMapGui(ImageMap mapToDelete, int currentPage) {
|
||||
this.mapToDelete = mapToDelete;
|
||||
this.currentPage = currentPage;
|
||||
|
||||
deleteMessages = 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."
|
||||
};
|
||||
|
||||
cancelMessages = 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"
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void display(Player player)
|
||||
{
|
||||
inventory = Bukkit.createInventory(player, 6 * 9, ChatColor.BLACK + "Are you sure?");
|
||||
|
||||
|
||||
/* ** 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);
|
||||
|
||||
setSlotData(beingDeleted, 13, "");
|
||||
|
||||
|
||||
/* ** Buttons ** */
|
||||
|
||||
int slot = FIRST_SLOT_DELETE_BUTTON;
|
||||
for(; slot < inventory.getSize() - (9 - BUTTONS_WIDTH); slot++)
|
||||
{
|
||||
setSlotData(createDeleteSubButton(), slot, "delete");
|
||||
setSlotData(createCancelSubButton(), slot + SHIFT_CANCEL_BUTTON, "cancel");
|
||||
|
||||
if((slot + 1) % 9 == (9 - BUTTONS_WIDTH - 1))
|
||||
slot += 5;
|
||||
}
|
||||
|
||||
player.openInventory(inventory);
|
||||
}
|
||||
|
||||
private ItemStack createDeleteSubButton()
|
||||
{
|
||||
// Orange? Nooo. In the real world this is red. True story.
|
||||
return createSubButton(DyeColor.ORANGE, ChatColor.RED + "Delete the map", deleteMessages);
|
||||
}
|
||||
|
||||
private ItemStack createCancelSubButton()
|
||||
{
|
||||
// YES. Purple = lime. BECAUSE. Just accept it.
|
||||
return createSubButton(DyeColor.PURPLE, ChatColor.GREEN + "Cancel", cancelMessages);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onClick(Player player, ItemStack stack, String action) {
|
||||
switch(action)
|
||||
{
|
||||
case "cancel":
|
||||
GuiManager.openGui(player, new MapDetailGui(mapToDelete, currentPage));
|
||||
return;
|
||||
|
||||
case "delete":
|
||||
MapManager.clear(player.getInventory(), mapToDelete);
|
||||
try
|
||||
{
|
||||
MapManager.deleteMap(mapToDelete);
|
||||
player.sendMessage(ChatColor.GRAY + "Map successfully deleted.");
|
||||
}
|
||||
catch (MapManagerException ex)
|
||||
{
|
||||
PluginLogger.warning("A non-existent map was requested to be deleted", ex);
|
||||
player.sendMessage(ChatColor.RED + "This map does not exists.");
|
||||
}
|
||||
|
||||
GuiManager.openGui(player, new MapListGui(currentPage));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,370 +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.gui.list;
|
||||
|
||||
import fr.moribus.imageonmap.gui.core.AbstractGui;
|
||||
import fr.moribus.imageonmap.gui.core.GuiManager;
|
||||
import fr.moribus.imageonmap.guiproko.core.Gui;
|
||||
import fr.moribus.imageonmap.map.ImageMap;
|
||||
import fr.moribus.imageonmap.map.PosterMap;
|
||||
import fr.moribus.imageonmap.ui.MapItemManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.event.inventory.InventoryAction;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
|
||||
public class MapDetailGui extends AbstractGui
|
||||
{
|
||||
|
||||
/**
|
||||
* The max width of the window open on the image.
|
||||
*/
|
||||
private final int MAX_WINDOW_WIDTH = 8;
|
||||
|
||||
/**
|
||||
* The max height of the window open on the image.
|
||||
*/
|
||||
private final int MAX_WINDOW_HEIGHT = 5;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The map displayed in this GUI.
|
||||
*/
|
||||
private ImageMap map;
|
||||
|
||||
/**
|
||||
* The previously-viewed page of the list GUI.
|
||||
* Used to be able to bring the user back to the same page.
|
||||
*/
|
||||
private int currentPage;
|
||||
|
||||
/**
|
||||
* The row currently at the top of the window open on the displayed map.
|
||||
*/
|
||||
private int topRow = 0;
|
||||
|
||||
/**
|
||||
* The column currently at the top of the window open on the displayed map.
|
||||
*/
|
||||
private int topColumn = 0;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param map The map displayed in this GUI.
|
||||
*/
|
||||
public MapDetailGui(ImageMap map)
|
||||
{
|
||||
this(map, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param map The map displayed in this GUI.
|
||||
* @param currentPage The previously-viewed page of the list GUI.
|
||||
*/
|
||||
public MapDetailGui(ImageMap map, int currentPage)
|
||||
{
|
||||
this.map = map;
|
||||
this.currentPage = currentPage;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void display(Player player)
|
||||
{
|
||||
inventory = Bukkit.createInventory(player, 6 * 9, ChatColor.BLACK + "Your maps");
|
||||
|
||||
ItemStack back = new ItemStack(Material.EMERALD);
|
||||
ItemMeta meta = back.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.GREEN + "« Back");
|
||||
meta.setLore(Collections.singletonList(
|
||||
ChatColor.GRAY + "Go back to the list."
|
||||
));
|
||||
back.setItemMeta(meta);
|
||||
|
||||
ItemStack rename = new ItemStack(Material.BOOK_AND_QUILL);
|
||||
meta = rename.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.BLUE + "Rename this image");
|
||||
meta.setLore(Arrays.asList(
|
||||
ChatColor.GRAY + "Click here to rename this image;",
|
||||
ChatColor.GRAY + "this is used for your own organization."
|
||||
));
|
||||
rename.setItemMeta(meta);
|
||||
|
||||
ItemStack delete = new ItemStack(Material.BARRIER);
|
||||
meta = delete.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.RED + "Delete this image");
|
||||
meta.setLore(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."
|
||||
));
|
||||
delete.setItemMeta(meta);
|
||||
|
||||
|
||||
setSlotData(rename, inventory.getSize() - 7, "rename");
|
||||
setSlotData(delete, inventory.getSize() - 6, "delete");
|
||||
|
||||
|
||||
// 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 = inventory.getSize() - 4;
|
||||
|
||||
if(map instanceof PosterMap && ((PosterMap) map).getColumnCount() <= MAX_WINDOW_WIDTH)
|
||||
backSlot++;
|
||||
|
||||
setSlotData(back, backSlot, "back");
|
||||
|
||||
|
||||
update(player);
|
||||
|
||||
open(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Player player)
|
||||
{
|
||||
if(map instanceof PosterMap && ((PosterMap) map).hasColumnData()) {
|
||||
int slot = 0;
|
||||
|
||||
for (int row = topRow; row < topRow + MAX_WINDOW_HEIGHT; row++)
|
||||
{
|
||||
for (int col = topColumn; col < topColumn + MAX_WINDOW_WIDTH; col++)
|
||||
{
|
||||
if(col < ((PosterMap) map).getColumnCount() && row < ((PosterMap) map).getRowCount())
|
||||
{
|
||||
setSlotData(getMapPartRepresentation(col, row), slot, col + ";" + row);
|
||||
}
|
||||
else
|
||||
{
|
||||
setSlotData(new ItemStack(Material.AIR), slot, "");
|
||||
}
|
||||
|
||||
slot++;
|
||||
}
|
||||
|
||||
slot++;
|
||||
}
|
||||
|
||||
placeArrowSlider('\u2B07', canGoDown() , ((PosterMap) map).getRowCount() > MAX_WINDOW_HEIGHT, 44, "down" );
|
||||
placeArrowSlider('\u2B06', canGoUp() , ((PosterMap) map).getRowCount() > MAX_WINDOW_HEIGHT, 8 , "up" );
|
||||
placeArrowSlider('«' , canGoLeft() , ((PosterMap) map).getColumnCount() > MAX_WINDOW_WIDTH , 45, "left" );
|
||||
placeArrowSlider('»' , canGoRight(), ((PosterMap) map).getColumnCount() > MAX_WINDOW_WIDTH , 52, "right");
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
setSlotData(getMapPartRepresentation(0, 0), 13, "0;0");
|
||||
}
|
||||
}
|
||||
|
||||
private ItemStack getMapPartRepresentation(int col, int row)
|
||||
{
|
||||
Material partMaterial = Material.PAPER;
|
||||
if((col % 2 == 0 && row % 2 == 0) || (col % 2 == 1 && row % 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 + (col + 1),
|
||||
ChatColor.GRAY + "Row: " + ChatColor.WHITE + (row + 1),
|
||||
"",
|
||||
ChatColor.GRAY + "» Click to get only this part"
|
||||
));
|
||||
|
||||
part.setItemMeta(meta);
|
||||
return part;
|
||||
}
|
||||
|
||||
private void placeArrowSlider(Character nameCharacter, boolean active, boolean availableInThisView, int slot, String action)
|
||||
{
|
||||
/* ** Item ** */
|
||||
|
||||
if(!availableInThisView)
|
||||
{
|
||||
setSlotData(new ItemStack(Material.AIR), slot, "");
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack slider = new ItemStack(active ? Material.ARROW : Material.STICK);
|
||||
ItemMeta meta = slider.getItemMeta();
|
||||
|
||||
String title = "";
|
||||
for(int i = 0; i < 5; i++)
|
||||
title += nameCharacter;
|
||||
|
||||
meta.setDisplayName((active ? ChatColor.GREEN : ChatColor.GRAY) + title);
|
||||
|
||||
slider.setItemMeta(meta);
|
||||
|
||||
|
||||
/* ** Placement ** */
|
||||
|
||||
setSlotData(slider, slot, active ? action : "");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onClick(Player player, ItemStack stack, String action, ClickType click, InventoryAction invAction, InventoryClickEvent ev)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case "down":
|
||||
goDown(player);
|
||||
return;
|
||||
|
||||
case "up":
|
||||
goUp(player);
|
||||
return;
|
||||
|
||||
case "left":
|
||||
goLeft(player);
|
||||
return;
|
||||
|
||||
case "right":
|
||||
goRight(player);
|
||||
return;
|
||||
|
||||
case "back":
|
||||
goBack(player);
|
||||
return;
|
||||
|
||||
case "rename":
|
||||
// TODO (no GUI ready for that yet)
|
||||
return;
|
||||
|
||||
case "delete":
|
||||
GuiManager.openGui(player, new ConfirmDeleteMapGui(map, currentPage));
|
||||
//Gui.open(player, new fr.moribus.imageonmap.guiproko.list.ConfirmDeleteMapGui());
|
||||
return;
|
||||
|
||||
default:
|
||||
|
||||
Integer col;
|
||||
Integer row;
|
||||
|
||||
if(map instanceof PosterMap && ((PosterMap) map).hasColumnData()) {
|
||||
String[] coords = action.split(";");
|
||||
|
||||
if (coords.length != 2) return; // Other unhandled action.
|
||||
|
||||
try {
|
||||
col = Integer.valueOf(coords[0]);
|
||||
row = Integer.valueOf(coords[1]);
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
return; // Other unhandled action.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
col = row = 0;
|
||||
}
|
||||
|
||||
ev.setCursor(MapItemManager.createSubMapItem(map, col, row));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void goDown(Player player)
|
||||
{
|
||||
if (!(map instanceof PosterMap)) return;
|
||||
|
||||
if(canGoDown())
|
||||
{
|
||||
topRow++;
|
||||
update(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void goUp(Player player)
|
||||
{
|
||||
if (!(map instanceof PosterMap)) return;
|
||||
|
||||
if(canGoUp())
|
||||
{
|
||||
topRow--;
|
||||
update(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void goRight(Player player)
|
||||
{
|
||||
if (!(map instanceof PosterMap)) return;
|
||||
|
||||
if(canGoRight())
|
||||
{
|
||||
topColumn++;
|
||||
update(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void goLeft(Player player)
|
||||
{
|
||||
if (!(map instanceof PosterMap)) return;
|
||||
|
||||
if(canGoLeft())
|
||||
{
|
||||
topColumn--;
|
||||
update(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void goBack(Player player)
|
||||
{
|
||||
GuiManager.openGui(player, new MapListGui(currentPage));
|
||||
}
|
||||
|
||||
|
||||
private boolean canGoDown()
|
||||
{
|
||||
return topRow + MAX_WINDOW_HEIGHT < ((PosterMap) map).getRowCount();
|
||||
}
|
||||
|
||||
private boolean canGoUp()
|
||||
{
|
||||
return topRow > 0;
|
||||
}
|
||||
|
||||
private boolean canGoRight()
|
||||
{
|
||||
return topColumn + MAX_WINDOW_WIDTH < ((PosterMap) map).getColumnCount();
|
||||
}
|
||||
|
||||
private boolean canGoLeft()
|
||||
{
|
||||
return topColumn > 0;
|
||||
}
|
||||
}
|
@ -1,354 +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.gui.list;
|
||||
|
||||
import fr.moribus.imageonmap.*;
|
||||
import fr.moribus.imageonmap.gui.core.*;
|
||||
import fr.moribus.imageonmap.map.*;
|
||||
import fr.moribus.imageonmap.ui.MapItemManager;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.event.inventory.*;
|
||||
import org.bukkit.inventory.*;
|
||||
import org.bukkit.inventory.meta.*;
|
||||
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public class MapListGui extends AbstractGui
|
||||
{
|
||||
private final Integer MAPS_PER_PAGE = 7 * 3;
|
||||
|
||||
private final NumberFormat bigNumbersFormatter = new DecimalFormat("###,###,###,###", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
|
||||
|
||||
|
||||
private List<ImageMap> maps = new ArrayList<>();
|
||||
|
||||
private int currentPage = 0;
|
||||
private int lastPage = 0;
|
||||
|
||||
|
||||
public MapListGui() {
|
||||
|
||||
}
|
||||
|
||||
public MapListGui(Integer initialPage) {
|
||||
currentPage = initialPage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void display(Player player) {
|
||||
|
||||
inventory = Bukkit.createInventory(player, 6 * 9, ChatColor.BLACK + "Your maps");
|
||||
|
||||
player.openInventory(getInventory());
|
||||
|
||||
|
||||
/* ** Statistics ** */
|
||||
|
||||
int imagesCount = MapManager.getMapList(player.getUniqueId()).size();
|
||||
int mapPartCount = MapManager.getMapPartCount(player.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));
|
||||
lore.add("");
|
||||
|
||||
meta.setLore(lore);
|
||||
}
|
||||
|
||||
GuiUtils.removeVanillaInfos(meta);
|
||||
|
||||
statistics.setItemMeta(meta);
|
||||
setSlotData(statistics, inventory.getSize() - 5, "");
|
||||
|
||||
|
||||
/* ** Maps ** */
|
||||
|
||||
update(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Player player) {
|
||||
update(player, false);
|
||||
}
|
||||
|
||||
public void update(final Player player, final Boolean noCache) {
|
||||
if (maps == null || maps.isEmpty() || noCache) {
|
||||
updateMapCache(player);
|
||||
}
|
||||
|
||||
|
||||
if(maps.isEmpty()) {
|
||||
ItemStack empty = new ItemStack(Material.BARRIER);
|
||||
ItemMeta meta = empty.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.RED + "Nothing to display here");
|
||||
meta.setLore(Arrays.asList(
|
||||
ChatColor.GRAY + "You don't have any map.",
|
||||
ChatColor.GRAY + "Get started by creating a new one",
|
||||
ChatColor.GRAY + "with " + ChatColor.WHITE + "/tomap <URL> [resize]" + ChatColor.GRAY + "!"
|
||||
));
|
||||
|
||||
empty.setItemMeta(meta);
|
||||
|
||||
setSlotData(empty, 13, "");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int index = currentPage * MAPS_PER_PAGE;
|
||||
int lastIndex = index + MAPS_PER_PAGE;
|
||||
int slot = 10;
|
||||
|
||||
ImageMap map;
|
||||
|
||||
for (; index < lastIndex; index++) {
|
||||
try {
|
||||
map = maps.get(index);
|
||||
setSlotData(getMapIcon(map), slot, map.getId());
|
||||
} catch(IndexOutOfBoundsException e) {
|
||||
setSlotData(new ItemStack(Material.AIR), slot, "");
|
||||
}
|
||||
|
||||
if (slot % 9 == 7) slot += 3;
|
||||
else slot++;
|
||||
}
|
||||
|
||||
if (currentPage != 0)
|
||||
setSlotData(getPageIcon(currentPage - 1), inventory.getSize() - 9, "previousPage");
|
||||
else
|
||||
setSlotData(new ItemStack(Material.AIR), inventory.getSize() - 9, "");
|
||||
|
||||
if (currentPage != lastPage)
|
||||
setSlotData(getPageIcon(currentPage + 1), inventory.getSize() - 1, "nextPage");
|
||||
else
|
||||
setSlotData(new ItemStack(Material.AIR), inventory.getSize() - 1, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(Player player, ItemStack stack, String action, ClickType clickType, InventoryAction invAction, InventoryClickEvent ev)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case "previousPage":
|
||||
previousPage(player);
|
||||
return;
|
||||
|
||||
case "nextPage":
|
||||
nextPage(player);
|
||||
return;
|
||||
|
||||
default:
|
||||
// The action is the map ID
|
||||
ImageMap map = null;
|
||||
for(ImageMap lookupMap : maps)
|
||||
{
|
||||
if(lookupMap.getId().equals(action))
|
||||
{
|
||||
map = lookupMap;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(map == null) return;
|
||||
|
||||
switch (clickType)
|
||||
{
|
||||
case LEFT:
|
||||
case SHIFT_LEFT:
|
||||
|
||||
if(map.getType() == ImageMap.Type.SINGLE)
|
||||
{
|
||||
if(invAction == InventoryAction.MOVE_TO_OTHER_INVENTORY)
|
||||
{
|
||||
map.give(player);
|
||||
}
|
||||
else
|
||||
{
|
||||
ev.setCursor(MapItemManager.createMapItem(map.getMapsIDs()[0], map.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (map.give(player)) {
|
||||
player.sendMessage(ChatColor.GRAY + "The requested map was too big to fit in your inventory.");
|
||||
player.sendMessage(ChatColor.GRAY + "Use '/maptool getremaining' to get the remaining maps.");
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RIGHT:
|
||||
case SHIFT_RIGHT:
|
||||
GuiManager.openGui(player, new MapDetailGui(map, currentPage));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemDeposit(Player player, ItemStack stack, ClickType clickType, InventoryAction invAction, InventoryClickEvent ev) {
|
||||
ev.setCancelled(true);
|
||||
|
||||
if (stack.getType() == Material.MAP && MapManager.managesMap(stack))
|
||||
{
|
||||
ImageMap map = MapManager.getMap(stack);
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
MapManager.clear(player.getInventory(), map);
|
||||
|
||||
// Deprecated? Yes. Alternatives? No, as usual...
|
||||
ev.setCursor(new ItemStack(Material.AIR));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void nextPage(Player player)
|
||||
{
|
||||
if(currentPage < lastPage) currentPage++;
|
||||
|
||||
update(player);
|
||||
}
|
||||
|
||||
private void previousPage(Player player)
|
||||
{
|
||||
if(currentPage > 0) currentPage--;
|
||||
|
||||
update(player);
|
||||
}
|
||||
|
||||
|
||||
private void updateMapCache(Player player)
|
||||
{
|
||||
maps = MapManager.getMapList(player.getUniqueId());
|
||||
|
||||
lastPage = (int) Math.ceil(((double) maps.size()) / ((double) MAPS_PER_PAGE)) - 1;
|
||||
|
||||
if(currentPage > lastPage)
|
||||
currentPage = lastPage;
|
||||
}
|
||||
|
||||
private ItemStack getMapIcon(ImageMap map)
|
||||
{
|
||||
ItemStack icon = new ItemStack(Material.MAP);
|
||||
|
||||
|
||||
ItemMeta meta = icon.getItemMeta();
|
||||
|
||||
meta.setDisplayName(ChatColor.GREEN + "" + ChatColor.BOLD + map.getName());
|
||||
|
||||
meta.setLore(Arrays.asList(
|
||||
ChatColor.WHITE + "" + map.getMapCount() + " map" + (map.getMapCount() != 1 ? "s" : ""),
|
||||
"",
|
||||
ChatColor.GRAY + "Map ID: " + map.getId(),
|
||||
"",
|
||||
ChatColor.GRAY + "» Left-click to get this map",
|
||||
ChatColor.GRAY + "» Right-click for details"
|
||||
));
|
||||
|
||||
GuiUtils.removeVanillaInfos(meta);
|
||||
|
||||
icon.setItemMeta(meta);
|
||||
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
private ItemStack getPageIcon(Integer targetPage)
|
||||
{
|
||||
ItemStack icon = new ItemStack(Material.ARROW);
|
||||
ItemMeta meta = icon.getItemMeta();
|
||||
|
||||
|
||||
if(currentPage < targetPage) { // next page
|
||||
meta.setDisplayName(ChatColor.GREEN + "Next page");
|
||||
}
|
||||
else {
|
||||
meta.setDisplayName(ChatColor.GREEN + "Previous page");
|
||||
}
|
||||
|
||||
meta.setLore(Collections.singletonList(
|
||||
ChatColor.GRAY + "Go to page " + ChatColor.WHITE + (targetPage + 1) + ChatColor.GRAY + " of " + ChatColor.WHITE + (lastPage + 1)
|
||||
));
|
||||
|
||||
|
||||
icon.setItemMeta(meta);
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@ -1,382 +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.guiproko.core;
|
||||
|
||||
import fr.moribus.imageonmap.*;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.event.inventory.*;
|
||||
import org.bukkit.inventory.*;
|
||||
import org.bukkit.inventory.meta.*;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This class implements an action-based GUI.
|
||||
* Actions are buttons which trigger an event when getting clicked on by the user.
|
||||
* They are represented by (customizable) items, which are immutable by the user.
|
||||
*
|
||||
* Events handlers are (usually private) methods implemented in the derived
|
||||
* class(es). They are named using the pattern 'action_[action name]', and
|
||||
* are called when the associated action is triggered. They take an optional
|
||||
* argument (add it if you need it): the {@link InventoryClickEvent} triggered.
|
||||
*
|
||||
* @author ProkopyL (main) and Amaury Carrade
|
||||
*/
|
||||
abstract public class ActionGui extends Gui
|
||||
{
|
||||
/**
|
||||
* The prefix for action handlers.
|
||||
*/
|
||||
static private final String ACTION_HANDLER_NAME = "action_";
|
||||
|
||||
/**
|
||||
* The class of this GUI.
|
||||
* Useful to retrieve methods from the derived classes.
|
||||
*/
|
||||
private final Class<? extends ActionGui> guiClass = this.getClass();
|
||||
|
||||
/**
|
||||
* A map containing all the actions defined by the derived class, indexed by
|
||||
* their position in the inventory.
|
||||
*/
|
||||
private final HashMap<Integer, Action> actions = new HashMap<>();
|
||||
|
||||
|
||||
/* ===== Protected API ===== */
|
||||
|
||||
/**
|
||||
* Creates a new action, represented by the given item.
|
||||
* The item's metadata is changed to use the given title and lore.
|
||||
*
|
||||
* @param name The identifier of the action.
|
||||
* @param slot The slot the action will be placed on.
|
||||
* @param material The material used to represent the action.
|
||||
* @param title The title the item will show.
|
||||
* @param loreLines The lore the item will show.
|
||||
*/
|
||||
protected void action(String name, int slot, Material material, String title, String ... loreLines)
|
||||
{
|
||||
action(name, slot, new ItemStack(material), title, Arrays.asList(loreLines));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new action, represented by the given item.
|
||||
* The item's metadata is changed to use the given title and lore.
|
||||
*
|
||||
* @param name The identifier of the action.
|
||||
* @param slot The slot the action will be placed on.
|
||||
* @param item The item used to represent the action.
|
||||
* @param title The title the item will show.
|
||||
* @param loreLines The lore the item will show.
|
||||
*/
|
||||
protected void action(String name, int slot, ItemStack item, String title, String ... loreLines)
|
||||
{
|
||||
action(name, slot, item, title, Arrays.asList(loreLines));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new action, represented by the given item.
|
||||
* The item's metadata is changed to use the given title and lore.
|
||||
*
|
||||
* @param name The identifier of the action.
|
||||
* @param slot The slot the action will be placed on.
|
||||
* @param item The item used to represent the action.
|
||||
* @param title The title the item will show.
|
||||
* @param loreLines The lore the item will show.
|
||||
*/
|
||||
protected void action(String name, int slot, ItemStack item, String title, List<String> loreLines)
|
||||
{
|
||||
action(name, slot, GuiUtils.makeItem(item, title, loreLines));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new action, represented by the given material.
|
||||
*
|
||||
* @param name The identifier of the action.
|
||||
* @param slot The slot the action will be placed on.
|
||||
* @param material The material used to represent the action.
|
||||
*/
|
||||
protected void action(String name, int slot, Material material)
|
||||
{
|
||||
action(name, slot, GuiUtils.makeItem(material));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new action, represented by no item.
|
||||
* This action will not be rendered to the user until
|
||||
* {@link #updateAction(java.lang.String, org.bukkit.inventory.ItemStack, java.lang.String)}
|
||||
* is called.
|
||||
*
|
||||
* @param name The identifier of the action.
|
||||
* @param slot The slot the action will be placed on.
|
||||
*/
|
||||
protected void action(String name, int slot)
|
||||
{
|
||||
action(name, slot, (ItemStack) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new action, and adds it to the GUI.
|
||||
*
|
||||
* @param name The identifier of the action.
|
||||
* @param slot The slot the action will be placed on.
|
||||
* @param item The item used to represent the action.
|
||||
*/
|
||||
protected void action(String name, int slot, ItemStack item)
|
||||
{
|
||||
if(slot > getSize() || slot < 0)
|
||||
throw new IllegalArgumentException("Illegal slot ID");
|
||||
|
||||
action(new Action(name, slot, item, getActionHandler(guiClass, name)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an action to the GUI.
|
||||
*
|
||||
* @param action The {@link fr.moribus.imageonmap.guiproko.core.ActionGui.Action} to register.
|
||||
*/
|
||||
private void action(Action action)
|
||||
{
|
||||
actions.put(action.slot, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the action represented by the given name.
|
||||
*
|
||||
* @param name The name of the action to update.
|
||||
* @param item The new material to affect to the action.
|
||||
* @param title The new title to affect to the action.
|
||||
* @throws IllegalArgumentException If no action has the given name.
|
||||
*/
|
||||
protected void updateAction(String name, Material item, String title)
|
||||
{
|
||||
updateAction(name, new ItemStack(item), title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the action represented by the given name.
|
||||
*
|
||||
* @param name The name of the action to update.
|
||||
* @param item The new item to affect to the action.
|
||||
* @param title The new title to affect to the action.
|
||||
* @throws IllegalArgumentException If no action has the given name.
|
||||
*/
|
||||
protected void updateAction(String name, ItemStack item, String title)
|
||||
{
|
||||
updateAction(name, item);
|
||||
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName(title);
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the action represented by the given name.
|
||||
*
|
||||
* @param name The name of the action to update.
|
||||
* @param item The new item to affect to the action.
|
||||
* @throws IllegalArgumentException If no action has the given name.
|
||||
*/
|
||||
protected void updateAction(String name, ItemStack item)
|
||||
{
|
||||
getAction(name).item = item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the action represented by the given name.
|
||||
*
|
||||
* @param name The name of the action to retreive.
|
||||
* @return The action represented by the given name.
|
||||
* @throws IllegalArgumentException If no action has the given name.
|
||||
*/
|
||||
private Action getAction(String name) throws IllegalArgumentException
|
||||
{
|
||||
for(Action action : actions.values())
|
||||
{
|
||||
if(action.name.equals(name)) return action;
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown action name : " + name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Raised when the Gui needs to be updated.
|
||||
* Use this method to create your actions.
|
||||
*/
|
||||
@Override
|
||||
protected abstract void onUpdate();
|
||||
|
||||
/**
|
||||
* Raised when an action without any event handler has been triggered.
|
||||
*
|
||||
* @param name The name of the triggered action.
|
||||
* @param slot The slot of the action.
|
||||
* @param item The item of the action.
|
||||
* @param event The {@link InventoryClickEvent} raised when this action was triggered.
|
||||
*/
|
||||
protected void unknown_action(String name, int slot, ItemStack item, InventoryClickEvent event)
|
||||
{
|
||||
unknown_action(name, slot, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Raised when an action without any event handler has been triggered.
|
||||
*
|
||||
* @param name The name of the triggered action.
|
||||
* @param slot The slot of the action.
|
||||
* @param item The item of the action.
|
||||
*/
|
||||
protected void unknown_action(String name, int slot, ItemStack item) {}
|
||||
|
||||
|
||||
@Override
|
||||
public void update()
|
||||
{
|
||||
actions.clear();
|
||||
super.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void populate(Inventory inventory)
|
||||
{
|
||||
for(Action action : actions.values())
|
||||
{
|
||||
inventory.setItem(action.slot, action.item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onClick(InventoryClickEvent event)
|
||||
{
|
||||
if(event.getRawSlot() >= event.getInventory().getSize()) //The user clicked in its own inventory
|
||||
{
|
||||
if(!event.getAction().equals(InventoryAction.MOVE_TO_OTHER_INVENTORY))
|
||||
return;
|
||||
}
|
||||
|
||||
event.setCancelled(true);
|
||||
|
||||
callAction(actions.get(event.getRawSlot()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the given action's event handler.
|
||||
* @param action The action to trigger.
|
||||
*/
|
||||
private void callAction(Action action)
|
||||
{
|
||||
if(action == null) return;
|
||||
|
||||
if(action.callback == null)
|
||||
{
|
||||
unknown_action(action.name, action.slot, action.item);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
action.callback.invoke(this);
|
||||
}
|
||||
catch (IllegalAccessException | IllegalArgumentException ex)
|
||||
{
|
||||
PluginLogger.error("Could not invoke GUI action handler", ex);
|
||||
}
|
||||
catch (InvocationTargetException ex)
|
||||
{
|
||||
PluginLogger.error("Error while invoking action handler {0} of GUI {1}",
|
||||
ex.getCause(), action.name, guiClass.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the event handler matching the given name from a class (or any of its parents).
|
||||
*
|
||||
* @param klass The class to retrieve the event handler from.
|
||||
* @param name The name of the action.
|
||||
* @return The event handler matching the action name, or null if none was found.
|
||||
*/
|
||||
private Method getActionHandler(Class<?> klass, String name)
|
||||
{
|
||||
Method callback;
|
||||
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
callback = klass.getDeclaredMethod(ACTION_HANDLER_NAME + name, InventoryClickEvent.class);
|
||||
}
|
||||
catch(NoSuchMethodException e)
|
||||
{
|
||||
callback = klass.getDeclaredMethod(ACTION_HANDLER_NAME + name);
|
||||
}
|
||||
|
||||
callback.setAccessible(true);
|
||||
break;
|
||||
}
|
||||
catch (Throwable ex)
|
||||
{
|
||||
callback = null;
|
||||
klass = klass.getSuperclass();
|
||||
}
|
||||
} while (klass != null);
|
||||
|
||||
return callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if this GUI has any actions defined.
|
||||
*/
|
||||
protected boolean hasActions()
|
||||
{
|
||||
return !actions.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* This structure represents an action.
|
||||
*/
|
||||
static private class Action
|
||||
{
|
||||
/**
|
||||
* The name of the action.
|
||||
*/
|
||||
public String name;
|
||||
/**
|
||||
* The slot the action will be put in.
|
||||
*/
|
||||
public int slot;
|
||||
/**
|
||||
* The item this action will be represented by.
|
||||
*/
|
||||
public ItemStack item;
|
||||
/**
|
||||
* The callback this action will call when triggered.
|
||||
*/
|
||||
public Method callback;
|
||||
|
||||
public Action(String name, int slot, ItemStack item, Method callback)
|
||||
{
|
||||
this.name = name;
|
||||
this.slot = slot;
|
||||
this.item = item;
|
||||
this.callback = callback;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,708 +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.guiproko.core;
|
||||
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.event.inventory.InventoryAction;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* This class implements an exploration GUI, allowing users to see a set of data
|
||||
* in a paginated view, and to manipulate it or get it (if the
|
||||
* {@link fr.moribus.imageonmap.guiproko.core.ExplorerGui.Mode#CREATIVE Creative} mode
|
||||
* is enabled for this GUI — enabled by default).
|
||||
*
|
||||
* This GUI supports both one- and two-dimensional contents; two-dimensional content is
|
||||
* represented by a one-dimension list and a width, or by {@link #getViewItem(int, int)}
|
||||
* if you override it (in this case you need to call {@link #setDataShape(int, int)} in the
|
||||
* {@link #onUpdate()} method).
|
||||
*
|
||||
* @param <T> The type of data this GUI will display.
|
||||
*
|
||||
* @author ProkopyL (main) and Amaury Carrade
|
||||
*/
|
||||
abstract public class ExplorerGui<T> extends ActionGui
|
||||
{
|
||||
/**
|
||||
* The explorer GUI's reading mode.
|
||||
*
|
||||
* In creative mode (the default mode), the players are able to manipulate the content, get it
|
||||
* inside their own inventory (without consumption, just like the creative mode), and whatever
|
||||
* you want if you override some methods.
|
||||
*
|
||||
* In read-only mode, they are only able to browse the content.
|
||||
*/
|
||||
protected enum Mode {READONLY, CREATIVE}
|
||||
|
||||
private T[] data;
|
||||
private boolean isData2D = false;
|
||||
|
||||
private int viewSize;
|
||||
private int viewHeight;
|
||||
private int viewWidth;
|
||||
|
||||
private boolean keepHorizontalScrollingSpace = false;
|
||||
private boolean keepVerticalScrollingSpace = false;
|
||||
|
||||
private int currentPageX = 0;
|
||||
private int currentPageY = 0;
|
||||
|
||||
private int dataHeight = 0;
|
||||
private int dataWidth = 0;
|
||||
|
||||
private int pageCountX;
|
||||
private int pageCountY;
|
||||
|
||||
private Mode mode = Mode.CREATIVE;
|
||||
|
||||
|
||||
public ExplorerGui()
|
||||
{
|
||||
// Defined early to be able to use getSize() in the onUpdate method.
|
||||
setSize(MAX_INVENTORY_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the displayed data.
|
||||
*
|
||||
* @param data The data.
|
||||
* @param dataWidth The data's width, if this data is in two dimensions.
|
||||
* In this case the data array will be read like a matrix, with
|
||||
* lines stored in a consecutive way; the height is automatically
|
||||
* calculated.
|
||||
*/
|
||||
protected void setData(T[] data, int dataWidth)
|
||||
{
|
||||
this.data = data;
|
||||
if(dataWidth > 0)
|
||||
setDataShape(dataWidth, (int) Math.ceil((double) data.length / (double) dataWidth));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data's shape. Use this if you're providing data through
|
||||
* {@link #getViewItem(int, int)}, as example.
|
||||
*
|
||||
* @param dataWidth The data's width.
|
||||
* @param dataHeight The data's height.
|
||||
*/
|
||||
protected void setDataShape(int dataWidth, int dataHeight)
|
||||
{
|
||||
this.dataWidth = dataWidth;
|
||||
this.dataHeight = dataHeight;
|
||||
this.isData2D = dataWidth > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the displayed data, assuming this data is in one dimension.
|
||||
*
|
||||
* @param data The data.
|
||||
*/
|
||||
protected void setData(T[] data)
|
||||
{
|
||||
setData(data, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this GUI contains data, either with the data entry or through
|
||||
* {@link #getViewItem(int, int)} and {@link #setDataShape(int, int)}.
|
||||
*
|
||||
* @return {@code true} if this GUI contains some data.
|
||||
*/
|
||||
protected boolean hasData()
|
||||
{
|
||||
return (data == null || data.length == 0) && (dataWidth == 0 && dataHeight == 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void populate(Inventory inventory)
|
||||
{
|
||||
if(pageCountX > 1)
|
||||
{
|
||||
updateAction("next", getPageItem("next", canGoNext()));
|
||||
updateAction("previous", getPageItem("previous", canGoPrevious()));
|
||||
}
|
||||
|
||||
if(pageCountY > 1)
|
||||
{
|
||||
updateAction("up", getPageItem("up", canGoUp()));
|
||||
updateAction("down", getPageItem("down", canGoDown()));
|
||||
}
|
||||
|
||||
if(hasData())
|
||||
{
|
||||
if (!isData2D)
|
||||
{
|
||||
int start = currentPageX * viewSize;
|
||||
int max = Math.min(viewSize, data.length - start);
|
||||
|
||||
for (int i = 0; i < max; i++)
|
||||
{
|
||||
inventory.setItem(i, getViewItem(i + start));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int startX = currentPageX * viewWidth;
|
||||
int startY = currentPageY * viewHeight;
|
||||
|
||||
int maxX = Math.min(viewWidth, dataWidth - startX);
|
||||
int maxY = Math.min(viewHeight, dataHeight - startY);
|
||||
|
||||
for (int i = maxY; i-- > 0; )
|
||||
{
|
||||
for (int j = maxX; j-- > 0; )
|
||||
{
|
||||
inventory.setItem(i * INVENTORY_ROW_SIZE + j, getViewItem(j + startX, i + startY));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemStack emptyIndicator = getEmptyViewItem();
|
||||
if(emptyIndicator != null)
|
||||
{
|
||||
action("", 22, emptyIndicator);
|
||||
}
|
||||
}
|
||||
|
||||
if(hasActions()) super.populate(inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onClick(InventoryClickEvent event)
|
||||
{
|
||||
int slot = event.getRawSlot();
|
||||
|
||||
// Clicked in the action bar
|
||||
if(hasActions() &&
|
||||
slot >= MAX_INVENTORY_SIZE - INVENTORY_ROW_SIZE
|
||||
&& slot < MAX_INVENTORY_SIZE)
|
||||
{
|
||||
super.onClick(event);
|
||||
return;
|
||||
}
|
||||
|
||||
if(isData2D && pageCountY > 1 &&
|
||||
slot % INVENTORY_ROW_SIZE == INVENTORY_ROW_SIZE - 1)
|
||||
{
|
||||
super.onClick(event);
|
||||
return;
|
||||
}
|
||||
|
||||
// The user clicked in the GUI
|
||||
if(affectsGui(event))
|
||||
{
|
||||
if(hasData())
|
||||
{
|
||||
switch (event.getAction())
|
||||
{
|
||||
case PICKUP_ALL:
|
||||
case PICKUP_HALF:
|
||||
case PICKUP_ONE:
|
||||
case PICKUP_SOME:
|
||||
case HOTBAR_MOVE_AND_READD:
|
||||
case HOTBAR_SWAP:
|
||||
case MOVE_TO_OTHER_INVENTORY:
|
||||
onActionPickup(event);
|
||||
break;
|
||||
|
||||
case PLACE_ALL:
|
||||
case PLACE_ONE:
|
||||
case PLACE_SOME:
|
||||
case SWAP_WITH_CURSOR:
|
||||
onActionPut(event);
|
||||
break;
|
||||
|
||||
case DROP_ALL_CURSOR:
|
||||
case DROP_ONE_CURSOR:
|
||||
break;
|
||||
|
||||
default:
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(event.getAction().equals(InventoryAction.MOVE_TO_OTHER_INVENTORY))
|
||||
onActionMove(event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDrag(InventoryDragEvent event)
|
||||
{
|
||||
if(!affectsGui(event)) return;
|
||||
|
||||
for(int slot : event.getRawSlots())
|
||||
{
|
||||
// Clicked in the action bar
|
||||
if(hasActions() &&
|
||||
slot >= MAX_INVENTORY_SIZE - INVENTORY_ROW_SIZE
|
||||
&& slot < MAX_INVENTORY_SIZE)
|
||||
{
|
||||
super.onDrag(event);
|
||||
return;
|
||||
}
|
||||
|
||||
if(isData2D && pageCountY > 1 &&
|
||||
slot % INVENTORY_ROW_SIZE == INVENTORY_ROW_SIZE - 1)
|
||||
{
|
||||
super.onDrag(event);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
event.setCancelled(true);
|
||||
|
||||
if(mode.equals(Mode.READONLY)) return;
|
||||
if(!onPutItem(event.getOldCursor())) return;
|
||||
|
||||
event.setCursor(new ItemStack(Material.AIR));
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered when a player clicks on the GUI to get an item.
|
||||
*
|
||||
* @param event The triggered event.
|
||||
*/
|
||||
private void onActionPickup(InventoryClickEvent event)
|
||||
{
|
||||
int dataIndex = getDataIndex(event.getSlot());
|
||||
if(event.getClick().equals(ClickType.RIGHT))
|
||||
{
|
||||
onRightClick(getData(dataIndex));
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack pickedUpItem = getPickedUpItem(dataIndex);
|
||||
if(pickedUpItem == null || mode.equals(Mode.READONLY))
|
||||
{
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
event.setCurrentItem(pickedUpItem);
|
||||
GuiUtils.setItemLater(this, event.getSlot(), getViewItem(dataIndex));
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered when a player clicks on the GUI to place an item.
|
||||
*
|
||||
* @param event The triggered event.
|
||||
*/
|
||||
private void onActionPut(InventoryClickEvent event)
|
||||
{
|
||||
event.setCancelled(true);
|
||||
if(mode.equals(Mode.READONLY)) return;
|
||||
if(!onPutItem(event.getCursor())) return;
|
||||
event.setCursor(new ItemStack(Material.AIR));
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered when a player moves an item on the GUI.
|
||||
*
|
||||
* @param event The triggered event.
|
||||
*/
|
||||
private void onActionMove(InventoryClickEvent event)
|
||||
{
|
||||
event.setCancelled(true);
|
||||
if(mode.equals(Mode.READONLY)) return;
|
||||
if(!onPutItem(event.getCurrentItem())) return;
|
||||
event.setCurrentItem(new ItemStack(Material.AIR));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAfterUpdate()
|
||||
{
|
||||
//Calculating page count
|
||||
if(data != null && data.length <= 0)
|
||||
{
|
||||
viewWidth = INVENTORY_ROW_SIZE;
|
||||
viewHeight = 1;
|
||||
viewSize = viewWidth;
|
||||
|
||||
pageCountX = 1;
|
||||
pageCountY = 1;
|
||||
}
|
||||
else if(!isData2D)
|
||||
{
|
||||
int dataLength = (data == null) ? 0 : data.length;
|
||||
|
||||
viewWidth = INVENTORY_ROW_SIZE;
|
||||
viewHeight = Math.min((int)Math.ceil((double)dataLength / (double)viewWidth),
|
||||
MAX_INVENTORY_COLUMN_SIZE);
|
||||
|
||||
if(hasActions() || dataLength > MAX_INVENTORY_SIZE || keepHorizontalScrollingSpace)
|
||||
viewHeight--;
|
||||
|
||||
viewSize = viewWidth * viewHeight;
|
||||
|
||||
pageCountX = (int)Math.ceil((double)dataLength / (double)viewSize);
|
||||
pageCountY = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
viewWidth = Math.min(dataWidth, INVENTORY_ROW_SIZE);
|
||||
viewHeight = Math.min(dataHeight, MAX_INVENTORY_COLUMN_SIZE);
|
||||
|
||||
pageCountX = (int)Math.ceil((double)dataWidth / (double)viewWidth);
|
||||
pageCountY = (int)Math.ceil((double)dataHeight / (double)viewHeight);
|
||||
|
||||
if((pageCountY > 1 && viewWidth == INVENTORY_ROW_SIZE) || keepVerticalScrollingSpace)
|
||||
viewWidth--;
|
||||
|
||||
if((pageCountX > 1 && viewHeight == MAX_INVENTORY_COLUMN_SIZE) || keepHorizontalScrollingSpace)
|
||||
viewHeight--;
|
||||
|
||||
pageCountX = (int)Math.ceil((double)dataWidth / (double)viewWidth);
|
||||
pageCountY = (int)Math.ceil((double)dataHeight / (double)viewHeight);
|
||||
}
|
||||
|
||||
if(pageCountX > 1)
|
||||
{
|
||||
action("previous", MAX_INVENTORY_SIZE - INVENTORY_ROW_SIZE);
|
||||
action("next", MAX_INVENTORY_SIZE - 1 - (pageCountY > 1 ? 1 : 0));
|
||||
}
|
||||
if(pageCountY > 1)
|
||||
{
|
||||
action("up", INVENTORY_ROW_SIZE - 1);
|
||||
action("down", MAX_INVENTORY_SIZE - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void action_next()
|
||||
{
|
||||
next();
|
||||
}
|
||||
|
||||
private void action_previous()
|
||||
{
|
||||
previous();
|
||||
}
|
||||
|
||||
private void action_up()
|
||||
{
|
||||
up();
|
||||
}
|
||||
|
||||
private void action_down()
|
||||
{
|
||||
down();
|
||||
}
|
||||
|
||||
private int getDataIndex(int inventorySlot)
|
||||
{
|
||||
if(isData2D)
|
||||
{
|
||||
int column = currentPageX * viewWidth + inventorySlot % INVENTORY_ROW_SIZE;
|
||||
int row = currentPageY * viewHeight + inventorySlot / INVENTORY_ROW_SIZE;
|
||||
return row * dataWidth + column;
|
||||
}
|
||||
else
|
||||
{
|
||||
return currentPageX * viewSize + inventorySlot;
|
||||
}
|
||||
}
|
||||
|
||||
private T getData(int i)
|
||||
{
|
||||
if(i < 0 || i >= data.length)
|
||||
return null;
|
||||
|
||||
return data[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the stack to display at the given index.
|
||||
*
|
||||
* @param i The index.
|
||||
* @return The stack.
|
||||
*/
|
||||
protected ItemStack getViewItem(int i)
|
||||
{
|
||||
return getViewItem(getData(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the stack to display at the given coordinates.
|
||||
*
|
||||
* @param x The x-coordinate (left to right).
|
||||
* @param y The y-coordinate (top to bottom).
|
||||
* @return The stack.
|
||||
*/
|
||||
protected ItemStack getViewItem(int x, int y)
|
||||
{
|
||||
return getViewItem(y * dataWidth + x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ItemStack representation of the given piece of data.
|
||||
*
|
||||
* @param data The piece of data.
|
||||
* @return The piece's representation.
|
||||
*/
|
||||
protected ItemStack getViewItem(T data) { return null; }
|
||||
|
||||
/**
|
||||
* Returns the stack displayed in the center of the GUI if it is empty.
|
||||
*
|
||||
* @return The stack.
|
||||
*/
|
||||
protected ItemStack getEmptyViewItem() { return null; }
|
||||
|
||||
|
||||
private ItemStack getPickedUpItem(int dataIndex)
|
||||
{
|
||||
if(dataIndex < 0 || dataIndex >= data.length)
|
||||
return null;
|
||||
|
||||
return getPickedUpItem(getData(dataIndex));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the stack the players will get when they try to take an item from
|
||||
* the GUI, in {@link fr.moribus.imageonmap.guiproko.core.ExplorerGui.Mode#CREATIVE}
|
||||
* mode.
|
||||
*
|
||||
* @param data The picked-up piece of data.
|
||||
* @return The stack to pick-up ({@code null} to cancel the pick-up).
|
||||
*/
|
||||
protected ItemStack getPickedUpItem(T data) { return getViewItem(data); }
|
||||
|
||||
/**
|
||||
* Returns the item to use to display the pagination buttons.
|
||||
*
|
||||
* @param paginationButtonType The type of button (either "next", "previous", "up", "down").
|
||||
* @param canUse {@code true} if the button is usable (i.e. not in the last or first page of
|
||||
* its kind.
|
||||
* @return The item.
|
||||
*/
|
||||
protected ItemStack getPageItem(String paginationButtonType, boolean canUse)
|
||||
{
|
||||
ItemStack icon = new ItemStack(canUse ? Material.ARROW : Material.STICK);
|
||||
ItemMeta meta = icon.getItemMeta();
|
||||
|
||||
String title;
|
||||
Integer newPage;
|
||||
Integer lastPage;
|
||||
|
||||
switch (paginationButtonType)
|
||||
{
|
||||
case "next":
|
||||
title = canUse ? "Next page" : "No next page";
|
||||
|
||||
newPage = currentPageX + 1;
|
||||
lastPage = getPageCount();
|
||||
break;
|
||||
|
||||
case "previous":
|
||||
title = canUse ? "Previous page" : "No previous page";
|
||||
|
||||
newPage = currentPageX - 1;
|
||||
lastPage = getPageCount();
|
||||
break;
|
||||
|
||||
case "up":
|
||||
title = canUse ? "Go up" : "Top page";
|
||||
|
||||
newPage = currentPageY + 1;
|
||||
lastPage = getVerticalPageCount();
|
||||
break;
|
||||
|
||||
case "down":
|
||||
title = canUse ? "Go down" : "Bottom page";
|
||||
|
||||
newPage = currentPageY - 1;
|
||||
lastPage = getVerticalPageCount();
|
||||
break;
|
||||
|
||||
default:
|
||||
return null; // invalid page type
|
||||
}
|
||||
|
||||
meta.setDisplayName((canUse ? ChatColor.WHITE : ChatColor.GRAY) + title);
|
||||
|
||||
if(canUse)
|
||||
{
|
||||
meta.setLore(Collections.singletonList(
|
||||
ChatColor.GRAY + "Go to page " + ChatColor.WHITE + (newPage + 1) + ChatColor.GRAY + " of " + ChatColor.WHITE + lastPage
|
||||
));
|
||||
}
|
||||
|
||||
icon.setItemMeta(meta);
|
||||
return icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered when the player right-clicks an item on the GUI.
|
||||
*
|
||||
* @param data The right-clicked piece of data.
|
||||
*/
|
||||
protected void onRightClick(T data) {}
|
||||
|
||||
/**
|
||||
* Triggered when the player try to place an item inside the GUI.
|
||||
*
|
||||
* This will not place the item in the GUI, it's up to you to update the data and refresh
|
||||
* the GUI if you need so.
|
||||
*
|
||||
* @param item The {@link ItemStack} the player is trying to put.
|
||||
* @return {@code false} to cancel the placement; {@code true} to accept it.
|
||||
*/
|
||||
protected boolean onPutItem(ItemStack item) { return true; }
|
||||
|
||||
/**
|
||||
* Displays the next horizontal page, if possible.
|
||||
*/
|
||||
public void next()
|
||||
{
|
||||
if(!canGoNext()) return;
|
||||
currentPageX++;
|
||||
refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the previous horizontal page, if possible.
|
||||
*/
|
||||
public void previous()
|
||||
{
|
||||
if(!canGoPrevious()) return;
|
||||
currentPageX--;
|
||||
refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the previous vertical page, if possible.
|
||||
*/
|
||||
public void up()
|
||||
{
|
||||
if(!canGoUp()) return;
|
||||
currentPageY--;
|
||||
refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the next vertical page, if possible.
|
||||
*/
|
||||
public void down()
|
||||
{
|
||||
if(!canGoDown()) return;
|
||||
currentPageY++;
|
||||
refresh();
|
||||
}
|
||||
|
||||
public boolean canGoNext()
|
||||
{
|
||||
return currentPageX < pageCountX - 1;
|
||||
}
|
||||
|
||||
public boolean canGoPrevious()
|
||||
{
|
||||
return currentPageX > 0;
|
||||
}
|
||||
|
||||
public boolean canGoUp()
|
||||
{
|
||||
return currentPageY > 0;
|
||||
}
|
||||
|
||||
public boolean canGoDown()
|
||||
{
|
||||
return currentPageY < pageCountY - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of horizontal pages.
|
||||
*
|
||||
* @return The pages' amount.
|
||||
*/
|
||||
public int getPageCount()
|
||||
{
|
||||
return pageCountX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of vertical pages.
|
||||
* This will always be 1 if the GUI is representing a one-dimensional data set.
|
||||
*
|
||||
* @return The pages' amount.
|
||||
*/
|
||||
public int getVerticalPageCount()
|
||||
{
|
||||
return pageCountY;
|
||||
}
|
||||
|
||||
/** @return The GUI's manipulation mode. */
|
||||
protected Mode getMode()
|
||||
{
|
||||
return mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the GUI's manipulation mode.
|
||||
* @param mode The mode.
|
||||
*/
|
||||
protected void setMode(Mode mode)
|
||||
{
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to {@code true}, the horizontal scrolling line will remain empty even without
|
||||
* scrolls (with one page typically), so you can place buttons or things like that in this
|
||||
* area.
|
||||
*
|
||||
* Else, with one page, the place will be used to display an additional row of data.
|
||||
*
|
||||
* @param keepHorizontalScrollingSpace {@code true} if enabled.
|
||||
*/
|
||||
public void setKeepHorizontalScrollingSpace(boolean keepHorizontalScrollingSpace)
|
||||
{
|
||||
this.keepHorizontalScrollingSpace = keepHorizontalScrollingSpace;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to {@code true}, the vertical scrolling line will remain empty even without
|
||||
* scrolls (with one page typically), so you can place buttons or things like that in this
|
||||
* area.
|
||||
*
|
||||
* Else, with one page, the place will be used to display an additional column of data.
|
||||
*
|
||||
* @param keepVerticalScrollingSpace {@code true} if enabled.
|
||||
*/
|
||||
public void setKeepVerticalScrollingSpace(boolean keepVerticalScrollingSpace)
|
||||
{
|
||||
this.keepVerticalScrollingSpace = keepVerticalScrollingSpace;
|
||||
}
|
||||
}
|
@ -1,345 +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.guiproko.core;
|
||||
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.event.*;
|
||||
import org.bukkit.event.inventory.*;
|
||||
import org.bukkit.inventory.*;
|
||||
import org.bukkit.plugin.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This class provides the basic needs for chest-type GUIs.
|
||||
* It allows you to create custom GUIs by simply providing an inventory
|
||||
* to fill, as well as rerouting basic events to it.
|
||||
*/
|
||||
abstract public class Gui
|
||||
{
|
||||
static protected final int INVENTORY_ROW_SIZE = 9;
|
||||
static protected final int MAX_INVENTORY_COLUMN_SIZE = 6;
|
||||
static protected final int MAX_INVENTORY_SIZE = INVENTORY_ROW_SIZE * MAX_INVENTORY_COLUMN_SIZE;
|
||||
|
||||
/**
|
||||
* The player this Gui instance is associated to.
|
||||
*/
|
||||
private Player player;
|
||||
|
||||
/**
|
||||
* The size of the inventory.
|
||||
*/
|
||||
private int size = 0;
|
||||
|
||||
/**
|
||||
* The title of the inventory.
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* The current Bukkit inventory.
|
||||
*/
|
||||
private Inventory inventory;
|
||||
|
||||
/**
|
||||
* If the inventory is currently open.
|
||||
*/
|
||||
private boolean open = false;
|
||||
|
||||
|
||||
private void open(Player player)
|
||||
{
|
||||
this.player = player;
|
||||
openGuis.put(player, this);
|
||||
this.update();
|
||||
player.openInventory(inventory);
|
||||
this.open = true;
|
||||
}
|
||||
|
||||
|
||||
/* ===== Public API ===== */
|
||||
|
||||
/**
|
||||
* Asks the GUI to update its data, and refresh its view accordingly.
|
||||
* The inventory may be regenerated when calling this method.
|
||||
*/
|
||||
public void update()
|
||||
{
|
||||
onUpdate();
|
||||
onAfterUpdate();
|
||||
|
||||
//If inventory does not need to be regenerated
|
||||
if(inventory != null && inventory.getTitle().equals(title) && inventory.getSize() == size)
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
else
|
||||
{
|
||||
inventory = Bukkit.createInventory(player, size, title);
|
||||
populate(inventory);
|
||||
|
||||
if(isOpen()) // Reopening the inventory
|
||||
{
|
||||
player.closeInventory();
|
||||
player.openInventory(inventory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks the GUI to recreate its view.
|
||||
* The inventory is cleared, but never regenerated when calling this method.
|
||||
*/
|
||||
public void refresh()
|
||||
{
|
||||
inventory.clear();
|
||||
populate(inventory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this inventory.
|
||||
*/
|
||||
public void close()
|
||||
{
|
||||
this.open = false;
|
||||
player.closeInventory();
|
||||
openGuis.remove(player);
|
||||
}
|
||||
|
||||
/* ===== Protected API ===== */
|
||||
|
||||
/**
|
||||
* Raised when the {@link Gui#update()} method is called.
|
||||
* Use this method to update your internal data.
|
||||
*/
|
||||
protected void onUpdate() {}
|
||||
|
||||
/**
|
||||
* Raised when the {@link Gui#update()} method is called, but before the inventory is populated.
|
||||
* Use this method in a Gui subclass to analyze given data and set other parameters accordingly.
|
||||
*/
|
||||
protected void onAfterUpdate() {}
|
||||
|
||||
/**
|
||||
* Called when the inventory needs to be (re)populated.
|
||||
*
|
||||
* @param inventory The inventory to populate
|
||||
*/
|
||||
abstract protected void populate(Inventory inventory);
|
||||
|
||||
/**
|
||||
* Raised when an action is performed on an item in the inventory.
|
||||
*
|
||||
* @param event The click event data.
|
||||
*/
|
||||
abstract protected void onClick(InventoryClickEvent event);
|
||||
|
||||
|
||||
/**
|
||||
* Raised when an drag is performed on the inventory.
|
||||
* The default behaviour is to cancel any event that affects the GUI.
|
||||
*
|
||||
* @param event The drag event data.
|
||||
*/
|
||||
protected void onDrag(InventoryDragEvent event)
|
||||
{
|
||||
if(affectsGui(event)) event.setCancelled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the given event affects the GUI's inventory.
|
||||
*
|
||||
* @param event The event to test
|
||||
* @return {@code true} if the event's slot is in the GUI's inventory,
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
static protected boolean affectsGui(InventoryClickEvent event)
|
||||
{
|
||||
return event.getRawSlot() < event.getInventory().getSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the given event affects the GUI's inventory.
|
||||
*
|
||||
* @param event The event to test
|
||||
* @return true if any of the event's slots is in the GUI's inventory,
|
||||
* false otherwise.
|
||||
*/
|
||||
static protected boolean affectsGui(InventoryDragEvent event)
|
||||
{
|
||||
for(int slot : event.getRawSlots())
|
||||
{
|
||||
if(slot < event.getInventory().getSize())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Raised when the GUI is being closed.
|
||||
* Use this method to cleanup data.
|
||||
*/
|
||||
protected void onClose() {}
|
||||
|
||||
|
||||
/* ===== Getters & Setters ===== */
|
||||
|
||||
/** @return If the GUI is currently open or not. */
|
||||
public boolean isOpen() { return open; }
|
||||
|
||||
/** @return The player this Gui instance is associated to. */
|
||||
protected Player getPlayer() { return player; }
|
||||
|
||||
/** @return The size of the inventory. */
|
||||
protected int getSize() { return size; }
|
||||
|
||||
/**
|
||||
* Sets the new size of the inventory.
|
||||
* The given value is raised to be a multiple of the size of an inventory's
|
||||
* row, and is capped to the maximal size of an inventory.
|
||||
* It will be applied on the next GUI update.
|
||||
* @param size The new size of the inventory.
|
||||
*/
|
||||
protected void setSize(int size)
|
||||
{
|
||||
this.size = Math.min(((int)(Math.ceil((double) size / INVENTORY_ROW_SIZE))) * INVENTORY_ROW_SIZE, MAX_INVENTORY_SIZE);
|
||||
}
|
||||
|
||||
/** @return The title of the inventory. */
|
||||
protected String getTitle() { return title; }
|
||||
|
||||
/**
|
||||
* Sets the new title of the inventory.
|
||||
* It will be applied on the next GUI update.
|
||||
* @param title The new title of the inventory
|
||||
*/
|
||||
protected void setTitle(String title){this.title = title;}
|
||||
|
||||
/** @return The underlying inventory, or null if the Gui has not been opened yet. */
|
||||
public Inventory getInventory() { return inventory; }
|
||||
|
||||
|
||||
/* ===== Static API ===== */
|
||||
|
||||
/**
|
||||
* A map of all the currently open GUIs, associated to the HumanEntity
|
||||
* that requested it.
|
||||
*/
|
||||
static private HashMap<Player, Gui> openGuis = null;
|
||||
|
||||
/**
|
||||
* The Bukkit listener for all GUI-related events.
|
||||
*/
|
||||
static private GuiListener listener = null;
|
||||
|
||||
/**
|
||||
* Initializes the GUI listeners.
|
||||
* This method must be called on plugin enabling.
|
||||
* @param plugin The plugin the GUI listeners will be registered on
|
||||
*/
|
||||
static public void init(Plugin plugin)
|
||||
{
|
||||
openGuis = new HashMap<>();
|
||||
listener = new GuiListener();
|
||||
plugin.getServer().getPluginManager().registerEvents(listener, plugin);
|
||||
GuiUtils.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the GUI states.
|
||||
* This method must be called on plugin disabling.
|
||||
*/
|
||||
static public void exit()
|
||||
{
|
||||
openGuis.clear();
|
||||
openGuis = null;
|
||||
listener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a GUI for a player.
|
||||
* @param <T> A GUI type.
|
||||
* @param owner The player the GUI will be shown to.
|
||||
* @param gui The GUI.
|
||||
* @return The opened GUI.
|
||||
*/
|
||||
static public <T extends Gui> T open(Player owner, T gui)
|
||||
{
|
||||
close(owner);
|
||||
((Gui)gui).open(owner);/* JAVA GENERICS Y U NO WORK */
|
||||
|
||||
return gui;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes any open GUI for a given player.
|
||||
* @param owner The player.
|
||||
*/
|
||||
static public void close(Player owner)
|
||||
{
|
||||
Gui openGui = openGuis.get(owner);
|
||||
if(openGui != null) openGui.close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements a Bukkit listener for all GUI-related events.
|
||||
*/
|
||||
static private class GuiListener implements Listener
|
||||
{
|
||||
@EventHandler
|
||||
public void onInventoryDrag(InventoryDragEvent event)
|
||||
{
|
||||
if(!(event.getWhoClicked() instanceof Player)) return;
|
||||
Player owner = (Player) event.getWhoClicked();
|
||||
Gui openGui = openGuis.get(owner);
|
||||
if(openGui == null) return;
|
||||
|
||||
openGui.onDrag(event);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClick(InventoryClickEvent event)
|
||||
{
|
||||
if(!(event.getWhoClicked() instanceof Player)) return;
|
||||
Player owner = (Player) event.getWhoClicked();
|
||||
Gui openGui = openGuis.get(owner);
|
||||
if(openGui == null) return;
|
||||
|
||||
openGui.onClick(event);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClose(InventoryCloseEvent event)
|
||||
{
|
||||
if(!(event.getPlayer() instanceof Player)) return;
|
||||
Player owner = (Player) event.getPlayer();
|
||||
Gui openGui = openGuis.get(owner);
|
||||
if(openGui == null) return;
|
||||
if(!openGui.isOpen()) return;
|
||||
|
||||
openGui.onClose();
|
||||
openGuis.remove(owner);
|
||||
}
|
||||
}
|
||||
}
|
@ -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.guiproko.core;
|
||||
|
||||
import fr.moribus.imageonmap.*;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.inventory.*;
|
||||
import org.bukkit.inventory.meta.*;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* Various utility methods for GUIs.
|
||||
*/
|
||||
abstract public class GuiUtils
|
||||
{
|
||||
static private Method addItemFlagsMethod = null;
|
||||
static private Object[] itemFlagValues = null;
|
||||
|
||||
/**
|
||||
* Initializes the GUI utilities. This method must be called on plugin enabling.
|
||||
*/
|
||||
static public void init()
|
||||
{
|
||||
try
|
||||
{
|
||||
Class<?> itemFlagClass = Class.forName("org.bukkit.inventory.ItemFlag");
|
||||
Method valuesMethod = itemFlagClass.getDeclaredMethod("values");
|
||||
itemFlagValues = (Object[]) valuesMethod.invoke(null);
|
||||
addItemFlagsMethod = ItemMeta.class.getMethod("addItemFlags", itemFlagClass);
|
||||
addItemFlagsMethod.setAccessible(true);
|
||||
}
|
||||
catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e)
|
||||
{
|
||||
// Not supported :c
|
||||
}
|
||||
catch (InvocationTargetException e)
|
||||
{
|
||||
PluginLogger.error("Exception occurred while looking for the ItemFlag API.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides all the item attributes of the given {@link ItemMeta}.
|
||||
*
|
||||
* @param meta The {@link ItemMeta} to hide attributes from.
|
||||
*/
|
||||
static public void hideItemAttributes(ItemMeta meta)
|
||||
{
|
||||
if (addItemFlagsMethod == null) return;
|
||||
try
|
||||
{
|
||||
addItemFlagsMethod.invoke(meta, itemFlagValues);
|
||||
}
|
||||
catch (IllegalAccessException | InvocationTargetException ex)
|
||||
{
|
||||
PluginLogger.error("Exception occurred while invoking the ItemMeta.addItemFlags method.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stores the ItemStack at the given index of a GUI's inventory. The inventory is only updated
|
||||
* the next time the Bukkit Scheduler runs (i.e. next server tick).
|
||||
*
|
||||
* @param gui The GUI to update
|
||||
* @param slot The slot where to put the ItemStack
|
||||
* @param item The ItemStack to set
|
||||
*/
|
||||
static public void setItemLater(Gui gui, int slot, ItemStack item)
|
||||
{
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(ImageOnMap.getPlugin(),
|
||||
new CreateDisplayItemTask(gui.getInventory(), item, slot));
|
||||
}
|
||||
|
||||
/**
|
||||
* One-liner to construct an {@link ItemStack}.
|
||||
*
|
||||
* @param material The stack's material.
|
||||
*
|
||||
* @return The constructed {@link ItemStack}.
|
||||
*/
|
||||
static public ItemStack makeItem(Material material)
|
||||
{
|
||||
return makeItem(material, null, (List<String>) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* One-liner to construct an {@link ItemStack}.
|
||||
*
|
||||
* @param material The stack's material.
|
||||
* @param title The stack's title.
|
||||
*
|
||||
* @return The constructed {@link ItemStack}.
|
||||
*/
|
||||
static public ItemStack makeItem(Material material, String title)
|
||||
{
|
||||
return makeItem(material, title, (List<String>) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* One-liner to construct an {@link ItemStack}.
|
||||
*
|
||||
* @param material The stack's material.
|
||||
* @param title The stack's title.
|
||||
* @param loreLines The stack's lore lines.
|
||||
*
|
||||
* @return The constructed {@link ItemStack}.
|
||||
*/
|
||||
static public ItemStack makeItem(Material material, String title, String... loreLines)
|
||||
{
|
||||
return makeItem(material, title, Arrays.asList(loreLines));
|
||||
}
|
||||
|
||||
/**
|
||||
* One-liner to construct an {@link ItemStack}.
|
||||
*
|
||||
* @param material The stack's material.
|
||||
* @param title The stack's title.
|
||||
* @param loreLines The stack's lore lines.
|
||||
*
|
||||
* @return The constructed {@link ItemStack}.
|
||||
*/
|
||||
static public ItemStack makeItem(Material material, String title, List<String> loreLines)
|
||||
{
|
||||
return makeItem(new ItemStack(material), title, loreLines);
|
||||
}
|
||||
|
||||
/**
|
||||
* One-liner to update an {@link ItemStack}'s {@link ItemMeta}.
|
||||
*
|
||||
* If the stack is a map, it's attributes will be hidden.
|
||||
*
|
||||
* @param itemStack The original {@link ItemStack}. This stack will be directly modified.
|
||||
* @param title The stack's title.
|
||||
* @param loreLines A list containing the stack's lines.
|
||||
*
|
||||
* @return The same {@link ItemStack}, but with an updated {@link ItemMeta}.
|
||||
*/
|
||||
static public ItemStack makeItem(ItemStack itemStack, String title, List<String> loreLines)
|
||||
{
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
meta.setDisplayName(title);
|
||||
meta.setLore(loreLines);
|
||||
|
||||
if (itemStack.getType().equals(Material.MAP))
|
||||
hideItemAttributes(meta);
|
||||
|
||||
itemStack.setItemMeta(meta);
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements a bukkit runnable that updates an inventory slot later.
|
||||
*/
|
||||
static private class CreateDisplayItemTask implements Runnable
|
||||
{
|
||||
private final Inventory inventory;
|
||||
private final ItemStack item;
|
||||
private final int slot;
|
||||
|
||||
public CreateDisplayItemTask(Inventory inventory, ItemStack item, int slot)
|
||||
{
|
||||
this.inventory = inventory;
|
||||
this.item = item;
|
||||
this.slot = slot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
inventory.setItem(slot, item);
|
||||
for (HumanEntity player : inventory.getViewers())
|
||||
{
|
||||
((Player) player).updateInventory();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,187 +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.guiproko.list;
|
||||
|
||||
import fr.moribus.imageonmap.*;
|
||||
import fr.moribus.imageonmap.guiproko.core.*;
|
||||
import fr.moribus.imageonmap.map.*;
|
||||
import fr.moribus.imageonmap.ui.*;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.inventory.*;
|
||||
import org.bukkit.inventory.meta.*;
|
||||
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public class MapListGui extends ExplorerGui<ImageMap>
|
||||
{
|
||||
private final NumberFormat bigNumbersFormatter = new DecimalFormat("###,###,###,###", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
|
||||
|
||||
|
||||
@Override
|
||||
protected ItemStack getViewItem(ImageMap map)
|
||||
{
|
||||
ItemStack icon = new ItemStack(Material.MAP);
|
||||
|
||||
|
||||
ItemMeta meta = icon.getItemMeta();
|
||||
|
||||
meta.setDisplayName(ChatColor.GREEN + "" + ChatColor.BOLD + map.getName());
|
||||
|
||||
String mapDescription;
|
||||
if(map instanceof SingleMap)
|
||||
mapDescription = "Single map";
|
||||
else
|
||||
mapDescription = "Poster map (" + ((PosterMap) map).getColumnCount() + "×" + ((PosterMap) map).getRowCount() + ")";
|
||||
|
||||
meta.setLore(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"
|
||||
));
|
||||
|
||||
GuiUtils.hideItemAttributes(meta);
|
||||
|
||||
icon.setItemMeta(meta);
|
||||
|
||||
|
||||
return 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));
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
@ -1,47 +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.guiproko.list;
|
||||
|
||||
import fr.moribus.imageonmap.guiproko.core.ExplorerGui;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class MaterialGui extends ExplorerGui<Material>
|
||||
{
|
||||
|
||||
@Override
|
||||
protected ItemStack getViewItem(Material data)
|
||||
{
|
||||
return new ItemStack(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRightClick(Material data)
|
||||
{
|
||||
getPlayer().sendMessage("You clicked : " + data.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUpdate()
|
||||
{
|
||||
setTitle("All da materials");
|
||||
setData(Material.values());
|
||||
}
|
||||
|
||||
}
|
@ -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 IO", 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -18,10 +18,10 @@
|
||||
|
||||
package fr.moribus.imageonmap.ui;
|
||||
|
||||
import fr.moribus.imageonmap.guiproko.core.GuiUtils;
|
||||
import fr.moribus.imageonmap.map.ImageMap;
|
||||
import fr.moribus.imageonmap.map.PosterMap;
|
||||
import fr.moribus.imageonmap.map.SingleMap;
|
||||
import fr.zcraft.zlib.components.gui.GuiUtils;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user