Merge pull request #56 from JEFF-Media-GbR/refill-hotbar

7.7-pre1
This commit is contained in:
JEFF 2020-05-20 19:27:14 +02:00 committed by GitHub
commit fe9fca02ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 388 additions and 890 deletions

View File

@ -1,5 +1,10 @@
# Changelog
## 7.7-pre1
- Moved /invsort command to separate class
- Moved registerPlayerIfNeeded from Listener to main class
- Save player configs only if they have changed
## 7.6.1
- Changed description for hotkeys in config.yml
- Updated French translation

View File

@ -6,7 +6,7 @@
<groupId>de.jeffclan</groupId>
<artifactId>JeffChestSort</artifactId>
<version>7.6.1</version>
<version>7.7-pre1</version>
<packaging>jar</packaging>
<name>JeffChestSort</name>

View File

@ -0,0 +1,92 @@
package de.jeffclan.JeffChestSort;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import de.jeffclan.JeffChestSort.JeffChestSortPlayerSetting;
import de.jeffclan.JeffChestSort.JeffChestSortPlugin;
public class JeffChestSortChestSortCommand implements CommandExecutor {
JeffChestSortPlugin plugin;
JeffChestSortChestSortCommand(JeffChestSortPlugin plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
// This command toggles automatic chest sorting for the player that runs the command
if (!command.getName().equalsIgnoreCase("chestsort")) {
return false;
}
if (!(sender instanceof Player)) {
if(args.length!=0) {
if(args[0].equalsIgnoreCase("debug")) {
plugin.debug=true;
plugin.getLogger().info("ChestSort debug mode enabled.");
return true;
}
}
sender.sendMessage(plugin.messages.MSG_PLAYERSONLY);
return true;
}
Player p = (Player) sender;
// fix for Spigot's stupid /reload function
plugin.registerPlayerIfNeeded(p);
// Settings GUI
if(args.length>0) {
if(args[0].equalsIgnoreCase("hotkey") || args[0].equalsIgnoreCase("hotkeys")) {
// if(plugin.hotkeyGUI==false) {
// p.sendMessage(plugin.messages.MSG_ERR_HOTKEYSDISABLED);
// return true;
// }
plugin.settingsGUI.openGUI(p);
return true;
}
}
// Settings GUI End
JeffChestSortPlayerSetting setting = plugin.perPlayerSettings.get(p.getUniqueId().toString());
if(args.length>0
&& !args[0].equalsIgnoreCase("toggle")
&& !args[0].equalsIgnoreCase("on")
&& !args[0].equalsIgnoreCase("off")) {
p.sendMessage(String.format(plugin.messages.MSG_INVALIDOPTIONS,"\""+args[0]+"\"","\"toggle\", \"on\", \"off\", \"hotkeys\""));
return true;
}
if(args.length==0 || args[0].equalsIgnoreCase("toggle")) {
setting.toggleChestSorting();
}
else if(args[0].equalsIgnoreCase("on")) {
setting.enableChestSorting();
}
else if(args[0].equalsIgnoreCase("off")) {
setting.disableChestSorting();
}
setting.hasSeenMessage=true;
if (setting.sortingEnabled) {
p.sendMessage(plugin.messages.MSG_ACTIVATED);
} else {
p.sendMessage(plugin.messages.MSG_DEACTIVATED);
}
return true;
}
}

View File

@ -1,149 +0,0 @@
package de.jeffclan.JeffChestSort;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class JeffChestSortCommandExecutor implements CommandExecutor {
JeffChestSortPlugin plugin;
JeffChestSortCommandExecutor(JeffChestSortPlugin plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
// This command toggles automatic chest sorting for the player that runs the command
if (command.getName().equalsIgnoreCase("chestsort")) {
if (!(sender instanceof Player)) {
if(args.length!=0) {
if(args[0].equalsIgnoreCase("debug")) {
plugin.debug=true;
sender.sendMessage("ChestSort debug mode enabled.");
return true;
} else if(args[0].equalsIgnoreCase("reload")) {
// TODO: EXPERIMENTAL
plugin.onDisable();
plugin.onEnable();
}
}
sender.sendMessage(plugin.messages.MSG_PLAYERSONLY);
return true;
}
Player p = (Player) sender;
// fix for Spigot's stupid /reload function
plugin.listener.registerPlayerIfNeeded(p);
// Settings GUI
if(args.length>0) {
if(args[0].equalsIgnoreCase("hotkey") || args[0].equalsIgnoreCase("hotkeys")) {
// if(plugin.hotkeyGUI==false) {
// p.sendMessage(plugin.messages.MSG_ERR_HOTKEYSDISABLED);
// return true;
// }
plugin.settingsGUI.openGUI(p);
return true;
}
}
// Settings GUI End
JeffChestSortPlayerSetting setting = plugin.PerPlayerSettings.get(p.getUniqueId().toString());
if(args.length>0
&& !args[0].equalsIgnoreCase("toggle")
&& !args[0].equalsIgnoreCase("on")
&& !args[0].equalsIgnoreCase("off")) {
p.sendMessage(String.format(plugin.messages.MSG_INVALIDOPTIONS,"\""+args[0]+"\"","\"toggle\", \"on\", \"off\", \"hotkeys\""));
return true;
}
if(args.length==0 || args[0].equalsIgnoreCase("toggle")) {
setting.sortingEnabled = !setting.sortingEnabled;
}
else if(args[0].equalsIgnoreCase("on")) {
setting.sortingEnabled = true;
}
else if(args[0].equalsIgnoreCase("off")) {
setting.sortingEnabled = false;
}
setting.hasSeenMessage=true;
if (setting.sortingEnabled) {
p.sendMessage(plugin.messages.MSG_ACTIVATED);
} else {
p.sendMessage(plugin.messages.MSG_DEACTIVATED);
}
return true;
} else if(command.getName().equalsIgnoreCase("invsort")) {
// This command sorts the player's inventory
if (!(sender instanceof Player)) {
sender.sendMessage(plugin.messages.MSG_PLAYERSONLY);
return true;
}
Player p = (Player) sender;
int start = 9;
int end = 35;
JeffChestSortPlayerSetting setting = plugin.PerPlayerSettings.get(p.getUniqueId().toString());
if(args.length>0) {
if(args[0].equalsIgnoreCase("all")) {
start=0;
end=35;
} else if(args[0].equalsIgnoreCase("hotbar")) {
start=0;
end=8;
} else if(args[0].equalsIgnoreCase("inv")) {
start=9;
end=35;
} else if(args[0].equalsIgnoreCase("on")) {
setting.invSortingEnabled = true;
p.sendMessage(plugin.messages.MSG_INVACTIVATED);
return true;
} else if(args[0].equalsIgnoreCase("off")) {
setting.invSortingEnabled = false;
p.sendMessage(plugin.messages.MSG_INVDEACTIVATED);
return true;
} else if(args[0].equalsIgnoreCase("toggle")) {
setting.invSortingEnabled = !setting.invSortingEnabled;
if(setting.invSortingEnabled) {
p.sendMessage(plugin.messages.MSG_INVACTIVATED);
} else {
p.sendMessage(plugin.messages.MSG_INVDEACTIVATED);
}
return true;
}
else {
p.sendMessage(String.format(plugin.messages.MSG_INVALIDOPTIONS,"\""+args[0]+"\"","\"on\", \"off\", \"toggle\", \"inv\", \"hotbar\", \"all\""));
return true;
}
}
plugin.sortInventory(p.getInventory(), start, end);
p.sendMessage(plugin.messages.MSG_PLAYERINVSORTED);
return true;
}
return false;
}
}

View File

@ -0,0 +1,76 @@
package de.jeffclan.JeffChestSort;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class JeffChestSortInvSortCommand implements CommandExecutor {
JeffChestSortPlugin plugin;
JeffChestSortInvSortCommand(JeffChestSortPlugin plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
// This command toggles automatic chest sorting for the player that runs the command
if (!command.getName().equalsIgnoreCase("invsort")) {
return false;
}
if (!(sender instanceof Player)) {
sender.sendMessage(plugin.messages.MSG_PLAYERSONLY);
return true;
}
Player p = (Player) sender;
int start = 9;
int end = 35;
JeffChestSortPlayerSetting setting = plugin.perPlayerSettings.get(p.getUniqueId().toString());
if(args.length>0) {
if(args[0].equalsIgnoreCase("all")) {
start=0;
end=35;
} else if(args[0].equalsIgnoreCase("hotbar")) {
start=0;
end=8;
} else if(args[0].equalsIgnoreCase("inv")) {
start=9;
end=35;
} else if(args[0].equalsIgnoreCase("on")) {
setting.enableInvSorting();
p.sendMessage(plugin.messages.MSG_INVACTIVATED);
return true;
} else if(args[0].equalsIgnoreCase("off")) {
setting.disableInvSorting();
p.sendMessage(plugin.messages.MSG_INVDEACTIVATED);
return true;
} else if(args[0].equalsIgnoreCase("toggle")) {
setting.toggleInvSorting();
if(setting.invSortingEnabled) {
p.sendMessage(plugin.messages.MSG_INVACTIVATED);
} else {
p.sendMessage(plugin.messages.MSG_INVDEACTIVATED);
}
return true;
}
else {
p.sendMessage(String.format(plugin.messages.MSG_INVALIDOPTIONS,"\""+args[0]+"\"","\"on\", \"off\", \"toggle\", \"inv\", \"hotbar\", \"all\""));
return true;
}
}
plugin.sortInventory(p.getInventory(), start, end);
p.sendMessage(plugin.messages.MSG_PLAYERINVSORTED);
return true;
}
}

View File

@ -1,13 +1,9 @@
package de.jeffclan.JeffChestSort;
import java.io.File;
import java.util.UUID;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.block.Chest;
import org.bukkit.block.DoubleChest;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -38,11 +34,6 @@ public class JeffChestSortListener implements Listener {
// DEBUG
// To enable debug mode, put debug: true into your config.yml
// Checking for my username because I always forget to comment this out before
// releases
// if (event.getPlayer().getName().equalsIgnoreCase("mfnalex")) {
// plugin.debug = true;
// }
// OPs will get an update notice if a new update is available
if (event.getPlayer().isOp()) {
@ -50,67 +41,10 @@ public class JeffChestSortListener implements Listener {
}
// Put player into our perPlayerSettings map
registerPlayerIfNeeded(event.getPlayer());
plugin.registerPlayerIfNeeded(event.getPlayer());
}
// Put player into our perPlayerSettings map
void registerPlayerIfNeeded(Player p) {
// Players are stored by their UUID, so that name changes don't break player's
// settings
UUID uniqueId = p.getUniqueId();
// Add player to map only if they aren't registered already
if (!plugin.PerPlayerSettings.containsKey(uniqueId.toString())) {
// Player settings are stored in a file named after the player's UUID
File playerFile = new File(plugin.getDataFolder() + File.separator + "playerdata",
p.getUniqueId().toString() + ".yml");
YamlConfiguration playerConfig = YamlConfiguration.loadConfiguration(playerFile);
playerConfig.addDefault("invSortingEnabled", plugin.getConfig().getBoolean("inv-sorting-enabled-by-default"));
playerConfig.addDefault("middleClick", plugin.getConfig().getBoolean("hotkeys.middle-click"));
playerConfig.addDefault("shiftClick", plugin.getConfig().getBoolean("hotkeys.shift-click"));
playerConfig.addDefault("doubleClick", plugin.getConfig().getBoolean("hotkeys.double-click"));
playerConfig.addDefault("shiftRightClick", plugin.getConfig().getBoolean("hotkeys.shift-right-click"));
boolean activeForThisPlayer = false;
boolean invActiveForThisPlayer = false;
boolean middleClick, shiftClick, doubleClick, shiftRightClick;
if (!playerFile.exists()) {
// If the player settings file does not exist for this player, set it to the
// default value
activeForThisPlayer = plugin.getConfig().getBoolean("sorting-enabled-by-default");
invActiveForThisPlayer = plugin.getConfig().getBoolean("inv-sorting-enabled-by-default");
middleClick = plugin.getConfig().getBoolean("hotkeys.middle-click");
shiftClick = plugin.getConfig().getBoolean("hotkeys.shift-click");
doubleClick = plugin.getConfig().getBoolean("hotkeys.double-click");
shiftRightClick = plugin.getConfig().getBoolean("hotkeys.shift-right-click");
} else {
// If the file exists, check if the player has sorting enabled
activeForThisPlayer = playerConfig.getBoolean("sortingEnabled");
invActiveForThisPlayer = playerConfig.getBoolean("invSortingEnabled");
middleClick = playerConfig.getBoolean("middleClick");
shiftClick = playerConfig.getBoolean("shiftClick");
doubleClick = playerConfig.getBoolean("doubleClick");
shiftRightClick = playerConfig.getBoolean("shiftRightClick");
}
JeffChestSortPlayerSetting newSettings = new JeffChestSortPlayerSetting(activeForThisPlayer,invActiveForThisPlayer,middleClick,shiftClick,doubleClick,shiftRightClick);
// when "show-message-again-after-logout" is enabled, we don't care if the
// player already saw the message
if (!plugin.getConfig().getBoolean("show-message-again-after-logout")) {
newSettings.hasSeenMessage = playerConfig.getBoolean("hasSeenMessage");
}
// Finally add the PlayerSetting object to the map
plugin.PerPlayerSettings.put(uniqueId.toString(), newSettings);
}
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
plugin.unregisterPlayer(event.getPlayer());
@ -127,9 +61,9 @@ public class JeffChestSortListener implements Listener {
Player p = (Player) event.getInventory().getHolder();
if(!p.hasPermission("chestsort.use.inventory")) return;
registerPlayerIfNeeded(p);
plugin.registerPlayerIfNeeded(p);
JeffChestSortPlayerSetting setting = plugin.PerPlayerSettings.get(p.getUniqueId().toString());
JeffChestSortPlayerSetting setting = plugin.perPlayerSettings.get(p.getUniqueId().toString());
if(!setting.invSortingEnabled) return;
plugin.organizer.sortInventory(p.getInventory(),9,35);
@ -251,12 +185,12 @@ public class JeffChestSortListener implements Listener {
}
// Fixes exception when using Spigot's stupid /reload command
registerPlayerIfNeeded(p);
plugin.registerPlayerIfNeeded(p);
// Get the current player's settings
// We do not immediately cancel when sorting is disabled because we might want
// to show the hint message
JeffChestSortPlayerSetting setting = plugin.PerPlayerSettings.get(p.getUniqueId().toString());
JeffChestSortPlayerSetting setting = plugin.perPlayerSettings.get(p.getUniqueId().toString());
// Show "how to enable ChestSort" message when ALL of the following criteria are
// met:
@ -323,7 +257,7 @@ public class JeffChestSortListener implements Listener {
Player p = (Player) event.getWhoClicked();
registerPlayerIfNeeded(p);
plugin.registerPlayerIfNeeded(p);
if(!plugin.getConfig().getBoolean("allow-hotkeys")) {
return;
@ -349,7 +283,7 @@ public class JeffChestSortListener implements Listener {
boolean sort = false;
JeffChestSortPlayerSetting setting = plugin.PerPlayerSettings.get(p.getUniqueId().toString());
JeffChestSortPlayerSetting setting = plugin.perPlayerSettings.get(p.getUniqueId().toString());
// Do not sort the GUI inventory
if(event.getClickedInventory() == setting.guiInventory) {
@ -439,55 +373,5 @@ public class JeffChestSortListener implements Listener {
}
}
}
@EventHandler
void onGUIInteract(InventoryClickEvent event) {
if(plugin.hotkeyGUI==false) {
return;
}
if(!(event.getWhoClicked() instanceof Player)) {
return;
}
Player p = (Player) event.getWhoClicked();
registerPlayerIfNeeded(p);
JeffChestSortPlayerSetting setting = plugin.PerPlayerSettings.get(p.getUniqueId().toString());
if(setting.guiInventory==null) {
return;
}
if(event.getClickedInventory()==null) {
return;
}
if(!event.getClickedInventory().equals(setting.guiInventory)) {
return;
}
// We only get this far if the player has clicked inside his GUI inventory
event.setCancelled(true);
if(event.getClick() != ClickType.LEFT) {
return;
}
if(event.getSlot() == JeffChestSortSettingsGUI.slotMiddleClick) {
setting.middleClick = !setting.middleClick;
plugin.settingsGUI.openGUI(p);
return;
}
else if(event.getSlot() == JeffChestSortSettingsGUI.slotShiftClick) {
setting.shiftClick = !setting.shiftClick;
plugin.settingsGUI.openGUI(p);
return;
} else if(event.getSlot() == JeffChestSortSettingsGUI.slotDoubleClick) {
setting.doubleClick = !setting.doubleClick;
plugin.settingsGUI.openGUI(p);
return;
} else if(event.getSlot() == JeffChestSortSettingsGUI.slotShiftRightClick) {
setting.shiftRightClick = !setting.shiftRightClick;
plugin.settingsGUI.openGUI(p);
return;
}
}
}

View File

@ -22,14 +22,59 @@ public class JeffChestSortPlayerSetting {
// Did we already show the message how to activate sorting?
boolean hasSeenMessage = false;
// Do we have to save these settings?
boolean changed = false;
JeffChestSortPlayerSetting(boolean sortingEnabled, boolean invSortingEnabled, boolean middleClick, boolean shiftClick, boolean doubleClick, boolean shiftRightClick) {
JeffChestSortPlayerSetting(boolean sortingEnabled, boolean invSortingEnabled, boolean middleClick, boolean shiftClick, boolean doubleClick, boolean shiftRightClick, boolean changed) {
this.sortingEnabled = sortingEnabled;
this.middleClick = middleClick;
this.shiftClick = shiftClick;
this.doubleClick = doubleClick;
this.shiftRightClick = shiftRightClick;
this.invSortingEnabled = invSortingEnabled;
this.changed = changed;
}
void toggleMiddleClick() {
middleClick = !middleClick;
changed = true;
}
void toggleShiftClick() {
shiftClick = !shiftClick;
changed = true;
}
void toggleDoubleClick() {
doubleClick = !doubleClick;
changed = true;
}
void toggleShiftRightClick() {
shiftRightClick = !shiftRightClick;
changed = true;
}
void enableChestSorting() {
sortingEnabled = true;
changed = true;
}
void disableChestSorting() {
sortingEnabled = false;
changed = true;
}
void toggleChestSorting() {
sortingEnabled = !sortingEnabled;
changed = true;
}
void enableInvSorting() {
invSortingEnabled = true;
changed = true;
}
void disableInvSorting() {
invSortingEnabled = false;
changed = true;
}
void toggleInvSorting() {
invSortingEnabled = !invSortingEnabled;
changed = true;
}
}

View File

@ -1,6 +1,3 @@
package de.jeffclan.JeffChestSort;
import java.io.BufferedWriter;
/*
@ -18,9 +15,6 @@ import java.io.BufferedWriter;
Please DO NOT post bug reports or feature requests in the review section at SpigotMC.org. Thank you.
NOTE: The project has been converted to maven by Azzurite (thanks again). You will need to
`mvn install` to create a working .jar.
=============================================================================================
TECHNICAL INFORMATION:
@ -32,6 +26,9 @@ import java.io.BufferedWriter;
*/
package de.jeffclan.JeffChestSort;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
@ -47,7 +44,6 @@ import java.util.UUID;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
@ -59,7 +55,7 @@ import de.jeffclan.utils.Utils;
public class JeffChestSortPlugin extends JavaPlugin {
// We need a map to store each player's settings
Map<String, JeffChestSortPlayerSetting> PerPlayerSettings = new HashMap<String, JeffChestSortPlayerSetting>();
Map<String, JeffChestSortPlayerSetting> perPlayerSettings = new HashMap<String, JeffChestSortPlayerSetting>();
JeffChestSortMessages messages;
JeffChestSortOrganizer organizer;
JeffChestSortUpdateChecker updateChecker;
@ -69,7 +65,7 @@ public class JeffChestSortPlugin extends JavaPlugin {
ArrayList<String> disabledWorlds;
int currentConfigVersion = 22;
boolean usingMatchingConfig = true;
boolean debug = false;
protected boolean debug = false;
boolean verbose = true;
boolean hotkeyGUI = true;
@ -163,7 +159,6 @@ public class JeffChestSortPlugin extends JavaPlugin {
getConfig().addDefault("hook-crackshot", true);
getConfig().addDefault("hook-crackshot-prefix", "crackshot_weapon");
getConfig().addDefault("hook-inventorypages", true);
getConfig().addDefault("verbose", true); // Prints some information in onEnable()
@ -193,31 +188,6 @@ public class JeffChestSortPlugin extends JavaPlugin {
getLogger().warning("==============================================");
}
private void renameConfigIfTooOld() {
getLogger().warning("========================================================");
getLogger().warning("You are using a config file that has been generated");
getLogger().warning("prior to ChestSort version 2.0.0.");
getLogger().warning("To allow everyone to use the new features, your config");
getLogger().warning("has been renamed to config.old.yml and a new one has");
getLogger().warning("been generated. Please examine the new config file to");
getLogger().warning("see the new possibilities and adjust your settings.");
getLogger().warning("========================================================");
File configFile = new File(getDataFolder().getAbsolutePath() + File.separator + "config.yml");
File oldConfigFile = new File(getDataFolder().getAbsolutePath() + File.separator + "config.old.yml");
if (oldConfigFile.getAbsoluteFile().exists()) {
oldConfigFile.getAbsoluteFile().delete();
}
configFile.getAbsoluteFile().renameTo(oldConfigFile.getAbsoluteFile());
saveDefaultConfig();
try {
getConfig().load(configFile.getAbsoluteFile());
} catch (IOException | InvalidConfigurationException e) {
getLogger().warning("Could not load freshly generated config file!");
e.printStackTrace();
}
}
@Override
public void onDisable() {
// We have to unregister every player to save their perPlayerSettings
@ -233,12 +203,6 @@ public class JeffChestSortPlugin extends JavaPlugin {
mcVersion = tmpVersion.substring(tmpVersion.lastIndexOf('.') + 1);
tmpVersion = mcVersion.substring(mcVersion.indexOf("_")+1);
mcMinorVersion = Integer.parseInt(tmpVersion.substring(0,tmpVersion.indexOf("_")));
//getLogger().info("Running MC version 1."+mcMinorVersion);
// if(mcMinorVersion < 9) {
// getLogger().info("You are running a Minecraft version below 1.9. Hotkey GUI will be disabled.");
// hotkeyGUI = false;
// }
// Create the config file, including checks for old config versions, and load
// the default values for unset options
@ -281,19 +245,25 @@ public class JeffChestSortPlugin extends JavaPlugin {
// the Organizer to sort inventories when a player closes a chest, shulkerbox or
// barrel inventory
listener = new JeffChestSortListener(this);
//hotbarRefiller = new JeffChestSortHotbarRefiller(this);
// The sorting method will determine how stuff is sorted
sortingMethod = getConfig().getString("sorting-method");
// Register the events for our Listener
getServer().getPluginManager().registerEvents(listener, this);
// Register events for the GUI interaction
getServer().getPluginManager().registerEvents(settingsGUI, this);
// Create the CommandExecutor, register commands and set their TabCompleter
JeffChestSortCommandExecutor commandExecutor = new JeffChestSortCommandExecutor(this);
JeffChestSortChestSortCommand chestsortCommandExecutor = new JeffChestSortChestSortCommand(this);
JeffChestSortTabCompleter tabCompleter = new JeffChestSortTabCompleter();
this.getCommand("chestsort").setExecutor(commandExecutor);
this.getCommand("chestsort").setExecutor(chestsortCommandExecutor);
this.getCommand("chestsort").setTabCompleter(tabCompleter);
this.getCommand("invsort").setExecutor(commandExecutor);
JeffChestSortInvSortCommand invsortCommandExecutor = new JeffChestSortInvSortCommand(this);
this.getCommand("invsort").setExecutor(invsortCommandExecutor);
this.getCommand("invsort").setTabCompleter(tabCompleter);
// Does anyone actually need this?
@ -315,7 +285,6 @@ public class JeffChestSortPlugin extends JavaPlugin {
}
// Check for updates (async, of course)
// When set to true, we check for updates right now, and every 24 hours (see
// updateCheckInterval)
if (getConfig().getString("check-for-updates", "true").equalsIgnoreCase("true")) {
@ -333,6 +302,8 @@ public class JeffChestSortPlugin extends JavaPlugin {
registerMetrics();
// When dump is set to true in config.yml, we dump all items with their categories
// to find out which items are still missing in the category files
if(getConfig().getBoolean("dump")) {
try {
dump();
@ -341,7 +312,6 @@ public class JeffChestSortPlugin extends JavaPlugin {
e.printStackTrace();
}
}
}
private String getCategoryList() {
@ -483,13 +453,13 @@ public class JeffChestSortPlugin extends JavaPlugin {
// server ;) I am sometimes getting stacktraces although it is clearly stated
// that /reload is NOT
// supported. So, here is a quick fix
if (PerPlayerSettings == null) {
PerPlayerSettings = new HashMap<String, JeffChestSortPlayerSetting>();
if (perPlayerSettings == null) {
perPlayerSettings = new HashMap<String, JeffChestSortPlayerSetting>();
}
listener.registerPlayerIfNeeded(p);
listener.plugin.registerPlayerIfNeeded(p);
// End of quick fix
return PerPlayerSettings.get(p.getUniqueId().toString()).sortingEnabled;
return perPlayerSettings.get(p.getUniqueId().toString()).sortingEnabled;
}
// Unregister a player and save their settings in the playerdata folder
@ -501,8 +471,9 @@ public class JeffChestSortPlugin extends JavaPlugin {
// When using /reload or some other obscure features, it can happen that players
// are online
// but not registered. So, we only continue when the player has been registered
if (PerPlayerSettings.containsKey(uniqueId.toString())) {
JeffChestSortPlayerSetting setting = PerPlayerSettings.get(p.getUniqueId().toString());
if (perPlayerSettings.containsKey(uniqueId.toString())) {
JeffChestSortPlayerSetting setting = perPlayerSettings.get(p.getUniqueId().toString());
File playerFile = new File(getDataFolder() + File.separator + "playerdata",
p.getUniqueId().toString() + ".yml");
YamlConfiguration playerConfig = YamlConfiguration.loadConfiguration(playerFile);
@ -514,12 +485,18 @@ public class JeffChestSortPlugin extends JavaPlugin {
playerConfig.set("doubleClick",setting.doubleClick);
playerConfig.set("shiftRightClick",setting.shiftRightClick);
try {
playerConfig.save(playerFile);
// Only saved if the config has been changed
if(setting.changed) {
if(debug) {
getLogger().info("PlayerSettings for "+p.getName()+" have changed, saving to file.");
}
playerConfig.save(playerFile);
}
} catch (IOException e) {
e.printStackTrace();
}
PerPlayerSettings.remove(uniqueId.toString());
perPlayerSettings.remove(uniqueId.toString());
}
}
@ -535,4 +512,68 @@ public class JeffChestSortPlugin extends JavaPlugin {
bw.close();
}
void registerPlayerIfNeeded(Player p) {
// Players are stored by their UUID, so that name changes don't break player's
// settings
UUID uniqueId = p.getUniqueId();
// Add player to map only if they aren't registered already
if (!perPlayerSettings.containsKey(uniqueId.toString())) {
// Player settings are stored in a file named after the player's UUID
File playerFile = new File(getDataFolder() + File.separator + "playerdata",
p.getUniqueId().toString() + ".yml");
YamlConfiguration playerConfig = YamlConfiguration.loadConfiguration(playerFile);
playerConfig.addDefault("invSortingEnabled", getConfig().getBoolean("inv-sorting-enabled-by-default"));
playerConfig.addDefault("middleClick", getConfig().getBoolean("hotkeys.middle-click"));
playerConfig.addDefault("shiftClick", getConfig().getBoolean("hotkeys.shift-click"));
playerConfig.addDefault("doubleClick", getConfig().getBoolean("hotkeys.double-click"));
playerConfig.addDefault("shiftRightClick", getConfig().getBoolean("hotkeys.shift-right-click"));
boolean activeForThisPlayer = false;
boolean invActiveForThisPlayer = false;
boolean middleClick, shiftClick, doubleClick, shiftRightClick;
boolean changed = false;
if (!playerFile.exists()) {
// If the player settings file does not exist for this player, set it to the
// default value
activeForThisPlayer = getConfig().getBoolean("sorting-enabled-by-default");
invActiveForThisPlayer = getConfig().getBoolean("inv-sorting-enabled-by-default");
middleClick = getConfig().getBoolean("hotkeys.middle-click");
shiftClick = getConfig().getBoolean("hotkeys.shift-click");
doubleClick = getConfig().getBoolean("hotkeys.double-click");
shiftRightClick = getConfig().getBoolean("hotkeys.shift-right-click");
if(debug) {
getLogger().info("Player "+p.getName()+" does not have player settings yet, using default values.");
}
// Because this is new a file, we have to save it on shutdown/disconnect
changed=true;
} else {
// If the file exists, check if the player has sorting enabled
activeForThisPlayer = playerConfig.getBoolean("sortingEnabled");
invActiveForThisPlayer = playerConfig.getBoolean("invSortingEnabled");
middleClick = playerConfig.getBoolean("middleClick");
shiftClick = playerConfig.getBoolean("shiftClick");
doubleClick = playerConfig.getBoolean("doubleClick");
shiftRightClick = playerConfig.getBoolean("shiftRightClick");
}
JeffChestSortPlayerSetting newSettings = new JeffChestSortPlayerSetting(activeForThisPlayer,invActiveForThisPlayer,middleClick,shiftClick,doubleClick,shiftRightClick,changed);
// when "show-message-again-after-logout" is enabled, we don't care if the
// player already saw the message
if (!getConfig().getBoolean("show-message-again-after-logout")) {
newSettings.hasSeenMessage = playerConfig.getBoolean("hasSeenMessage");
}
// Finally add the PlayerSetting object to the map
perPlayerSettings.put(uniqueId.toString(), newSettings);
}
}
}

View File

@ -4,12 +4,16 @@ import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
public class JeffChestSortSettingsGUI {
public class JeffChestSortSettingsGUI implements Listener {
JeffChestSortPlugin plugin;
@ -32,17 +36,6 @@ public class JeffChestSortSettingsGUI {
ItemStack getItem(boolean active, Hotkey hotkey) {
ItemStack is = null;
String suffix;
//Material green = Material.getMaterial("GREEN_WOOL");
//Material red = Material.getMaterial("RED_WOOL");
//Material green = Material.GREEN_WOOL;
//Material red = Material.RED_WOOL;
// if(green==null || red==null) {
// //plugin.getLogger().warning("Using unsupported Minecraft version");
// green = Material.EMERALD_BLOCK;
// red = Material.REDSTONE_BLOCK;
// //return null;
// }
if(active) {
is = new ItemStack(green);
@ -80,13 +73,7 @@ public class JeffChestSortSettingsGUI {
void openGUI(Player player) {
Inventory inventory = createGUI("ChestSort", player);
JeffChestSortPlayerSetting setting = plugin.PerPlayerSettings.get(player.getUniqueId().toString());
// Test if running 1.13 or later
// if(Material.getMaterial("GREEN_WOOL") == null) {
// player.sendMessage(plugin.messages.MSG_ERR_HOTKEYSDISABLED);
// return;
// }
JeffChestSortPlayerSetting setting = plugin.perPlayerSettings.get(player.getUniqueId().toString());
inventory.setItem(slotMiddleClick, getItem(setting.middleClick,Hotkey.MiddleClick));
inventory.setItem(slotShiftClick, getItem(setting.shiftClick,Hotkey.ShiftClick));
@ -101,4 +88,54 @@ public class JeffChestSortSettingsGUI {
Inventory inventory = Bukkit.createInventory(inventoryHolder, InventoryType.CHEST, name);
return inventory;
}
@EventHandler
void onGUIInteract(InventoryClickEvent event) {
if(plugin.hotkeyGUI==false) {
return;
}
if(!(event.getWhoClicked() instanceof Player)) {
return;
}
Player p = (Player) event.getWhoClicked();
plugin.listener.plugin.registerPlayerIfNeeded(p);
JeffChestSortPlayerSetting setting = plugin.perPlayerSettings.get(p.getUniqueId().toString());
if(setting.guiInventory==null) {
return;
}
if(event.getClickedInventory()==null) {
return;
}
if(!event.getClickedInventory().equals(setting.guiInventory)) {
return;
}
// We only get this far if the player has clicked inside his GUI inventory
event.setCancelled(true);
if(event.getClick() != ClickType.LEFT) {
return;
}
if(event.getSlot() == JeffChestSortSettingsGUI.slotMiddleClick) {
setting.toggleMiddleClick();
plugin.settingsGUI.openGUI(p);
return;
}
else if(event.getSlot() == JeffChestSortSettingsGUI.slotShiftClick) {
setting.toggleShiftClick();
plugin.settingsGUI.openGUI(p);
return;
} else if(event.getSlot() == JeffChestSortSettingsGUI.slotDoubleClick) {
setting.toggleDoubleClick();
plugin.settingsGUI.openGUI(p);
return;
} else if(event.getSlot() == JeffChestSortSettingsGUI.slotShiftRightClick) {
setting.toggleShiftRightClick();
plugin.settingsGUI.openGUI(p);
return;
}
}
}

View File

@ -1,539 +0,0 @@
/*
* Copyright 2011-2013 Tyler Blair. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and contributors and should not be interpreted as representing official policies,
* either expressed or implied, of anybody else.
*/
package de.jeffclan.JeffChestSort;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.scheduler.BukkitTask;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.UUID;
import java.util.logging.Level;
import java.util.zip.GZIPOutputStream;
public class MetricsLite {
/**
* The current revision number
*/
private final static int REVISION = 7;
/**
* The base url of the metrics domain
*/
private static final String BASE_URL = "http://report.mcstats.org";
/**
* The url used to report a server's status
*/
private static final String REPORT_URL = "/plugin/%s";
/**
* Interval of time to ping (in minutes)
*/
private final static int PING_INTERVAL = 15;
/**
* The plugin this metrics submits for
*/
private final Plugin plugin;
/**
* The plugin configuration file
*/
private final YamlConfiguration configuration;
/**
* The plugin configuration file
*/
private final File configurationFile;
/**
* Unique server id
*/
private final String guid;
/**
* Debug mode
*/
private final boolean debug;
/**
* Lock for synchronization
*/
private final Object optOutLock = new Object();
/**
* Id of the scheduled task
*/
private volatile BukkitTask task = null;
public MetricsLite(Plugin plugin) throws IOException {
if (plugin == null) {
throw new IllegalArgumentException("Plugin cannot be null");
}
this.plugin = plugin;
// load the config
configurationFile = getConfigFile();
configuration = YamlConfiguration.loadConfiguration(configurationFile);
// add some defaults
configuration.addDefault("opt-out", false);
configuration.addDefault("guid", UUID.randomUUID().toString());
configuration.addDefault("debug", false);
// Do we need to create the file?
if (configuration.get("guid", null) == null) {
configuration.options().header("http://mcstats.org").copyDefaults(true);
configuration.save(configurationFile);
}
// Load the guid then
guid = configuration.getString("guid");
debug = configuration.getBoolean("debug", false);
}
/**
* Start measuring statistics. This will immediately create an async repeating task as the plugin and send
* the initial data to the metrics backend, and then after that it will post in increments of
* PING_INTERVAL * 1200 ticks.
*
* @return True if statistics measuring is running, otherwise false.
*/
public boolean start() {
synchronized (optOutLock) {
// Did we opt out?
if (isOptOut()) {
return false;
}
// Is metrics already running?
if (task != null) {
return true;
}
// Begin hitting the server with glorious data
task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() {
private boolean firstPost = true;
public void run() {
try {
// This has to be synchronized or it can collide with the disable method.
synchronized (optOutLock) {
// Disable Task, if it is running and the server owner decided to opt-out
if (isOptOut() && task != null) {
task.cancel();
task = null;
}
}
// We use the inverse of firstPost because if it is the first time we are posting,
// it is not a interval ping, so it evaluates to FALSE
// Each time thereafter it will evaluate to TRUE, i.e PING!
postPlugin(!firstPost);
// After the first post we set firstPost to false
// Each post thereafter will be a ping
firstPost = false;
} catch (IOException e) {
if (debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage());
}
}
}
}, 0, PING_INTERVAL * 1200);
return true;
}
}
/**
* Has the server owner denied plugin metrics?
*
* @return true if metrics should be opted out of it
*/
public boolean isOptOut() {
synchronized (optOutLock) {
try {
// Reload the metrics file
configuration.load(getConfigFile());
} catch (IOException ex) {
if (debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
}
return true;
} catch (InvalidConfigurationException ex) {
if (debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
}
return true;
}
return configuration.getBoolean("opt-out", false);
}
}
/**
* Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task.
*
* @throws java.io.IOException
*/
public void enable() throws IOException {
// This has to be synchronized or it can collide with the check in the task.
synchronized (optOutLock) {
// Check if the server owner has already set opt-out, if not, set it.
if (isOptOut()) {
configuration.set("opt-out", false);
configuration.save(configurationFile);
}
// Enable Task, if it is not running
if (task == null) {
start();
}
}
}
/**
* Disables metrics for the server by setting "opt-out" to true in the config file and canceling the metrics task.
*
* @throws java.io.IOException
*/
public void disable() throws IOException {
// This has to be synchronized or it can collide with the check in the task.
synchronized (optOutLock) {
// Check if the server owner has already set opt-out, if not, set it.
if (!isOptOut()) {
configuration.set("opt-out", true);
configuration.save(configurationFile);
}
// Disable Task, if it is running
if (task != null) {
task.cancel();
task = null;
}
}
}
/**
* Gets the File object of the config file that should be used to store data such as the GUID and opt-out status
*
* @return the File object for the config file
*/
public File getConfigFile() {
// I believe the easiest way to get the base folder (e.g craftbukkit set via -P) for plugins to use
// is to abuse the plugin object we already have
// plugin.getDataFolder() => base/plugins/PluginA/
// pluginsFolder => base/plugins/
// The base is not necessarily relative to the startup directory.
File pluginsFolder = plugin.getDataFolder().getParentFile();
// return => base/plugins/PluginMetrics/config.yml
return new File(new File(pluginsFolder, "PluginMetrics"), "config.yml");
}
/**
* Gets the online player (backwards compatibility)
*
* @return online player amount
*/
private int getOnlinePlayers() {
try {
Method onlinePlayerMethod = Server.class.getMethod("getOnlinePlayers");
if(onlinePlayerMethod.getReturnType().equals(Collection.class)) {
return ((Collection<?>)onlinePlayerMethod.invoke(Bukkit.getServer())).size();
} else {
return ((Player[])onlinePlayerMethod.invoke(Bukkit.getServer())).length;
}
} catch (Exception ex) {
if (debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
}
}
return 0;
}
/**
* Generic method that posts a plugin to the metrics website
*/
private void postPlugin(boolean isPing) throws IOException {
// Server software specific section
PluginDescriptionFile description = plugin.getDescription();
String pluginName = description.getName();
boolean onlineMode = Bukkit.getServer().getOnlineMode(); // TRUE if online mode is enabled
String pluginVersion = description.getVersion();
String serverVersion = Bukkit.getVersion();
int playersOnline = this.getOnlinePlayers();
// END server software specific section -- all code below does not use any code outside of this class / Java
// Construct the post data
StringBuilder json = new StringBuilder(1024);
json.append('{');
// The plugin's description file containg all of the plugin data such as name, version, author, etc
appendJSONPair(json, "guid", guid);
appendJSONPair(json, "plugin_version", pluginVersion);
appendJSONPair(json, "server_version", serverVersion);
appendJSONPair(json, "players_online", Integer.toString(playersOnline));
// New data as of R6
String osname = System.getProperty("os.name");
String osarch = System.getProperty("os.arch");
String osversion = System.getProperty("os.version");
String java_version = System.getProperty("java.version");
int coreCount = Runtime.getRuntime().availableProcessors();
// normalize os arch .. amd64 -> x86_64
if (osarch.equals("amd64")) {
osarch = "x86_64";
}
appendJSONPair(json, "osname", osname);
appendJSONPair(json, "osarch", osarch);
appendJSONPair(json, "osversion", osversion);
appendJSONPair(json, "cores", Integer.toString(coreCount));
appendJSONPair(json, "auth_mode", onlineMode ? "1" : "0");
appendJSONPair(json, "java_version", java_version);
// If we're pinging, append it
if (isPing) {
appendJSONPair(json, "ping", "1");
}
// close json
json.append('}');
// Create the url
URL url = new URL(BASE_URL + String.format(REPORT_URL, urlEncode(pluginName)));
// Connect to the website
URLConnection connection;
// Mineshafter creates a socks proxy, so we can safely bypass it
// It does not reroute POST requests so we need to go around it
if (isMineshafterPresent()) {
connection = url.openConnection(Proxy.NO_PROXY);
} else {
connection = url.openConnection();
}
byte[] uncompressed = json.toString().getBytes();
byte[] compressed = gzip(json.toString());
// Headers
connection.addRequestProperty("User-Agent", "MCStats/" + REVISION);
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Content-Encoding", "gzip");
connection.addRequestProperty("Content-Length", Integer.toString(compressed.length));
connection.addRequestProperty("Accept", "application/json");
connection.addRequestProperty("Connection", "close");
connection.setDoOutput(true);
if (debug) {
System.out.println("[Metrics] Prepared request for " + pluginName + " uncompressed=" + uncompressed.length + " compressed=" + compressed.length);
}
// Write the data
OutputStream os = connection.getOutputStream();
os.write(compressed);
os.flush();
// Now read the response
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String response = reader.readLine();
// close resources
os.close();
reader.close();
if (response == null || response.startsWith("ERR") || response.startsWith("7")) {
if (response == null) {
response = "null";
} else if (response.startsWith("7")) {
response = response.substring(response.startsWith("7,") ? 2 : 1);
}
throw new IOException(response);
}
}
/**
* GZip compress a string of bytes
*
* @param input
* @return
*/
public static byte[] gzip(String input) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzos = null;
try {
gzos = new GZIPOutputStream(baos);
gzos.write(input.getBytes("UTF-8"));
} catch (IOException e) {
e.printStackTrace();
} finally {
if (gzos != null) try {
gzos.close();
} catch (IOException ignore) {
}
}
return baos.toByteArray();
}
/**
* Check if mineshafter is present. If it is, we need to bypass it to send POST requests
*
* @return true if mineshafter is installed on the server
*/
private boolean isMineshafterPresent() {
try {
Class.forName("mineshafter.MineServer");
return true;
} catch (Exception e) {
return false;
}
}
/**
* Appends a json encoded key/value pair to the given string builder.
*
* @param json
* @param key
* @param value
* @throws UnsupportedEncodingException
*/
private static void appendJSONPair(StringBuilder json, String key, String value) throws UnsupportedEncodingException {
boolean isValueNumeric = false;
try {
if (value.equals("0") || !value.endsWith("0")) {
Double.parseDouble(value);
isValueNumeric = true;
}
} catch (NumberFormatException e) {
isValueNumeric = false;
}
if (json.charAt(json.length() - 1) != '{') {
json.append(',');
}
json.append(escapeJSON(key));
json.append(':');
if (isValueNumeric) {
json.append(value);
} else {
json.append(escapeJSON(value));
}
}
/**
* Escape a string to create a valid JSON string
*
* @param text
* @return
*/
private static String escapeJSON(String text) {
StringBuilder builder = new StringBuilder();
builder.append('"');
for (int index = 0; index < text.length(); index++) {
char chr = text.charAt(index);
switch (chr) {
case '"':
case '\\':
builder.append('\\');
builder.append(chr);
break;
case '\b':
builder.append("\\b");
break;
case '\t':
builder.append("\\t");
break;
case '\n':
builder.append("\\n");
break;
case '\r':
builder.append("\\r");
break;
default:
if (chr < ' ') {
String t = "000" + Integer.toHexString(chr);
builder.append("\\u" + t.substring(t.length() - 4));
} else {
builder.append(chr);
}
break;
}
}
builder.append('"');
return builder.toString();
}
/**
* Encode text as UTF-8
*
* @param text the text to encode
* @return the encoded text, as UTF-8
*/
private static String urlEncode(final String text) throws UnsupportedEncodingException {
return URLEncoder.encode(text, "UTF-8");
}
}

View File

@ -1,6 +1,6 @@
main: de.jeffclan.JeffChestSort.JeffChestSortPlugin
name: ChestSort
version: 7.6.1
version: 7.7-pre1
api-version: 1.13
description: Allows automatic chest sorting
author: mfnalex
@ -12,16 +12,22 @@ softdepend: [CrackShot, InventoryPages]
commands:
chestsort:
description: Toggle automatic chest sorting.
usage: /<command>
usage: /<command> [on|off|toggle]
aliases: sort
permission: chestsort.use
invsort:
description: Sorts the player's inventory. When no option is specified, only the regular inventory (excluding the hotbar) is sorted.
usage: /<command> [inv|hotbar|all]
description: Toggle automatic inventory sorting or sorts the player's inventory. When no option is specified, only the regular inventory (excluding the hotbar) is sorted.
usage: /<command> [on|off|toggle|inv|hotbar|all]
aliases: [isort,inventorysort]
permission: chestsort.use.inventory
refill:
description: Allows auto-refilling items in the hotbar
usage: /<command> [on|off|toggle]
permission: chestsort.use.refill
permissions:
chestsort.use:
description: Allows chest sorting
chestsort.use.inventory:
description: Allows inventory sorting
chestsort.use.refill:
description: Allows auto-refilling the hotbar