diff --git a/config.yml b/config.yml index 1869a05..91d24b8 100644 --- a/config.yml +++ b/config.yml @@ -24,7 +24,6 @@ store: # default: false unsafe: false - # InventoryFolder # The folder inside the datadir-folder (plugin/LimitedCreative) where the inventories are saved to. # By default the inventories are saved to "plugin/LimitedCreative/inventories". @@ -39,11 +38,24 @@ limit: # default: true enabled: true + # RemoveDrops + # When player not allowed to drop items, remove the item instead of putting it back to inventory/quickbar. + # You may disable this to get rid of the server.log-message: "Fetching addPacket for removed entity: CraftItem" + # default: true + remove_drops: true + # BlockPickup # Prevents the pickup of items while in creative mode # default: false pickup: false + # RemovePickup + # Instead of blocking the pickup, you may want to disappear the item from world (good when destroying walls with + # signs or playing with minecarts). Only works when BlockPickup: false. + # The permission nolimit.pickup bypasses the removing. + # default: false + remove_pickup: true + # BlockSign # Prevents interacting with signs (right-click), while in creative mode, so trading becomes more difficult. # Attention: this will also block useful signs, like Lifts. diff --git a/lang/default.yml b/lang/default.yml index c8e4164..fee4b94 100644 --- a/lang/default.yml +++ b/lang/default.yml @@ -16,7 +16,12 @@ command: survival: Changes the game mode of a player to survival creative: Changes the game mode of a player to creative config: - overview: storecreative|blockpickup|blocksign|permissions|perm_keepinventory + overview: "[setting] - empty for list of settings" + settings: + - "Available Settings: storecreative," + - "removedrop, removepickup, blockpickup, blocksign," + - "permissions, perm_keepinventory" + reload: Reloads plugin (doesn't work on update!) gamemode: changed: "{0}'s game mode has been changed" no_change: Already in that game mode. diff --git a/plugin.yml b/plugin.yml index 00bb363..3a90499 100644 --- a/plugin.yml +++ b/plugin.yml @@ -1,15 +1,15 @@ name: LimitedCreative main: de.jaschastarke.minecraft.limitedcreative.LimitedCreativeCore -version: 0.8.1-beta +version: 0.8.2-beta softdepend: [WorldGuard, WorldEdit, MultiInv] dev-url: http://dev.bukkit.org/server-mods/limited-creative/ commands: limitedcreative: - description: Main LimitedCreative-Controlling-Commands + description: "LimitedCreative: GameMode-Switch, Creative-Regions, Config" aliases: lc usage: / - displays LimitedCreative-Help /region: - description: Alternate region command, to use for WorldGuard-Integration + description: "LimitedCreative-Region-Command: configure creative regions" aliases: lcregion usage: / info|flag [#] - set/get region options permissions: diff --git a/src/de/jaschastarke/minecraft/limitedcreative/Commands.java b/src/de/jaschastarke/minecraft/limitedcreative/Commands.java index e2e6ee7..c522726 100644 --- a/src/de/jaschastarke/minecraft/limitedcreative/Commands.java +++ b/src/de/jaschastarke/minecraft/limitedcreative/Commands.java @@ -40,6 +40,7 @@ public class Commands { E, ENABLE, D, DISABLE, R, REGION, + RELOAD }; @Override @@ -74,6 +75,10 @@ public class Commands { args = Arrays.copyOfRange(args, 1, args.length); plugin.getCommand("/region").execute(sender, "/region", args); return true; + case RELOAD: + plugin.getServer().getPluginManager().disablePlugin(plugin); + plugin.getServer().getPluginManager().enablePlugin(plugin); + return true; } } catch (CommandException e) { LimitedCreativeCore.debug("CommandException: "+e.getMessage()); @@ -87,10 +92,11 @@ public class Commands { StringBuilder message = new StringBuilder(); message.append("/"+c+" s[urvival] ["+L("command.player")+"] - "+L("command.switch.survival")+"\n"); message.append("/"+c+" c[reative] ["+L("command.player")+"] - "+L("command.switch.creative")+"\n"); - if (plugin.perm.hasPermission(sender, "limitedcreative.config")) + if (plugin.perm.hasPermission(sender, "limitedcreative.config")) { message.append("/"+c+" e[nable] "+L("command.config.overview")+"\n"); - if (plugin.perm.hasPermission(sender, "limitedcreative.config")) message.append("/"+c+" d[isable] "+L("command.config.overview")+"\n"); + message.append("/"+c+" reload "+L("command.config.reload")+"\n"); + } if (plugin.perm.hasPermission(sender, "limitedcreative.regions")) message.append("/"+c+" r[egion] "+L("command.worldguard.alias")+"\n"); if (message.length() > 0) { @@ -110,6 +116,8 @@ public class Commands { BLOCKSIGN, PERMISSIONS, PERM_KEEPINVENTORY, + REMOVEDROP, + REMOVEPICKUP, DEBUG, }; @@ -119,8 +127,11 @@ public class Commands { } if (args.length > 2) throw new InvalidCommandException("exception.command.tomuchparameter"); - if (args.length < 2) - throw new InvalidCommandException("exception.command.missingparameter"); + if (args.length < 2) { + for (String l : L("command.config.settings").split("\n")) + sender.sendMessage(l); + return; + } Option opt = null; try { @@ -145,6 +156,15 @@ public class Commands { case PERM_KEEPINVENTORY: plugin.config.setPermissionToKeepInventory(b); break; + case REMOVEDROP: + plugin.config.setRemoveDrop(b); + break; + case REMOVEPICKUP: + plugin.config.setRemovePickup(b); + break; + case DEBUG: + plugin.config.setDebug(b); + break; } sender.sendMessage(L("command.option.done")); } diff --git a/src/de/jaschastarke/minecraft/limitedcreative/Configuration.java b/src/de/jaschastarke/minecraft/limitedcreative/Configuration.java index 71b08d7..b920422 100644 --- a/src/de/jaschastarke/minecraft/limitedcreative/Configuration.java +++ b/src/de/jaschastarke/minecraft/limitedcreative/Configuration.java @@ -75,6 +75,13 @@ public class Configuration { public boolean getSignBlock() { return c.getBoolean("limit.sign", true); } + public boolean getRemoveDrop() { + return c.getBoolean("limit.remove_drops", true); + } + public boolean getRemovePickup() { + return c.getBoolean("limit.remove_pickup", false); + } + public boolean getPermissionsEnabled() { return c.getBoolean("permissions.enabled", false); } @@ -118,6 +125,16 @@ public class Configuration { c.set("permissions.keepinventory", value); this.save(); } + public void setRemoveDrop(boolean value) { + this.reload(); + c.set("limit.remove_drops", value); + this.save(); + } + public void setRemovePickup(boolean value) { + this.reload(); + c.set("limit.remove_pickup", value); + this.save(); + } protected void reload() { _block_break = null; diff --git a/src/de/jaschastarke/minecraft/limitedcreative/Inventory.java b/src/de/jaschastarke/minecraft/limitedcreative/Inventory.java index 4e390dc..e074565 100644 --- a/src/de/jaschastarke/minecraft/limitedcreative/Inventory.java +++ b/src/de/jaschastarke/minecraft/limitedcreative/Inventory.java @@ -37,18 +37,23 @@ public class Inventory { public Inventory(Player p) { player = p; - inv = p.getInventory(); + } + + private PlayerInventory inv() { + return player.getInventory(); } public void save() { + LimitedCreativeCore.debug(player.getName() + " storing inventory "+player.getGameMode().toString()); File f = new File(LimitedCreativeCore.plugin.getDataFolder(), getFileName(player, player.getGameMode())); - storeInventory(inv, f); + storeInventory(inv(), f); } public void load(GameMode gm) { + LimitedCreativeCore.debug(player.getName() + " loading inventory "+gm.toString()); File f = new File(LimitedCreativeCore.plugin.getDataFolder(), getFileName(player, gm)); try { - restoreInventory(inv, f); + restoreInventory(inv(), f); } catch (IllegalArgumentException e) { if (LimitedCreativeCore.plugin.config.getUnsafeStorage()) { throw e; @@ -62,13 +67,13 @@ public class Inventory { } public void clear() { - inv.setArmorContents(new ItemStack[]{ + inv().setArmorContents(new ItemStack[]{ new ItemStack(0), new ItemStack(0), new ItemStack(0), new ItemStack(0), }); - inv.clear(); + inv().clear(); } private String getFileName(Player player, GameMode gm) { diff --git a/src/de/jaschastarke/minecraft/limitedcreative/LCPlayer.java b/src/de/jaschastarke/minecraft/limitedcreative/LCPlayer.java index 5cfda0c..96ee059 100644 --- a/src/de/jaschastarke/minecraft/limitedcreative/LCPlayer.java +++ b/src/de/jaschastarke/minecraft/limitedcreative/LCPlayer.java @@ -20,6 +20,7 @@ package de.jaschastarke.minecraft.limitedcreative; import java.io.File; import java.io.IOException; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import org.bukkit.ChatColor; @@ -46,38 +47,70 @@ import static de.jaschastarke.minecraft.utils.Locale.L; public class LCPlayer { private static LimitedCreativeCore plugin = LimitedCreativeCore.plugin; - private static Map players = new HashMap(); + private static Map players = new HashMap(); private Player player; private Map tempinv = null; + private Inventory _inv; + private boolean _isPermanentCreative = false; + private boolean _isRegionCreative = false; + private long _timestamp; + public static final long CLEANUP_TIMEOUT = 90000; // 90s * 20ticks private static File _store_file = new File(plugin.getDataFolder(), "players.yml"); public static YamlConfiguration store = YamlConfiguration.loadConfiguration(_store_file); - private boolean _isPermanentCreative = false; - private boolean _isRegionCreative = false; - - private LCPlayer(Player pplayer) { - player = pplayer; + private LCPlayer(Player player) { + this.player = player; _isRegionCreative = store.getBoolean(player.getName()+".region_creative", false) && player.getGameMode() == GameMode.CREATIVE; if (player.getGameMode() == GameMode.CREATIVE && !this.isRegionCreative()) { LimitedCreativeCore.debug(player.getName() + " was already creative"); setPermanentCreative(true); } } + private void updatePlayer(Player player) { + this.player = player; + _inv = null; + } public Player getRaw() { return player; } - public static LCPlayer get(Player pplayer) { - if (!players.containsKey(pplayer)) { - LCPlayer p = new LCPlayer(pplayer); - players.put(pplayer, p); + public void touch() { + _timestamp = System.currentTimeMillis(); + } + + public boolean isOutdated() { + return !getRaw().isOnline() && _timestamp < (System.currentTimeMillis() - CLEANUP_TIMEOUT); + } + + public static LCPlayer get(Player player) { + LimitedCreativeCore.debug("player: " + player.getName() + " - " + ((Object)player).hashCode() + " - " + player.getEntityId() + " - " + player.getUniqueId()); + if (!players.containsKey(player.getName())) { + LCPlayer p = new LCPlayer(player); + players.put(player.getName(), p); + p.touch(); return p; } else { - return players.get(pplayer); + LCPlayer p = players.get(player.getName()); + if (player != p.getRaw()) + p.updatePlayer(player); + p.touch(); + return p; } } + public static void cleanUp() { + int count = players.size(); + Iterator> i = players.entrySet().iterator(); + while (i.hasNext()) { + Map.Entry entry = i.next(); + if (entry.getValue().isOutdated()) { + LimitedCreativeCore.debug("removing "+entry.getValue().getRaw().getName()); + i.remove(); + } + } + LimitedCreativeCore.debug("cleanup done: player count: "+count+" / "+players.size()); + } public boolean isRegionCreative() { return _isRegionCreative; @@ -124,16 +157,21 @@ public class LCPlayer { if (plugin.config.getStoreEnabled()) { if (plugin.config.getPermissionToKeepInventory() && hasPermission("limitedcreative.keepinventory")) return true; - Inventory inv = new Inventory(player); - inv.save(); - if (plugin.config.getStoreCreative() && inv.isStored(GameMode.CREATIVE)) { - inv.load(GameMode.CREATIVE); + inv().save(); + if (plugin.config.getStoreCreative() && inv().isStored(GameMode.CREATIVE)) { + inv().load(GameMode.CREATIVE); } else { - inv.clear(); + inv().clear(); } } return true; } + private Inventory inv() { + if (_inv == null) + _inv = new Inventory(player); + return _inv; + } + public boolean onSetSurvival() { LimitedCreativeCore.debug(player.getName() + " going into survival"); if (isRegionCreative()) { @@ -147,27 +185,36 @@ public class LCPlayer { if (plugin.config.getStoreEnabled()) { if (plugin.config.getPermissionToKeepInventory() && hasPermission("limitedcreative.keepinventory")) return true; - Inventory inv = new Inventory(player); if (plugin.config.getStoreCreative()) { - inv.save(); + inv().save(); } - if (inv.isStored(GameMode.SURVIVAL)) - inv.load(GameMode.SURVIVAL); + if (inv().isStored(GameMode.SURVIVAL)) + inv().load(GameMode.SURVIVAL); } return true; } public void onDropItem(PlayerDropItemEvent event) { + LimitedCreativeCore.debug(player.getName() + " ("+player.getGameMode()+") drops items " + event.getItemDrop().getItemStack().getType()); if (player.getGameMode() == GameMode.CREATIVE) { if (plugin.config.getPermissionsEnabled() && hasPermission("limitedcreative.nolimit.drop")) return; - event.getItemDrop().remove(); + LimitedCreativeCore.debug("removed"); + if (plugin.config.getRemoveDrop()) + event.getItemDrop().remove(); + else + event.setCancelled(true); } } public void onPickupItem(PlayerPickupItemEvent event) { - if (player.getGameMode() == GameMode.CREATIVE && plugin.config.getBlockPickupInCreative()) { + if (player.getGameMode() == GameMode.CREATIVE) { if (plugin.config.getPermissionsEnabled() && hasPermission("limitedcreative.nolimit.pickup")) return; - event.setCancelled(true); + if (plugin.config.getBlockPickupInCreative()) { + event.setCancelled(true); + } else if(plugin.config.getRemovePickup()) { + event.getItem().remove(); + event.setCancelled(true); + } } } diff --git a/src/de/jaschastarke/minecraft/limitedcreative/LimitedCreativeCore.java b/src/de/jaschastarke/minecraft/limitedcreative/LimitedCreativeCore.java index 590fabf..f8bab7b 100644 --- a/src/de/jaschastarke/minecraft/limitedcreative/LimitedCreativeCore.java +++ b/src/de/jaschastarke/minecraft/limitedcreative/LimitedCreativeCore.java @@ -39,6 +39,7 @@ public class LimitedCreativeCore extends JavaPlugin { @Override public void onDisable() { + plugin.getServer().getScheduler().cancelTasks(this); plugin = null; worldguard = null; config = null; @@ -82,6 +83,13 @@ public class LimitedCreativeCore extends JavaPlugin { Commands.register(this); + plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, new Runnable() { + @Override + public void run() { + LCPlayer.cleanUp(); + } + }, LCPlayer.CLEANUP_TIMEOUT / 50L, LCPlayer.CLEANUP_TIMEOUT / 50L); // 50 = 1000ms / 20ticks + PluginDescriptionFile df = this.getDescription(); if (worldguard != null) logger.info("["+df.getName() + " v" + df.getVersion() + "] "+L("basic.loaded.worldguard")); diff --git a/src/de/jaschastarke/minecraft/limitedcreative/listeners/MainListener.java b/src/de/jaschastarke/minecraft/limitedcreative/listeners/MainListener.java index 1963869..16f36bf 100644 --- a/src/de/jaschastarke/minecraft/limitedcreative/listeners/MainListener.java +++ b/src/de/jaschastarke/minecraft/limitedcreative/listeners/MainListener.java @@ -47,6 +47,10 @@ public class MainListener implements Listener { @EventHandler public void onPlayerGameModeChange(PlayerGameModeChangeEvent event) { + LimitedCreativeCore.debug("onPlayerGameModeChange: "+event.getPlayer().getName()); + LimitedCreativeCore.debug("Current GameMode: "+event.getPlayer().getGameMode()); + LimitedCreativeCore.debug("New GameMode: "+event.getNewGameMode()); + LimitedCreativeCore.debug("isCancelled: "+event.isCancelled()); if (event.getNewGameMode() == GameMode.CREATIVE) { if (!LCPlayer.get(event.getPlayer()).onSetCreative()) event.setCancelled(true); diff --git a/src/de/jaschastarke/minecraft/utils/Locale.java b/src/de/jaschastarke/minecraft/utils/Locale.java index 7ba678a..ece0d4c 100644 --- a/src/de/jaschastarke/minecraft/utils/Locale.java +++ b/src/de/jaschastarke/minecraft/utils/Locale.java @@ -19,6 +19,7 @@ package de.jaschastarke.minecraft.utils; import java.io.File; import java.text.MessageFormat; +import java.util.List; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.java.JavaPlugin; @@ -40,8 +41,16 @@ public class Locale { return "lang/"+locale+".yml"; } public String get(String msg) { - if (lang.contains(msg)) - return lang.getString(msg); + if (lang.contains(msg)) { + if (lang.isList(msg)) { + List list = lang.getStringList(msg); + String[] lines = new String[list.size()]; + list.toArray(lines); + return Util.join(lines, "\n"); + } else { + return lang.getString(msg); + } + } return msg; } diff --git a/src/de/jaschastarke/minecraft/utils/Util.java b/src/de/jaschastarke/minecraft/utils/Util.java index 7d93607..cb2f13e 100644 --- a/src/de/jaschastarke/minecraft/utils/Util.java +++ b/src/de/jaschastarke/minecraft/utils/Util.java @@ -83,4 +83,7 @@ final public class Util { public static String join(String[] list) { return join(list, " ", 0, list.length); } + public static String join(String[] list, String sep) { + return join(list, sep, 0, list.length); + } }