diff --git a/Essentials/nbproject/project.properties b/Essentials/nbproject/project.properties index 4e80ceafa..71fea5cf9 100644 --- a/Essentials/nbproject/project.properties +++ b/Essentials/nbproject/project.properties @@ -76,6 +76,7 @@ file.reference.MultiCurrency.jar=../lib/MultiCurrency.jar file.reference.Permissions3.jar=../lib/Permissions3.jar file.reference.PermissionsBukkit-1.2.jar=../lib/PermissionsBukkit-1.2.jar file.reference.PermissionsEx.jar=../lib/PermissionsEx.jar +file.reference.Privileges.jar=..\\lib\\Privileges.jar file.reference.Vault.jar=../lib/Vault.jar includes=** jar.archive.disabled=${jnlp.enabled} @@ -95,7 +96,8 @@ javac.classpath=\ ${reference.EssentialsGroupManager.jar}:\ ${file.reference.bukkit.jar}:\ ${file.reference.craftbukkit.jar}:\ - ${file.reference.Vault.jar} + ${file.reference.Vault.jar}:\ + ${file.reference.Privileges.jar} # Space-separated list of extra javac options javac.compilerargs= javac.deprecation=false diff --git a/Essentials/src/com/earth2me/essentials/Essentials.java b/Essentials/src/com/earth2me/essentials/Essentials.java index 21f2e38ea..3ee7c1777 100644 --- a/Essentials/src/com/earth2me/essentials/Essentials.java +++ b/Essentials/src/com/earth2me/essentials/Essentials.java @@ -32,15 +32,20 @@ import com.earth2me.essentials.signs.SignPlayerListener; import java.io.File; import java.io.FileReader; import java.io.IOException; +import java.lang.reflect.Array; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.bukkit.ChatColor; import org.bukkit.Server; import org.bukkit.World; import org.bukkit.command.Command; +import org.bukkit.command.CommandException; import org.bukkit.command.CommandSender; import org.bukkit.command.PluginCommand; import org.bukkit.entity.Player; @@ -277,7 +282,29 @@ public class Essentials extends JavaPlugin implements IEssentials if (pc != null) { alternativeCommandsHandler.executed(commandLabel, pc.getLabel()); - return pc.execute(sender, commandLabel, args); + try + { + return pc.execute(sender, commandLabel, args); + } + catch (final Exception ex) + { + final ArrayList elements = new ArrayList(Arrays.asList(ex.getStackTrace())); + elements.remove(0); + final ArrayList toRemove = new ArrayList(); + for (final StackTraceElement e : elements) + { + if (e.getClassName().equals("com.earth2me.essentials.Essentials")) + { + toRemove.add(e); + } + } + elements.removeAll(toRemove); + final StackTraceElement[] trace = elements.toArray(new StackTraceElement[elements.size()]); + ex.setStackTrace(trace); + ex.printStackTrace(); + sender.sendMessage(ChatColor.RED + "An internal error occurred while attempting to perform this command"); + return true; + } } } diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandping.java b/Essentials/src/com/earth2me/essentials/commands/Commandping.java index 1fad701b2..0956f4082 100644 --- a/Essentials/src/com/earth2me/essentials/commands/Commandping.java +++ b/Essentials/src/com/earth2me/essentials/commands/Commandping.java @@ -1,8 +1,9 @@ package com.earth2me.essentials.commands; import static com.earth2me.essentials.I18n._; -import com.earth2me.essentials.User; +import com.earth2me.essentials.Util; import org.bukkit.Server; +import org.bukkit.command.CommandSender; public class Commandping extends EssentialsCommand @@ -13,8 +14,16 @@ public class Commandping extends EssentialsCommand } @Override - public void run(Server server, User player, String commandLabel, String[] args) throws Exception + public void run(final Server server, final CommandSender sender, final String commandLabel, final String[] args) throws Exception { - player.sendMessage(_("pong")); + if (args.length < 1) + { + + sender.sendMessage(_("pong")); + } + else + { + sender.sendMessage(Util.replaceColor(getFinalArg(args, 0))); + } } } diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandspawner.java b/Essentials/src/com/earth2me/essentials/commands/Commandspawner.java index 73c86eba4..d52315241 100644 --- a/Essentials/src/com/earth2me/essentials/commands/Commandspawner.java +++ b/Essentials/src/com/earth2me/essentials/commands/Commandspawner.java @@ -2,6 +2,7 @@ package com.earth2me.essentials.commands; import static com.earth2me.essentials.I18n._; import com.earth2me.essentials.Mob; +import com.earth2me.essentials.Trade; import com.earth2me.essentials.User; import com.earth2me.essentials.Util; import java.util.Locale; @@ -47,11 +48,14 @@ public class Commandspawner extends EssentialsCommand { throw new Exception(_("unableToSpawnMob")); } - if (!user.isAuthorized("essentials.spawner." + mob.name.toLowerCase())) + if (!user.isAuthorized("essentials.spawner." + mob.name.toLowerCase(Locale.ENGLISH))) { throw new Exception(_("unableToSpawnMob")); } + final Trade charge = new Trade("spawner-" + mob.name.toLowerCase(Locale.ENGLISH), ess); + charge.isAffordableFor(user); ((CreatureSpawner)target.getBlock().getState()).setCreatureType(mob.getType()); + charge.charge(user); user.sendMessage(_("setSpawner", mob.name)); } catch (Throwable ex) diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandsudo.java b/Essentials/src/com/earth2me/essentials/commands/Commandsudo.java index 7f758ad2e..86394e502 100644 --- a/Essentials/src/com/earth2me/essentials/commands/Commandsudo.java +++ b/Essentials/src/com/earth2me/essentials/commands/Commandsudo.java @@ -30,7 +30,13 @@ public class Commandsudo extends EssentialsCommand } //TODO: Translate this. - sender.sendMessage("Running the command as " + user.getDisplayName()); + if (user.isAuthorized("essentials.sudo.exempt")) + { + throw new Exception("You cannot sudo this user"); + } + + //TODO: Translate this. + sender.sendMessage("Forcing " + user.getDisplayName() + " to run: /" + command + " " + arguments); final PluginCommand execCommand = ess.getServer().getPluginCommand(command); if (execCommand != null) diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandtpaccept.java b/Essentials/src/com/earth2me/essentials/commands/Commandtpaccept.java index 2e3e024a3..891742043 100644 --- a/Essentials/src/com/earth2me/essentials/commands/Commandtpaccept.java +++ b/Essentials/src/com/earth2me/essentials/commands/Commandtpaccept.java @@ -22,7 +22,9 @@ public class Commandtpaccept extends EssentialsCommand final User target = user.getTeleportRequest(); if (target == null || target.getBase() instanceof OfflinePlayer - || (user.isTeleportRequestHere() && !target.isAuthorized("essentials.tpahere"))) + || (user.isTeleportRequestHere() && !target.isAuthorized("essentials.tpahere")) + || (!user.isTeleportRequestHere() && !target.isAuthorized("essentials.tpa") && !target.isAuthorized("essentials.tpaall")) + ) { throw new Exception(_("noPendingRequest")); } diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandwarp.java b/Essentials/src/com/earth2me/essentials/commands/Commandwarp.java index 51b64563b..62641172b 100644 --- a/Essentials/src/com/earth2me/essentials/commands/Commandwarp.java +++ b/Essentials/src/com/earth2me/essentials/commands/Commandwarp.java @@ -8,6 +8,7 @@ import com.earth2me.essentials.Warps; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Locale; import org.bukkit.Server; import org.bukkit.command.CommandSender; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; @@ -44,10 +45,10 @@ public class Commandwarp extends EssentialsCommand { throw new Exception(_("playerNotFound")); } - warpUser(otherUser, args[0]); + warpUser(user, otherUser, args[0]); throw new NoChargeException(); } - warpUser(user, args[0]); + warpUser(user, user, args[0]); throw new NoChargeException(); } } @@ -65,7 +66,7 @@ public class Commandwarp extends EssentialsCommand { throw new Exception(_("playerNotFound")); } - warpUser(otherUser, args[0]); + otherUser.getTeleport().warp(args[0], null, TeleportCause.COMMAND); throw new NoChargeException(); } @@ -112,17 +113,12 @@ public class Commandwarp extends EssentialsCommand } } - private void warpUser(final User user, final String name) throws Exception + private void warpUser(final User owner, final User user, final String name) throws Exception { - final Trade charge = new Trade(this.getName(), ess); - charge.isAffordableFor(user); - if (ess.getSettings().getPerWarpPermission()) + final Trade charge = new Trade("warp-" + name.toLowerCase(Locale.ENGLISH).replace('_', '-'), ess); + charge.isAffordableFor(owner); + if (ess.getSettings().getPerWarpPermission() && !owner.isAuthorized("essentials.warp." + name)) { - if (user.isAuthorized("essentials.warp." + name)) - { - user.getTeleport().warp(name, charge, TeleportCause.COMMAND); - return; - } throw new Exception(_("warpUsePermission")); } user.getTeleport().warp(name, charge, TeleportCause.COMMAND); diff --git a/Essentials/src/com/earth2me/essentials/perm/PermissionsHandler.java b/Essentials/src/com/earth2me/essentials/perm/PermissionsHandler.java index 8c16aab7a..aa786934e 100644 --- a/Essentials/src/com/earth2me/essentials/perm/PermissionsHandler.java +++ b/Essentials/src/com/earth2me/essentials/perm/PermissionsHandler.java @@ -144,6 +144,17 @@ public class PermissionsHandler implements IPermissionsHandler return; } + final Plugin privPlugin = pluginManager.getPlugin("Privileges"); + if (privPlugin != null && privPlugin.isEnabled()) + { + if (!(handler instanceof PrivilegesHandler)) + { + LOGGER.log(Level.INFO, "Essentials: Using Privileges based permissions."); + handler = new PrivilegesHandler(privPlugin); + } + return; + } + final Plugin permPlugin = pluginManager.getPlugin("Permissions"); if (permPlugin != null && permPlugin.isEnabled()) { diff --git a/Essentials/src/com/earth2me/essentials/perm/PrivilegesHandler.java b/Essentials/src/com/earth2me/essentials/perm/PrivilegesHandler.java new file mode 100644 index 000000000..c81f93cbc --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/perm/PrivilegesHandler.java @@ -0,0 +1,61 @@ +package com.earth2me.essentials.perm; + +import java.util.ArrayList; +import java.util.List; +import net.krinsoft.privileges.Privileges; +import net.krinsoft.privileges.groups.Group; +import net.krinsoft.privileges.groups.GroupManager; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + +public class PrivilegesHandler extends SuperpermsHandler +{ + private final transient Privileges plugin; + private final GroupManager manager; + + public PrivilegesHandler(final Plugin plugin) + { + this.plugin = (Privileges) plugin; + this.manager = this.plugin.getGroupManager(); + } + + @Override + public String getGroup(final Player base) + { + Group group = manager.getGroup(base); + if (group == null) + { + return null; + } + return group.getName(); + } + + @Override + public List getGroups(final Player base) + { + Group group = manager.getGroup(base); + if (group == null) + { + return new ArrayList(); + } + return group.getGroupTree(); + } + + @Override + public boolean inGroup(final Player base, final String group) + { + Group pGroup = manager.getGroup(base); + if (pGroup == null) + { + return false; + } + return pGroup.isMemberOf(group); + } + + @Override + public boolean canBuild(Player base, String group) + { + return base.hasPermission("essentials.build") || base.hasPermission("privileges.build"); + } + +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignTrade.java b/Essentials/src/com/earth2me/essentials/signs/SignTrade.java index 943a14a83..6b47ebc76 100644 --- a/Essentials/src/com/earth2me/essentials/signs/SignTrade.java +++ b/Essentials/src/com/earth2me/essentials/signs/SignTrade.java @@ -36,7 +36,7 @@ public class SignTrade extends EssentialsSign try { stored = getTrade(sign, 1, true, true, ess); - substractAmount(sign, 1, stored, ess); + subtractAmount(sign, 1, stored, ess); stored.pay(player); } catch (SignException e) @@ -53,12 +53,14 @@ public class SignTrade extends EssentialsSign final Trade charge = getTrade(sign, 1, false, false, ess); final Trade trade = getTrade(sign, 2, false, true, ess); charge.isAffordableFor(player); + addAmount(sign, 1, charge, ess); + subtractAmount(sign, 2, trade, ess); if (!trade.pay(player, false)) { + subtractAmount(sign, 1, charge, ess); + addAmount(sign, 2, trade, ess); throw new ChargeException("Full inventory"); } - substractAmount(sign, 2, trade, ess); - addAmount(sign, 1, charge, ess); charge.charge(player); Trade.log("Sign", "Trade", "Interact", sign.getLine(3), charge, username, trade, sign.getBlock().getLocation(), ess); } @@ -256,7 +258,7 @@ public class SignTrade extends EssentialsSign throw new SignException(_("invalidSignLine", index + 1)); } - protected final void substractAmount(final ISign sign, final int index, final Trade trade, final IEssentials ess) throws SignException + protected final void subtractAmount(final ISign sign, final int index, final Trade trade, final IEssentials ess) throws SignException { final Double money = trade.getMoney(); if (money != null) @@ -294,6 +296,7 @@ public class SignTrade extends EssentialsSign } } + //TODO: Translate these exceptions. private void changeAmount(final ISign sign, final int index, final double value, final IEssentials ess) throws SignException { @@ -313,7 +316,7 @@ public class SignTrade extends EssentialsSign final String newline = Util.formatCurrency(money, ess) + ":" + Util.formatCurrency(amount + value, ess).substring(1); if (newline.length() > 15) { - throw new SignException("Line too long!"); + throw new SignException("This sign is full: Line too long!"); } sign.setLine(index, newline); return; @@ -329,7 +332,7 @@ public class SignTrade extends EssentialsSign final String newline = stackamount + " " + split[1] + ":" + (amount + Math.round(value)); if (newline.length() > 15) { - throw new SignException("Line too long!"); + throw new SignException("This sign is full: Line too long!"); } sign.setLine(index, newline); return; @@ -343,7 +346,7 @@ public class SignTrade extends EssentialsSign final String newline = stackamount + " " + split[1] + ":" + (amount + Math.round(value)); if (newline.length() > 15) { - throw new SignException("Line too long!"); + throw new SignException("This sign is full: Line too long!"); } sign.setLine(index, newline); return; diff --git a/EssentialsChat/src/com/earth2me/essentials/chat/ChatStore.java b/EssentialsChat/src/com/earth2me/essentials/chat/ChatStore.java index 38239abfe..d353d5d6c 100644 --- a/EssentialsChat/src/com/earth2me/essentials/chat/ChatStore.java +++ b/EssentialsChat/src/com/earth2me/essentials/chat/ChatStore.java @@ -36,7 +36,7 @@ public class ChatStore public String getLongType() { - return type.length() > 0 ? "chat" : "chat-" + type; + return type.length() == 0 ? "chat" : "chat-" + type; } public long getRadius() diff --git a/EssentialsGroupManager/src/Changelog.txt b/EssentialsGroupManager/src/Changelog.txt index 41b5613af..b79d56d07 100644 --- a/EssentialsGroupManager/src/Changelog.txt +++ b/EssentialsGroupManager/src/Changelog.txt @@ -125,4 +125,17 @@ v 1.9: - Fixed an infinite loop error when using '/manudel' on a logged in player. It caused setDefaultGroup to trigger a bukkit update when no GM User existed yet. - do not allow inherited permissions to negate higher perms. - Fixed a bug when pushing superperms in the wrong order. - - Fix players retaining permissions when demoted. \ No newline at end of file + - Fix players retaining permissions when demoted. + - Auto sort permissions on load to speed up population of superperms. + - Negating a parent node after adding all nodes with * will now correctly remove all child nodes of that parent before populating superperms. + eg. + - '*' + - -vanish.* + - vanish.standard + - Track the 'onPlayerChangeWorld' event as some teleports seem to not be triggering a world move. + - Catch all errors in badly formatted groups. + - Fix a bug with getWorldData return the main world data for all mirrors, instead of the worlds parent data. + - Prevent getAllPlayersPermissions() processing a group more than once. Improves performance when using complex inheritance structures. + - Fix world mirroring so it correctly creates data files and data sources for partially mirrored worlds. + - Fixed world mirroring so it returns the correct data for the requested world. + - Change Service registration to register WorldsHolder instead of AnjoPermissionsHandler. This is the correct entry point for all data. \ No newline at end of file diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/GroupManager.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/GroupManager.java index 43b764faf..b87d1de8c 100644 --- a/EssentialsGroupManager/src/org/anjocaido/groupmanager/GroupManager.java +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/GroupManager.java @@ -158,7 +158,7 @@ public class GroupManager extends JavaPlugin { System.out.println(pdfFile.getName() + " version " + pdfFile.getVersion() + " is enabled!"); // Register as a service - this.getServer().getServicesManager().register(AnjoPermissionsHandler.class, this.permissionHandler, this, ServicePriority.Lowest); + this.getServer().getServicesManager().register(WorldsHolder.class, this.worldsHolder, this, ServicePriority.Lowest); } public static boolean isLoaded() { @@ -1485,7 +1485,7 @@ public class GroupManager extends JavaPlugin { try { worldsHolder.saveChanges(forced); - sender.sendMessage(ChatColor.YELLOW + " The changes were saved."); + sender.sendMessage(ChatColor.YELLOW + " All changes were saved."); } catch (IllegalStateException ex) { sender.sendMessage(ChatColor.RED + ex.getMessage()); } @@ -1522,6 +1522,7 @@ public class GroupManager extends JavaPlugin { } // WORKING config.load(); + globalGroups.load(); worldsHolder.mirrorSetUp(); isLoaded = false; @@ -1538,7 +1539,7 @@ public class GroupManager extends JavaPlugin { sender.sendMessage("The request to world '" + auxString + "' was sent."); } else { worldsHolder.reloadAll(); - sender.sendMessage(ChatColor.YELLOW + " The current world was reloaded."); + sender.sendMessage(ChatColor.YELLOW + " All worlds were reloaded."); } isLoaded = true; @@ -1762,9 +1763,9 @@ public class GroupManager extends JavaPlugin { dataHolder = worldsHolder.getWorldData(worldsHolder.getDefaultWorld().getName()); permissionHandler = dataHolder.getPermissionsHandler(); - selectedWorlds.put(sender, dataHolder.getName()); if ((dataHolder != null) && (permissionHandler != null)) { + selectedWorlds.put(sender, dataHolder.getName()); sender.sendMessage(ChatColor.RED + "Couldn't retrieve your world. Default world '" + worldsHolder.getDefaultWorld().getName() + "' selected."); return true; } diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/DataUnit.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/DataUnit.java index a35b5aeee..e3250a1c1 100644 --- a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/DataUnit.java +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/DataUnit.java @@ -65,8 +65,19 @@ public abstract class DataUnit { hash = 71 * hash + (this.name != null ? this.name.toLowerCase().hashCode() : 0); return hash; } + + /** + * Set the data source to point to a different worldDataHolder + * + * @param source + */ + public void setDataSource(WorldDataHolder source) { + this.dataSource = source; + } /** + * Get the current worldDataHolder this object is pointing to + * * @return the dataSource */ public WorldDataHolder getDataSource() { diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/User.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/User.java index 980b0846c..30fe3f709 100644 --- a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/User.java +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/User.java @@ -138,8 +138,8 @@ public class User extends DataUnit implements Cloneable { String oldGroup = this.group; this.group = group.getName(); flagAsChanged(); - if (GroupManager.isLoaded() && (updatePerms)) { - if (!GroupManager.BukkitPermissions.isPlayer_join()) + if (GroupManager.isLoaded()) { + if (!GroupManager.BukkitPermissions.isPlayer_join() && (updatePerms)) GroupManager.BukkitPermissions.updatePlayer(getBukkitPlayer()); // Do we notify of the group change? diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/GroupsDataHolder.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/GroupsDataHolder.java index 4fc819245..5d681013e 100644 --- a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/GroupsDataHolder.java +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/GroupsDataHolder.java @@ -9,15 +9,14 @@ import org.anjocaido.groupmanager.data.Group; /** + * This container holds all Groups loaded from the relevant groupsFile. + * * @author ElgarL * */ public class GroupsDataHolder { - /** - * Root World name this set of groups is associated with. - */ - private String name; + private WorldDataHolder dataSource; private Group defaultGroup = null; private File groupsFile; private boolean haveGroupsChanged = false; @@ -33,16 +32,12 @@ public class GroupsDataHolder { */ protected GroupsDataHolder() { } - - protected void setWorldName(String worldName) { - name = worldName; - } - - /** - * @return the name - */ - public String getWorldName() { - return name; + + public void setDataSource(WorldDataHolder dataSource) { + this.dataSource = dataSource; + //push this data source to the users, so they pull the correct groups data. + for (Group group : groups.values()) + group.setDataSource(this.dataSource); } /** diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/UsersDataHolder.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/UsersDataHolder.java index 37e1c4b43..fa2ccaf84 100644 --- a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/UsersDataHolder.java +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/UsersDataHolder.java @@ -9,15 +9,14 @@ import org.anjocaido.groupmanager.data.User; /** + * This container holds all Users loaded from the relevant usersFile. + * * @author ElgarL * */ public class UsersDataHolder { - /** - * Root World name this set of groups is associated with. - */ - private String name; + private WorldDataHolder dataSource; private File usersFile; private boolean haveUsersChanged = false; private long timeStampUsers = 0; @@ -32,19 +31,13 @@ public class UsersDataHolder { */ protected UsersDataHolder() { } - - /** - * @param worldName - */ - public void setWorldName(String worldName) { - this.name = worldName; - } - /** - * @return the name - */ - public String getWorldName() { - return this.name; + public void setDataSource(WorldDataHolder dataSource) { + this.dataSource = dataSource; + //push this data source to the users, so they pull the correct groups data. + for (User user : users.values()) + user.setDataSource(this.dataSource); + } /** diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/WorldDataHolder.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/WorldDataHolder.java index 3cbfbd50b..8115b1a75 100644 --- a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/WorldDataHolder.java +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/WorldDataHolder.java @@ -36,8 +36,11 @@ import org.yaml.snakeyaml.constructor.SafeConstructor; import org.yaml.snakeyaml.reader.UnicodeReader; /** - * - * @author gabrielcouto + * One instance of this should exist per world/mirror + * it contains all functions to manage these data sets + * and points to the relevant users and groups objects. + * + * @author gabrielcouto, ElgarL */ public class WorldDataHolder { @@ -80,6 +83,16 @@ public class WorldDataHolder { //this.defaultGroup = defaultGroup; } + + /** + * update the dataSource to point to this object. + * + * This should be called whenever a set of world data is fetched. + */ + public void updateDataSource() { + this.groups.setDataSource(this); + this.users.setDataSource(this); + } /** * Search for a user. If it doesn't exist, create a new one with @@ -445,13 +458,13 @@ public class WorldDataHolder { //PROCESS GROUPS FILE Map> inheritance = new HashMap>(); - //try { + try { Map allGroupsNode = (Map) groupsRootDataNode.get("groups"); for (String groupKey : allGroupsNode.keySet()) { Map thisGroupNode = (Map) allGroupsNode.get(groupKey); Group thisGrp = ph.createGroup(groupKey); if (thisGrp == null) { - throw new IllegalArgumentException("I think this user was declared more than once: " + groupKey + " in file: " + groupsFile.getPath()); + throw new IllegalArgumentException("I think this Group was declared more than once: " + groupKey + " in file: " + groupsFile.getPath()); } if (thisGroupNode.get("default") == null) { thisGroupNode.put("default", false); @@ -465,57 +478,72 @@ public class WorldDataHolder { } //PERMISSIONS NODE - if (thisGroupNode.get("permissions") == null) { - thisGroupNode.put("permissions", new ArrayList()); - } - if (thisGroupNode.get("permissions") instanceof List) { - for (Object o : ((List) thisGroupNode.get("permissions"))) { - try { - thisGrp.addPermission(o.toString()); - } catch (NullPointerException e) { - // Ignore this entry as it's null. - //throw new IllegalArgumentException("Invalid permission node in group: " + thisGrp.getName() + " in file: " + groupsFile.getPath()); - } - } - } else if (thisGroupNode.get("permissions") instanceof String) { - thisGrp.addPermission((String) thisGroupNode.get("permissions")); - } else { - throw new IllegalArgumentException("Unknown type of permissions node(Should be String or List) for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath()); + try { + if (thisGroupNode.get("permissions") == null) { + thisGroupNode.put("permissions", new ArrayList()); + } else { + if (thisGroupNode.get("permissions") instanceof List) { + for (Object o : ((List) thisGroupNode.get("permissions"))) { + try { + thisGrp.addPermission(o.toString()); + } catch (NullPointerException e) { + // Ignore this entry as it's null. + //throw new IllegalArgumentException("Invalid permission node in group: " + thisGrp.getName() + " in file: " + groupsFile.getPath()); + } + } + } else if (thisGroupNode.get("permissions") instanceof String) { + thisGrp.addPermission((String) thisGroupNode.get("permissions")); + } else { + throw new IllegalArgumentException("Unknown type of permissions node(Should be String or List) for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath()); + } + thisGrp.sortPermissions(); + } + } catch (Exception e) { + throw new IllegalArgumentException("Invalid formatting found in permissions section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath()); } //INFO NODE - if (thisGroupNode.get("info") instanceof Map) { - Map infoNode = (Map) thisGroupNode.get("info"); - if (infoNode != null) { - thisGrp.setVariables(infoNode); - } - } else - throw new IllegalArgumentException("Unknown entry found in Info section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath()); + try { + if (thisGroupNode.get("info") instanceof Map) { + Map infoNode = (Map) thisGroupNode.get("info"); + if (infoNode != null) { + thisGrp.setVariables(infoNode); + } + } else + throw new IllegalArgumentException("Unknown entry found in Info section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath()); + } catch (Exception e1) { + throw new IllegalArgumentException("Invalid formatting found in info section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath()); + } //END INFO NODE - if (thisGroupNode.get("inheritance") == null || thisGroupNode.get("inheritance") instanceof List) { - Object inheritNode = thisGroupNode.get("inheritance"); - if (inheritNode == null) { - thisGroupNode.put("inheritance", new ArrayList()); - } else if (inheritNode instanceof List) { - List groupsInh = (List) inheritNode; - for (String grp : groupsInh) { - if (inheritance.get(groupKey) == null) { - List thisInherits = new ArrayList(); - inheritance.put(groupKey, thisInherits); - } - inheritance.get(groupKey).add(grp); - - } - } - }else - throw new IllegalArgumentException("Unknown entry found in inheritance section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath()); + try { + if (thisGroupNode.get("inheritance") == null || thisGroupNode.get("inheritance") instanceof List) { + Object inheritNode = thisGroupNode.get("inheritance"); + if (inheritNode == null) { + thisGroupNode.put("inheritance", new ArrayList()); + } else if (inheritNode instanceof List) { + List groupsInh = (List) inheritNode; + for (String grp : groupsInh) { + if (inheritance.get(groupKey) == null) { + List thisInherits = new ArrayList(); + inheritance.put(groupKey, thisInherits); + } + inheritance.get(groupKey).add(grp); + + } + } + }else + throw new IllegalArgumentException("Unknown entry found in inheritance section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath()); + } catch (Exception e2) { + throw new IllegalArgumentException("Invalid formatting found in inheritance section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath()); + } } - //} catch (Exception ex) { - // ex.printStackTrace(); - // throw new IllegalArgumentException("Your Permissions config file is invalid. See console for details."); - //} + } catch (Exception ex) { + ex.printStackTrace(); + throw new IllegalArgumentException("Your " + groupsFile.getPath() + " file is invalid. See console for details."); + } + if (ph.getDefaultGroup() == null) { throw new IllegalArgumentException("There was no Default Group declared in file: " + groupsFile.getPath()); } @@ -581,18 +609,20 @@ public class WorldDataHolder { } if (thisUserNode.get("permissions") == null) { thisUserNode.put("permissions", new ArrayList()); - } - if (thisUserNode.get("permissions") instanceof List) { - for (Object o : ((List) thisUserNode.get("permissions"))) { - thisUser.addPermission(o.toString()); - } - } else if (thisUserNode.get("permissions") instanceof String) { - try { - thisUser.addPermission(thisUserNode.get("permissions").toString()); - } catch (NullPointerException e) { - // Ignore this entry as it's null. - //throw new IllegalArgumentException("Invalid permission node for user: " + thisUser.getName() + " in file: " + UserFile.getPath()); - } + } else { + if (thisUserNode.get("permissions") instanceof List) { + for (Object o : ((List) thisUserNode.get("permissions"))) { + thisUser.addPermission(o.toString()); + } + } else if (thisUserNode.get("permissions") instanceof String) { + try { + thisUser.addPermission(thisUserNode.get("permissions").toString()); + } catch (NullPointerException e) { + // Ignore this entry as it's null. + //throw new IllegalArgumentException("Invalid permission node for user: " + thisUser.getName() + " in file: " + UserFile.getPath()); + } + } + thisUser.sortPermissions(); } //SUBGROUPS LOADING diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/worlds/WorldsHolder.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/worlds/WorldsHolder.java index 686a5495d..e72118468 100644 --- a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/worlds/WorldsHolder.java +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/worlds/WorldsHolder.java @@ -10,6 +10,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; @@ -45,7 +46,7 @@ public class WorldsHolder { private Map mirrorsGroup = new HashMap(); private Map mirrorsUser = new HashMap(); - private OverloadedWorldHolder defaultWorld; + //private OverloadedWorldHolder defaultWorld; private String serverDefaultWorldName; private GroupManager plugin; private File worldsFolder; @@ -59,7 +60,7 @@ public class WorldsHolder { // Setup folders and check files exist for the primary world verifyFirstRun(); initialLoad(); - if (defaultWorld == null) { + if (serverDefaultWorldName == null) { throw new IllegalStateException("There is no default group! OMG!"); } } @@ -76,7 +77,7 @@ public class WorldsHolder { private void initialWorldLoading() { //Load the default world loadWorld(serverDefaultWorldName); - defaultWorld = worldsData.get(serverDefaultWorldName); + //defaultWorld = getUpdatedWorldData(serverDefaultWorldName); } private void loadAllSearchedWorlds() { @@ -117,6 +118,8 @@ public class WorldsHolder { mirrorsGroup.clear(); mirrorsUser.clear(); Map mirrorsMap = plugin.getGMConfig().getMirrorsMap(); + + HashSet mirroredWorlds = new HashSet(); if (mirrorsMap != null) { for (String source : mirrorsMap.keySet()) { @@ -140,6 +143,10 @@ public class WorldsHolder { } mirrorsGroup.put(world, getWorldData(source).getName()); mirrorsUser.put(world, getWorldData(source).getName()); + + // Track this world so we can create a datasource for it later + mirroredWorlds.add(o.toString()); + } else GroupManager.logger.log(Level.WARNING, "Mirroring error with " + o.toString() + ". Recursive loop detected!"); } @@ -171,11 +178,13 @@ public class WorldsHolder { if (type.equals("users")) mirrorsUser.put(key.toLowerCase(), getWorldData(source).getName()); } + + // Track this world so we can create a datasource for it later + mirroredWorlds.add(key); + } else GroupManager.logger.log(Level.WARNING, "Mirroring error with " + key + ". Recursive loop detected!"); - - } else { throw new IllegalStateException("Unknown mirroring format for " + key); } @@ -183,6 +192,14 @@ public class WorldsHolder { } } } + + // Create a datasource for any worlds not already loaded + for (String world : mirroredWorlds){ + if (!worldsData.containsKey(world.toLowerCase())) { + setupWorldFolder(world); + loadWorld(world, true); + } + } } } @@ -320,7 +337,8 @@ public class WorldsHolder { * If the world is not on the worlds list, returns the default world * holder. * - * Mirrors return original world data. + * Mirrors return their parent world data. + * If no mirroring data it returns the default world. * * @param worldName * @return OverloadedWorldHolder @@ -328,12 +346,55 @@ public class WorldsHolder { public OverloadedWorldHolder getWorldData(String worldName) { String worldNameLowered = worldName.toLowerCase(); - if (worldsData.containsKey(worldNameLowered)) - return worldsData.get(worldNameLowered); - + // Find this worlds data + if (worldsData.containsKey(worldNameLowered)) { + + String usersMirror = mirrorsUser.get(worldNameLowered); + String groupsMirror = mirrorsGroup.get(worldNameLowered); + + if (usersMirror != null) { + + // If both are mirrored + if (groupsMirror != null) { + + // if the data sources are the same, return the parent + if (usersMirror == groupsMirror) + return getUpdatedWorldData(usersMirror.toLowerCase()); + + // Both data sources are mirrors, but they are from different parents + // so we return the actual data object. + return getUpdatedWorldData(worldNameLowered); + } + + // Groups isn't a mirror so return this this worlds data source + return getUpdatedWorldData(worldNameLowered); + } + + // users isn't mirrored so we need to return this worlds data source + return getUpdatedWorldData(worldNameLowered); + } + + // Oddly no data source was found for this world so return the default. GroupManager.logger.finest("Requested world " + worldName + " not found or badly mirrored. Returning default world..."); return getDefaultWorld(); } + + /** + * Get the requested world data and update it's dataSource to be relevant for this world + * + * @param worldName + * @return updated world holder + */ + private OverloadedWorldHolder getUpdatedWorldData(String worldName) { + + if (worldsData.containsKey(worldName.toLowerCase())) { + OverloadedWorldHolder data = worldsData.get(worldName.toLowerCase()); + data.updateDataSource(); + return data; + } + return null; + + } /** * Do a matching of playerName, if its found only one player, do @@ -353,6 +414,7 @@ public class WorldsHolder { /** * Retrieves the field player.getWorld().getName() and do * getWorld(worldName) + * * @param player * @return OverloadedWorldHolder */ @@ -476,18 +538,29 @@ public class WorldsHolder { } /** + * Wrapper for LoadWorld(String,Boolean) for backwards compatibility + * * Load a world from file. * If it already been loaded, summon reload method from dataHolder. * @param worldName */ public void loadWorld(String worldName) { + loadWorld(worldName, false); + } + + /** + * Load a world from file. + * If it already been loaded, summon reload method from dataHolder. + * @param worldName + */ + public void loadWorld(String worldName, Boolean isMirror) { if (worldsData.containsKey(worldName.toLowerCase())) { worldsData.get(worldName.toLowerCase()).reload(); return; } GroupManager.logger.finest("Trying to load world " + worldName + "..."); File thisWorldFolder = new File(worldsFolder, worldName); - if (thisWorldFolder.exists() && thisWorldFolder.isDirectory()) { + if ((isMirror) || (thisWorldFolder.exists() && thisWorldFolder.isDirectory())) { // Setup file handles, if not mirrored File groupsFile = (mirrorsGroup.containsKey(worldName.toLowerCase()))? null : new File(thisWorldFolder, "groups.yml"); @@ -564,17 +637,43 @@ public class WorldsHolder { * @return the defaultWorld */ public OverloadedWorldHolder getDefaultWorld() { - return defaultWorld; + return getUpdatedWorldData(serverDefaultWorldName); } /** - * Returns all physically loaded worlds. + * Returns all physically loaded worlds which have at least + * one of their own data sets for users or groups. + * * @return ArrayList of all loaded worlds */ public ArrayList allWorldsDataList() { ArrayList list = new ArrayList(); for (OverloadedWorldHolder data : worldsData.values()) { - if (!list.contains(data)) { + if ((!list.contains(data)) && (!mirrorsGroup.containsKey(data.getName().toLowerCase()) || !mirrorsUser.containsKey(data.getName().toLowerCase()))) { + + String worldNameLowered = data.getName().toLowerCase(); + String usersMirror = mirrorsUser.get(worldNameLowered); + String groupsMirror = mirrorsGroup.get(worldNameLowered); + + // is users mirrored? + if (usersMirror != null) { + + // If both are mirrored + if (groupsMirror != null) { + + // if the data sources are the same, return the parent + if (usersMirror == groupsMirror) { + if (!list.contains(usersMirror.toLowerCase())) + list.add(worldsData.get(usersMirror.toLowerCase())); + continue; + } + // Both data sources are mirrors, but they are from different parents + // so fall through to add the actual data object. + } + // Groups isn't a mirror so fall through to add this this worlds data source + } + + // users isn't mirrored so we need to add this worlds data source list.add(data); } } diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/AnjoPermissionsHandler.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/AnjoPermissionsHandler.java index 2e008e223..bd2829f38 100644 --- a/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/AnjoPermissionsHandler.java +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/AnjoPermissionsHandler.java @@ -121,27 +121,34 @@ public class AnjoPermissionsHandler extends PermissionsReaderInterface { // Add the players own permissions. playerPermArray.addAll(populatePerms(ph.getUser(userName).getPermissionList(), includeChildren)); + ArrayList alreadyProcessed = new ArrayList(); + // fetch all group permissions for (String group : getGroups(userName)) { - Set groupPermArray = new HashSet(); - - if (group.startsWith("g:") && GroupManager.getGlobalGroups().hasGroup(group)) { - // GlobalGroups - groupPermArray = populatePerms(GroupManager.getGlobalGroups().getGroupsPermissions(group), includeChildren); + // Don't process a group more than once. + if (!alreadyProcessed.contains(group)) { + alreadyProcessed.add(group); - } else { - // World Groups - groupPermArray = populatePerms(ph.getGroup(group).getPermissionList(), includeChildren); - } - - // Add all group permissions, unless negated by earlier permissions. - for (String perm : groupPermArray) { - boolean negated = (perm.startsWith("-")); - // Perm doesn't already exists and there is no negation for it - // or It's a negated perm where a normal perm doesn't exists (don't allow inheritance to negate higher perms) - if ((!negated && !playerPermArray.contains(perm) && !playerPermArray.contains("-" + perm)) - || (negated && !playerPermArray.contains(perm.substring(1)))) - playerPermArray.add(perm); + Set groupPermArray = new HashSet(); + + if (group.startsWith("g:") && GroupManager.getGlobalGroups().hasGroup(group)) { + // GlobalGroups + groupPermArray = populatePerms(GroupManager.getGlobalGroups().getGroupsPermissions(group), includeChildren); + + } else { + // World Groups + groupPermArray = populatePerms(ph.getGroup(group).getPermissionList(), includeChildren); + } + + // Add all group permissions, unless negated by earlier permissions. + for (String perm : groupPermArray) { + boolean negated = (perm.startsWith("-")); + // Perm doesn't already exists and there is no negation for it + // or It's a negated perm where a normal perm doesn't exists (don't allow inheritance to negate higher perms) + if ((!negated && !playerPermArray.contains(perm) && !playerPermArray.contains("-" + perm)) + || (negated && !playerPermArray.contains(perm.substring(1)))) + playerPermArray.add(perm); + } } } @@ -153,15 +160,23 @@ public class AnjoPermissionsHandler extends PermissionsReaderInterface { private Set populatePerms (List perms, boolean includeChildren) { Set permArray = new HashSet(); + Boolean allPerms = false; - // Allow * node to populate ALL perms in Bukkit. + // Allow * node to populate ALL permissions to Bukkit. if (perms.contains("*")) { permArray.addAll(GroupManager.BukkitPermissions.getAllRegisteredPermissions(includeChildren)); + allPerms = true; } for (String perm : perms) { if (!perm.equalsIgnoreCase("*")) { + + /** + * all permission sets are passed here pre-sorted, alphabetically. + * This means negated nodes will be processed before all permissions + * other than *. + */ boolean negated = false; if (perm.startsWith("-")) negated = true; @@ -172,12 +187,17 @@ public class AnjoPermissionsHandler extends PermissionsReaderInterface { if ((negated) && (permArray.contains(perm.substring(1)))) permArray.remove(perm.substring(1)); - if (includeChildren) { + /** + * Process child nodes if required, + * or this is a negated node AND we used * to include all permissions, + * in which case we need to remove all children of that node. + */ + if ((includeChildren) || (negated && allPerms)) { Map children = GroupManager.BukkitPermissions.getAllChildren((negated ? perm.substring(1) : perm), new HashSet()); if (children != null) { - if (negated) { + if (negated || (negated && allPerms)) { // Remove children of negated nodes for (String child : children.keySet()) @@ -185,7 +205,7 @@ public class AnjoPermissionsHandler extends PermissionsReaderInterface { if (permArray.contains(child)) permArray.remove(child); - } else { + } else if (!negated){ // Add child nodes for (String child : children.keySet()) diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/BukkitPermissions.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/BukkitPermissions.java index d1193510e..1409f774d 100644 --- a/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/BukkitPermissions.java +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/BukkitPermissions.java @@ -34,6 +34,7 @@ import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerChangedWorldEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerKickEvent; import org.bukkit.event.player.PlayerPortalEvent; @@ -358,6 +359,11 @@ public class BukkitPermissions { } setPlayer_join(false); } + + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerChangeWorld(PlayerChangedWorldEvent event) { // will portal into another world + updatePermissions(event.getPlayer(), event.getPlayer().getWorld().getName()); + } @EventHandler(priority = EventPriority.LOWEST) public void onPlayerPortal(PlayerPortalEvent event) { // will portal into another world diff --git a/lib/Privileges.jar b/lib/Privileges.jar new file mode 100644 index 000000000..e9dd1d04d Binary files /dev/null and b/lib/Privileges.jar differ