summaryrefslogtreecommitdiffstats
path: root/EssentialsGroupManager
diff options
context:
space:
mode:
authorIaccidentally <coryhuckaby@gmail.com>2013-01-11 19:59:22 -0500
committerIaccidentally <coryhuckaby@gmail.com>2013-01-11 19:59:22 -0500
commiteb7cedd6fd5dae2353bdd47b2ce09942460fd8a6 (patch)
tree4c8a85944a28daeffd50b47b8646aaa71b10e71d /EssentialsGroupManager
parent859ca6e9199b2fe3ce652d3cb56a76559c2b4aca (diff)
downloadEssentials-eb7cedd6fd5dae2353bdd47b2ce09942460fd8a6.tar
Essentials-eb7cedd6fd5dae2353bdd47b2ce09942460fd8a6.tar.gz
Essentials-eb7cedd6fd5dae2353bdd47b2ce09942460fd8a6.tar.lz
Essentials-eb7cedd6fd5dae2353bdd47b2ce09942460fd8a6.tar.xz
Essentials-eb7cedd6fd5dae2353bdd47b2ce09942460fd8a6.zip
Revert "Remove GM from 3.0"
This reverts commit a4c93fef05493e6210e8d3d72af7b6d492f4e121.
Diffstat (limited to 'EssentialsGroupManager')
-rw-r--r--EssentialsGroupManager/pom.xml13
-rw-r--r--EssentialsGroupManager/src/Changelog.txt186
-rw-r--r--EssentialsGroupManager/src/config.yml42
-rw-r--r--EssentialsGroupManager/src/globalgroups.yml309
-rw-r--r--EssentialsGroupManager/src/groups.yml74
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/GMConfiguration.java101
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/GlobalGroups.java461
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/GroupManager.java2038
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/Tasks/BukkitPermsUpdateTask.java29
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/data/DataUnit.java181
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Group.java187
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/data/GroupVariables.java94
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/data/User.java273
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/data/UserVariables.java53
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Variables.java208
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/GroupsDataHolder.java123
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/OverloadedWorldHolder.java214
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/UsersDataHolder.java107
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/WorldDataHolder.java1348
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/worlds/WorldsHolder.java719
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMGroupEvent.java87
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMSystemEvent.java62
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMUserEvent.java87
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMWorldListener.java46
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GroupManagerEventHandler.java53
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/AnjoPermissionsHandler.java1184
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/BukkitPermissions.java491
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/PermissionsReaderInterface.java252
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/GMLoggerHandler.java27
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/GroupManagerPermissions.java53
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/PermissionCheckResult.java67
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/StringPermissionComparator.java52
-rw-r--r--EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/Tasks.java175
-rw-r--r--EssentialsGroupManager/src/plugin.yml171
-rw-r--r--EssentialsGroupManager/src/users.yml15
35 files changed, 9582 insertions, 0 deletions
diff --git a/EssentialsGroupManager/pom.xml b/EssentialsGroupManager/pom.xml
new file mode 100644
index 000000000..f0ec22557
--- /dev/null
+++ b/EssentialsGroupManager/pom.xml
@@ -0,0 +1,13 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>net.essentials3</groupId>
+ <artifactId>BuildAll</artifactId>
+ <version>3.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>EssentialsGroupManager</artifactId>
+</project>
diff --git a/EssentialsGroupManager/src/Changelog.txt b/EssentialsGroupManager/src/Changelog.txt
new file mode 100644
index 000000000..4a3c232be
--- /dev/null
+++ b/EssentialsGroupManager/src/Changelog.txt
@@ -0,0 +1,186 @@
+Changelog
+
+v 1.1:
+ - Fixed users being able to use 'manuadd' to add users to higher groups than their own.
+ - Added SuperPerms support so GM will update and provide the permissions to plugins which only support Bukkit Perms.
+ - Added more helpful output to errors on argument lengths.
+ - GroupManager will now attempt to select the default world when using commands instead of failing and telling you to use '/manselect <world>'.
+ - Invalid groups assigned to players in users.yml will no longer cause a crash. GM will now set them to the default group instead.
+ - Fix for Users.yml containing only 'users:' causing a crash.
+ - GroupManager will now generate a fresh Users and Groups yml if either file is empty.
+ - Fix for an infinite loop bug with the new Bukkit Perms during a new user creation.
+ - Fixed BukkitPerms population. Wasn't correctly setting superperms.
+ - Push updates to superperms for all valid GM commands.
+ - All GroupManager commands issued by players are now echoed in the console.
+ - Reverted WorldHolder static change to maintain backward plugin compatibility.
+ - Update to handle 'getDescription().getPermissions(') returning a list (CB 1172).
+ - Fix for null in PLAYER_TELEPORT for bukkit perms.
+ - Fixed wasteful updating of perms on a manload.
+ - manulistp now accepts an additional + to list ALL Superperms effective permissions (/manulistp <name> +).
+ - manucheckp also outputs superperms results.
+ - Removed superperms update on plugins unloading. Unneeded and created undesired lag on shutdown.
+ - Added a BukkitPermsUpdateTask to only update superperms once on a load/reload.
+ - Fix for GM not checking inheritance for known superperms nodes.
+ - Optimized getAllPlayersPermissions and fixed pushing unknown perms to superperms.
+v 1.2:
+ - Changed priority of Registered events to lowest.
+ - Fixed an issue with superperms where plugins define perms with inheritance after the root perms
+v 1.3:
+ - Rewrote Config loading to use Bukkits Configuration features
+ - Added an opOverride setting in config.
+ If present and set to false, op's will not get overriding permissions in GroupManager.
+ (one op will not be able to alter another op's settings)
+ - GM will now create all relevant world data files for non mirrored worlds.
+ (for all worlds named in config.yml)
+ - Attempt to stop GM wiping groups/users yml's on a bad shut down.
+ - Added event handling to manage new world creation at runtime.
+ - Added the ability to handle unknown worlds at server start.
+ (GM will create the data files for any worlds it finds which are not in the config.yml)
+ - Fix for Bukkit passing a null To location on a player Portaling
+ - Fixed manudelsub not correctly selecting the group to remove.
+ - Added two new permission nodes - groupmanager.notify.self & groupmanager.notify.other
+ These allow players/admins to be notified when players are moved between groups.
+v 1.4:
+ - Updated for Bukkits new YamlConfiguration.
+ - Cleared remaining Cast errors cause by object cloning.
+ - Removed extra notification messages for the player issuing the group move command.
+ - Added a config setting - bukkit_perms_override: false
+ Enable to allow default Bukkit based permissions to remain enabled, unless directly negated within GroupManager.
+ - Fixed reading world mirrors from the config.
+ - Simplified config.yml while retaining backwards compatibility.
+ - Added data.save.hours setting to config. This allow control over how long backups are retained.
+v 1.5:
+ - Fixed opOverrides and bukkit_perms_override to read the correct entries.
+ - Better commenting in config.yml
+ - Fixed GM to recognize Superperm child nodes.
+ If you add a node like Towny.admin GM will now correctly report on all child nodes.
+ - Fixed GM loading world data files twice at startup.
+ - Improved error reporting for invalid groups.yml
+ - Added Global Groups
+ Defined in groupmanager/globalgroups.yml.
+ Create groups in the yml with a g: prefix, then inherit in the worlds groups files.
+ - Added Info node support to Global Groups.
+ - Fixed an error on 'manucheckv'. If the users doesn't have the variable it fell through causing an exception.
+ - Added checking of subgroups for Info nodes.
+ - Expanded 'canUserBuild()' to include inheritance and subgroups.
+ - Added a config.yml setting of 'validate_toggle' for those who prefer 'mantogglevalidate' to always be off.
+ - Prevent setting 'minutes' in the config to zero causing an error.
+ - GM will now check to see if it's data files have been changed at each scheduled save.
+ If the files have been altered (on disc) it will reload, so long as the in-memory data hasn't changed.
+ If the files on Disc have changed AND there have been changes to it's in-memory data it will show a warning.
+ You then MUST issue a '/mansave force' to overwrite the disc files, or a '/manload' to overwrite the memory data.
+ - Fix for an error in checkFullUserPermission caused by players disconnecting mid perms update.
+ - Notification of being moved to the default group only happens if it's a demotion/promotion (not on join).
+ - Fixed GM holding files open and causing the time stamp to be incorrect. This caused GM to require a '/mansave force' when it shouldn't be needed.
+ - Fixed a crash on reload due to bukkit not unloading plugins before reloading.
+v 1.6:
+ - Prevent Group.equals tests throwing a NullPointerException for GlobalGroups.
+ - Stop throwing errors on an empty users file.
+ - Optimize sorting to speedup permission tests.
+ - Fix superperms to pass all tests http://dev.bukkit.org/server-mods/superpermstest/
+ - Optimizations include changing the return of comparePermissionString.
+ - Added file details in error messages for loading groups/users.
+v 1.7:
+ - GM now supports offline players without having to mantogglevalidate
+ - Offline player checks now support partial name matches.
+ - Added custom events so plugins can now be notified of changes within GroupManager.
+ - GM now registers with Bukkits ServicesManager.
+ - deleting the contents of GlobalGroups.yml will no longer thrown a NullPointerException.
+ - Removed op permissions from admins in the default GloblaGroups.yml.
+v 1.8:
+ - Changed ServicesManager registration to lowest from normal.
+ - Fixed 'manucheckp' returning a null for the searched node when it's a group/subgroup.
+ - 'manpromote' and 'mandemote' now correctly send the notification to the console if the command was issued there.
+ - Expanded GlobalGroups.yml and Groups.yml to include Towny permissions.
+ - Delayed GroupManager events so Superperms will be fully updated before plugins receive the events.
+ - Changed the way events are raised to prevent variable corruption.
+ - Reload GlobalGroups when you perform a world load.
+ - Changed GlobalGroups to save/load before local groups in the scheduled data saving/loading
+ - Fix 'manucheckp' to correctly report if a permission is available from GroupManager or Bukkit.
+ - Changed over to a reflection method for populating superperms as Bukkit lags when you handle permissions one at a time.
+ - Major, MAJOR changes to support partial/full world mirroring.
+ You can now mirror groups.yml, users.yml or both files between different worlds.
+ - Catch NullPointerErrors generated by blank permission nodes.
+ - Removed '- bukkit.command' form the globalgroups permission nodes.
+v 1.9:
+ - Optimize populating Bukkit perms so we no longer calculate the child nodes (Bukkit already does this).
+ - Added a tidy error message for invalid permission entries in GlobalGroups.
+ - Better optimize assembling of a players permissions and allow the * node to populate all registered superperms.
+ - Fixed text when adding a subgroup to not say the player was moved.
+ - Update to new Bukkit Event system.
+ - Update GroupManagerBridge for new event system.
+ - Fixed a random null error upon a player portaling.
+ - Fixed infinite loop error on player join.
+ - Optimized code to only update the player logging in instead of all players online.
+ - Added recursive loop detection for World mirroring (you may not set the main world as a mirror of another).
+ - Fixed fetching world data so it no longer returns the mirrored world for groups. Each world data holder now points to the correct data set, so can be returned as an object.
+ - Changed addSubGroup() to only add the group if it doesn't already exist (no need to update an already existing group).
+ - addSubGroup now returns a boolean for success/failure.
+ - '/manuaddsub' now correctly reports if it was able to add the sub group.
+ - Allow negation to the * permission node when populating superperms.
+ - Fix trying to modify an unmodifiable collection breaking superperms.
+ - Fixed subgroups (I broke earlier).
+ - Check for a null player object in the PlayerTeleportEvent.
+ - Trap errors in fetching the mirrors map.
+ - 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.
+ - 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.
+ - Depreciate PlayerTeleportEvent, PlayerRespawnEvent and PlayerPortalEvent as it's all handled in PlayerChangedWorldEvent.
+ This also means we no longer update permissions before we change worlds.
+ - A command of '/manload' with no world arguments now performs a full reload of GM.
+ - Update for Bukkit R5 compatability.
+ - Removed BukkitPermsOverride as this is now the default with bukkit handling child nodes.
+ - Prevent adding inheritances and info nodes to globalgroups. These are permissions collections, not player groups.
+ - Prevent promoting players to, and demoting to GlobalGroups.
+ - Make 'manload' reload the config correctly.
+ - Minor optimization when checking bukkit permissions.
+ - Better reporting when a users.yml is failing to load.
+ - Expanded '/manuadd'to accept an optional variable for the world (eg '/manuadd <player> <group> <world>').
+ - Removed some debug spam.
+ - Don't remove an attachment on a player leaving as Bukkit never forgets it. This fixes non mirrored permissions being messed up if a player relogs.
+ - Treat all world names as lower case for file handling (please check in your worlds folder. You should have no folders with upper case letters from now).
+ - Auto rename all case sensitive world folders to lower case (if possible).
+ - Update GlobalGroups.yml for new/changed Towny permission nodes.
+ - Stop attempting to push empty permissions when players edit the yml's incorrectly.
+ - Catch errors caused by bad indentation in yml's.
+ - Force remove player attachments on disconnect, and tidyup during player join in case of any errors. Fixes a bug of losing permissions.
+ - Added a new permission node 'groupmanager.op'. This will cause players with this node to be treated as op's when
+ using GroupManager commands (they will still require each commands permission node to use them).
+ - Prevent Null entries in group inheritance from throwing errors.
+v 2.0:
+ - Fix GM reporting of permission inheritance to retain the correct order. Lower inheritance groups can no longer negate a higher groups permissions.
+ - Fix an error I caused trying to modify an unmodifiable list when parsing '*' permissions.
+ - Don't throw errors when attempting to remove permission attachments (bukkit will have already removed it).
+ - Remove all permission attachments when performing a manload or restart.
+ - Expand 'manwhois' to also list a users subgroups.
+ - Fix a concurrent modification error when removing all attachments.
+ - Better handling of errors in user and group yml's.
+ - Added missing confirmation message on '/manload'.
+ - Stop the error on shutdown if GM failed to load at startup.
+ - GroupManager will now generate it's own log (in the GM folder) to keep things tidy, but also to account of those players unable to find/access their server.log.
+ - Startup errors will now lock out ALL commands other than '/manload'
+ - Fix 'manuadd' to use the default or selected world (via 'manselect'), if the world is not specified in the command.
+ - Expand GlobalGroups.yml and groups.yml to cover the VanishNoPacket plugin. Demonstrating how to negate and add nodes when using the '*' permission with inheritance.
+ - Fix silly nested throw/catch statements. Errors are now correctly generated when reading yml's.
+ - Unregister the worldsHolder as a service on a reload/shutdown instead of the whole plugin.
+ - Update all code formatting to use tabs for indentation.
+ - Stop using our own deprecated methods as we tell others to do.
+ - Finally remove all deprecated methods.
+ - Re-initialize the WorldsHolder on a reload, as un-registering and re-registering a new holder means all plugins have to check for the new service on every quiery.
+ - Prevent null perms getting past the GlobalGroups loader.
+ - Fix forgetting sub groups on a manload.
+ - Allow 'manucheckp' to notify when superperms reports false but it is really negated. \ No newline at end of file
diff --git a/EssentialsGroupManager/src/config.yml b/EssentialsGroupManager/src/config.yml
new file mode 100644
index 000000000..cc90bea6f
--- /dev/null
+++ b/EssentialsGroupManager/src/config.yml
@@ -0,0 +1,42 @@
+settings:
+ config:
+ # With this enabled anyone set as op has full permissions when managing GroupManager
+ # The user will be able to promote players to the same group or even above.
+ opOverrides: true
+
+ # Default setting for 'mantoglevalidate'
+ # true will cause GroupManager to attempt name matching by default.
+ validate_toggle: true
+
+ data:
+ save:
+ # How often GroupManager will save it's data back to groups and users.yml
+ minutes: 10
+ # Number of hours to retain backups (plugins/GroupManager/backup)
+ hours: 24
+
+ logging:
+ # level of detail GroupManager will use when logging.
+ # Acceptable entries are - ALL,CONFIG,FINE,FINER,FINEST,INFO,OFF,SEVERE,WARNING
+ level: INFO
+
+ mirrors:
+ # Worlds listed here have their settings mirrored in their children.
+ # The first element 'world' is the main worlds name
+ # subsequent elements 'world_nether' and 'world_the_end' are worlds which will use
+ # the same user/groups files as the parent.
+ # Each child world can be configured to mirror the 'groups', 'users' or both files from it's parent.
+ world:
+ world_nether:
+ - users
+ - groups
+ world_the_end:
+ - users
+ - groups
+ # world2: (World2 would have it's own set of user and groups files)
+ # world3:
+ # - users (World3 would use the users.yml from world2, but it's own groups.yml)
+ # world4:
+ # - groups (World4 would use the groups.yml from world2, but it's own users.yml)
+ # world5:
+ # - world6 (this would cause world6 to mirror both files from world5) \ No newline at end of file
diff --git a/EssentialsGroupManager/src/globalgroups.yml b/EssentialsGroupManager/src/globalgroups.yml
new file mode 100644
index 000000000..04b670ae7
--- /dev/null
+++ b/EssentialsGroupManager/src/globalgroups.yml
@@ -0,0 +1,309 @@
+# These groups only contain permission nodes.
+#
+# **** You can NOT add anything other than permission nodes ****
+#
+# These collections are to be inherited in your different worlds groups.yml's
+# They can also be added as one of a users subgroups, but NOT as a primary group.
+# These collections are available to ALL group and user yml's.
+#
+# Add to and customize these groups to fit yoru needs.
+
+groups:
+
+# Permission nodes for GroupManager
+# by ElgarL, snowleo, continued from gabrielcouto's original
+# http://dev.bukkit.org/server-mods/essentials/
+
+ g:groupmanager_default:
+ permissions:
+ - groupmanager.notify.self
+
+ g:groupmanager_moderator:
+ permissions:
+ - groupmanager.listgroups
+ - groupmanager.mandemote
+ - groupmanager.manpromote
+ - groupmanager.manselect
+ - groupmanager.manuadd
+ - groupmanager.manudel
+ - groupmanager.manwhois
+ - groupmanager.notify.other
+
+ g:groupmanager_admin:
+ permissions:
+ - groupmanager.mantogglevalidate
+ - groupmanager.mansave
+ - groupmanager.mangcheckp
+ - groupmanager.manglistp
+ - groupmanager.manucheckp
+ - groupmanager.manulistp
+
+# Permission nodes for CraftBukkit
+# by many devs and contributors
+# http://dl.bukkit.org/
+
+ g:bukkit_default:
+ permissions:
+ - bukkit.broadcast.user
+ - -bukkit.command.plugins
+
+ g:bukkit_moderator:
+ permissions:
+ - bukkit.command.ban
+ - bukkit.command.ban.ip
+ - bukkit.command.ban.player
+ - bukkit.command.gamemode
+ - bukkit.command.kick
+ - bukkit.command.unban
+ - bukkit.command.unban.ip
+ - bukkit.command.unban.player
+
+ g:bukkit_admin:
+ permissions:
+ - bukkit.broadcast
+ - bukkit.broadcast.admin
+ - bukkit.command.give
+ - bukkit.command.help
+ - bukkit.command.kill
+ - bukkit.command.list
+ - bukkit.command.me
+ - -bukkit.command.op
+ - -bukkit.command.op.give
+ - -bukkit.command.op.take
+ - bukkit.command.plugins
+ - bukkit.command.reload
+ - bukkit.command.save
+ - bukkit.command.save.disable
+ - bukkit.command.save.enable
+ - bukkit.command.save.perform
+ - bukkit.command.say
+ - bukkit.command.stop
+ - bukkit.command.teleport
+ - bukkit.command.tell
+ - bukkit.command.time
+ - bukkit.command.time.add
+ - bukkit.command.time.set
+ - bukkit.command.version
+ - bukkit.command.whitelist
+ - bukkit.command.whitelist.add
+ - bukkit.command.whitelist.disable
+ - bukkit.command.whitelist.enable
+ - bukkit.command.whitelist.list
+ - bukkit.command.whitelist.reload
+ - bukkit.command.whitelist.remove
+
+# Permission nodes for Essentials
+# by ementalo, snowleo, and KHobbits
+# http://dev.bukkit.org/server-mods/essentials/
+
+ g:essentials_default:
+ permissions:
+ - essentials.help
+ - essentials.helpop
+ - essentials.list
+ - essentials.motd
+ - essentials.rules
+ - essentials.spawn
+
+ g:essentials_builder:
+ permissions:
+ - essentials.afk
+ - essentials.back
+ - essentials.back.ondeath
+ - essentials.balance
+ - essentials.balance.others
+ - essentials.balancetop
+ - essentials.chat.color
+ - essentials.chat.format
+ - essentials.chat.shout
+ - essentials.chat.question
+ - essentials.compass
+ - essentials.delhome
+ - essentials.depth
+ - essentials.getpos
+ - essentials.home
+ - essentials.ignore
+ - essentials.itemdb
+ - essentials.kit
+ - essentials.kit.tools
+ - essentials.mail
+ - essentials.mail.send
+ - essentials.me
+ - essentials.msg
+ - essentials.msg.color
+ - essentials.msg.format
+ - essentials.nick
+ - essentials.pay
+ - essentials.ping
+ - essentials.powertool
+ - essentials.powertooltoggle
+ - essentials.protect
+ - essentials.seen
+ - essentials.sethome
+ - essentials.sethome.multiple
+ - essentials.signs.use.*
+ - essentials.signs.create.disposal
+ - essentials.signs.create.mail
+ - essentials.signs.create.protection
+ - essentials.signs.create.trade
+ - essentials.signs.break.disposal
+ - essentials.signs.break.mail
+ - essentials.signs.break.protection
+ - essentials.signs.break.trade
+ - essentials.suicide
+ - essentials.time
+ - essentials.tpa
+ - essentials.tpaccept
+ - essentials.tpahere
+ - essentials.tpdeny
+ - essentials.warp
+ - essentials.warp.list
+ - essentials.worth
+
+ g:essentials_moderator:
+ permissions:
+ - -essentials.spawner.enderdragon
+ - essentials.afk.kickexempt
+ - essentials.ban
+ - essentials.ban.notify
+ - essentials.banip
+ - essentials.broadcast
+ - essentials.chat.url
+ - essentials.chat.magic
+ - essentials.clearinventory
+ - essentials.delwarp
+ - essentials.eco.loan
+ - essentials.ext
+ - essentials.fly
+ - essentials.getpos
+ - essentials.getpos.others
+ - essentials.helpop.recieve
+ - essentials.home.others
+ - essentials.invsee
+ - essentials.jails
+ - essentials.jump
+ - essentials.kick
+ - essentials.kick.notify
+ - essentials.kill
+ - essentials.kit.*
+ - essentials.msg.magic
+ - essentials.mute
+ - essentials.nick.color
+ - essentials.nick.others
+ - essentials.realname
+ - essentials.seen.banreason
+ - essentials.seen.extra
+ - essentials.setwarp
+ - essentials.signs.create.*
+ - essentials.signs.break.*
+ - essentials.spawner
+ - essentials.spawner.*
+ - essentials.thunder
+ - essentials.time
+ - essentials.time.set
+ - essentials.protect.alerts
+ - essentials.protect.admin
+ - essentials.protect.ownerinfo
+ - essentials.ptime
+ - essentials.ptime.others
+ - essentials.togglejail
+ - essentials.top
+ - essentials.tp
+ - essentials.tp.others
+ - essentials.tphere
+ - essentials.tppos
+ - essentials.tptoggle
+ - essentials.unban
+ - essentials.unbanip
+ - essentials.weather
+ - essentials.whois
+ - essentials.world
+ - essentials.world.*
+
+ g:essentials_admin:
+ permissions:
+ - -essentials.backup
+ - -essentials.essentials
+ - -essentials.setspawn
+ - -essentials.reloadall
+ - -essentials.plugin
+ - essentials.*
+
+# Permission nodes for Towny by ElgarL
+# http://dev.bukkit.org/server-mods/towny-advanced/
+
+ g:towny_default:
+ permissions:
+ - towny.chat.general
+ - towny.chat.local
+
+ g:towny_builder:
+ permissions:
+ - towny.town.*
+ - towny.nation.*
+ - towny.chat.town
+ - towny.chat.nation
+ - towny.wild.build.6
+ - towny.wild.destroy.6
+ - towny.wild.destroy.14
+ - towny.wild.destroy.15
+ - towny.wild.destroy.16
+ - towny.wild.build.17
+ - towny.wild.destroy.17
+ - towny.wild.destroy.18
+ - towny.wild.destroy.21
+ - towny.wild.destroy.31
+ - towny.wild.destroy.37
+ - towny.wild.destroy.38
+ - towny.wild.destroy.39
+ - towny.wild.destroy.40
+ - towny.wild.destroy.50
+ - towny.wild.destroy.56
+ - towny.wild.destroy.73
+ - towny.wild.destroy.74
+ - towny.wild.destroy.78
+ - towny.wild.destroy.81
+ - towny.wild.destroy.82
+ - towny.wild.destroy.83
+ - towny.wild.destroy.86
+ - towny.wild.destroy.103
+ - towny.wild.destroy.106
+ - towny.wild.destroy.111
+ - towny.wild.destroy.115
+
+ g:towny_moderator:
+ permissions:
+ - towny.chat.mod
+ - towny.wild.switch.64
+ - towny.wild.build.83
+ - towny.wild.build.86
+ - towny.wild.build.103
+ - towny.wild.build.111
+ - towny.wild.build.115
+
+ g:towny_admin:
+ permissions:
+ - towny.admin
+ - -towny.wild.destroy.119
+ - -towny.wild.destroy.120
+ - towny.chat.admin
+
+# Permission nodes for VanishNoPacket by mbaxter
+# http://dev.bukkit.org/server-mods/vanish/
+
+ g:vanish_moderator:
+ permissions:
+ - -vanish.*
+ - vanish.vanish
+ - vanish.smokin
+ - vanish.nofollow
+ - vanish.nopickup
+ - vanish.preventincomingdamage
+ - vanish.hooks.dynmap.alwayshidden
+ - vanish.hooks.essentials.hide
+
+ g:vanish_admin:
+ permissions:
+ - vanish.silentjoin
+ - vanish.silentquit
+ - vanish.silentchests
diff --git a/EssentialsGroupManager/src/groups.yml b/EssentialsGroupManager/src/groups.yml
new file mode 100644
index 000000000..9c63ffd94
--- /dev/null
+++ b/EssentialsGroupManager/src/groups.yml
@@ -0,0 +1,74 @@
+# Group inheritance
+#
+# Any inherited groups prefixed with a g: are global groups
+# and are inherited from the GlobalGroups.yml.
+#
+# Groups without the g: prefix are groups local to this world
+# and are defined in the this groups.yml file.
+#
+# Local group inheritances define your promotion tree when using 'manpromote/mandemote'
+
+groups:
+ Default:
+ default: true
+ permissions:
+ - -bukkit.command.kill
+ inheritance:
+ - g:groupmanager_default
+ - g:bukkit_default
+ - g:essentials_default
+ - g:towny_default
+ info:
+ prefix: '&e'
+ build: false
+ suffix: ''
+ Builder:
+ default: false
+ permissions: []
+ inheritance:
+ - default
+ - g:essentials_builder
+ - g:towny_builder
+ info:
+ prefix: '&2'
+ build: true
+ suffix: ''
+ Moderator:
+ default: false
+ permissions: []
+ inheritance:
+ - builder
+ - g:groupmanager_moderator
+ - g:bukkit_moderator
+ - g:essentials_moderator
+ - g:towny_moderator
+ - g:vanish_moderator
+ info:
+ prefix: '&5'
+ build: true
+ suffix: ''
+ Admin:
+ default: false
+ permissions: []
+ inheritance:
+ - moderator
+ - g:groupmanager_admin
+ - g:bukkit_admin
+ - g:essentials_admin
+ - g:towny_admin
+ - g:vanish_admin
+ info:
+ prefix: '&c'
+ build: true
+ suffix: ''
+ Owner:
+ default: false
+ permissions:
+ - '*'
+ - -vanish.*
+ inheritance:
+ - admin
+ info:
+ prefix: '&4'
+ build: true
+ suffix: ''
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/GMConfiguration.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/GMConfiguration.java
new file mode 100644
index 000000000..0832000f2
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/GMConfiguration.java
@@ -0,0 +1,101 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anjocaido.groupmanager;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+import java.util.logging.Level;
+
+import org.anjocaido.groupmanager.utils.Tasks;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+/**
+ *
+ * @author gabrielcouto
+ */
+public class GMConfiguration {
+
+ private GroupManager plugin;
+ private File configFile;
+ private YamlConfiguration GMconfig;
+
+ public GMConfiguration(GroupManager plugin) {
+
+ this.plugin = plugin;
+ load();
+ }
+
+ public void load() {
+
+ if (!plugin.getDataFolder().exists()) {
+ plugin.getDataFolder().mkdirs();
+ }
+ configFile = new File(plugin.getDataFolder(), "config.yml");
+
+ if (!configFile.exists()) {
+ try {
+ Tasks.copy(plugin.getResourceAsStream("config.yml"), configFile);
+ } catch (IOException ex) {
+ GroupManager.logger.log(Level.SEVERE, null, ex);
+ }
+ }
+
+ GMconfig = new YamlConfiguration();
+
+ try {
+ GMconfig.load(configFile);
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("The following file couldn't pass on Parser.\n" + configFile.getPath(), ex);
+ }
+
+ // Setup defaults
+ adjustLoggerLevel();
+ plugin.setValidateOnlinePlayer(isToggleValidate());
+ }
+
+ public boolean isOpOverride() {
+
+ return GMconfig.getBoolean("settings.config.opOverrides", true);
+ }
+
+ public boolean isToggleValidate() {
+
+ return GMconfig.getBoolean("settings.config.validate_toggle", true);
+ }
+
+ public Map<String, Object> getMirrorsMap() {
+
+ // Try to fetch the old mirror path first
+ if (GMconfig.isConfigurationSection("settings.permission.world.mirror")) {
+ return (Map<String, Object>) GMconfig.getConfigurationSection("settings.permission.world.mirror").getValues(false);
+ } else if (GMconfig.isConfigurationSection("settings.mirrors")) {
+ return (Map<String, Object>) GMconfig.getConfigurationSection("settings.mirrors").getValues(false);
+ }
+ return null;
+
+ }
+
+ public Integer getSaveInterval() {
+
+ return GMconfig.getInt("settings.data.save.minutes", 10);
+ }
+
+ public Integer getBackupDuration() {
+
+ return GMconfig.getInt("settings.data.save.hours", 24);
+ }
+
+ public void adjustLoggerLevel() {
+
+ try {
+ GroupManager.logger.setLevel(Level.parse(GMconfig.getString("settings.logging.level", "INFO")));
+ return;
+ } catch (Exception e) {
+ }
+
+ GroupManager.logger.setLevel(Level.INFO);
+ }
+} \ No newline at end of file
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/GlobalGroups.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/GlobalGroups.java
new file mode 100644
index 000000000..04d9e86be
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/GlobalGroups.java
@@ -0,0 +1,461 @@
+package org.anjocaido.groupmanager;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+
+import org.anjocaido.groupmanager.data.Group;
+import org.anjocaido.groupmanager.events.GMGroupEvent;
+import org.anjocaido.groupmanager.events.GroupManagerEventHandler;
+import org.anjocaido.groupmanager.utils.PermissionCheckResult;
+import org.anjocaido.groupmanager.utils.Tasks;
+import org.bukkit.configuration.MemorySection;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * @author ElgarL
+ *
+ */
+public class GlobalGroups {
+
+ private GroupManager plugin;
+ private YamlConfiguration GGroups;
+
+ private Map<String, Group> groups;
+
+ protected long timeStampGroups = 0;
+ protected boolean haveGroupsChanged = false;
+ protected File GlobalGroupsFile = null;
+
+ public GlobalGroups(GroupManager plugin) {
+
+ this.plugin = plugin;
+ load();
+ }
+
+ /**
+ * @return the haveGroupsChanged
+ */
+ public boolean haveGroupsChanged() {
+
+ if (this.haveGroupsChanged) {
+ return true;
+ }
+ for (Group g : groups.values()) {
+ if (g.isChanged()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return the timeStampGroups
+ */
+ public long getTimeStampGroups() {
+
+ return timeStampGroups;
+ }
+
+ /**
+ * @param timeStampGroups the timeStampGroups to set
+ */
+ protected void setTimeStampGroups(long timeStampGroups) {
+
+ this.timeStampGroups = timeStampGroups;
+ }
+
+ /**
+ * @param haveGroupsChanged
+ * the haveGroupsChanged to set
+ */
+ public void setGroupsChanged(boolean haveGroupsChanged) {
+
+ this.haveGroupsChanged = haveGroupsChanged;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void load() {
+
+ GGroups = new YamlConfiguration();
+
+ GroupManager.setLoaded(false);
+
+ // READ globalGroups FILE
+ if (GlobalGroupsFile == null)
+ GlobalGroupsFile = new File(plugin.getDataFolder(), "globalgroups.yml");
+
+ if (!GlobalGroupsFile.exists()) {
+ try {
+ // Create a new file if it doesn't exist.
+ Tasks.copy(plugin.getResourceAsStream("globalgroups.yml"), GlobalGroupsFile);
+ } catch (IOException ex) {
+ GroupManager.logger.log(Level.SEVERE, null, ex);
+ }
+ }
+
+ try {
+ GGroups.load(GlobalGroupsFile);
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("The following file couldn't pass on Parser.\n" + GlobalGroupsFile.getPath(), ex);
+ }
+
+ // Clear out old groups
+ resetGlobalGroups();
+
+ if (!GGroups.getKeys(false).isEmpty()) {
+ // Read all global groups
+ Map<String, Object> allGroups = new HashMap<String, Object>();
+
+ try {
+ allGroups = (Map<String, Object>) GGroups.getConfigurationSection("groups").getValues(false);
+ } catch (Exception ex) {
+ // ex.printStackTrace();
+ throw new IllegalArgumentException("Your " + GlobalGroupsFile.getPath() + " file is invalid. See console for details.", ex);
+ }
+
+ // Load each groups permissions list.
+ if (allGroups != null) {
+
+ Iterator<String> groupItr = allGroups.keySet().iterator();
+ String groupName;
+ Integer groupCount = 0;
+
+ /*
+ * loop each group entry
+ * and read it's data.
+ */
+ while (groupItr.hasNext()) {
+ try {
+ groupCount++;
+ // Attempt to fetch the next group name.
+ groupName = groupItr.next();
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Invalid group name for GlobalGroup entry (" + groupCount + ") in file: " + GlobalGroupsFile.getPath(), ex);
+ }
+
+ /*
+ * Create a new group with this name.
+ */
+ Group newGroup = new Group(groupName.toLowerCase());
+ Object element;
+
+ // Permission nodes
+ element = GGroups.get("groups." + groupName + ".permissions");
+
+ if (element != null)
+ if (element instanceof List) {
+ try {
+ for (String node : (List<String>) element) {
+ if ((node != null) && !node.isEmpty())
+ newGroup.addPermission(node);
+ }
+ } catch (ClassCastException ex) {
+ throw new IllegalArgumentException("Invalid permission node for global group: " + groupName, ex);
+ }
+ } else if (element instanceof String) {
+ if ((element != null) && !((String)element).isEmpty())
+ newGroup.addPermission((String) element);
+ } else
+ throw new IllegalArgumentException("Unknown type of permission node for global group: " + groupName);
+
+ // Info nodes
+ element = GGroups.get("groups." + groupName + ".info");
+
+ if (element != null)
+ if (element instanceof MemorySection) {
+ Map<String, Object> vars = new HashMap<String, Object>();
+ for (String key : ((MemorySection) element).getKeys(false)) {
+ vars.put(key, ((MemorySection) element).get(key));
+ }
+ newGroup.setVariables(vars);
+ } else
+ throw new IllegalArgumentException("Unknown type of info node for global group: " + groupName);
+
+ // Push a new group
+ addGroup(newGroup);
+ }
+ }
+
+ removeGroupsChangedFlag();
+ }
+
+ setTimeStampGroups(GlobalGroupsFile.lastModified());
+ GroupManager.setLoaded(true);
+ // GlobalGroupsFile = null;
+ }
+
+ /**
+ * Write the globalgroups.yml file
+ */
+
+ public void writeGroups(boolean overwrite) {
+
+ // File GlobalGroupsFile = new File(plugin.getDataFolder(), "globalgroups.yml");
+
+ if (haveGroupsChanged()) {
+ if (overwrite || (!overwrite && (getTimeStampGroups() >= GlobalGroupsFile.lastModified()))) {
+ Map<String, Object> root = new HashMap<String, Object>();
+
+ Map<String, Object> groupsMap = new HashMap<String, Object>();
+ root.put("groups", groupsMap);
+ for (String groupKey : groups.keySet()) {
+ Group group = groups.get(groupKey);
+
+ // Group header
+ Map<String, Object> aGroupMap = new HashMap<String, Object>();
+ groupsMap.put(group.getName(), aGroupMap);
+
+ // Info nodes
+ Map<String, Object> infoMap = new HashMap<String, Object>();
+ aGroupMap.put("info", infoMap);
+
+ for (String infoKey : group.getVariables().getVarKeyList()) {
+ infoMap.put(infoKey, group.getVariables().getVarObject(infoKey));
+ }
+
+ // Permission nodes
+ aGroupMap.put("permissions", group.getPermissionList());
+ }
+
+ if (!root.isEmpty()) {
+ DumperOptions opt = new DumperOptions();
+ opt.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
+ final Yaml yaml = new Yaml(opt);
+ try {
+ yaml.dump(root, new OutputStreamWriter(new FileOutputStream(GlobalGroupsFile), "UTF-8"));
+ } catch (UnsupportedEncodingException ex) {
+ } catch (FileNotFoundException ex) {
+ }
+ }
+ setTimeStampGroups(GlobalGroupsFile.lastModified());
+ } else {
+ // Newer file found.
+ GroupManager.logger.log(Level.WARNING, "Newer GlobalGroups file found, but we have local changes!");
+ throw new IllegalStateException("Unable to save unless you issue a '/mansave force'");
+ }
+ removeGroupsChangedFlag();
+ } else {
+ // Check for newer file as no local changes.
+ if (getTimeStampGroups() < GlobalGroupsFile.lastModified()) {
+ System.out.print("Newer GlobalGroups file found (Loading changes)!");
+ // Backup GlobalGroups file
+ backupFile();
+ load();
+ }
+ }
+
+ }
+
+ /**
+ * Backup the BlobalGroups file
+ *
+ * @param w
+ */
+ private void backupFile() {
+
+ File backupFile = new File(plugin.getBackupFolder(), "bkp_ggroups_" + Tasks.getDateString() + ".yml");
+ try {
+ Tasks.copy(GlobalGroupsFile, backupFile);
+ } catch (IOException ex) {
+ GroupManager.logger.log(Level.SEVERE, null, ex);
+ }
+ }
+
+ /**
+ * Adds a group, or replaces an existing one.
+ *
+ * @param groupToAdd
+ */
+ public void addGroup(Group groupToAdd) {
+
+ // Create a new group if it already exists
+ if (hasGroup(groupToAdd.getName())) {
+ groupToAdd = groupToAdd.clone();
+ removeGroup(groupToAdd.getName());
+ }
+
+ newGroup(groupToAdd);
+ haveGroupsChanged = true;
+ if (GroupManager.isLoaded())
+ GroupManagerEventHandler.callEvent(groupToAdd, GMGroupEvent.Action.GROUP_ADDED);
+ }
+
+ /**
+ * Creates a new group if it doesn't already exist.
+ *
+ * @param newGroup
+ */
+ public Group newGroup(Group newGroup) {
+
+ // Push a new group
+ if (!groups.containsKey(newGroup.getName().toLowerCase())) {
+ groups.put(newGroup.getName().toLowerCase(), newGroup);
+ this.setGroupsChanged(true);
+ return newGroup;
+ }
+ return null;
+ }
+
+ /**
+ * Delete a group if it exist.
+ *
+ * @param groupName
+ */
+ public boolean removeGroup(String groupName) {
+
+ // Push a new group
+ if (groups.containsKey(groupName.toLowerCase())) {
+ groups.remove(groupName.toLowerCase());
+ this.setGroupsChanged(true);
+ if (GroupManager.isLoaded())
+ GroupManagerEventHandler.callEvent(groupName.toLowerCase(), GMGroupEvent.Action.GROUP_REMOVED);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the Global Group exists in the globalgroups.yml
+ *
+ * @param groupName
+ * @return true if the group exists
+ */
+ public boolean hasGroup(String groupName) {
+
+ return groups.containsKey(groupName.toLowerCase());
+ }
+
+ /**
+ * Returns true if the group has the correct permission node.
+ *
+ * @param groupName
+ * @param permissionNode
+ * @return true if node exists
+ */
+ public boolean hasPermission(String groupName, String permissionNode) {
+
+ if (!hasGroup(groupName))
+ return false;
+
+ return groups.get(groupName.toLowerCase()).hasSamePermissionNode(permissionNode);
+
+ }
+
+ /**
+ * Returns a PermissionCheckResult of the permission node for the group to
+ * be tested against.
+ *
+ * @param groupName
+ * @param permissionNode
+ * @return PermissionCheckResult object
+ */
+ public PermissionCheckResult checkPermission(String groupName, String permissionNode) {
+
+ PermissionCheckResult result = new PermissionCheckResult();
+ result.askedPermission = permissionNode;
+ result.resultType = PermissionCheckResult.Type.NOTFOUND;
+
+ if (!hasGroup(groupName))
+ return result;
+
+ Group tempGroup = groups.get(groupName.toLowerCase());
+
+ if (tempGroup.hasSamePermissionNode(permissionNode))
+ result.resultType = PermissionCheckResult.Type.FOUND;
+ if (tempGroup.hasSamePermissionNode("-" + permissionNode))
+ result.resultType = PermissionCheckResult.Type.NEGATION;
+ if (tempGroup.hasSamePermissionNode("+" + permissionNode))
+ result.resultType = PermissionCheckResult.Type.EXCEPTION;
+
+ return result;
+ }
+
+ /**
+ * Returns a List of all permission nodes for this group null if none
+ *
+ * @param groupName
+ * @return List of all group names
+ */
+ public List<String> getGroupsPermissions(String groupName) {
+
+ if (!hasGroup(groupName))
+ return null;
+
+ return groups.get(groupName.toLowerCase()).getPermissionList();
+ }
+
+ /**
+ * Returns a Set of all global group names.
+ *
+ * @return Set containing all group names.
+ */
+ public Set<String> getGlobalGroups() {
+
+ return groups.keySet();
+ }
+
+ /**
+ * Resets GlobalGroups.
+ */
+ public void resetGlobalGroups() {
+
+ this.groups = new HashMap<String, Group>();
+ }
+
+ /**
+ *
+ * @return a collection of the groups
+ */
+ public Collection<Group> getGroupList() {
+
+ return groups.values();
+ }
+
+ /**
+ * Returns the Global Group or null if it doesn't exist.
+ *
+ * @param groupName
+ * @return Group object
+ */
+ public Group getGroup(String groupName) {
+
+ if (!hasGroup(groupName))
+ return null;
+
+ return groups.get(groupName.toLowerCase());
+
+ }
+
+ /**
+ * @return the globalGroupsFile
+ */
+ public File getGlobalGroupsFile() {
+
+ return GlobalGroupsFile;
+ }
+
+ /**
+ *
+ */
+ public void removeGroupsChangedFlag() {
+
+ setGroupsChanged(false);
+ for (Group g : groups.values()) {
+ g.flagAsSaved();
+ }
+ }
+
+} \ No newline at end of file
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/GroupManager.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/GroupManager.java
new file mode 100644
index 000000000..5f357641a
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/GroupManager.java
@@ -0,0 +1,2038 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anjocaido.groupmanager;
+
+import org.anjocaido.groupmanager.permissions.AnjoPermissionsHandler;
+import org.anjocaido.groupmanager.permissions.BukkitPermissions;
+import org.anjocaido.groupmanager.utils.GroupManagerPermissions;
+import org.anjocaido.groupmanager.Tasks.BukkitPermsUpdateTask;
+import org.anjocaido.groupmanager.data.Variables;
+import org.anjocaido.groupmanager.data.User;
+import org.anjocaido.groupmanager.data.Group;
+import org.anjocaido.groupmanager.dataholder.OverloadedWorldHolder;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.anjocaido.groupmanager.dataholder.worlds.WorldsHolder;
+import org.anjocaido.groupmanager.events.GMSystemEvent;
+import org.anjocaido.groupmanager.events.GMWorldListener;
+import org.anjocaido.groupmanager.events.GroupManagerEventHandler;
+import org.anjocaido.groupmanager.utils.GMLoggerHandler;
+import org.anjocaido.groupmanager.utils.PermissionCheckResult;
+import org.anjocaido.groupmanager.utils.Tasks;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.ConsoleCommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.PluginDescriptionFile;
+import org.bukkit.plugin.ServicePriority;
+import org.bukkit.plugin.java.JavaPlugin;
+
+
+/**
+ *
+ * @author gabrielcouto, ElgarL
+ */
+public class GroupManager extends JavaPlugin {
+
+ private File backupFolder;
+ private Runnable commiter;
+ private ScheduledThreadPoolExecutor scheduler;
+ private Map<String, ArrayList<User>> overloadedUsers = new HashMap<String, ArrayList<User>>();
+ private Map<CommandSender, String> selectedWorlds = new HashMap<CommandSender, String>();
+ private WorldsHolder worldsHolder;
+ private boolean validateOnlinePlayer = true;
+
+ private static boolean isLoaded = false;
+ protected GMConfiguration config;
+
+ protected static GlobalGroups globalGroups;
+
+ private GMLoggerHandler ch;
+ public static BukkitPermissions BukkitPermissions;
+ private static GMWorldListener WorldEvents;
+ public static final Logger logger = Logger.getLogger(GroupManager.class.getName());
+
+ // PERMISSIONS FOR COMMAND BEING LOADED
+ private OverloadedWorldHolder dataHolder = null;
+ private AnjoPermissionsHandler permissionHandler = null;
+
+ private String lastError = "";
+
+ @Override
+ public void onDisable() {
+
+ onDisable(false);
+ }
+
+ @Override
+ public void onEnable() {
+
+ onEnable(false);
+ }
+
+ public void onDisable(boolean restarting) {
+
+ setLoaded(false);
+
+ if (!restarting) {
+ // Unregister this service if we are shutting down.
+ this.getServer().getServicesManager().unregister(this.worldsHolder);
+ }
+
+ disableScheduler(); // Shutdown before we save, so it doesn't interfere.
+ if (worldsHolder != null) {
+ try {
+ worldsHolder.saveChanges(false);
+ } catch (IllegalStateException ex) {
+ GroupManager.logger.log(Level.WARNING, ex.getMessage());
+ }
+ }
+
+
+
+ // Remove all attachments before clearing
+ if (BukkitPermissions != null) {
+ BukkitPermissions.removeAllAttachments();
+ }
+
+ if (!restarting) {
+
+ if (WorldEvents != null)
+ WorldEvents = null;
+
+ BukkitPermissions = null;
+
+ }
+
+ // EXAMPLE: Custom code, here we just output some info so we can check that all is well
+ PluginDescriptionFile pdfFile = this.getDescription();
+ System.out.println(pdfFile.getName() + " version " + pdfFile.getVersion() + " is disabled!");
+
+ if (!restarting)
+ GroupManager.logger.removeHandler(ch);
+ }
+
+ public void onEnable(boolean restarting) {
+
+ try {
+ /*
+ * reset local variables.
+ */
+ overloadedUsers = new HashMap<String, ArrayList<User>>();
+ selectedWorlds = new HashMap<CommandSender, String>();
+ lastError = "";
+
+ /*
+ * Setup our logger if we are not restarting.
+ */
+ if (!restarting) {
+ GroupManager.logger.setUseParentHandlers(false);
+ ch = new GMLoggerHandler();
+ GroupManager.logger.addHandler(ch);
+ }
+ logger.setLevel(Level.ALL);
+
+ // Create the backup folder, if it doesn't exist.
+ prepareFileFields();
+ // Load the config.yml
+ prepareConfig();
+ // Load the global groups
+ globalGroups = new GlobalGroups(this);
+
+ /*
+ * Configure the worlds holder.
+ */
+ if (!restarting)
+ worldsHolder = new WorldsHolder(this);
+ else
+ worldsHolder.resetWorldsHolder();
+
+ /*
+ * This should NEVER happen. No idea why it's still here.
+ */
+ PluginDescriptionFile pdfFile = this.getDescription();
+ if (worldsHolder == null) {
+ GroupManager.logger.severe("Can't enable " + pdfFile.getName() + " version " + pdfFile.getVersion() + ", bad loading!");
+ this.getServer().getPluginManager().disablePlugin(this);
+ throw new IllegalStateException("An error ocurred while loading GroupManager");
+ }
+
+ /*
+ * Prevent our registered events from triggering
+ * updates as we are not fully loaded.
+ */
+ setLoaded(false);
+
+ /*
+ * Initialize the world listener and bukkit permissions
+ * to handle events if this is a fresh start
+ *
+ * else
+ *
+ * Reset bukkit perms.
+ */
+ if (!restarting) {
+ WorldEvents = new GMWorldListener(this);
+ BukkitPermissions = new BukkitPermissions(this);
+ } else {
+ BukkitPermissions.reset();
+ }
+
+ /*
+ * Start the scheduler for data saving.
+ */
+ enableScheduler();
+
+ /*
+ * Schedule a Bukkit Permissions update for 1 tick later.
+ * All plugins will be loaded by then
+ */
+
+ if (getServer().getScheduler().scheduleSyncDelayedTask(this, new BukkitPermsUpdateTask(), 1) == -1) {
+ GroupManager.logger.severe("Could not schedule superperms Update.");
+ /*
+ * Flag that we are now loaded and should start processing events.
+ */
+ setLoaded(true);
+ }
+
+ System.out.println(pdfFile.getName() + " version " + pdfFile.getVersion() + " is enabled!");
+
+ // Register as a service
+ if (!restarting)
+ this.getServer().getServicesManager().register(WorldsHolder.class, this.worldsHolder, this, ServicePriority.Lowest);
+
+ } catch (Exception ex) {
+
+ /*
+ * Store the error and write to the log.
+ */
+ saveErrorLog(ex);
+
+ /*
+ * Throw an error so Bukkit knows about it.
+ */
+ throw new IllegalArgumentException(ex.getMessage(), ex);
+
+ }
+ }
+
+ /**
+ * Write an error.log
+ *
+ * @param ex
+ */
+ private void saveErrorLog(Exception ex) {
+
+ if (!getDataFolder().exists()) {
+ getDataFolder().mkdirs();
+ }
+
+ lastError = ex.getMessage();
+
+ GroupManager.logger.severe("===================================================");
+ GroupManager.logger.severe("= ERROR REPORT START =");
+ GroupManager.logger.severe("===================================================");
+ GroupManager.logger.severe("=== PLEASE COPY AND PASTE THE ERROR.LOG FROM THE ==");
+ GroupManager.logger.severe("= GROUPMANAGER FOLDER TO AN ESSENTIALS DEVELOPER =");
+ GroupManager.logger.severe("===================================================");
+ GroupManager.logger.severe(lastError);
+ GroupManager.logger.severe("===================================================");
+ GroupManager.logger.severe("= ERROR REPORT ENDED =");
+ GroupManager.logger.severe("===================================================");
+
+ // Append this error to the error log.
+ try {
+ String error = "=============================== GM ERROR LOG ===============================\n\n";
+ error += Tasks.getStackTraceAsString(ex);
+ error += "\n============================================================================\n";
+
+ Tasks.appendStringToFile(error, (getDataFolder() + System.getProperty("file.separator") + "ERROR.LOG"));
+ } catch (IOException e) {
+ // Failed to write file.
+ e.printStackTrace();
+ }
+
+ }
+
+ /**
+ * @return the validateOnlinePlayer
+ */
+ public boolean isValidateOnlinePlayer() {
+
+ return validateOnlinePlayer;
+ }
+
+ /**
+ * @param validateOnlinePlayer the validateOnlinePlayer to set
+ */
+ public void setValidateOnlinePlayer(boolean validateOnlinePlayer) {
+
+ this.validateOnlinePlayer = validateOnlinePlayer;
+ }
+
+ public static boolean isLoaded() {
+
+ return isLoaded;
+ }
+
+ public static void setLoaded(boolean isLoaded) {
+
+ GroupManager.isLoaded = isLoaded;
+ }
+
+ public InputStream getResourceAsStream(String fileName) {
+
+ return this.getClassLoader().getResourceAsStream(fileName);
+ }
+
+ private void prepareFileFields() {
+
+ backupFolder = new File(this.getDataFolder(), "backup");
+ if (!backupFolder.exists()) {
+ getBackupFolder().mkdirs();
+ }
+ }
+
+ private void prepareConfig() {
+
+ config = new GMConfiguration(this);
+ }
+
+ public void enableScheduler() {
+
+ if (worldsHolder != null) {
+ disableScheduler();
+ commiter = new Runnable() {
+
+ @Override
+ public void run() {
+
+ try {
+ worldsHolder.saveChanges(false);
+ GroupManager.logger.log(Level.INFO, " Data files refreshed.");
+ } catch (IllegalStateException ex) {
+ GroupManager.logger.log(Level.WARNING, ex.getMessage());
+ }
+ }
+ };
+ scheduler = new ScheduledThreadPoolExecutor(1);
+ long minutes = (long) getGMConfig().getSaveInterval();
+ if (minutes > 0) {
+ scheduler.scheduleAtFixedRate(commiter, minutes, minutes, TimeUnit.MINUTES);
+ GroupManager.logger.info("Scheduled Data Saving is set for every " + minutes + " minutes!");
+ } else
+ GroupManager.logger.info("Scheduled Data Saving is Disabled!");
+
+ GroupManager.logger.info("Backups will be retained for " + getGMConfig().getBackupDuration() + " hours!");
+ }
+ }
+
+ public void disableScheduler() {
+
+ if (scheduler != null) {
+ try {
+ scheduler.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
+ scheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
+ scheduler.shutdown();
+ } catch (Exception e) {
+ }
+ scheduler = null;
+ GroupManager.logger.info("Scheduled Data Saving is disabled!");
+ }
+ }
+
+ public WorldsHolder getWorldsHolder() {
+
+ return worldsHolder;
+ }
+
+ /**
+ * Called when a command registered by this plugin is received.
+ *
+ * @param sender
+ * @param cmd
+ * @param args
+ */
+ @Override
+ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
+
+ boolean playerCanDo = false;
+ boolean isConsole = false;
+ Player senderPlayer = null, targetPlayer = null;
+ Group senderGroup = null;
+ User senderUser = null;
+ boolean isOpOverride = config.isOpOverride();
+
+ // DETERMINING PLAYER INFORMATION
+ if (sender instanceof Player) {
+ senderPlayer = (Player) sender;
+
+ if (!lastError.isEmpty() && !commandLabel.equalsIgnoreCase("manload")) {
+ sender.sendMessage(ChatColor.RED + "All commands are locked due to an error. Check the log and then try a '/manload'.)");
+ return true;
+ }
+
+ senderUser = worldsHolder.getWorldData(senderPlayer).getUser(senderPlayer.getName());
+ senderGroup = senderUser.getGroup();
+ isOpOverride = (isOpOverride && (senderPlayer.isOp() || worldsHolder.getWorldPermissions(senderPlayer).has(senderPlayer, "groupmanager.op")));
+
+ System.out.println("[PLAYER_COMMAND] " + senderPlayer.getName() + ": /" + commandLabel + " " + Tasks.join(args, " "));
+ if (isOpOverride || worldsHolder.getWorldPermissions(senderPlayer).has(senderPlayer, "groupmanager." + cmd.getName())) {
+ playerCanDo = true;
+ }
+ } else if (sender instanceof ConsoleCommandSender) {
+
+ if (!lastError.isEmpty() && !commandLabel.equalsIgnoreCase("manload")) {
+ sender.sendMessage(ChatColor.RED + "All commands are locked due to an error. Check the log and then try a '/manload'.)");
+ return true;
+ }
+
+ isConsole = true;
+ }
+
+ // PERMISSIONS FOR COMMAND BEING LOADED
+ dataHolder = null;
+ permissionHandler = null;
+
+ if (senderPlayer != null) {
+ dataHolder = worldsHolder.getWorldData(senderPlayer);
+ }
+
+ String selectedWorld = selectedWorlds.get(sender);
+ if (selectedWorld != null) {
+ dataHolder = worldsHolder.getWorldData(selectedWorld);
+ }
+
+ if (dataHolder != null) {
+ permissionHandler = dataHolder.getPermissionsHandler();
+ }
+
+ // VARIABLES USED IN COMMANDS
+
+ int count;
+ PermissionCheckResult permissionResult = null;
+ ArrayList<User> removeList = null;
+ String auxString = null;
+ List<String> match = null;
+ User auxUser = null;
+ Group auxGroup = null;
+ Group auxGroup2 = null;
+
+ GroupManagerPermissions execCmd = null;
+ try {
+ execCmd = GroupManagerPermissions.valueOf(cmd.getName());
+ } catch (Exception e) {
+ // this error happened once with someone. now im prepared... i think
+ GroupManager.logger.severe("===================================================");
+ GroupManager.logger.severe("= ERROR REPORT START =");
+ GroupManager.logger.severe("===================================================");
+ GroupManager.logger.severe("= COPY AND PASTE THIS TO A GROUPMANAGER DEVELOPER =");
+ GroupManager.logger.severe("===================================================");
+ GroupManager.logger.severe(this.getDescription().getName());
+ GroupManager.logger.severe(this.getDescription().getVersion());
+ GroupManager.logger.severe("An error occured while trying to execute command:");
+ GroupManager.logger.severe(cmd.getName());
+ GroupManager.logger.severe("With " + args.length + " arguments:");
+ for (String ar : args) {
+ GroupManager.logger.severe(ar);
+ }
+ GroupManager.logger.severe("The field '" + cmd.getName() + "' was not found in enum.");
+ GroupManager.logger.severe("And could not be parsed.");
+ GroupManager.logger.severe("FIELDS FOUND IN ENUM:");
+ for (GroupManagerPermissions val : GroupManagerPermissions.values()) {
+ GroupManager.logger.severe(val.name());
+ }
+ GroupManager.logger.severe("===================================================");
+ GroupManager.logger.severe("= ERROR REPORT ENDED =");
+ GroupManager.logger.severe("===================================================");
+ sender.sendMessage("An error occurred. Ask the admin to take a look at the console.");
+ }
+
+ if (isConsole || playerCanDo) {
+ switch (execCmd) {
+ case manuadd:
+
+ // Validating arguments
+ if ((args.length != 2) && (args.length != 3)) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <player> <group> | optional [world])");
+ return false;
+ }
+
+ // Select the relevant world (if specified)
+ if (args.length == 3) {
+ dataHolder = worldsHolder.getWorldData(args[2]);
+ permissionHandler = dataHolder.getPermissionsHandler();
+ }
+
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+
+ if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) {
+ return false;
+ }
+
+ if (match != null) {
+ auxUser = dataHolder.getUser(match.get(0));
+ } else {
+ auxUser = dataHolder.getUser(args[0]);
+ }
+ auxGroup = dataHolder.getGroup(args[1]);
+ if (auxGroup == null) {
+ sender.sendMessage(ChatColor.RED + "Group not found!");
+ return false;
+ }
+ if (auxGroup.isGlobal()) {
+ sender.sendMessage(ChatColor.RED + "Players may not be members of GlobalGroups directly.");
+ return false;
+ }
+
+ // Validating permissions
+ if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getName(), senderGroup.getName()) : false)) {
+ sender.sendMessage(ChatColor.RED + "Can't modify a player with the same permissions as you, or higher.");
+ return false;
+ }
+ if (!isConsole && !isOpOverride && (permissionHandler.hasGroupInInheritance(auxGroup, senderGroup.getName()))) {
+ sender.sendMessage(ChatColor.RED + "The destination group can't be the same as yours, or higher.");
+ return false;
+ }
+ if (!isConsole && !isOpOverride && (!permissionHandler.inGroup(senderUser.getName(), auxUser.getGroupName()) || !permissionHandler.inGroup(senderUser.getName(), auxGroup.getName()))) {
+ sender.sendMessage(ChatColor.RED + "You can't modify a player involving a group that you don't inherit.");
+ return false;
+ }
+
+ // Seems OK
+ auxUser.setGroup(auxGroup);
+ if (!sender.hasPermission("groupmanager.notify.other") || (isConsole))
+ sender.sendMessage(ChatColor.YELLOW + "You changed player '" + auxUser.getName() + "' group to '" + auxGroup.getName() + "' in world '" + dataHolder.getName() + "'.");
+
+ return true;
+
+ case manudel:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 1) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <player>)");
+ return false;
+ }
+ if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) {
+ return false;
+ }
+
+ if (match != null) {
+ auxUser = dataHolder.getUser(match.get(0));
+ } else {
+ auxUser = dataHolder.getUser(args[0]);
+ }
+ // Validating permission
+ if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getName(), senderGroup.getName()) : false)) {
+ sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher.");
+ return false;
+ }
+ // Seems OK
+ dataHolder.removeUser(auxUser.getName());
+ sender.sendMessage(ChatColor.YELLOW + "You changed player '" + auxUser.getName() + "' to default settings.");
+
+ // If the player is online, this will create new data for the user.
+ targetPlayer = this.getServer().getPlayer(auxUser.getName());
+ if (targetPlayer != null)
+ BukkitPermissions.updatePermissions(targetPlayer);
+
+ return true;
+
+ case manuaddsub:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender)) {
+ sender.sendMessage(ChatColor.RED + "Couldn't retrieve your world. World selection is needed.");
+ sender.sendMessage(ChatColor.RED + "Use /manselect <world>");
+ return true;
+ }
+ }
+ // Validating arguments
+ if (args.length != 2) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <player> <group>)");
+ return false;
+ }
+ if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) {
+ return false;
+ }
+
+ if (match != null) {
+ auxUser = dataHolder.getUser(match.get(0));
+ } else {
+ auxUser = dataHolder.getUser(args[0]);
+ }
+ auxGroup = dataHolder.getGroup(args[1]);
+ if (auxGroup == null) {
+ sender.sendMessage(ChatColor.RED + "Group not found!");
+ return false;
+ }
+ // Validating permission
+ if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getName(), senderGroup.getName()) : false)) {
+ sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher.");
+ return false;
+ }
+ // Seems OK
+ if (auxUser.addSubGroup(auxGroup))
+ sender.sendMessage(ChatColor.YELLOW + "You added subgroup '" + auxGroup.getName() + "' to player '" + auxUser.getName() + "'.");
+ else
+ sender.sendMessage(ChatColor.RED + "The subgroup '" + auxGroup.getName() + "' is already available to '" + auxUser.getName() + "'.");
+
+ return true;
+
+ case manudelsub:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 2) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/manudelsub <user> <group>)");
+ return false;
+ }
+ if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) {
+ return false;
+ }
+
+ if (match != null) {
+ auxUser = dataHolder.getUser(match.get(0));
+ } else {
+ auxUser = dataHolder.getUser(args[0]);
+ }
+ auxGroup = dataHolder.getGroup(args[1]);
+ if (auxGroup == null) {
+ sender.sendMessage(ChatColor.RED + "Group not found!");
+ return false;
+ }
+
+ // Validating permission
+ if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getName(), senderGroup.getName()) : false)) {
+ sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher.");
+ return false;
+ }
+ // Seems OK
+ auxUser.removeSubGroup(auxGroup);
+ sender.sendMessage(ChatColor.YELLOW + "You removed subgroup '" + auxGroup.getName() + "' from player '" + auxUser.getName() + "' list.");
+
+ // targetPlayer = this.getServer().getPlayer(auxUser.getName());
+ // if (targetPlayer != null)
+ // BukkitPermissions.updatePermissions(targetPlayer);
+
+ return true;
+
+ case mangadd:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 1) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <group>)");
+ return false;
+ }
+ auxGroup = dataHolder.getGroup(args[0]);
+ if (auxGroup != null) {
+ sender.sendMessage(ChatColor.RED + "Group already exists!");
+ return false;
+ }
+ // Seems OK
+ auxGroup = dataHolder.createGroup(args[0]);
+ sender.sendMessage(ChatColor.YELLOW + "You created a group named: " + auxGroup.getName());
+
+ return true;
+
+ case mangdel:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 1) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <group>)");
+ return false;
+ }
+ auxGroup = dataHolder.getGroup(args[0]);
+ if (auxGroup == null) {
+ sender.sendMessage(ChatColor.RED + "Group not exists!");
+ return false;
+ }
+ // Seems OK
+ dataHolder.removeGroup(auxGroup.getName());
+ sender.sendMessage(ChatColor.YELLOW + "You deleted a group named " + auxGroup.getName() + ", it's users are default group now.");
+
+ BukkitPermissions.updateAllPlayers();
+
+ return true;
+
+ case manuaddp:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 2) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <player> <permission>)");
+ return false;
+ }
+ if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) {
+ return false;
+ }
+
+ if (match != null) {
+ auxUser = dataHolder.getUser(match.get(0));
+ } else {
+ auxUser = dataHolder.getUser(args[0]);
+ }
+ // Validating your permissions
+ if (!isConsole && (senderGroup != null ? permissionHandler.inGroup(auxUser.getName(), senderGroup.getName()) : false)) {
+ sender.sendMessage(ChatColor.RED + "Can't modify player with same group than you, or higher.");
+ return false;
+ }
+ permissionResult = permissionHandler.checkFullUserPermission(senderUser, args[1]);
+ if (!isConsole && !isOpOverride && (permissionResult.resultType.equals(PermissionCheckResult.Type.NOTFOUND) || permissionResult.resultType.equals(PermissionCheckResult.Type.NEGATION))) {
+ sender.sendMessage(ChatColor.RED + "You can't add a permission you don't have.");
+ return false;
+ }
+ // Validating permissions of user
+ permissionResult = permissionHandler.checkUserOnlyPermission(auxUser, args[1]);
+ if (args[1].startsWith("+")) {
+ if (permissionResult.resultType.equals(PermissionCheckResult.Type.EXCEPTION)) {
+ sender.sendMessage(ChatColor.RED + "The user already has direct access to that permission.");
+ sender.sendMessage(ChatColor.RED + "Node: " + permissionResult.accessLevel);
+ return false;
+ }
+ } else if (args[1].startsWith("-")) {
+ if (permissionResult.resultType.equals(PermissionCheckResult.Type.EXCEPTION)) {
+ sender.sendMessage(ChatColor.RED + "The user already has an exception for this node.");
+ sender.sendMessage(ChatColor.RED + "Node: " + permissionResult.accessLevel);
+ return false;
+ } else if (permissionResult.resultType.equals(PermissionCheckResult.Type.NEGATION)) {
+ sender.sendMessage(ChatColor.RED + "The user already has a matching node ");
+ sender.sendMessage(ChatColor.RED + "Node: " + permissionResult.accessLevel);
+ return false;
+ }
+ } else {
+ if (permissionResult.resultType.equals(PermissionCheckResult.Type.FOUND)) {
+ sender.sendMessage(ChatColor.RED + "The user already has direct access to that permission.");
+ sender.sendMessage(ChatColor.RED + "Node: " + permissionResult.accessLevel);
+ return false;
+ }
+ }
+ // Seems OK
+ auxUser.addPermission(args[1]);
+ sender.sendMessage(ChatColor.YELLOW + "You added '" + args[1] + "' to player '" + auxUser.getName() + "' permissions.");
+
+ targetPlayer = this.getServer().getPlayer(auxUser.getName());
+ if (targetPlayer != null)
+ BukkitPermissions.updatePermissions(targetPlayer);
+
+ return true;
+
+ case manudelp:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 2) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <player> <permission>)");
+ return false;
+ }
+ if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) {
+ return false;
+ }
+
+ if (match != null) {
+ auxUser = dataHolder.getUser(match.get(0));
+ } else {
+ auxUser = dataHolder.getUser(args[0]);
+ }
+ // Validating your permissions
+ if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getName(), senderGroup.getName()) : false)) {
+ sender.sendMessage(ChatColor.RED + "You can't modify a player with same group as you, or higher.");
+ return false;
+ }
+ permissionResult = permissionHandler.checkFullUserPermission(senderUser, args[1]);
+ if (!isConsole && !isOpOverride && (permissionResult.resultType.equals(PermissionCheckResult.Type.NOTFOUND) || permissionResult.resultType.equals(PermissionCheckResult.Type.NEGATION))) {
+ sender.sendMessage(ChatColor.RED + "You can't remove a permission you don't have.");
+ return false;
+ }
+ // Validating permissions of user
+ permissionResult = permissionHandler.checkUserOnlyPermission(auxUser, args[1]);
+ if (permissionResult.resultType.equals(PermissionCheckResult.Type.NOTFOUND)) {
+ sender.sendMessage(ChatColor.RED + "The user doesn't have direct access to that permission.");
+ return false;
+ }
+ if (!auxUser.hasSamePermissionNode(args[1])) {
+ sender.sendMessage(ChatColor.RED + "This permission node doesn't match any node.");
+ sender.sendMessage(ChatColor.RED + "But might match node: " + permissionResult.accessLevel);
+ return false;
+ }
+ // Seems OK
+ auxUser.removePermission(args[1]);
+ sender.sendMessage(ChatColor.YELLOW + "You removed '" + args[1] + "' from player '" + auxUser.getName() + "' permissions.");
+
+ targetPlayer = this.getServer().getPlayer(auxUser.getName());
+ if (targetPlayer != null)
+ BukkitPermissions.updatePermissions(targetPlayer);
+
+ return true;
+
+ case manulistp:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if ((args.length == 0) || (args.length > 2)) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <player> (+))");
+ return false;
+ }
+
+ if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) {
+ return false;
+ }
+
+ if (match != null) {
+ auxUser = dataHolder.getUser(match.get(0));
+ } else {
+ auxUser = dataHolder.getUser(args[0]);
+ }
+ // Validating permission
+ // Seems OK
+ auxString = "";
+ for (String perm : auxUser.getPermissionList()) {
+ auxString += perm + ", ";
+ }
+ if (auxString.lastIndexOf(",") > 0) {
+ auxString = auxString.substring(0, auxString.lastIndexOf(","));
+ sender.sendMessage(ChatColor.YELLOW + "The player '" + auxUser.getName() + "' has following permissions: " + ChatColor.WHITE + auxString);
+ sender.sendMessage(ChatColor.YELLOW + "And all permissions from group: " + auxUser.getGroupName());
+ auxString = "";
+ for (String subGroup : auxUser.subGroupListStringCopy()) {
+ auxString += subGroup + ", ";
+ }
+ if (auxString.lastIndexOf(",") > 0) {
+ auxString = auxString.substring(0, auxString.lastIndexOf(","));
+ sender.sendMessage(ChatColor.YELLOW + "And all permissions from subgroups: " + auxString);
+ }
+ } else {
+ sender.sendMessage(ChatColor.YELLOW + "The player '" + auxUser.getName() + "' has no specific permissions.");
+ sender.sendMessage(ChatColor.YELLOW + "Only all permissions from group: " + auxUser.getGroupName());
+ auxString = "";
+ for (String subGroup : auxUser.subGroupListStringCopy()) {
+ auxString += subGroup + ", ";
+ }
+ if (auxString.lastIndexOf(",") > 0) {
+ auxString = auxString.substring(0, auxString.lastIndexOf(","));
+ sender.sendMessage(ChatColor.YELLOW + "And all permissions from subgroups: " + auxString);
+ }
+ }
+
+ // bukkit perms
+ if ((args.length == 2) && (args[1].equalsIgnoreCase("+"))) {
+ targetPlayer = this.getServer().getPlayer(auxUser.getName());
+ if (targetPlayer != null) {
+ sender.sendMessage(ChatColor.YELLOW + "Superperms reports: ");
+ for (String line : BukkitPermissions.listPerms(targetPlayer))
+ sender.sendMessage(ChatColor.YELLOW + line);
+
+ }
+ }
+
+ return true;
+
+ case manucheckp:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 2) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <player> <permission>)");
+ return false;
+ }
+
+ if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) {
+ return false;
+ }
+
+ if (match != null) {
+ auxUser = dataHolder.getUser(match.get(0));
+ } else {
+ auxUser = dataHolder.getUser(args[0]);
+ }
+ targetPlayer = this.getServer().getPlayer(auxUser.getName());
+ // Validating permission
+ permissionResult = permissionHandler.checkFullGMPermission(auxUser, args[1], false);
+
+ if (permissionResult.resultType.equals(PermissionCheckResult.Type.NOTFOUND)) {
+ // No permissions found in GM so fall through and check Bukkit.
+ sender.sendMessage(ChatColor.RED + "The player doesn't have access to that permission");
+
+ } else {
+ // This permission was found in groupmanager.
+ if (permissionResult.owner instanceof User) {
+ if (permissionResult.resultType.equals(PermissionCheckResult.Type.NEGATION)) {
+ sender.sendMessage(ChatColor.RED + "The user has directly a negation node for that permission.");
+ } else {
+ sender.sendMessage(ChatColor.YELLOW + "The user has directly this permission.");
+ }
+ sender.sendMessage(ChatColor.YELLOW + "Permission Node: " + permissionResult.accessLevel);
+ } else if (permissionResult.owner instanceof Group) {
+ if (permissionResult.resultType.equals(PermissionCheckResult.Type.NEGATION)) {
+ sender.sendMessage(ChatColor.RED + "The user inherits a negation permission from group: " + permissionResult.owner.getName());
+ } else {
+ sender.sendMessage(ChatColor.YELLOW + "The user inherits the permission from group: " + permissionResult.owner.getName());
+ }
+ sender.sendMessage(ChatColor.YELLOW + "Permission Node: " + permissionResult.accessLevel);
+ }
+ }
+
+ // superperms
+ if (targetPlayer != null) {
+ sender.sendMessage(ChatColor.YELLOW + "SuperPerms reports Node: " + targetPlayer.hasPermission(args[1]) + ((!targetPlayer.hasPermission(args[1]) && targetPlayer.isPermissionSet(args[1])) ? " (Negated)": ""));
+ }
+
+ return true;
+
+ case mangaddp:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 2) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <group> <permission>)");
+ return false;
+ }
+ auxGroup = dataHolder.getGroup(args[0]);
+ if (auxGroup == null) {
+ sender.sendMessage(ChatColor.RED + "The specified group does not exist!");
+ return false;
+ }
+ // Validating your permissions
+ permissionResult = permissionHandler.checkFullUserPermission(senderUser, args[1]);
+ if (!isConsole && (permissionResult.resultType.equals(PermissionCheckResult.Type.NOTFOUND) || permissionResult.resultType.equals(PermissionCheckResult.Type.NEGATION))) {
+ sender.sendMessage(ChatColor.RED + "You can't add a permission you don't have.");
+ return false;
+ }
+ // Validating permissions of user
+ permissionResult = permissionHandler.checkGroupOnlyPermission(auxGroup, args[1]);
+ if (args[1].startsWith("+")) {
+ if (permissionResult.resultType.equals(PermissionCheckResult.Type.EXCEPTION)) {
+ sender.sendMessage(ChatColor.RED + "The group already has direct access to that permission.");
+ sender.sendMessage(ChatColor.RED + "Node: " + permissionResult.accessLevel);
+ return false;
+ }
+ } else if (args[1].startsWith("-")) {
+ if (permissionResult.resultType.equals(PermissionCheckResult.Type.EXCEPTION)) {
+ sender.sendMessage(ChatColor.RED + "The group already has an exception for this node.");
+ sender.sendMessage(ChatColor.RED + "Node: " + permissionResult.accessLevel);
+ return false;
+ } else if (permissionResult.resultType.equals(PermissionCheckResult.Type.NEGATION)) {
+ sender.sendMessage(ChatColor.RED + "The group already has a matching node.");
+ sender.sendMessage(ChatColor.RED + "Node: " + permissionResult.accessLevel);
+ return false;
+ }
+ } else {
+ if (permissionResult.resultType.equals(PermissionCheckResult.Type.FOUND)) {
+ sender.sendMessage(ChatColor.RED + "The group already has direct access to that permission.");
+ sender.sendMessage(ChatColor.RED + "Node: " + permissionResult.accessLevel);
+ return false;
+ }
+ }
+ // Seems OK
+ auxGroup.addPermission(args[1]);
+ sender.sendMessage(ChatColor.YELLOW + "You added '" + args[1] + "' to group '" + auxGroup.getName() + "' permissions.");
+
+ BukkitPermissions.updateAllPlayers();
+
+ return true;
+
+ case mangdelp:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 2) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <group> <permission>)");
+ return false;
+ }
+ auxGroup = dataHolder.getGroup(args[0]);
+ if (auxGroup == null) {
+ sender.sendMessage(ChatColor.RED + "The specified group does not exist!");
+ return false;
+ }
+ // Validating your permissions
+ permissionResult = permissionHandler.checkFullUserPermission(senderUser, args[1]);
+ if (!isConsole && (permissionResult.resultType.equals(PermissionCheckResult.Type.NOTFOUND) || permissionResult.resultType.equals(PermissionCheckResult.Type.NEGATION))) {
+ sender.sendMessage(ChatColor.RED + "Can't remove a permission you don't have.");
+ return false;
+ }
+ // Validating permissions of user
+ permissionResult = permissionHandler.checkGroupOnlyPermission(auxGroup, args[1]);
+ if (permissionResult.resultType.equals(PermissionCheckResult.Type.NOTFOUND)) {
+ sender.sendMessage(ChatColor.RED + "The group doesn't have direct access to that permission.");
+ return false;
+ }
+ if (!auxGroup.hasSamePermissionNode(args[1])) {
+ sender.sendMessage(ChatColor.RED + "This permission node doesn't match any node.");
+ sender.sendMessage(ChatColor.RED + "But might match node: " + permissionResult.accessLevel);
+ return false;
+ }
+ // Seems OK
+ auxGroup.removePermission(args[1]);
+ sender.sendMessage(ChatColor.YELLOW + "You removed '" + args[1] + "' from group '" + auxGroup.getName() + "' permissions.");
+
+ BukkitPermissions.updateAllPlayers();
+
+ return true;
+
+ case manglistp:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 1) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <group>)");
+ return false;
+ }
+ auxGroup = dataHolder.getGroup(args[0]);
+ if (auxGroup == null) {
+ sender.sendMessage(ChatColor.RED + "The specified group does not exist!");
+ return false;
+ }
+ // Validating permission
+
+ // Seems OK
+ auxString = "";
+ for (String perm : auxGroup.getPermissionList()) {
+ auxString += perm + ", ";
+ }
+ if (auxString.lastIndexOf(",") > 0) {
+ auxString = auxString.substring(0, auxString.lastIndexOf(","));
+ sender.sendMessage(ChatColor.YELLOW + "The group '" + auxGroup.getName() + "' has following permissions: " + ChatColor.WHITE + auxString);
+ auxString = "";
+ for (String grp : auxGroup.getInherits()) {
+ auxString += grp + ", ";
+ }
+ if (auxString.lastIndexOf(",") > 0) {
+ auxString = auxString.substring(0, auxString.lastIndexOf(","));
+ sender.sendMessage(ChatColor.YELLOW + "And all permissions from groups: " + auxString);
+ }
+
+ } else {
+ sender.sendMessage(ChatColor.YELLOW + "The group '" + auxGroup.getName() + "' has no specific permissions.");
+ auxString = "";
+ for (String grp : auxGroup.getInherits()) {
+ auxString += grp + ", ";
+ }
+ if (auxString.lastIndexOf(",") > 0) {
+ auxString = auxString.substring(0, auxString.lastIndexOf(","));
+ sender.sendMessage(ChatColor.YELLOW + "Only all permissions from groups: " + auxString);
+ }
+
+ }
+ return true;
+
+ case mangcheckp:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 2) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <group> <permission>)");
+ return false;
+ }
+ auxGroup = dataHolder.getGroup(args[0]);
+ if (auxGroup == null) {
+ sender.sendMessage(ChatColor.RED + "The specified group does not exist!");
+ return false;
+ }
+ // Validating permission
+ permissionResult = permissionHandler.checkGroupPermissionWithInheritance(auxGroup, args[1]);
+ if (permissionResult.resultType.equals(PermissionCheckResult.Type.NOTFOUND)) {
+ sender.sendMessage(ChatColor.RED + "The group doesn't have access to that permission");
+ return false;
+ }
+ // Seems OK
+ // auxString = permissionHandler.checkUserOnlyPermission(auxUser, args[1]);
+ if (permissionResult.owner instanceof Group) {
+ if (permissionResult.resultType.equals(PermissionCheckResult.Type.NEGATION)) {
+ sender.sendMessage(ChatColor.RED + "The group inherits the a negation permission from group: " + permissionResult.owner.getName());
+ } else {
+ sender.sendMessage(ChatColor.YELLOW + "The user inherits the permission from group: " + permissionResult.owner.getName());
+ }
+ sender.sendMessage(ChatColor.YELLOW + "Permission Node: " + permissionResult.accessLevel);
+
+ }
+ return true;
+
+ case mangaddi:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 2) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <group1> <group2>)");
+ return false;
+ }
+ auxGroup = dataHolder.getGroup(args[0]);
+ if (auxGroup == null) {
+ sender.sendMessage(ChatColor.RED + "Group 1 does not exist!");
+ return false;
+ }
+ auxGroup2 = dataHolder.getGroup(args[1]);
+ if (auxGroup2 == null) {
+ sender.sendMessage(ChatColor.RED + "Group 2 does not exist!");
+ return false;
+ }
+ if (auxGroup.isGlobal()) {
+ sender.sendMessage(ChatColor.RED + "GlobalGroups do NOT support inheritance.");
+ return false;
+ }
+
+ // Validating permission
+ if (permissionHandler.hasGroupInInheritance(auxGroup, auxGroup2.getName())) {
+ sender.sendMessage(ChatColor.RED + "Group " + auxGroup.getName() + " already inherits " + auxGroup2.getName() + " (might not be directly)");
+ return false;
+ }
+ // Seems OK
+ auxGroup.addInherits(auxGroup2);
+ sender.sendMessage(ChatColor.RED + "Group " + auxGroup2.getName() + " is now in " + auxGroup.getName() + " inheritance list.");
+
+ BukkitPermissions.updateAllPlayers();
+
+ return true;
+
+ case mangdeli:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 2) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <group1> <group2>)");
+ return false;
+ }
+ auxGroup = dataHolder.getGroup(args[0]);
+ if (auxGroup == null) {
+ sender.sendMessage(ChatColor.RED + "Group 1 does not exist!");
+ return false;
+ }
+ auxGroup2 = dataHolder.getGroup(args[1]);
+ if (auxGroup2 == null) {
+ sender.sendMessage(ChatColor.RED + "Group 2 does not exist!");
+ return false;
+ }
+ if (auxGroup.isGlobal()) {
+ sender.sendMessage(ChatColor.RED + "GlobalGroups do NOT support inheritance.");
+ return false;
+ }
+
+ // Validating permission
+ if (!permissionHandler.hasGroupInInheritance(auxGroup, auxGroup2.getName())) {
+ sender.sendMessage(ChatColor.RED + "Group " + auxGroup.getName() + " does not inherits " + auxGroup2.getName() + ".");
+ return false;
+ }
+ if (!auxGroup.getInherits().contains(auxGroup2.getName())) {
+ sender.sendMessage(ChatColor.RED + "Group " + auxGroup.getName() + " does not inherits " + auxGroup2.getName() + " directly.");
+ return false;
+ }
+ // Seems OK
+ auxGroup.removeInherits(auxGroup2.getName());
+ sender.sendMessage(ChatColor.RED + "Group " + auxGroup2.getName() + " was removed from " + auxGroup.getName() + " inheritance list.");
+
+ BukkitPermissions.updateAllPlayers();
+
+ return true;
+
+ case manuaddv:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length < 3) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <user> <variable> <value>)");
+ return false;
+ }
+ if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) {
+ return false;
+ }
+
+ if (match != null) {
+ auxUser = dataHolder.getUser(match.get(0));
+ } else {
+ auxUser = dataHolder.getUser(args[0]);
+ }
+ // Validating permission
+ // Seems OK
+ auxString = "";
+ for (int i = 2; i < args.length; i++) {
+ auxString += args[i];
+ if ((i + 1) < args.length) {
+ auxString += " ";
+ }
+ }
+ auxUser.getVariables().addVar(args[1], Variables.parseVariableValue(auxString));
+ sender.sendMessage(ChatColor.YELLOW + "Variable " + ChatColor.GOLD + args[1] + ChatColor.YELLOW + ":'" + ChatColor.GREEN + auxString + ChatColor.YELLOW + "' added to the user " + auxUser.getName());
+
+ return true;
+
+ case manudelv:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 2) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <user> <variable>)");
+ return false;
+ }
+ if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) {
+ return false;
+ }
+
+ if (match != null) {
+ auxUser = dataHolder.getUser(match.get(0));
+ } else {
+ auxUser = dataHolder.getUser(args[0]);
+ }
+ // Validating permission
+ if (!auxUser.getVariables().hasVar(args[1])) {
+ sender.sendMessage(ChatColor.RED + "The user doesn't have directly that variable!");
+ }
+ // Seems OK
+ auxUser.getVariables().removeVar(args[1]);
+ sender.sendMessage(ChatColor.YELLOW + "Variable " + ChatColor.GOLD + args[1] + ChatColor.YELLOW + " removed from the user " + ChatColor.GREEN + auxUser.getName());
+
+ return true;
+
+ case manulistv:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 1) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <user>)");
+ return false;
+ }
+ if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) {
+ return false;
+ }
+ if (match != null) {
+ auxUser = dataHolder.getUser(match.get(0));
+ } else {
+ auxUser = dataHolder.getUser(args[0]);
+ }
+ // Validating permission
+ // Seems OK
+ auxString = "";
+ for (String varKey : auxUser.getVariables().getVarKeyList()) {
+ Object o = auxUser.getVariables().getVarObject(varKey);
+ auxString += ChatColor.GOLD + varKey + ChatColor.WHITE + ":'" + ChatColor.GREEN + o.toString() + ChatColor.WHITE + "', ";
+ }
+ if (auxString.lastIndexOf(",") > 0) {
+ auxString = auxString.substring(0, auxString.lastIndexOf(","));
+ }
+ sender.sendMessage(ChatColor.YELLOW + "Variables of user " + auxUser.getName() + ": ");
+ sender.sendMessage(auxString + ".");
+ sender.sendMessage(ChatColor.YELLOW + "Plus all variables from group: " + auxUser.getGroupName());
+
+ return true;
+
+ case manucheckv:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 2) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <user> <variable>)");
+ return false;
+ }
+ if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) {
+ return false;
+ }
+ if (match != null) {
+ auxUser = dataHolder.getUser(match.get(0));
+ } else {
+ auxUser = dataHolder.getUser(args[0]);
+ }
+ // Validating permission
+ auxGroup = auxUser.getGroup();
+ auxGroup2 = permissionHandler.nextGroupWithVariable(auxGroup, args[1]);
+
+ if (!auxUser.getVariables().hasVar(args[1])) {
+ // Check sub groups
+ if (!auxUser.isSubGroupsEmpty() && auxGroup2 == null)
+ for (Group subGroup : auxUser.subGroupListCopy()) {
+ auxGroup2 = permissionHandler.nextGroupWithVariable(subGroup, args[1]);
+ if (auxGroup2 != null)
+ continue;
+ }
+ if (auxGroup2 == null) {
+ sender.sendMessage(ChatColor.RED + "The user doesn't have access to that variable!");
+ return false;
+ }
+ }
+ // Seems OK
+ if (auxUser.getVariables().hasVar(auxString)) {
+ sender.sendMessage(ChatColor.YELLOW + "The value of variable '" + ChatColor.GOLD + args[1] + ChatColor.YELLOW + "' is: '" + ChatColor.GREEN + auxUser.getVariables().getVarObject(args[1]).toString() + ChatColor.WHITE + "'");
+ sender.sendMessage(ChatColor.YELLOW + "This user own directly the variable");
+ }
+ sender.sendMessage(ChatColor.YELLOW + "The value of variable '" + ChatColor.GOLD + args[1] + ChatColor.YELLOW + "' is: '" + ChatColor.GREEN + auxGroup2.getVariables().getVarObject(args[1]).toString() + ChatColor.WHITE + "'");
+ if (!auxGroup.equals(auxGroup2)) {
+ sender.sendMessage(ChatColor.YELLOW + "And the value was inherited from group: " + ChatColor.GREEN + auxGroup2.getName());
+ }
+
+ return true;
+
+ case mangaddv:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length < 3) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <group> <variable> <value>)");
+ return false;
+ }
+ auxGroup = dataHolder.getGroup(args[0]);
+ if (auxGroup == null) {
+ sender.sendMessage(ChatColor.RED + "The specified group does not exist!");
+ return false;
+ }
+ if (auxGroup.isGlobal()) {
+ sender.sendMessage(ChatColor.RED + "GlobalGroups do NOT support Info Nodes.");
+ return false;
+ }
+ // Validating permission
+ // Seems OK
+ auxString = "";
+ for (int i = 2; i < args.length; i++) {
+ auxString += args[i];
+ if ((i + 1) < args.length) {
+ auxString += " ";
+ }
+ }
+ auxGroup.getVariables().addVar(args[1], Variables.parseVariableValue(auxString));
+ sender.sendMessage(ChatColor.YELLOW + "Variable " + ChatColor.GOLD + args[1] + ChatColor.YELLOW + ":'" + ChatColor.GREEN + auxString + ChatColor.YELLOW + "' added to the group " + auxGroup.getName());
+
+ return true;
+
+ case mangdelv:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 2) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <group> <variable>)");
+ return false;
+ }
+ auxGroup = dataHolder.getGroup(args[0]);
+ if (auxGroup == null) {
+ sender.sendMessage(ChatColor.RED + "The specified group does not exist!");
+ return false;
+ }
+ if (auxGroup.isGlobal()) {
+ sender.sendMessage(ChatColor.RED + "GlobalGroups do NOT support Info Nodes.");
+ return false;
+ }
+ // Validating permission
+ if (!auxGroup.getVariables().hasVar(args[1])) {
+ sender.sendMessage(ChatColor.RED + "The group doesn't have directly that variable!");
+ }
+ // Seems OK
+ auxGroup.getVariables().removeVar(args[1]);
+ sender.sendMessage(ChatColor.YELLOW + "Variable " + ChatColor.GOLD + args[1] + ChatColor.YELLOW + " removed from the group " + ChatColor.GREEN + auxGroup.getName());
+
+ return true;
+
+ case manglistv:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 1) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <group>)");
+ return false;
+ }
+ auxGroup = dataHolder.getGroup(args[0]);
+ if (auxGroup == null) {
+ sender.sendMessage(ChatColor.RED + "The specified group does not exist!");
+ return false;
+ }
+ if (auxGroup.isGlobal()) {
+ sender.sendMessage(ChatColor.RED + "GlobalGroups do NOT support Info Nodes.");
+ return false;
+ }
+ // Validating permission
+ // Seems OK
+ auxString = "";
+ for (String varKey : auxGroup.getVariables().getVarKeyList()) {
+ Object o = auxGroup.getVariables().getVarObject(varKey);
+ auxString += ChatColor.GOLD + varKey + ChatColor.WHITE + ":'" + ChatColor.GREEN + o.toString() + ChatColor.WHITE + "', ";
+ }
+ if (auxString.lastIndexOf(",") > 0) {
+ auxString = auxString.substring(0, auxString.lastIndexOf(","));
+ }
+ sender.sendMessage(ChatColor.YELLOW + "Variables of group " + auxGroup.getName() + ": ");
+ sender.sendMessage(auxString + ".");
+ auxString = "";
+ for (String grp : auxGroup.getInherits()) {
+ auxString += grp + ", ";
+ }
+ if (auxString.lastIndexOf(",") > 0) {
+ auxString = auxString.substring(0, auxString.lastIndexOf(","));
+ sender.sendMessage(ChatColor.YELLOW + "Plus all variables from groups: " + auxString);
+ }
+
+ return true;
+
+ case mangcheckv:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 2) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <group> <variable>)");
+ return false;
+ }
+ auxGroup = dataHolder.getGroup(args[0]);
+ if (auxGroup == null) {
+ sender.sendMessage(ChatColor.RED + "The specified group does not exist!");
+ return false;
+ }
+ if (auxGroup.isGlobal()) {
+ sender.sendMessage(ChatColor.RED + "GlobalGroups do NOT support Info Nodes.");
+ return false;
+ }
+ // Validating permission
+ auxGroup2 = permissionHandler.nextGroupWithVariable(auxGroup, args[1]);
+ if (auxGroup2 == null) {
+ sender.sendMessage(ChatColor.RED + "The group doesn't have access to that variable!");
+ }
+ // Seems OK
+ sender.sendMessage(ChatColor.YELLOW + "The value of variable '" + ChatColor.GOLD + args[1] + ChatColor.YELLOW + "' is: '" + ChatColor.GREEN + auxGroup2.getVariables().getVarObject(args[1]).toString() + ChatColor.WHITE + "'");
+ if (!auxGroup.equals(auxGroup2)) {
+ sender.sendMessage(ChatColor.YELLOW + "And the value was inherited from group: " + ChatColor.GREEN + auxGroup2.getName());
+ }
+
+ return true;
+
+ case manwhois:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 1) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <player>)");
+ return false;
+ }
+ if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) {
+ return false;
+ }
+ if (match != null) {
+ auxUser = dataHolder.getUser(match.get(0));
+ } else {
+ auxUser = dataHolder.getUser(args[0]);
+ }
+ // Seems OK
+ sender.sendMessage(ChatColor.YELLOW + "Name: " + ChatColor.GREEN + auxUser.getName());
+ sender.sendMessage(ChatColor.YELLOW + "Group: " + ChatColor.GREEN + auxUser.getGroup().getName());
+ // Compile a list of subgroups
+ auxString = "";
+ for (String subGroup : auxUser.subGroupListStringCopy()) {
+ auxString += subGroup + ", ";
+ }
+ if (auxString.lastIndexOf(",") > 0) {
+ auxString = auxString.substring(0, auxString.lastIndexOf(","));
+ sender.sendMessage(ChatColor.YELLOW + "subgroups: " + auxString);
+ }
+
+ sender.sendMessage(ChatColor.YELLOW + "Overloaded: " + ChatColor.GREEN + dataHolder.isOverloaded(auxUser.getName()));
+ auxGroup = dataHolder.surpassOverload(auxUser.getName()).getGroup();
+ if (!auxGroup.equals(auxUser.getGroup())) {
+ sender.sendMessage(ChatColor.YELLOW + "Original Group: " + ChatColor.GREEN + auxGroup.getName());
+ }
+ // victim.permissions.add(args[1]);
+ return true;
+
+ case tempadd:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 1) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <player>)");
+ return false;
+ }
+ if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) {
+ return false;
+ }
+ if (match != null) {
+ auxUser = dataHolder.getUser(match.get(0));
+ } else {
+ auxUser = dataHolder.getUser(args[0]);
+ }
+ // Validating permission
+ if (!isConsole && (senderGroup != null ? permissionHandler.inGroup(auxUser.getName(), senderGroup.getName()) : false)) {
+ sender.sendMessage(ChatColor.RED + "Can't modify player with same permissions than you, or higher.");
+ return false;
+ }
+ // Seems OK
+ if (overloadedUsers.get(dataHolder.getName().toLowerCase()) == null) {
+ overloadedUsers.put(dataHolder.getName().toLowerCase(), new ArrayList<User>());
+ }
+ dataHolder.overloadUser(auxUser.getName());
+ overloadedUsers.get(dataHolder.getName().toLowerCase()).add(dataHolder.getUser(auxUser.getName()));
+ sender.sendMessage(ChatColor.YELLOW + "Player overloaded!");
+
+ return true;
+
+ case tempdel:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 1) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <player>)");
+ return false;
+ }
+ if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) {
+ return false;
+ }
+ if (match != null) {
+ auxUser = dataHolder.getUser(match.get(0));
+ } else {
+ auxUser = dataHolder.getUser(args[0]);
+ }
+ // Validating permission
+ if (!isConsole && (senderGroup != null ? permissionHandler.inGroup(auxUser.getName(), senderGroup.getName()) : false)) {
+ sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher.");
+ return false;
+ }
+ // Seems OK
+ if (overloadedUsers.get(dataHolder.getName().toLowerCase()) == null) {
+ overloadedUsers.put(dataHolder.getName().toLowerCase(), new ArrayList<User>());
+ }
+ dataHolder.removeOverload(auxUser.getName());
+ if (overloadedUsers.get(dataHolder.getName().toLowerCase()).contains(auxUser)) {
+ overloadedUsers.get(dataHolder.getName().toLowerCase()).remove(auxUser);
+ }
+ sender.sendMessage(ChatColor.YELLOW + "You removed that player's overload. He's back to normal!");
+
+ return true;
+
+ case templist:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // WORKING
+ auxString = "";
+ removeList = new ArrayList<User>();
+ count = 0;
+ for (User u : overloadedUsers.get(dataHolder.getName().toLowerCase())) {
+ if (!dataHolder.isOverloaded(u.getName())) {
+ removeList.add(u);
+ } else {
+ auxString += u.getName() + ", ";
+ count++;
+ }
+ }
+ if (count == 0) {
+ sender.sendMessage(ChatColor.YELLOW + "There are no users in overload mode.");
+ return true;
+ }
+ auxString = auxString.substring(0, auxString.lastIndexOf(","));
+ if (overloadedUsers.get(dataHolder.getName().toLowerCase()) == null) {
+ overloadedUsers.put(dataHolder.getName().toLowerCase(), new ArrayList<User>());
+ }
+ overloadedUsers.get(dataHolder.getName().toLowerCase()).removeAll(removeList);
+ sender.sendMessage(ChatColor.YELLOW + " " + count + " Users in overload mode: " + ChatColor.WHITE + auxString);
+
+ return true;
+
+ case tempdelall:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // WORKING
+ removeList = new ArrayList<User>();
+ count = 0;
+ for (User u : overloadedUsers.get(dataHolder.getName().toLowerCase())) {
+ if (dataHolder.isOverloaded(u.getName())) {
+ dataHolder.removeOverload(u.getName());
+ count++;
+ }
+ }
+ if (count == 0) {
+ sender.sendMessage(ChatColor.YELLOW + "There are no users in overload mode.");
+ return true;
+ }
+ if (overloadedUsers.get(dataHolder.getName().toLowerCase()) == null) {
+ overloadedUsers.put(dataHolder.getName().toLowerCase(), new ArrayList<User>());
+ }
+ overloadedUsers.get(dataHolder.getName().toLowerCase()).clear();
+ sender.sendMessage(ChatColor.YELLOW + " " + count + "All users in overload mode are now normal again.");
+
+ return true;
+
+ case mansave:
+
+ boolean forced = false;
+
+ if ((args.length == 1) && (args[0].equalsIgnoreCase("force")))
+ forced = true;
+
+ try {
+ worldsHolder.saveChanges(forced);
+ sender.sendMessage(ChatColor.YELLOW + " All changes were saved.");
+ } catch (IllegalStateException ex) {
+ sender.sendMessage(ChatColor.RED + ex.getMessage());
+ }
+ return true;
+
+ case manload:
+
+ /**
+ * Attempt to reload a specific world
+ */
+ if (args.length > 0) {
+
+ if (!lastError.isEmpty()) {
+ sender.sendMessage(ChatColor.RED + "All commands are locked due to an error. Check the log and then try a '/manload'.)");
+ return true;
+ }
+
+ auxString = "";
+ for (int i = 0; i < args.length; i++) {
+ auxString += args[i];
+ if ((i + 1) < args.length) {
+ auxString += " ";
+ }
+ }
+
+ isLoaded = false; // Disable Bukkit Perms update and event triggers
+
+ globalGroups.load();
+ worldsHolder.loadWorld(auxString);
+
+ sender.sendMessage("The request to reload world '" + auxString + "' was attempted.");
+
+ isLoaded = true;
+
+ BukkitPermissions.updateAllPlayers();
+
+ } else {
+
+ /**
+ * Reload all settings and data as no world was specified.
+ */
+
+ /*
+ * Attempting a fresh load.
+ */
+ onDisable(true);
+ onEnable(true);
+
+ sender.sendMessage("All settings and worlds were reloaded!");
+ }
+
+ /**
+ * Fire an event as none will have been triggered in the reload.
+ */
+ if (GroupManager.isLoaded())
+ GroupManagerEventHandler.callEvent(GMSystemEvent.Action.RELOADED);
+
+ return true;
+
+ case listgroups:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // WORKING
+ auxString = "";
+ for (Group g : dataHolder.getGroupList()) {
+ auxString += g.getName() + ", ";
+ }
+ for (Group g : getGlobalGroups().getGroupList()) {
+ auxString += g.getName() + ", ";
+ }
+ if (auxString.lastIndexOf(",") > 0) {
+ auxString = auxString.substring(0, auxString.lastIndexOf(","));
+ }
+ sender.sendMessage(ChatColor.YELLOW + " Groups Available: " + ChatColor.WHITE + auxString);
+
+ return true;
+
+ case manpromote:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 2) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <player> <group>)");
+ return false;
+ }
+ if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) {
+ return false;
+ }
+ if (match != null) {
+ auxUser = dataHolder.getUser(match.get(0));
+ } else {
+ auxUser = dataHolder.getUser(args[0]);
+ }
+ auxGroup = dataHolder.getGroup(args[1]);
+ if (auxGroup == null) {
+ sender.sendMessage(ChatColor.RED + "Group not found!");
+ return false;
+ }
+ if (auxGroup.isGlobal()) {
+ sender.sendMessage(ChatColor.RED + "Players may not be members of GlobalGroups directly.");
+ return false;
+ }
+ // Validating permission
+ if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getName(), senderGroup.getName()) : false)) {
+ sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher.");
+ return false;
+ }
+ if (!isConsole && !isOpOverride && (permissionHandler.hasGroupInInheritance(auxGroup, senderGroup.getName()))) {
+ sender.sendMessage(ChatColor.RED + "The destination group can't be the same as yours, or higher.");
+ return false;
+ }
+ if (!isConsole && !isOpOverride && (!permissionHandler.inGroup(senderUser.getName(), auxUser.getGroupName()) || !permissionHandler.inGroup(senderUser.getName(), auxGroup.getName()))) {
+ sender.sendMessage(ChatColor.RED + "You can't modify a player involving a group that you don't inherit.");
+ return false;
+ }
+ if (!isConsole && !isOpOverride && (!permissionHandler.hasGroupInInheritance(auxUser.getGroup(), auxGroup.getName()) && !permissionHandler.hasGroupInInheritance(auxGroup, auxUser.getGroupName()))) {
+ sender.sendMessage(ChatColor.RED + "You can't modify a player using groups with different heritage line.");
+ return false;
+ }
+ if (!isConsole && !isOpOverride && (!permissionHandler.hasGroupInInheritance(auxGroup, auxUser.getGroupName()))) {
+ sender.sendMessage(ChatColor.RED + "The new group must be a higher rank.");
+ return false;
+ }
+ // Seems OK
+ auxUser.setGroup(auxGroup);
+ if (!sender.hasPermission("groupmanager.notify.other") || (isConsole))
+ sender.sendMessage(ChatColor.YELLOW + "You changed " + auxUser.getName() + " group to " + auxGroup.getName() + ".");
+
+ return true;
+
+ case mandemote:
+ // Validating state of sender
+ if (dataHolder == null || permissionHandler == null) {
+ if (!setDefaultWorldHandler(sender))
+ return true;
+ }
+ // Validating arguments
+ if (args.length != 2) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <player> <group>)");
+ return false;
+ }
+ if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) {
+ return false;
+ }
+ if (match != null) {
+ auxUser = dataHolder.getUser(match.get(0));
+ } else {
+ auxUser = dataHolder.getUser(args[0]);
+ }
+ auxGroup = dataHolder.getGroup(args[1]);
+ if (auxGroup == null) {
+ sender.sendMessage(ChatColor.RED + "Group not found!");
+ return false;
+ }
+ if (auxGroup.isGlobal()) {
+ sender.sendMessage(ChatColor.RED + "Players may not be members of GlobalGroups directly.");
+ return false;
+ }
+ // Validating permission
+ if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getName(), senderGroup.getName()) : false)) {
+ sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher.");
+ return false;
+ }
+ if (!isConsole && !isOpOverride && (permissionHandler.hasGroupInInheritance(auxGroup, senderGroup.getName()))) {
+ sender.sendMessage(ChatColor.RED + "The destination group can't be the same as yours, or higher.");
+ return false;
+ }
+ if (!isConsole && !isOpOverride && (!permissionHandler.inGroup(senderUser.getName(), auxUser.getGroupName()) || !permissionHandler.inGroup(senderUser.getName(), auxGroup.getName()))) {
+ sender.sendMessage(ChatColor.RED + "You can't modify a player involving a group that you don't inherit.");
+ return false;
+ }
+ if (!isConsole && !isOpOverride && (!permissionHandler.hasGroupInInheritance(auxUser.getGroup(), auxGroup.getName()) && !permissionHandler.hasGroupInInheritance(auxGroup, auxUser.getGroupName()))) {
+ sender.sendMessage(ChatColor.RED + "You can't modify a player using groups with different heritage line.");
+ return false;
+ }
+ if (!isConsole && !isOpOverride && (permissionHandler.hasGroupInInheritance(auxGroup, auxUser.getGroupName()))) {
+ sender.sendMessage(ChatColor.RED + "The new group must be a lower rank.");
+ return false;
+ }
+ // Seems OK
+ auxUser.setGroup(auxGroup);
+ if (!sender.hasPermission("groupmanager.notify.other") || (isConsole))
+ sender.sendMessage(ChatColor.YELLOW + "You changed " + auxUser.getName() + " group to " + auxGroup.getName() + ".");
+
+ return true;
+
+ case mantogglevalidate:
+ validateOnlinePlayer = !validateOnlinePlayer;
+ sender.sendMessage(ChatColor.YELLOW + "Validade if player is online, now set to: " + Boolean.toString(validateOnlinePlayer));
+ if (!validateOnlinePlayer) {
+ sender.sendMessage(ChatColor.GOLD + "From now on you can edit players not connected... BUT:");
+ sender.sendMessage(ChatColor.LIGHT_PURPLE + "From now on you should type the whole name of the player, correctly.");
+ }
+ return true;
+ case mantogglesave:
+ if (scheduler == null) {
+ enableScheduler();
+ sender.sendMessage(ChatColor.YELLOW + "The auto-saving is enabled!");
+ } else {
+ disableScheduler();
+ sender.sendMessage(ChatColor.YELLOW + "The auto-saving is disabled!");
+ }
+ return true;
+ case manworld:
+ auxString = selectedWorlds.get(sender);
+ if (auxString != null) {
+ sender.sendMessage(ChatColor.YELLOW + "You have the world '" + dataHolder.getName() + "' in your selection.");
+ } else {
+ if (dataHolder == null) {
+ sender.sendMessage(ChatColor.YELLOW + "There is no world selected. And no world is available now.");
+ } else {
+ sender.sendMessage(ChatColor.YELLOW + "You don't have a world in your selection..");
+ sender.sendMessage(ChatColor.YELLOW + "Working with the direct world where your player is.");
+ sender.sendMessage(ChatColor.YELLOW + "Your world now uses permissions of world name: '" + dataHolder.getName() + "' ");
+ }
+ }
+
+ return true;
+
+ case manselect:
+ if (args.length < 1) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count! (/<command> <world>)");
+ sender.sendMessage(ChatColor.YELLOW + "Worlds available: ");
+ ArrayList<OverloadedWorldHolder> worlds = worldsHolder.allWorldsDataList();
+ auxString = "";
+ for (int i = 0; i < worlds.size(); i++) {
+ auxString += worlds.get(i).getName();
+ if ((i + 1) < worlds.size()) {
+ auxString += ", ";
+ }
+ }
+ sender.sendMessage(ChatColor.YELLOW + auxString);
+ return false;
+ }
+ auxString = "";
+ for (int i = 0; i < args.length; i++) {
+ if (args[i] == null) {
+ logger.warning("Bukkit gave invalid arguments array! Cmd: " + cmd.getName() + " args.length: " + args.length);
+ return false;
+ }
+ auxString += args[i];
+ if (i < (args.length - 1)) {
+ auxString += " ";
+ }
+ }
+ dataHolder = worldsHolder.getWorldData(auxString);
+ permissionHandler = dataHolder.getPermissionsHandler();
+ selectedWorlds.put(sender, dataHolder.getName());
+ sender.sendMessage(ChatColor.YELLOW + "You have selected world '" + dataHolder.getName() + "'.");
+
+ return true;
+
+ case manclear:
+ if (args.length != 0) {
+ sender.sendMessage(ChatColor.RED + "Review your arguments count!");
+ return false;
+ }
+ selectedWorlds.remove(sender);
+ sender.sendMessage(ChatColor.YELLOW + "You have removed your world selection. Working with current world(if possible).");
+
+ return true;
+
+ default:
+ break;
+ }
+ }
+ sender.sendMessage(ChatColor.RED + "You are not allowed to use that command.");
+ return false;
+ }
+
+ /**
+ * Sets up the default world for use.
+ */
+ private boolean setDefaultWorldHandler(CommandSender sender) {
+
+ dataHolder = worldsHolder.getWorldData(worldsHolder.getDefaultWorld().getName());
+ permissionHandler = dataHolder.getPermissionsHandler();
+
+ 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;
+ }
+
+ sender.sendMessage(ChatColor.RED + "Couldn't retrieve your world. World selection is needed.");
+ sender.sendMessage(ChatColor.RED + "Use /manselect <world>");
+ return false;
+
+ }
+
+ /**
+ * Send confirmation of a group change. using permission nodes...
+ *
+ * groupmanager.notify.self groupmanager.notify.other
+ *
+ * @param name
+ * @param msg
+ */
+ public static void notify(String name, String msg) {
+
+ Player player = Bukkit.getServer().getPlayerExact(name);
+
+ for (Player test : Bukkit.getServer().getOnlinePlayers()) {
+ if (!test.equals(player)) {
+ if (test.hasPermission("groupmanager.notify.other"))
+ test.sendMessage(ChatColor.YELLOW + name + " was" + msg);
+ } else if ((player != null) && ((player.hasPermission("groupmanager.notify.self")) || (player.hasPermission("groupmanager.notify.other"))))
+ player.sendMessage(ChatColor.YELLOW + "You were" + msg);
+ }
+
+ }
+
+ /**
+ * Load a List of players matching the name given. If none online, check
+ * Offline.
+ *
+ * @param playerName, sender
+ * @return true if a single match is found
+ */
+ private List<String> validatePlayer(String playerName, CommandSender sender) {
+
+ List<Player> players = new ArrayList<Player>();
+ List<String> match = new ArrayList<String>();
+
+ players = this.getServer().matchPlayer(playerName);
+ if (players.isEmpty()) {
+ // Check for an offline player (exact match).
+ if (Arrays.asList(this.getServer().getOfflinePlayers()).contains(Bukkit.getOfflinePlayer(playerName))) {
+ match.add(playerName);
+ } else {
+ // look for partial matches
+ for (OfflinePlayer offline : this.getServer().getOfflinePlayers()) {
+ if (offline.getName().toLowerCase().startsWith(playerName.toLowerCase()))
+ match.add(offline.getName());
+ }
+ }
+
+ } else {
+ for (Player player : players) {
+ match.add(player.getName());
+ }
+ }
+
+ if (match.isEmpty() || match == null) {
+ sender.sendMessage(ChatColor.RED + "Player not found!");
+ return null;
+ } else if (match.size() > 1) {
+ sender.sendMessage(ChatColor.RED + "Too many matches found! (" + match.toString() + ")");
+ return null;
+ }
+
+ return match;
+
+ }
+
+ /**
+ * @return the config
+ */
+ public GMConfiguration getGMConfig() {
+
+ return config;
+ }
+
+ /**
+ * @return the backupFolder
+ */
+ public File getBackupFolder() {
+
+ return backupFolder;
+ }
+
+ public static GlobalGroups getGlobalGroups() {
+
+ return globalGroups;
+
+ }
+} \ No newline at end of file
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/Tasks/BukkitPermsUpdateTask.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/Tasks/BukkitPermsUpdateTask.java
new file mode 100644
index 000000000..1a0fc2369
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/Tasks/BukkitPermsUpdateTask.java
@@ -0,0 +1,29 @@
+package org.anjocaido.groupmanager.Tasks;
+
+import org.anjocaido.groupmanager.GroupManager;
+
+/*
+ *
+ * Created by ElgarL
+ */
+
+public class BukkitPermsUpdateTask implements Runnable {
+
+ public BukkitPermsUpdateTask() {
+
+ super();
+ }
+
+ @Override
+ public void run() {
+
+ // Signal loaded and update BukkitPermissions.
+ GroupManager.setLoaded(true);
+ GroupManager.BukkitPermissions.collectPermissions();
+ GroupManager.BukkitPermissions.updateAllPlayers();
+
+ GroupManager.logger.info("Bukkit Permissions Updated!");
+
+ }
+
+} \ No newline at end of file
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/DataUnit.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/DataUnit.java
new file mode 100644
index 000000000..bb04fa3d7
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/DataUnit.java
@@ -0,0 +1,181 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anjocaido.groupmanager.data;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.anjocaido.groupmanager.GroupManager;
+import org.anjocaido.groupmanager.dataholder.WorldDataHolder;
+import org.anjocaido.groupmanager.utils.StringPermissionComparator;
+
+/**
+ *
+ * @author gabrielcouto
+ */
+public abstract class DataUnit {
+
+ private WorldDataHolder dataSource;
+ private String name;
+ private boolean changed, sorted = false;
+ private ArrayList<String> permissions = new ArrayList<String>();
+
+ public DataUnit(WorldDataHolder dataSource, String name) {
+
+ this.dataSource = dataSource;
+ this.name = name;
+ }
+
+ public DataUnit(String name) {
+
+ this.name = name;
+ }
+
+ /**
+ * Every group is matched only by their names and DataSources names.
+ *
+ * @param o
+ * @return true if they are equal. false if not.
+ */
+ @Override
+ public boolean equals(Object o) {
+
+ if (o instanceof DataUnit) {
+ DataUnit go = (DataUnit) o;
+ if (this.getName().equalsIgnoreCase(go.getName())) {
+ // Global Group match.
+ if (this.dataSource == null && go.getDataSource() == null)
+ return true;
+ // This is a global group, the object to test isn't.
+ if (this.dataSource == null && go.getDataSource() != null)
+ return false;
+ // This is not a global group, but the object to test is.
+ if (this.dataSource != null && go.getDataSource() == null)
+ return false;
+ // Match on group name and world name.
+ if (this.dataSource.getName().equalsIgnoreCase(go.getDataSource().getName()))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+
+ int hash = 5;
+ 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() {
+
+ return dataSource;
+ }
+
+ /**
+ * @return the name
+ */
+ public String getName() {
+
+ return name;
+ }
+
+ public void flagAsChanged() {
+
+ WorldDataHolder testSource = getDataSource();
+ String source = "";
+
+ if (testSource == null)
+ source = "GlobalGroups";
+ else
+ source = testSource.getName();
+
+ GroupManager.logger.finest("DataSource: " + source + " - DataUnit: " + getName() + " flagged as changed!");
+ // for(StackTraceElement st: Thread.currentThread().getStackTrace()){
+ // GroupManager.logger.finest(st.toString());
+ // }
+ sorted = false;
+ changed = true;
+ }
+
+ public boolean isChanged() {
+
+ return changed;
+ }
+
+ public void flagAsSaved() {
+
+ WorldDataHolder testSource = getDataSource();
+ String source = "";
+
+ if (testSource == null)
+ source = "GlobalGroups";
+ else
+ source = testSource.getName();
+
+ GroupManager.logger.finest("DataSource: " + source + " - DataUnit: " + getName() + " flagged as saved!");
+ changed = false;
+ }
+
+ public boolean hasSamePermissionNode(String permission) {
+
+ return permissions.contains(permission);
+ }
+
+ public void addPermission(String permission) {
+
+ if (!hasSamePermissionNode(permission)) {
+ permissions.add(permission);
+ }
+ flagAsChanged();
+ }
+
+ public boolean removePermission(String permission) {
+
+ flagAsChanged();
+ return permissions.remove(permission);
+ }
+
+ /**
+ * Use this only to list permissions.
+ * You can't edit the permissions using the returned ArrayList instance
+ *
+ * @return a copy of the permission list
+ */
+ public List<String> getPermissionList() {
+
+ return Collections.unmodifiableList(permissions);
+ }
+
+ public boolean isSorted() {
+
+ return this.sorted;
+ }
+
+ public void sortPermissions() {
+
+ if (!isSorted()) {
+ Collections.sort(permissions, StringPermissionComparator.getInstance());
+ sorted = true;
+ }
+ }
+} \ No newline at end of file
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Group.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Group.java
new file mode 100644
index 000000000..751dc8fd6
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Group.java
@@ -0,0 +1,187 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anjocaido.groupmanager.data;
+
+import org.anjocaido.groupmanager.GroupManager;
+import org.anjocaido.groupmanager.dataholder.WorldDataHolder;
+import org.anjocaido.groupmanager.events.GMGroupEvent.Action;
+import org.anjocaido.groupmanager.events.GroupManagerEventHandler;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * @author gabrielcouto/ElgarL
+ */
+public class Group extends DataUnit implements Cloneable {
+
+ /**
+ * The group it inherits DIRECTLY!
+ */
+ private ArrayList<String> inherits = new ArrayList<String>();
+ /**
+ * This one holds the fields in INFO node.
+ * like prefix = 'c'
+ * or build = false
+ */
+ private GroupVariables variables = new GroupVariables(this);
+
+ /**
+ * Constructor for individual World Groups.
+ *
+ * @param name
+ */
+ public Group(WorldDataHolder source, String name) {
+
+ super(source, name);
+ }
+
+ /**
+ * Constructor for Global Groups.
+ *
+ * @param name
+ */
+ public Group(String name) {
+
+ super(name);
+ }
+
+ /**
+ * Is this a GlobalGroup
+ *
+ * @return true if this is a global group
+ */
+ public boolean isGlobal() {
+
+ return (getDataSource() == null);
+ }
+
+ /**
+ * Clone this group
+ *
+ * @return a clone of this group
+ */
+ @Override
+ public Group clone() {
+
+ Group clone;
+
+ if (isGlobal()) {
+ clone = new Group(this.getName());
+ } else {
+ clone = new Group(getDataSource(), this.getName());
+ clone.inherits = new ArrayList<String>(this.getInherits());
+ }
+
+ for (String perm : this.getPermissionList()) {
+ clone.addPermission(perm);
+ }
+ clone.variables = ((GroupVariables) variables).clone(clone);
+ //clone.flagAsChanged();
+ return clone;
+ }
+
+ /**
+ * Use this to deliver a group from a different dataSource to another
+ *
+ * @param dataSource
+ * @return Null or Clone
+ */
+ public Group clone(WorldDataHolder dataSource) {
+
+ if (dataSource.groupExists(this.getName())) {
+ return null;
+ }
+
+ Group clone = dataSource.createGroup(this.getName());
+
+ // Don't add inheritance for GlobalGroups
+ if (!isGlobal()) {
+ clone.inherits = new ArrayList<String>(this.getInherits());
+ }
+ for (String perm : this.getPermissionList()) {
+ clone.addPermission(perm);
+ }
+ clone.variables = variables.clone(clone);
+ clone.flagAsChanged(); //use this to make the new dataSource save the new group
+ return clone;
+ }
+
+ /**
+ * an unmodifiable list of inherits list
+ * You can't manage the list by here
+ * Lol... version 0.6 had a problem because this.
+ *
+ * @return the inherits
+ */
+ public List<String> getInherits() {
+
+ return Collections.unmodifiableList(inherits);
+ }
+
+ /**
+ * @param inherit the inherits to set
+ */
+ public void addInherits(Group inherit) {
+
+ if (!isGlobal()) {
+ if (!this.getDataSource().groupExists(inherit.getName())) {
+ getDataSource().addGroup(inherit);
+ }
+ if (!inherits.contains(inherit.getName().toLowerCase())) {
+ inherits.add(inherit.getName().toLowerCase());
+ }
+ flagAsChanged();
+ if (GroupManager.isLoaded()) {
+ GroupManager.BukkitPermissions.updateAllPlayers();
+ GroupManagerEventHandler.callEvent(this, Action.GROUP_INHERITANCE_CHANGED);
+ }
+ }
+ }
+
+ public boolean removeInherits(String inherit) {
+
+ if (!isGlobal()) {
+ if (this.inherits.contains(inherit.toLowerCase())) {
+ this.inherits.remove(inherit.toLowerCase());
+ flagAsChanged();
+ GroupManagerEventHandler.callEvent(this, Action.GROUP_INHERITANCE_CHANGED);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return the variables
+ */
+ public GroupVariables getVariables() {
+
+ return variables;
+ }
+
+ /**
+ *
+ * @param varList
+ */
+ public void setVariables(Map<String, Object> varList) {
+
+ if (!isGlobal()) {
+ GroupVariables temp = new GroupVariables(this, varList);
+ variables.clearVars();
+ for (String key : temp.getVarKeyList()) {
+ variables.addVar(key, temp.getVarObject(key));
+ }
+ flagAsChanged();
+ if (GroupManager.isLoaded()) {
+ GroupManager.BukkitPermissions.updateAllPlayers();
+ GroupManagerEventHandler.callEvent(this, Action.GROUP_INFO_CHANGED);
+ }
+ }
+ }
+}
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/GroupVariables.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/GroupVariables.java
new file mode 100644
index 000000000..e08d1db7d
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/GroupVariables.java
@@ -0,0 +1,94 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anjocaido.groupmanager.data;
+
+import java.util.Map;
+
+/**
+ *
+ * @author gabrielcouto
+ */
+public class GroupVariables extends Variables implements Cloneable {
+
+ private Group owner;
+
+ public GroupVariables(Group owner) {
+
+ super(owner);
+ this.owner = owner;
+ addVar("prefix", "");
+ addVar("suffix", "");
+ addVar("build", false);
+ }
+
+ public GroupVariables(Group owner, Map<String, Object> varList) {
+
+ super(owner);
+ variables = varList;
+ if (variables.get("prefix") == null) {
+ variables.put("prefix", "");
+ owner.flagAsChanged();
+ }
+ //thisGrp.prefix = infoNode.get("prefix").toString();
+
+ if (variables.get("suffix") == null) {
+ variables.put("suffix", "");
+ owner.flagAsChanged();
+ }
+ //thisGrp.suffix = infoNode.get("suffix").toString();
+
+ if (variables.get("build") == null) {
+ variables.put("build", false);
+ owner.flagAsChanged();
+ }
+ this.owner = owner;
+ }
+
+ /**
+ * A clone of all vars here.
+ *
+ * @return GroupVariables clone
+ */
+ protected GroupVariables clone(Group newOwner) {
+
+ GroupVariables clone = new GroupVariables(newOwner);
+ for (String key : variables.keySet()) {
+ clone.variables.put(key, variables.get(key));
+ }
+ newOwner.flagAsChanged();
+ return clone;
+ }
+
+ /**
+ * Remove a var from the list
+ *
+ * @param name
+ */
+ @Override
+ public void removeVar(String name) {
+
+ try {
+ this.variables.remove(name);
+ } catch (Exception e) {
+ }
+ if (name.equals("prefix")) {
+ addVar("prefix", "");
+ } else if (name.equals("suffix")) {
+ addVar("suffix", "");
+ } else if (name.equals("build")) {
+ addVar("build", false);
+ }
+ owner.flagAsChanged();
+ }
+
+ /**
+ * @return the owner
+ */
+ @Override
+ public Group getOwner() {
+
+ return owner;
+ }
+}
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/User.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/User.java
new file mode 100644
index 000000000..6c74c2e50
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/User.java
@@ -0,0 +1,273 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anjocaido.groupmanager.data;
+
+//import com.sun.org.apache.bcel.internal.generic.AALOAD;
+import java.util.ArrayList;
+
+import org.anjocaido.groupmanager.GroupManager;
+import org.anjocaido.groupmanager.dataholder.WorldDataHolder;
+import org.anjocaido.groupmanager.events.GMUserEvent.Action;
+import org.anjocaido.groupmanager.events.GroupManagerEventHandler;
+
+import java.util.Map;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+/**
+ *
+ * @author gabrielcouto/ElgarL
+ */
+public class User extends DataUnit implements Cloneable {
+
+ /**
+ *
+ */
+ private String group = null;
+ private ArrayList<String> subGroups = new ArrayList<String>();
+ /**
+ * This one holds the fields in INFO node. like prefix = 'c' or build =
+ * false
+ */
+ private UserVariables variables = new UserVariables(this);
+ private transient Player bukkitPlayer = null;
+
+ /**
+ *
+ * @param name
+ */
+ public User(WorldDataHolder source, String name) {
+
+ super(source, name);
+ this.group = source.getDefaultGroup().getName();
+ }
+
+ /**
+ *
+ * @return User clone
+ */
+ @Override
+ public User clone() {
+
+ User clone = new User(getDataSource(), this.getName());
+ clone.group = this.group;
+ for (String perm : this.getPermissionList()) {
+ clone.addPermission(perm);
+ }
+ // clone.variables = this.variables.clone();
+ // clone.flagAsChanged();
+ return clone;
+ }
+
+ /**
+ * Use this to deliver a user from one WorldDataHolder to another
+ *
+ * @param dataSource
+ * @return null if given dataSource already contains the same user
+ */
+ public User clone(WorldDataHolder dataSource) {
+
+ if (dataSource.isUserDeclared(this.getName())) {
+ return null;
+ }
+ User clone = dataSource.createUser(this.getName());
+ if (dataSource.getGroup(group) == null) {
+ clone.setGroup(dataSource.getDefaultGroup());
+ } else {
+ clone.setGroup(dataSource.getGroup(this.getGroupName()));
+ }
+ for (String perm : this.getPermissionList()) {
+ clone.addPermission(perm);
+ }
+ clone.variables = this.variables.clone(this);
+ clone.flagAsChanged();
+ return clone;
+ }
+
+ public Group getGroup() {
+
+ Group result = getDataSource().getGroup(group);
+ if (result == null) {
+ this.setGroup(getDataSource().getDefaultGroup());
+ result = getDataSource().getDefaultGroup();
+ }
+ return result;
+ }
+
+ /**
+ * @return the group
+ */
+ public String getGroupName() {
+
+ Group result = getDataSource().getGroup(group);
+ if (result == null) {
+ group = getDataSource().getDefaultGroup().getName();
+ }
+ return group;
+ }
+
+
+ /**
+ * @param group
+ * the group to set
+ */
+ public void setGroup(Group group) {
+
+ setGroup(group, true);
+ }
+
+ /**
+ * @param group the group to set
+ * @param updatePerms if we are to trigger a superperms update.
+ *
+ */
+ public void setGroup(Group group, Boolean updatePerms) {
+
+ if (!this.getDataSource().groupExists(group.getName())) {
+ getDataSource().addGroup(group);
+ }
+ group = getDataSource().getGroup(group.getName());
+ String oldGroup = this.group;
+ this.group = group.getName();
+ flagAsChanged();
+ if (GroupManager.isLoaded()) {
+ if (!GroupManager.BukkitPermissions.isPlayer_join() && (updatePerms))
+ GroupManager.BukkitPermissions.updatePlayer(getBukkitPlayer());
+
+ // Do we notify of the group change?
+ String defaultGroupName = getDataSource().getDefaultGroup().getName();
+ // if we were not in the default group
+ // or we were in the default group and the move is to a different
+ // group.
+ boolean notify = (!oldGroup.equalsIgnoreCase(defaultGroupName)) || ((oldGroup.equalsIgnoreCase(defaultGroupName)) && (!this.group.equalsIgnoreCase(defaultGroupName)));
+
+ if (notify)
+ GroupManager.notify(this.getName(), String.format(" moved to the group %s.", group.getName()));
+
+ GroupManagerEventHandler.callEvent(this, Action.USER_GROUP_CHANGED);
+ }
+ }
+
+ public boolean addSubGroup(Group subGroup) {
+
+ // Don't allow adding a subgroup if it's already set as the primary.
+ if (this.group.equalsIgnoreCase(subGroup.getName())) {
+ return false;
+ }
+ // User already has this subgroup
+ if (containsSubGroup(subGroup))
+ return false;
+
+ // If the group doesn't exists add it
+ if (!this.getDataSource().groupExists(subGroup.getName())) {
+ getDataSource().addGroup(subGroup);
+ }
+
+ subGroups.add(subGroup.getName());
+ flagAsChanged();
+ if (GroupManager.isLoaded()) {
+ if (!GroupManager.BukkitPermissions.isPlayer_join())
+ GroupManager.BukkitPermissions.updatePlayer(getBukkitPlayer());
+ GroupManagerEventHandler.callEvent(this, Action.USER_SUBGROUP_CHANGED);
+ }
+ return true;
+
+ //subGroup = getDataSource().getGroup(subGroup.getName());
+ //removeSubGroup(subGroup);
+ //subGroups.add(subGroup.getName());
+ }
+
+ public int subGroupsSize() {
+
+ return subGroups.size();
+ }
+
+ public boolean isSubGroupsEmpty() {
+
+ return subGroups.isEmpty();
+ }
+
+ public boolean containsSubGroup(Group subGroup) {
+
+ return subGroups.contains(subGroup.getName());
+ }
+
+ public boolean removeSubGroup(Group subGroup) {
+
+ try {
+ if (subGroups.remove(subGroup.getName())) {
+ flagAsChanged();
+ if (GroupManager.isLoaded())
+ if (!GroupManager.BukkitPermissions.isPlayer_join())
+ GroupManager.BukkitPermissions.updatePlayer(getBukkitPlayer());
+ GroupManagerEventHandler.callEvent(this, Action.USER_SUBGROUP_CHANGED);
+ return true;
+ }
+ } catch (Exception e) {
+ }
+ return false;
+ }
+
+ public ArrayList<Group> subGroupListCopy() {
+
+ ArrayList<Group> val = new ArrayList<Group>();
+ for (String gstr : subGroups) {
+ Group g = getDataSource().getGroup(gstr);
+ if (g == null) {
+ removeSubGroup(g);
+ continue;
+ }
+ val.add(g);
+ }
+ return val;
+ }
+
+ public ArrayList<String> subGroupListStringCopy() {
+
+ return new ArrayList<String>(subGroups);
+ }
+
+ /**
+ * @return the variables
+ */
+ public UserVariables getVariables() {
+
+ return variables;
+ }
+
+ /**
+ *
+ * @param varList
+ */
+ public void setVariables(Map<String, Object> varList) {
+
+ //UserVariables temp = new UserVariables(this, varList);
+ variables.clearVars();
+ for (String key : varList.keySet()) {
+ variables.addVar(key, varList.get(key));
+ }
+ flagAsChanged();
+ if (GroupManager.isLoaded()) {
+ //if (!GroupManager.BukkitPermissions.isPlayer_join())
+ // GroupManager.BukkitPermissions.updatePlayer(this.getName());
+ GroupManagerEventHandler.callEvent(this, Action.USER_INFO_CHANGED);
+ }
+ }
+
+
+ public User updatePlayer(Player player) {
+
+ bukkitPlayer = player;
+ return this;
+ }
+
+ public Player getBukkitPlayer() {
+
+ if (bukkitPlayer == null) {
+ bukkitPlayer = Bukkit.getPlayer(this.getName());
+ }
+ return bukkitPlayer;
+ }
+}
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/UserVariables.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/UserVariables.java
new file mode 100644
index 000000000..f994595c1
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/UserVariables.java
@@ -0,0 +1,53 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anjocaido.groupmanager.data;
+
+import java.util.Map;
+
+/**
+ *
+ * @author gabrielcouto
+ */
+public class UserVariables extends Variables {
+
+ private User owner;
+
+ public UserVariables(User owner) {
+
+ super(owner);
+ this.owner = owner;
+ }
+
+ public UserVariables(User owner, Map<String, Object> varList) {
+
+ super(owner);
+ this.variables = varList;
+ this.owner = owner;
+ }
+
+ /**
+ * A clone of all vars here.
+ *
+ * @return UserVariables clone
+ */
+ protected UserVariables clone(User newOwner) {
+
+ UserVariables clone = new UserVariables(newOwner);
+ for (String key : variables.keySet()) {
+ clone.variables.put(key, variables.get(key));
+ }
+ newOwner.flagAsChanged();
+ return clone;
+ }
+
+ /**
+ * @return the owner
+ */
+ @Override
+ public User getOwner() {
+
+ return owner;
+ }
+}
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Variables.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Variables.java
new file mode 100644
index 000000000..42ceba7e4
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Variables.java
@@ -0,0 +1,208 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anjocaido.groupmanager.data;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A class that holds variables of a user/group.
+ * In groups, it holds the contents of INFO node.
+ * Like:
+ * prefix
+ * suffix
+ * build
+ *
+ * @author gabrielcouto
+ */
+public abstract class Variables implements Cloneable {
+
+ private DataUnit owner;
+ protected Map<String, Object> variables = new HashMap<String, Object>();
+
+ public Variables(DataUnit owner) {
+
+ this.owner = owner;
+ }
+
+ /**
+ * Add var to the the INFO node.
+ * examples:
+ * addVar("build",true);
+ * addVar("prefix","c");
+ *
+ * @param name key name of the var
+ * @param o the object value of the var
+ */
+ public void addVar(String name, Object o) {
+
+ if (o == null) {
+ return;
+ }
+ if (variables.containsKey(name)) {
+ variables.remove(name);
+ }
+ variables.put(name, o);
+ owner.flagAsChanged();
+ }
+
+ /**
+ * Returns the object inside the var
+ *
+ * @param name
+ * @return a Object if exists. null if doesn't exists
+ */
+ public Object getVarObject(String name) {
+
+ return variables.get(name);
+ }
+
+ /**
+ * Get the String value for the given var name
+ *
+ * @param name the var key name
+ * @return "" if null. or the toString() value of object
+ */
+ public String getVarString(String name) {
+
+ Object o = variables.get(name);
+ try {
+ return o == null ? "" : o.toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ /**
+ *
+ * @param name
+ * @return false if null. or a Boolean.parseBoolean of the string
+ */
+ public Boolean getVarBoolean(String name) {
+
+ Object o = variables.get(name);
+ try {
+ return o == null ? false : Boolean.parseBoolean(o.toString());
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ /**
+ *
+ * @param name
+ * @return -1 if null. or a parseInt of the string
+ */
+ public Integer getVarInteger(String name) {
+
+ Object o = variables.get(name);
+ try {
+ return o == null ? -1 : Integer.parseInt(o.toString());
+ } catch (Exception e) {
+ return -1;
+ }
+ }
+
+ /**
+ *
+ * @param name
+ * @return -1 if null. or a parseDouble of the string
+ */
+ public Double getVarDouble(String name) {
+
+ Object o = variables.get(name);
+ try {
+ return o == null ? -1.0D : Double.parseDouble(o.toString());
+ } catch (Exception e) {
+ return -1.0D;
+ }
+ }
+
+ /**
+ * All variable keys this is holding
+ *
+ * @return Set of all variable names.
+ */
+ public Set<String> getVarKeyList() {
+
+ return variables.keySet();
+ }
+
+ /**
+ * verify is a var exists
+ *
+ * @param name the key name of the var
+ * @return true if that var exists
+ */
+ public boolean hasVar(String name) {
+
+ return variables.containsKey(name);
+ }
+
+ /**
+ * Returns the quantity of vars this is holding
+ *
+ * @return the number of vars
+ */
+ public int getSize() {
+
+ return variables.size();
+ }
+
+ /**
+ * Remove a var from the list
+ *
+ * @param name
+ */
+ public void removeVar(String name) {
+
+ try {
+ variables.remove(name);
+ } catch (Exception e) {
+ }
+ owner.flagAsChanged();
+ }
+
+ public static Object parseVariableValue(String value) {
+
+ try {
+ Integer i = Integer.parseInt(value);
+ return i;
+ } catch (NumberFormatException e) {
+ }
+ try {
+ Double d = Double.parseDouble(value);
+ return d;
+ } catch (NumberFormatException e) {
+ }
+ if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("yes") || value.equalsIgnoreCase("on")) {
+ return true;
+ } else if (value.equalsIgnoreCase("false") || value.equalsIgnoreCase("no") || value.equalsIgnoreCase("off")) {
+ return false;
+ }
+ return value;
+
+ }
+
+ public void clearVars() {
+
+ variables.clear();
+ owner.flagAsChanged();
+ }
+
+ /**
+ * @return the owner
+ */
+ public DataUnit getOwner() {
+
+ return owner;
+ }
+
+ public boolean isEmpty() {
+
+ return variables.isEmpty();
+ }
+}
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/GroupsDataHolder.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/GroupsDataHolder.java
new file mode 100644
index 000000000..eaaaace74
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/GroupsDataHolder.java
@@ -0,0 +1,123 @@
+package org.anjocaido.groupmanager.dataholder;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.anjocaido.groupmanager.data.Group;
+
+/**
+ * This container holds all Groups loaded from the relevant groupsFile.
+ *
+ * @author ElgarL
+ *
+ */
+public class GroupsDataHolder {
+
+ private WorldDataHolder dataSource;
+ private Group defaultGroup = null;
+ private File groupsFile;
+ private boolean haveGroupsChanged = false;
+ private long timeStampGroups = 0;
+
+ /**
+ * The actual groups holder
+ */
+ private Map<String, Group> groups = new HashMap<String, Group>();
+
+ /**
+ * Constructor
+ */
+ protected GroupsDataHolder() {
+
+ }
+
+ 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);
+ }
+
+ /**
+ * @return the defaultGroup
+ */
+ public Group getDefaultGroup() {
+
+ return defaultGroup;
+ }
+
+ /**
+ * @param defaultGroup the defaultGroup to set
+ */
+ public void setDefaultGroup(Group defaultGroup) {
+
+ this.defaultGroup = defaultGroup;
+ }
+
+ /**
+ * @return the groups
+ */
+ public Map<String, Group> getGroups() {
+
+ return groups;
+ }
+
+ /**
+ * @param groups the groups to set
+ */
+ public void setGroups(Map<String, Group> groups) {
+
+ this.groups = groups;
+ }
+
+ /**
+ * @return the groupsFile
+ */
+ public File getGroupsFile() {
+
+ return groupsFile;
+ }
+
+ /**
+ * @param groupsFile the groupsFile to set
+ */
+ public void setGroupsFile(File groupsFile) {
+
+ this.groupsFile = groupsFile;
+ }
+
+ /**
+ * @return the haveGroupsChanged
+ */
+ public boolean HaveGroupsChanged() {
+
+ return haveGroupsChanged;
+ }
+
+ /**
+ * @param haveGroupsChanged the haveGroupsChanged to set
+ */
+ public void setGroupsChanged(boolean haveGroupsChanged) {
+
+ this.haveGroupsChanged = haveGroupsChanged;
+ }
+
+ /**
+ * @return the timeStampGroups
+ */
+ public long getTimeStampGroups() {
+
+ return timeStampGroups;
+ }
+
+ /**
+ * @param timeStampGroups the timeStampGroups to set
+ */
+ public void setTimeStampGroups(long timeStampGroups) {
+
+ this.timeStampGroups = timeStampGroups;
+ }
+
+} \ No newline at end of file
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/OverloadedWorldHolder.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/OverloadedWorldHolder.java
new file mode 100644
index 000000000..84561b6e5
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/OverloadedWorldHolder.java
@@ -0,0 +1,214 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anjocaido.groupmanager.dataholder;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import org.anjocaido.groupmanager.data.User;
+
+/**
+ *
+ * @author gabrielcouto
+ */
+public class OverloadedWorldHolder extends WorldDataHolder {
+
+ /**
+ *
+ */
+ protected Map<String, User> overloadedUsers = new HashMap<String, User>();
+
+ /**
+ *
+ * @param ph
+ */
+ public OverloadedWorldHolder(WorldDataHolder ph) {
+
+ super(ph.getName());
+ this.setGroupsFile(ph.getGroupsFile());
+ this.setUsersFile(ph.getUsersFile());
+ this.groups = ph.groups;
+ this.users = ph.users;
+ }
+
+ /**
+ *
+ * @param userName
+ * @return user object or a new user if none exists.
+ */
+ @Override
+ public User getUser(String userName) {
+
+ //OVERLOADED CODE
+ String userNameLowered = userName.toLowerCase();
+ if (overloadedUsers.containsKey(userNameLowered)) {
+ return overloadedUsers.get(userNameLowered);
+ }
+ //END CODE
+ if (getUsers().containsKey(userNameLowered)) {
+ return getUsers().get(userNameLowered);
+ }
+ User newUser = createUser(userName);
+ setUsersChanged(true);
+ return newUser;
+ }
+
+ /**
+ *
+ * @param theUser
+ */
+ @Override
+ public void addUser(User theUser) {
+
+ if (theUser.getDataSource() != this) {
+ theUser = theUser.clone(this);
+ }
+ if (theUser == null) {
+ return;
+ }
+ if ((theUser.getGroup() == null) || (!getGroups().containsKey(theUser.getGroupName().toLowerCase()))) {
+ theUser.setGroup(getDefaultGroup());
+ }
+ //OVERLOADED CODE
+ if (overloadedUsers.containsKey(theUser.getName().toLowerCase())) {
+ overloadedUsers.remove(theUser.getName().toLowerCase());
+ overloadedUsers.put(theUser.getName().toLowerCase(), theUser);
+ return;
+ }
+ //END CODE
+ removeUser(theUser.getName());
+ getUsers().put(theUser.getName().toLowerCase(), theUser);
+ setUsersChanged(true);
+ }
+
+ /**
+ *
+ * @param userName
+ * @return true if removed/false if not found.
+ */
+ @Override
+ public boolean removeUser(String userName) {
+
+ //OVERLOADED CODE
+ if (overloadedUsers.containsKey(userName.toLowerCase())) {
+ overloadedUsers.remove(userName.toLowerCase());
+ return true;
+ }
+ //END CODE
+ if (getUsers().containsKey(userName.toLowerCase())) {
+ getUsers().remove(userName.toLowerCase());
+ setUsersChanged(true);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean removeGroup(String groupName) {
+
+ if (groupName.equals(getDefaultGroup())) {
+ return false;
+ }
+ for (String key : getGroups().keySet()) {
+ if (groupName.equalsIgnoreCase(key)) {
+ getGroups().remove(key);
+ for (String userKey : getUsers().keySet()) {
+ User user = getUsers().get(userKey);
+ if (user.getGroupName().equalsIgnoreCase(key)) {
+ user.setGroup(getDefaultGroup());
+ }
+
+ }
+ //OVERLOADED CODE
+ for (String userKey : overloadedUsers.keySet()) {
+ User user = overloadedUsers.get(userKey);
+ if (user.getGroupName().equalsIgnoreCase(key)) {
+ user.setGroup(getDefaultGroup());
+ }
+
+ }
+ //END OVERLOAD
+ setGroupsChanged(true);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ *
+ * @return Collection of all users
+ */
+ @Override
+ public Collection<User> getUserList() {
+
+ Collection<User> overloadedList = new ArrayList<User>();
+ Collection<User> normalList = getUsers().values();
+ for (User u : normalList) {
+ if (overloadedUsers.containsKey(u.getName().toLowerCase())) {
+ overloadedList.add(overloadedUsers.get(u.getName().toLowerCase()));
+ } else {
+ overloadedList.add(u);
+ }
+ }
+ return overloadedList;
+ }
+
+ /**
+ *
+ * @param userName
+ * @return true if user is overloaded.
+ */
+ public boolean isOverloaded(String userName) {
+
+ return overloadedUsers.containsKey(userName.toLowerCase());
+ }
+
+ /**
+ *
+ * @param userName
+ */
+ public void overloadUser(String userName) {
+
+ if (!isOverloaded(userName)) {
+ User theUser = getUser(userName);
+ theUser = theUser.clone();
+ if (overloadedUsers.containsKey(theUser.getName().toLowerCase())) {
+ overloadedUsers.remove(theUser.getName().toLowerCase());
+ }
+ overloadedUsers.put(theUser.getName().toLowerCase(), theUser);
+ }
+ }
+
+ /**
+ *
+ * @param userName
+ */
+ public void removeOverload(String userName) {
+
+ overloadedUsers.remove(userName.toLowerCase());
+ }
+
+ /**
+ * Gets the user in normal state. Surpassing the overload state.
+ * It doesn't affect permissions. But it enables plugins change the
+ * actual user permissions even in overload mode.
+ *
+ * @param userName
+ * @return user object
+ */
+ public User surpassOverload(String userName) {
+
+ if (!isOverloaded(userName)) {
+ return getUser(userName);
+ }
+ if (getUsers().containsKey(userName.toLowerCase())) {
+ return getUsers().get(userName.toLowerCase());
+ }
+ User newUser = createUser(userName);
+ return newUser;
+ }
+} \ No newline at end of file
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/UsersDataHolder.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/UsersDataHolder.java
new file mode 100644
index 000000000..665fe227d
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/UsersDataHolder.java
@@ -0,0 +1,107 @@
+package org.anjocaido.groupmanager.dataholder;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.anjocaido.groupmanager.data.User;
+
+/**
+ * This container holds all Users loaded from the relevant usersFile.
+ *
+ * @author ElgarL
+ *
+ */
+public class UsersDataHolder {
+
+ private WorldDataHolder dataSource;
+ private File usersFile;
+ private boolean haveUsersChanged = false;
+ private long timeStampUsers = 0;
+
+ /**
+ * The actual groups holder
+ */
+ private Map<String, User> users = new HashMap<String, User>();
+
+ /**
+ * Constructor
+ */
+ protected UsersDataHolder() {
+
+ }
+
+ 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);
+
+ }
+
+ /**
+ * @return the users
+ */
+ public Map<String, User> getUsers() {
+
+ return users;
+ }
+
+ /**
+ * @param users the users to set
+ */
+ public void setUsers(Map<String, User> users) {
+
+ this.users = users;
+ }
+
+ /**
+ * @return the usersFile
+ */
+ public File getUsersFile() {
+
+ return usersFile;
+ }
+
+ /**
+ * @param usersFile the usersFile to set
+ */
+ public void setUsersFile(File usersFile) {
+
+ this.usersFile = usersFile;
+ }
+
+ /**
+ * @return the haveUsersChanged
+ */
+ public boolean HaveUsersChanged() {
+
+ return haveUsersChanged;
+ }
+
+ /**
+ * @param haveUsersChanged the haveUsersChanged to set
+ */
+ public void setUsersChanged(boolean haveUsersChanged) {
+
+ this.haveUsersChanged = haveUsersChanged;
+ }
+
+ /**
+ * @return the timeStampUsers
+ */
+ public long getTimeStampUsers() {
+
+ return timeStampUsers;
+ }
+
+ /**
+ * @param timeStampUsers the timeStampUsers to set
+ */
+ public void setTimeStampUsers(long timeStampUsers) {
+
+ this.timeStampUsers = timeStampUsers;
+ }
+
+} \ No newline at end of file
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/WorldDataHolder.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/WorldDataHolder.java
new file mode 100644
index 000000000..fefc698f9
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/WorldDataHolder.java
@@ -0,0 +1,1348 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anjocaido.groupmanager.dataholder;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.anjocaido.groupmanager.GroupManager;
+import org.anjocaido.groupmanager.data.Group;
+import org.anjocaido.groupmanager.data.User;
+import org.anjocaido.groupmanager.events.GMGroupEvent;
+import org.anjocaido.groupmanager.events.GMSystemEvent;
+import org.anjocaido.groupmanager.events.GMUserEvent;
+import org.anjocaido.groupmanager.events.GMUserEvent.Action;
+import org.anjocaido.groupmanager.events.GroupManagerEventHandler;
+import org.anjocaido.groupmanager.permissions.AnjoPermissionsHandler;
+import org.bukkit.Server;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.PluginManager;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.SafeConstructor;
+import org.yaml.snakeyaml.reader.UnicodeReader;
+
+/**
+ * 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 {
+
+ /**
+ * World name
+ */
+ protected String name;
+ /**
+ * The actual groups holder
+ */
+ protected GroupsDataHolder groups = new GroupsDataHolder();
+ /**
+ * The actual users holder
+ */
+ protected UsersDataHolder users = new UsersDataHolder();
+ /**
+ *
+ */
+ protected AnjoPermissionsHandler permissionsHandler;
+
+ /**
+ * Prevent direct instantiation
+ *
+ * @param worldName
+ */
+ public WorldDataHolder(String worldName) {
+
+ name = worldName;
+ }
+
+ /**
+ * The main constructor for a new WorldDataHolder
+ *
+ * @param worldName
+ * @param groups
+ * @param users
+ */
+ public WorldDataHolder(String worldName, GroupsDataHolder groups, UsersDataHolder users) {
+
+ this.name = worldName;
+ this.groups = groups;
+ this.users = users;
+
+ // 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
+ * default group.
+ *
+ * @param userName the name of the user
+ * @return class that manage that user permission
+ */
+ public User getUser(String userName) {
+
+ if (getUsers().containsKey(userName.toLowerCase())) {
+ return getUsers().get(userName.toLowerCase());
+ }
+ User newUser = createUser(userName);
+ return newUser;
+ }
+
+ /**
+ * Add a user to the list. If it already exists, overwrite the old.
+ *
+ * @param theUser the user you want to add to the permission list
+ */
+ public void addUser(User theUser) {
+
+ if (theUser.getDataSource() != this) {
+ theUser = theUser.clone(this);
+ }
+ if (theUser == null) {
+ return;
+ }
+ if ((theUser.getGroup() == null)) {
+ theUser.setGroup(groups.getDefaultGroup());
+ }
+ removeUser(theUser.getName());
+ getUsers().put(theUser.getName().toLowerCase(), theUser);
+ setUsersChanged(true);
+ if (GroupManager.isLoaded())
+ GroupManagerEventHandler.callEvent(theUser, Action.USER_ADDED);
+ }
+
+ /**
+ * Removes the user from the list. (he might become a default user)
+ *
+ * @param userName the username from the user to remove
+ * @return true if it had something to remove
+ */
+ public boolean removeUser(String userName) {
+
+ if (getUsers().containsKey(userName.toLowerCase())) {
+ getUsers().remove(userName.toLowerCase());
+ setUsersChanged(true);
+ if (GroupManager.isLoaded())
+ GroupManagerEventHandler.callEvent(userName, GMUserEvent.Action.USER_REMOVED);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ *
+ * @param userName
+ * @return true if we have data for this player.
+ */
+ public boolean isUserDeclared(String userName) {
+
+ return getUsers().containsKey(userName.toLowerCase());
+ }
+
+ /**
+ * Change the default group of the file.
+ *
+ * @param group the group you want make default.
+ */
+ public void setDefaultGroup(Group group) {
+
+ if (!getGroups().containsKey(group.getName().toLowerCase()) || (group.getDataSource() != this)) {
+ addGroup(group);
+ }
+ groups.setDefaultGroup(getGroup(group.getName()));
+ setGroupsChanged(true);
+ if (GroupManager.isLoaded())
+ GroupManagerEventHandler.callEvent(GMSystemEvent.Action.DEFAULT_GROUP_CHANGED);
+ }
+
+ /**
+ * Returns the default group of the file
+ *
+ * @return the default group
+ */
+ public Group getDefaultGroup() {
+
+ return groups.getDefaultGroup();
+ }
+
+ /**
+ * Returns a group of the given name
+ *
+ * @param groupName the name of the group
+ * @return a group if it is found. null if not found.
+ */
+ public Group getGroup(String groupName) {
+
+ if (groupName.toLowerCase().startsWith("g:"))
+ return GroupManager.getGlobalGroups().getGroup(groupName);
+ else
+ return getGroups().get(groupName.toLowerCase());
+ }
+
+ /**
+ * Check if a group exists.
+ * Its the same of getGroup, but check if it is null.
+ *
+ * @param groupName the name of the group
+ * @return true if exists. false if not.
+ */
+ public boolean groupExists(String groupName) {
+
+ if (groupName.toLowerCase().startsWith("g:"))
+ return GroupManager.getGlobalGroups().hasGroup(groupName);
+ else
+ return getGroups().containsKey(groupName.toLowerCase());
+ }
+
+ /**
+ * Add a group to the list
+ *
+ * @param groupToAdd
+ */
+ public void addGroup(Group groupToAdd) {
+
+ if (groupToAdd.getName().toLowerCase().startsWith("g:")) {
+ GroupManager.getGlobalGroups().addGroup(groupToAdd);
+ GroupManagerEventHandler.callEvent(groupToAdd, GMGroupEvent.Action.GROUP_ADDED);
+ return;
+ }
+
+ if (groupToAdd.getDataSource() != this) {
+ groupToAdd = groupToAdd.clone(this);
+ }
+ removeGroup(groupToAdd.getName());
+ getGroups().put(groupToAdd.getName().toLowerCase(), groupToAdd);
+ setGroupsChanged(true);
+ if (GroupManager.isLoaded())
+ GroupManagerEventHandler.callEvent(groupToAdd, GMGroupEvent.Action.GROUP_ADDED);
+ }
+
+ /**
+ * Remove the group from the list
+ *
+ * @param groupName
+ * @return true if had something to remove. false the group was default or
+ * non-existant
+ */
+ public boolean removeGroup(String groupName) {
+
+ if (groupName.toLowerCase().startsWith("g:")) {
+ return GroupManager.getGlobalGroups().removeGroup(groupName);
+ }
+
+ if (getDefaultGroup() != null && groupName.equalsIgnoreCase(getDefaultGroup().getName())) {
+ return false;
+ }
+ if (getGroups().containsKey(groupName.toLowerCase())) {
+ getGroups().remove(groupName.toLowerCase());
+ setGroupsChanged(true);
+ if (GroupManager.isLoaded())
+ GroupManagerEventHandler.callEvent(groupName.toLowerCase(), GMGroupEvent.Action.GROUP_REMOVED);
+ return true;
+ }
+ return false;
+
+ }
+
+ /**
+ * Creates a new User with the given name
+ * and adds it to this holder.
+ *
+ * @param userName the username you want
+ * @return null if user already exists. or new User
+ */
+ public User createUser(String userName) {
+
+ if (getUsers().containsKey(userName.toLowerCase())) {
+ return null;
+ }
+ User newUser = new User(this, userName);
+ newUser.setGroup(groups.getDefaultGroup(), false);
+ addUser(newUser);
+ setUsersChanged(true);
+ return newUser;
+ }
+
+ /**
+ * Creates a new Group with the given name
+ * and adds it to this holder
+ *
+ * @param groupName the groupname you want
+ * @return null if group already exists. or new Group
+ */
+ public Group createGroup(String groupName) {
+
+ if (groupName.toLowerCase().startsWith("g:")) {
+ Group newGroup = new Group(groupName);
+ return GroupManager.getGlobalGroups().newGroup(newGroup);
+ }
+
+ if (getGroups().containsKey(groupName.toLowerCase())) {
+ return null;
+ }
+
+ Group newGroup = new Group(this, groupName);
+ addGroup(newGroup);
+ setGroupsChanged(true);
+ return newGroup;
+ }
+
+ /**
+ *
+ * @return a collection of the groups
+ */
+ public Collection<Group> getGroupList() {
+
+ return getGroups().values();
+ }
+
+ /**
+ *
+ * @return a collection of the users
+ */
+ public Collection<User> getUserList() {
+
+ return getUsers().values();
+ }
+
+ /**
+ * reads the file again
+ */
+ public void reload() {
+
+ try {
+ reloadGroups();
+ reloadUsers();
+ } catch (Exception ex) {
+ Logger.getLogger(WorldDataHolder.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ }
+
+ /**
+ * Refresh Group data from file
+ */
+ public void reloadGroups() {
+
+ GroupManager.setLoaded(false);
+ try {
+ // temporary holder in case the load fails.
+ WorldDataHolder ph = new WorldDataHolder(this.getName());
+
+ loadGroups(ph, getGroupsFile());
+ // transfer new data
+ resetGroups();
+ for (Group tempGroup : ph.getGroupList()) {
+ tempGroup.clone(this);
+ }
+ this.setDefaultGroup(getGroup(ph.getDefaultGroup().getName()));
+ this.removeGroupsChangedFlag();
+ this.setTimeStampGroups(getGroupsFile().lastModified());
+
+ ph = null;
+ } catch (Exception ex) {
+ Logger.getLogger(WorldDataHolder.class.getName()).log(Level.WARNING, null, ex);
+ }
+ GroupManager.setLoaded(true);
+ GroupManagerEventHandler.callEvent(GMSystemEvent.Action.RELOADED);
+ }
+
+ /**
+ * Refresh Users data from file
+ */
+ public void reloadUsers() {
+
+ GroupManager.setLoaded(false);
+ try {
+ // temporary holder in case the load fails.
+ WorldDataHolder ph = new WorldDataHolder(this.getName());
+ // copy groups for reference
+ for (Group tempGroup : this.getGroupList()) {
+ tempGroup.clone(ph);
+ }
+ // setup the default group before loading user data.
+ ph.setDefaultGroup(ph.getGroup(getDefaultGroup().getName()));
+ loadUsers(ph, getUsersFile());
+ // transfer new data
+ resetUsers();
+ for (User tempUser : ph.getUserList()) {
+ tempUser.clone(this);
+ }
+ this.removeUsersChangedFlag();
+ this.setTimeStampUsers(getUsersFile().lastModified());
+
+ ph = null;
+ } catch (Exception ex) {
+ Logger.getLogger(WorldDataHolder.class.getName()).log(Level.WARNING, null, ex);
+ }
+ GroupManager.setLoaded(true);
+ GroupManagerEventHandler.callEvent(GMSystemEvent.Action.RELOADED);
+ }
+
+ public void loadGroups(File groupsFile) {
+
+ GroupManager.setLoaded(false);
+ try {
+ setGroupsFile(groupsFile);
+ loadGroups(this, groupsFile);
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ throw new IllegalArgumentException("The file which should contain groups does not exist!\n" + groupsFile.getPath());
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new IllegalArgumentException("Error access the groups file!\n" + groupsFile.getPath());
+ }
+
+ GroupManager.setLoaded(true);
+ }
+
+ public void loadUsers(File usersFile) {
+
+ GroupManager.setLoaded(false);
+ try {
+ setUsersFile(usersFile);
+ loadUsers(this, usersFile);
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ throw new IllegalArgumentException("The file which should contain users does not exist!\n" + usersFile.getPath());
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new IllegalArgumentException("Error access the users file!\n" + usersFile.getPath());
+ }
+
+ GroupManager.setLoaded(true);
+ }
+
+ /**
+ * Returns a NEW data holder containing data read from the files
+ *
+ * @param worldName
+ * @param groupsFile
+ * @param usersFile
+ *
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ public static WorldDataHolder load(String worldName, File groupsFile, File usersFile) throws FileNotFoundException, IOException {
+
+ WorldDataHolder ph = new WorldDataHolder(worldName);
+
+ GroupManager.setLoaded(false);
+ if (groupsFile != null)
+ loadGroups(ph, groupsFile);
+ if (usersFile != null)
+ loadUsers(ph, usersFile);
+ GroupManager.setLoaded(true);
+
+ return ph;
+ }
+
+ /**
+ * Updates the WorldDataHolder from the Groups file
+ *
+ * @param ph
+ * @param groupsFile
+ *
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ protected static void loadGroups(WorldDataHolder ph, File groupsFile) throws FileNotFoundException, IOException {
+
+ // READ GROUPS FILE
+
+ Yaml yamlGroups = new Yaml(new SafeConstructor());
+ Map<String, Object> groupsRootDataNode;
+
+ if (!groupsFile.exists()) {
+ throw new IllegalArgumentException("The file which should contain groups does not exist!\n" + groupsFile.getPath());
+ }
+ FileInputStream groupsInputStream = new FileInputStream(groupsFile);
+ try {
+ groupsRootDataNode = (Map<String, Object>) yamlGroups.load(new UnicodeReader(groupsInputStream));
+ if (groupsRootDataNode == null) {
+ throw new NullPointerException();
+ }
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("The following file couldn't pass on Parser.\n" + groupsFile.getPath(), ex);
+ } finally {
+ groupsInputStream.close();
+ }
+
+ // PROCESS GROUPS FILE
+
+ Map<String, List<String>> inheritance = new HashMap<String, List<String>>();
+ Map<String, Object> allGroupsNode = null;
+
+ /*
+ * Fetch all groups under the 'groups' entry.
+ */
+ try {
+ allGroupsNode = (Map<String, Object>) groupsRootDataNode.get("groups");
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Your " + groupsFile.getPath() + " file is invalid. See console for details.", ex);
+ }
+
+ Iterator<String> groupItr = allGroupsNode.keySet().iterator();
+ String groupKey;
+ Integer groupCount = 0;
+
+ /*
+ * loop each group entry
+ * and process it's data.
+ */
+ while (groupItr.hasNext()) {
+
+ try {
+ groupCount++;
+ // Attempt to fetch the next group name.
+ groupKey = groupItr.next();
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Invalid group name for group entry (" + groupCount + ") in file: " + groupsFile.getPath(), ex);
+ }
+
+ /*
+ * Fetch this groups child nodes
+ */
+ Map<String, Object> thisGroupNode = null;
+
+ try {
+ thisGroupNode = (Map<String, Object>) allGroupsNode.get(groupKey);
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Invalid child nodes for group '" + groupKey + "' in file: " + groupsFile.getPath(), ex);
+ }
+
+ /*
+ * Create a new group with this name
+ * in the assigned data source.
+ */
+ Group thisGrp = ph.createGroup(groupKey);
+
+ if (thisGrp == null) {
+ throw new IllegalArgumentException("I think this Group was declared more than once: " + groupKey + " in file: " + groupsFile.getPath());
+ }
+
+ // DEFAULT NODE
+
+ Object nodeData = null;
+ try {
+ nodeData = thisGroupNode.get("default");
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Bad format found in 'permissions' for group: " + groupKey + " in file: " + groupsFile.getPath());
+ }
+
+ if (nodeData == null) {
+ /*
+ * If no 'default' node is found do nothing.
+ */
+ } else if ((Boolean.parseBoolean(nodeData.toString()))) {
+ /*
+ * Set this as the default group.
+ * Warn if some other group has already claimed that position.
+ */
+ if (ph.getDefaultGroup() != null) {
+ GroupManager.logger.warning("The group '" + thisGrp.getName() + "' is claiming to be default where '" + ph.getDefaultGroup().getName() + "' already was.");
+ GroupManager.logger.warning("Overriding first default request in file: " + groupsFile.getPath());
+ }
+ ph.setDefaultGroup(thisGrp);
+ }
+
+ // PERMISSIONS NODE
+
+ nodeData = null;
+ try {
+ nodeData = thisGroupNode.get("permissions");
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Bad format found in 'permissions' for '" + groupKey + "' in file: " + groupsFile.getPath());
+ }
+
+ if (nodeData == null) {
+ /*
+ * If no permissions node is found, or it's empty
+ * do nothing.
+ */
+ } else {
+ /*
+ * There is a permission list Which seems to hold some data
+ */
+ if (nodeData instanceof List) {
+ /*
+ * Check each entry and add it as a new permission.
+ */
+ try {
+ for (Object o : ((List) nodeData)) {
+ try {
+ /*
+ * Only add this permission if it's not empty.
+ */
+ if (!o.toString().isEmpty())
+ thisGrp.addPermission(o.toString());
+
+ } catch (NullPointerException ex) {
+ // Ignore this entry as it's null. It can be
+ // safely dropped
+ }
+ }
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Invalid formatting found in 'permissions' section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath(), ex);
+ }
+
+ } else if (nodeData instanceof String) {
+ /*
+ * Only add this permission if it's not empty.
+ */
+ if (!nodeData.toString().isEmpty())
+ thisGrp.addPermission((String) nodeData);
+
+ } else {
+ throw new IllegalArgumentException("Unknown type of 'permissions' node(Should be String or List<String>) for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath());
+ }
+ /*
+ * Sort all permissions so they are in the correct order for
+ * checking.
+ */
+ thisGrp.sortPermissions();
+ }
+
+ // INFO NODE
+
+ nodeData = null;
+ try {
+ nodeData = thisGroupNode.get("info");
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Bad format found in 'info' section for group: " + groupKey + " in file: " + groupsFile.getPath());
+ }
+
+ if (nodeData == null) {
+ /*
+ * No info section was found, so leave all variables as
+ * defaults.
+ */
+ GroupManager.logger.warning("The group '" + thisGrp.getName() + "' has no 'info' section!");
+ GroupManager.logger.warning("Using default values: " + groupsFile.getPath());
+
+ } else if (nodeData instanceof Map) {
+ try {
+ if (nodeData != null) {
+ thisGrp.setVariables((Map<String, Object>) nodeData);
+ }
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Invalid formatting found in 'info' section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath(), ex);
+ }
+
+ } else
+ throw new IllegalArgumentException("Unknown entry found in 'info' section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath());
+
+ // INHERITANCE NODE
+
+ nodeData = null;
+ try {
+ nodeData = thisGroupNode.get("inheritance");
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Bad format found in 'inheritance' section for group: " + groupKey + " in file: " + groupsFile.getPath());
+ }
+
+ if (nodeData == null || nodeData instanceof List) {
+ if (nodeData == null) {
+ /*
+ * If no inheritance node is found, or it's empty
+ * do nothing.
+ */
+ } else if (nodeData instanceof List) {
+
+ try {
+ for (String grp : (List<String>) nodeData) {
+ if (inheritance.get(groupKey) == null) {
+ inheritance.put(groupKey, new ArrayList<String>());
+ }
+ inheritance.get(groupKey).add(grp);
+ }
+
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Invalid formatting found in 'inheritance' section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath(), ex);
+ }
+
+ }
+ } else
+ throw new IllegalArgumentException("Unknown entry found in 'inheritance' section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath());
+
+ // END GROUP
+
+ }
+
+ if (ph.getDefaultGroup() == null) {
+ throw new IllegalArgumentException("There was no Default Group declared in file: " + groupsFile.getPath());
+ }
+
+ /*
+ * Build the inheritance map and recored any errors
+ */
+ for (String group : inheritance.keySet()) {
+ List<String> inheritedList = inheritance.get(group);
+ Group thisGroup = ph.getGroup(group);
+ if (thisGroup != null)
+ for (String inheritedKey : inheritedList) {
+ if (inheritedKey != null) {
+ Group inheritedGroup = ph.getGroup(inheritedKey);
+ if (inheritedGroup != null) {
+ thisGroup.addInherits(inheritedGroup);
+ } else
+ GroupManager.logger.warning("Inherited group '" + inheritedKey + "' not found for group " + thisGroup.getName() + ". Ignoring entry in file: " + groupsFile.getPath());
+ }
+ }
+ }
+
+ ph.removeGroupsChangedFlag();
+ // Update the LastModified time.
+ ph.setGroupsFile(groupsFile);
+ ph.setTimeStampGroups(groupsFile.lastModified());
+
+ // return ph;
+ }
+
+ /**
+ * Updates the WorldDataHolder from the Users file
+ *
+ * @param ph
+ * @param usersFile
+ *
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ protected static void loadUsers(WorldDataHolder ph, File usersFile) throws FileNotFoundException, IOException {
+
+ // READ USERS FILE
+ Yaml yamlUsers = new Yaml(new SafeConstructor());
+ Map<String, Object> usersRootDataNode;
+ if (!usersFile.exists()) {
+ throw new IllegalArgumentException("The file which should contain users does not exist!\n" + usersFile.getPath());
+ }
+ FileInputStream usersInputStream = new FileInputStream(usersFile);
+ try {
+ usersRootDataNode = (Map<String, Object>) yamlUsers.load(new UnicodeReader(usersInputStream));
+ if (usersRootDataNode == null) {
+ throw new NullPointerException();
+ }
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("The following file couldn't pass on Parser.\n" + usersFile.getPath(), ex);
+ } finally {
+ usersInputStream.close();
+ }
+
+ // PROCESS USERS FILE
+
+ Map<String, Object> allUsersNode = null;
+
+ /*
+ * Fetch all child nodes under the 'users' entry.
+ */
+ try {
+ allUsersNode = (Map<String, Object>) usersRootDataNode.get("users");
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Your " + usersFile.getPath() + " file is invalid. See console for details.", ex);
+ }
+
+ // Load users if the file is NOT empty
+
+ if (allUsersNode != null) {
+
+ Iterator<String> usersItr = allUsersNode.keySet().iterator();
+ String usersKey;
+ Integer userCount = 0;
+
+ while (usersItr.hasNext()) {
+ try {
+ userCount++;
+ // Attempt to fetch the next user name.
+ usersKey = usersItr.next();
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Invalid node type for user entry (" + userCount + ") in file: " + usersFile.getPath(), ex);
+ }
+
+ Map<String, Object> thisUserNode = null;
+ try {
+ thisUserNode = (Map<String, Object>) allUsersNode.get(usersKey);
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Bad format found for user: " + usersKey + " in file: " + usersFile.getPath());
+ }
+
+ User thisUser = ph.createUser(usersKey);
+ if (thisUser == null) {
+ throw new IllegalArgumentException("I think this user was declared more than once: " + usersKey + " in file: " + usersFile.getPath());
+ }
+
+ // USER PERMISSIONS NODES
+
+ Object nodeData = null;
+ try {
+ nodeData = thisUserNode.get("permissions");
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Bad format found in 'permissions' for user: " + usersKey + " in file: " + usersFile.getPath());
+ }
+
+ if (nodeData == null) {
+ /*
+ * If no permissions node is found, or it's empty
+ * do nothing.
+ */
+ } else {
+ if (nodeData instanceof List) {
+ for (Object o : ((List) nodeData)) {
+ /*
+ * Only add this permission if it's not empty
+ */
+ if (!o.toString().isEmpty())
+ thisUser.addPermission(o.toString());
+ }
+ } else if (nodeData instanceof String) {
+ try {
+ /*
+ * Only add this permission if it's not empty
+ */
+ if (!nodeData.toString().isEmpty())
+ thisUser.addPermission(nodeData.toString());
+ } catch (NullPointerException e) {
+ // Ignore this entry as it's null.
+ }
+ }
+ thisUser.sortPermissions();
+ }
+
+ // SUBGROUPS NODES
+
+ nodeData = null;
+ try {
+ nodeData = thisUserNode.get("subgroups");
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Bad format found in 'subgroups' for user: " + usersKey + " in file: " + usersFile.getPath());
+ }
+
+ if (nodeData == null) {
+ /*
+ * If no subgroups node is found, or it's empty
+ * do nothing.
+ */
+ } else if (nodeData instanceof List) {
+ for (Object o : ((List) nodeData)) {
+ Group subGrp = ph.getGroup(o.toString());
+ if (subGrp != null) {
+ thisUser.addSubGroup(subGrp);
+ } else {
+ GroupManager.logger.warning("Subgroup '" + o.toString() + "' not found for user: " + thisUser.getName() + ". Ignoring entry in file: " + usersFile.getPath());
+ }
+ }
+ } else if (nodeData instanceof String) {
+ Group subGrp = ph.getGroup(nodeData.toString());
+ if (subGrp != null) {
+ thisUser.addSubGroup(subGrp);
+ } else {
+ GroupManager.logger.warning("Subgroup '" + nodeData.toString() + "' not found for user: " + thisUser.getName() + ". Ignoring entry in file: " + usersFile.getPath());
+ }
+ }
+
+ // USER INFO NODE
+
+ nodeData = null;
+ try {
+ nodeData = thisUserNode.get("info");
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Bad format found in 'info' section for user: " + usersKey + " in file: " + usersFile.getPath());
+ }
+
+ if (nodeData == null) {
+ /*
+ * If no info node is found, or it's empty
+ * do nothing.
+ */
+ } else if (nodeData instanceof Map) {
+ thisUser.setVariables((Map<String, Object>) nodeData);
+
+ } else
+ throw new IllegalArgumentException("Unknown entry found in 'info' section for user: " + thisUser.getName() + " in file: " + usersFile.getPath());
+
+ // END INFO NODE
+
+ // PRIMARY GROUP
+
+ nodeData = null;
+ try {
+ nodeData = thisUserNode.get("group");
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Bad format found in 'group' section for user: " + usersKey + " in file: " + usersFile.getPath());
+ }
+
+ if (nodeData != null) {
+ Group hisGroup = ph.getGroup(nodeData.toString());
+ if (hisGroup == null) {
+ GroupManager.logger.warning("There is no group " + thisUserNode.get("group").toString() + ", as stated for player " + thisUser.getName() + ": Set to '" + ph.getDefaultGroup().getName() + "' for file: " + usersFile.getPath());
+ hisGroup = ph.getDefaultGroup();
+ }
+ thisUser.setGroup(hisGroup);
+ } else {
+ thisUser.setGroup(ph.getDefaultGroup());
+ }
+ }
+ }
+
+ ph.removeUsersChangedFlag();
+ // Update the LastModified time.
+ ph.setUsersFile(usersFile);
+ ph.setTimeStampUsers(usersFile.lastModified());
+ }
+
+ /**
+ * Write a dataHolder in a specified file
+ *
+ * @param ph
+ * @param groupsFile
+ */
+ public static void writeGroups(WorldDataHolder ph, File groupsFile) {
+
+ Map<String, Object> root = new HashMap<String, Object>();
+
+ Map<String, Object> groupsMap = new HashMap<String, Object>();
+
+ root.put("groups", groupsMap);
+ for (String groupKey : ph.getGroups().keySet()) {
+ Group group = ph.getGroups().get(groupKey);
+
+ Map<String, Object> aGroupMap = new HashMap<String, Object>();
+ groupsMap.put(group.getName(), aGroupMap);
+
+ if (ph.getDefaultGroup() == null) {
+ GroupManager.logger.severe("There is no default group for world: " + ph.getName());
+ }
+ aGroupMap.put("default", group.equals(ph.getDefaultGroup()));
+
+ Map<String, Object> infoMap = new HashMap<String, Object>();
+ aGroupMap.put("info", infoMap);
+
+ for (String infoKey : group.getVariables().getVarKeyList()) {
+ infoMap.put(infoKey, group.getVariables().getVarObject(infoKey));
+ }
+
+ aGroupMap.put("inheritance", group.getInherits());
+
+ aGroupMap.put("permissions", group.getPermissionList());
+ }
+
+ if (!root.isEmpty()) {
+ DumperOptions opt = new DumperOptions();
+ opt.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
+ final Yaml yaml = new Yaml(opt);
+ try {
+ OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(groupsFile), "UTF-8");
+
+ String newLine = System.getProperty("line.separator");
+
+ out.write("# Group inheritance" + newLine);
+ out.write("#" + newLine);
+ out.write("# Any inherited groups prefixed with a g: are global groups" + newLine);
+ out.write("# and are inherited from the GlobalGroups.yml." + newLine);
+ out.write("#" + newLine);
+ out.write("# Groups without the g: prefix are groups local to this world" + newLine);
+ out.write("# and are defined in the this groups.yml file." + newLine);
+ out.write("#" + newLine);
+ out.write("# Local group inheritances define your promotion tree when using 'manpromote/mandemote'" + newLine);
+ out.write(newLine);
+
+ yaml.dump(root, out);
+ out.close();
+ } catch (UnsupportedEncodingException ex) {
+ } catch (FileNotFoundException ex) {
+ } catch (IOException e) {
+ }
+ }
+
+ // Update the LastModified time.
+ ph.setGroupsFile(groupsFile);
+ ph.setTimeStampGroups(groupsFile.lastModified());
+ ph.removeGroupsChangedFlag();
+
+ if (GroupManager.isLoaded())
+ GroupManagerEventHandler.callEvent(GMSystemEvent.Action.SAVED);
+
+ /*
+ * FileWriter tx = null;
+ * try {
+ * tx = new FileWriter(groupsFile, false);
+ * tx.write(yaml.dump(root));
+ * tx.flush();
+ * } catch (Exception e) {
+ * } finally {
+ * try {
+ * tx.close();
+ * } catch (IOException ex) {
+ * }
+ * }
+ */
+ }
+
+ /**
+ * Write a dataHolder in a specified file
+ *
+ * @param ph
+ * @param usersFile
+ */
+ public static void writeUsers(WorldDataHolder ph, File usersFile) {
+
+ Map<String, Object> root = new HashMap<String, Object>();
+
+ Map<String, Object> usersMap = new HashMap<String, Object>();
+ root.put("users", usersMap);
+ for (String userKey : ph.getUsers().keySet()) {
+ User user = ph.getUsers().get(userKey);
+ if ((user.getGroup() == null || user.getGroup().equals(ph.getDefaultGroup())) && user.getPermissionList().isEmpty() && user.getVariables().isEmpty() && user.isSubGroupsEmpty()) {
+ continue;
+ }
+
+ Map<String, Object> aUserMap = new HashMap<String, Object>();
+ usersMap.put(user.getName(), aUserMap);
+
+ if (user.getGroup() == null) {
+ aUserMap.put("group", ph.getDefaultGroup().getName());
+ } else {
+ aUserMap.put("group", user.getGroup().getName());
+ }
+ // USER INFO NODE - BETA
+ if (user.getVariables().getSize() > 0) {
+ Map<String, Object> infoMap = new HashMap<String, Object>();
+ aUserMap.put("info", infoMap);
+ for (String infoKey : user.getVariables().getVarKeyList()) {
+ infoMap.put(infoKey, user.getVariables().getVarObject(infoKey));
+ }
+ }
+ // END USER INFO NODE - BETA
+ aUserMap.put("permissions", user.getPermissionList());
+
+ // SUBGROUPS NODE - BETA
+ aUserMap.put("subgroups", user.subGroupListStringCopy());
+ // END SUBGROUPS NODE - BETA
+ }
+
+ if (!root.isEmpty()) {
+ DumperOptions opt = new DumperOptions();
+ opt.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
+ final Yaml yaml = new Yaml(opt);
+ try {
+ OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(usersFile), "UTF-8");
+ yaml.dump(root, out);
+ out.close();
+ } catch (UnsupportedEncodingException ex) {
+ } catch (FileNotFoundException ex) {
+ } catch (IOException e) {
+ }
+ }
+
+ // Update the LastModified time.
+ ph.setUsersFile(usersFile);
+ ph.setTimeStampUsers(usersFile.lastModified());
+ ph.removeUsersChangedFlag();
+
+ if (GroupManager.isLoaded())
+ GroupManagerEventHandler.callEvent(GMSystemEvent.Action.SAVED);
+
+ /*
+ * FileWriter tx = null;
+ * try {
+ * tx = new FileWriter(usersFile, false);
+ * tx.write(yaml.dump(root));
+ * tx.flush();
+ * } catch (Exception e) {
+ * } finally {
+ * try {
+ * tx.close();
+ * } catch (IOException ex) {
+ * }
+ * }
+ */
+ }
+
+ /**
+ * Don't use this. Unless you want to make this plugin to interact with
+ * original Nijikokun Permissions
+ * This method is supposed to make the original one reload the file, and
+ * propagate the changes made here.
+ *
+ * Prefer to use the AnjoCaido's fake version of Nijikokun's Permission
+ * plugin.
+ * The AnjoCaido's Permission can propagate the changes made on this plugin
+ * instantly,
+ * without need to save the file.
+ *
+ * @param server the server that holds the plugin
+ * @deprecated it is not used anymore... unless if you use original
+ * Permissions
+ */
+ @Deprecated
+ public static void reloadOldPlugins(Server server) {
+
+ // Only reload permissions
+ PluginManager pm = server.getPluginManager();
+ Plugin[] plugins = pm.getPlugins();
+ for (int i = 0; i < plugins.length; i++) {
+ // plugins[i].getConfiguration().load();
+ try {
+ plugins[i].getClass().getMethod("setupPermissions").invoke(plugins[i]);
+ } catch (Exception ex) {
+ continue;
+ }
+ }
+ }
+
+ /**
+ * @return the permissionsHandler
+ */
+ public AnjoPermissionsHandler getPermissionsHandler() {
+
+ if (permissionsHandler == null) {
+ permissionsHandler = new AnjoPermissionsHandler(this);
+ }
+ return permissionsHandler;
+ }
+
+ /**
+ * @param haveUsersChanged the haveUsersChanged to set
+ */
+ public void setUsersChanged(boolean haveUsersChanged) {
+
+ users.setUsersChanged(haveUsersChanged);
+ }
+
+ /**
+ *
+ * @return true if any user data has changed
+ */
+ public boolean haveUsersChanged() {
+
+ if (users.HaveUsersChanged()) {
+ return true;
+ }
+ for (User u : users.getUsers().values()) {
+ if (u.isChanged()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @param setGroupsChanged the haveGroupsChanged to set
+ */
+ public void setGroupsChanged(boolean setGroupsChanged) {
+
+ groups.setGroupsChanged(setGroupsChanged);
+ }
+
+ /**
+ *
+ * @return true if any group data has changed.
+ */
+ public boolean haveGroupsChanged() {
+
+ if (groups.HaveGroupsChanged()) {
+ return true;
+ }
+ for (Group g : groups.getGroups().values()) {
+ if (g.isChanged()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ *
+ */
+ public void removeUsersChangedFlag() {
+
+ setUsersChanged(false);
+ for (User u : getUsers().values()) {
+ u.flagAsSaved();
+ }
+ }
+
+ /**
+ *
+ */
+ public void removeGroupsChangedFlag() {
+
+ setGroupsChanged(false);
+ for (Group g : getGroups().values()) {
+ g.flagAsSaved();
+ }
+ }
+
+ /**
+ * @return the usersFile
+ */
+ public File getUsersFile() {
+
+ return users.getUsersFile();
+ }
+
+ /**
+ * @param file the usersFile to set
+ */
+ public void setUsersFile(File file) {
+
+ users.setUsersFile(file);
+ }
+
+ /**
+ * @return the groupsFile
+ */
+ public File getGroupsFile() {
+
+ return groups.getGroupsFile();
+ }
+
+ /**
+ * @param file the groupsFile to set
+ */
+ public void setGroupsFile(File file) {
+
+ groups.setGroupsFile(file);
+ }
+
+ /**
+ * @return the name
+ */
+ public String getName() {
+
+ return name;
+ }
+
+ /**
+ * Resets Groups.
+ */
+ public void resetGroups() {
+
+ // setDefaultGroup(null);
+ groups.setGroups(new HashMap<String, Group>());
+ }
+
+ /**
+ * Resets Users
+ */
+ public void resetUsers() {
+
+ users.setUsers(new HashMap<String, User>());
+ }
+
+ /**
+ * @return the groups
+ */
+ public Map<String, Group> getGroups() {
+
+ return groups.getGroups();
+ }
+
+ /**
+ * @return the users
+ */
+ public Map<String, User> getUsers() {
+
+ return users.getUsers();
+ }
+
+ /**
+ * @return the groups
+ */
+ public GroupsDataHolder getGroupsObject() {
+
+ return groups;
+ }
+
+ /**
+ * @param groupsDataHolder the GroupsDataHolder to set
+ */
+ public void setGroupsObject(GroupsDataHolder groupsDataHolder) {
+
+ groups = groupsDataHolder;
+ }
+
+ /**
+ * @return the users
+ */
+ public UsersDataHolder getUsersObject() {
+
+ return users;
+ }
+
+ /**
+ * @param usersDataHolder the UsersDataHolder to set
+ */
+ public void setUsersObject(UsersDataHolder usersDataHolder) {
+
+ users = usersDataHolder;
+ }
+
+ /**
+ * @return the timeStampGroups
+ */
+ public long getTimeStampGroups() {
+
+ return groups.getTimeStampGroups();
+ }
+
+ /**
+ * @return the timeStampUsers
+ */
+ public long getTimeStampUsers() {
+
+ return users.getTimeStampUsers();
+ }
+
+ /**
+ * @param timeStampGroups the timeStampGroups to set
+ */
+ protected void setTimeStampGroups(long timeStampGroups) {
+
+ groups.setTimeStampGroups(timeStampGroups);
+ }
+
+ /**
+ * @param timeStampUsers the timeStampUsers to set
+ */
+ protected void setTimeStampUsers(long timeStampUsers) {
+
+ users.setTimeStampUsers(timeStampUsers);
+ }
+
+ public void setTimeStamps() {
+
+ if (getGroupsFile() != null)
+ setTimeStampGroups(getGroupsFile().lastModified());
+ if (getUsersFile() != null)
+ setTimeStampUsers(getUsersFile().lastModified());
+ }
+
+}
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/worlds/WorldsHolder.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/worlds/WorldsHolder.java
new file mode 100644
index 000000000..27a7d9a59
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/worlds/WorldsHolder.java
@@ -0,0 +1,719 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anjocaido.groupmanager.dataholder.worlds;
+
+import java.io.File;
+import java.io.FileInputStream;
+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;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.anjocaido.groupmanager.GroupManager;
+import org.anjocaido.groupmanager.dataholder.WorldDataHolder;
+import org.anjocaido.groupmanager.dataholder.OverloadedWorldHolder;
+import org.anjocaido.groupmanager.permissions.AnjoPermissionsHandler;
+import org.anjocaido.groupmanager.utils.Tasks;
+import org.bukkit.World;
+import org.bukkit.configuration.MemorySection;
+import org.bukkit.entity.Player;
+
+/**
+ *
+ * @author gabrielcouto
+ */
+public class WorldsHolder {
+
+ /**
+ * Map with instances of loaded worlds.
+ */
+ private Map<String, OverloadedWorldHolder> worldsData = new HashMap<String, OverloadedWorldHolder>();
+
+ /**
+ * Map of mirrors: <nonExistingWorldName, existingAndLoadedWorldName>
+ * The key is the mirror.
+ * The object is the mirrored.
+ *
+ * Mirror shows the same data of mirrored.
+ */
+ private Map<String, String> mirrorsGroup = new HashMap<String, String>();
+ private Map<String, String> mirrorsUser = new HashMap<String, String>();
+
+ private String serverDefaultWorldName;
+ private GroupManager plugin;
+ private File worldsFolder;
+
+ /**
+ *
+ * @param plugin
+ */
+ public WorldsHolder(GroupManager plugin) {
+
+ this.plugin = plugin;
+ resetWorldsHolder();
+ }
+
+ public void resetWorldsHolder() {
+
+ worldsData = new HashMap<String, OverloadedWorldHolder>();
+ mirrorsGroup = new HashMap<String, String>();
+ mirrorsUser = new HashMap<String, String>();
+
+ // Setup folders and check files exist for the primary world
+ verifyFirstRun();
+ initialLoad();
+ if (serverDefaultWorldName == null)
+ throw new IllegalStateException("There is no default group! OMG!");
+ }
+
+ private void initialLoad() {
+
+ // load the initial world
+ initialWorldLoading();
+ // Configure and load any mirrors and additional worlds as defined in config.yml
+ mirrorSetUp();
+ // search the worlds folder for any manually created worlds (not listed in config.yml)
+ loadAllSearchedWorlds();
+ }
+
+ private void initialWorldLoading() {
+
+ //Load the default world
+ loadWorld(serverDefaultWorldName);
+ //defaultWorld = getUpdatedWorldData(serverDefaultWorldName);
+ }
+
+ private void loadAllSearchedWorlds() {
+
+ /*
+ * Read all known worlds from Bukkit
+ * Create the data files if they don't already exist,
+ * and they are not mirrored.
+ */
+ for (World world : plugin.getServer().getWorlds())
+ if ((!worldsData.containsKey(world.getName().toLowerCase())) && ((!mirrorsGroup.containsKey(world.getName().toLowerCase())) || (!mirrorsUser.containsKey(world.getName().toLowerCase()))))
+ setupWorldFolder(world.getName());
+ /*
+ * Loop over all folders within the worlds folder
+ * and attempt to load the world data
+ */
+ for (File folder : worldsFolder.listFiles()) {
+ if (folder.isDirectory()) {
+ GroupManager.logger.info("World Found: " + folder.getName());
+
+ /*
+ * don't load any worlds which are already loaded
+ * or fully mirrored worlds that don't need data.
+ */
+ if (!worldsData.containsKey(folder.getName().toLowerCase()) && ((!mirrorsGroup.containsKey(folder.getName().toLowerCase())) || (!mirrorsUser.containsKey(folder.getName().toLowerCase())))) {
+ /*
+ * Call setupWorldFolder to check case sensitivity
+ * and convert to lower case, before we attempt to load this
+ * world.
+ */
+ setupWorldFolder(folder.getName());
+ loadWorld(folder.getName().toLowerCase());
+ }
+
+ }
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ public void mirrorSetUp() {
+
+ mirrorsGroup.clear();
+ mirrorsUser.clear();
+ Map<String, Object> mirrorsMap = plugin.getGMConfig().getMirrorsMap();
+
+ HashSet<String> mirroredWorlds = new HashSet<String>();
+
+ if (mirrorsMap != null) {
+ for (String source : mirrorsMap.keySet()) {
+ // Make sure all non mirrored worlds have a set of data files.
+ setupWorldFolder(source);
+ // Load the world data
+ if (!worldsData.containsKey(source.toLowerCase()))
+ loadWorld(source);
+
+ if (mirrorsMap.get(source) instanceof ArrayList) {
+ ArrayList mirrorList = (ArrayList) mirrorsMap.get(source);
+
+ // These worlds fully mirror their parent
+ for (Object o : mirrorList) {
+ String world = o.toString().toLowerCase();
+ if (world != serverDefaultWorldName) {
+ try {
+ mirrorsGroup.remove(world);
+ mirrorsUser.remove(world);
+ } catch (Exception e) {
+ }
+ 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!");
+ }
+ } else if (mirrorsMap.get(source) instanceof MemorySection) {
+ MemorySection subSection = (MemorySection) mirrorsMap.get(source);
+
+ for (String key : subSection.getKeys(true)) {
+
+ if (key.toLowerCase() != serverDefaultWorldName) {
+
+ if (subSection.get(key) instanceof ArrayList) {
+ ArrayList mirrorList = (ArrayList) subSection.get(key);
+
+ // These worlds have defined mirroring
+ for (Object o : mirrorList) {
+ String type = o.toString().toLowerCase();
+ try {
+ if (type.equals("groups"))
+ mirrorsGroup.remove(key.toLowerCase());
+
+ if (type.equals("users"))
+ mirrorsUser.remove(key.toLowerCase());
+
+ } catch (Exception e) {
+ }
+ if (type.equals("groups"))
+ mirrorsGroup.put(key.toLowerCase(), getWorldData(source).getName());
+
+ 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);
+ }
+
+ }
+ }
+ }
+
+ // Create a datasource for any worlds not already loaded
+ for (String world : mirroredWorlds) {
+ if (!worldsData.containsKey(world.toLowerCase())) {
+ setupWorldFolder(world);
+ loadWorld(world, true);
+ }
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ public void reloadAll() {
+
+ // Load global groups
+ GroupManager.getGlobalGroups().load();
+
+ ArrayList<WorldDataHolder> alreadyDone = new ArrayList<WorldDataHolder>();
+ for (WorldDataHolder w : worldsData.values()) {
+ if (alreadyDone.contains(w)) {
+ continue;
+ }
+ if (!mirrorsGroup.containsKey(w.getName().toLowerCase()))
+ w.reloadGroups();
+ if (!mirrorsUser.containsKey(w.getName().toLowerCase()))
+ w.reloadUsers();
+
+ alreadyDone.add(w);
+ }
+
+ }
+
+ /**
+ *
+ * @param worldName
+ */
+ public void reloadWorld(String worldName) {
+
+ if (!mirrorsGroup.containsKey(worldName.toLowerCase()))
+ getWorldData(worldName).reloadGroups();
+ if (!mirrorsUser.containsKey(worldName.toLowerCase()))
+ getWorldData(worldName).reloadUsers();
+ }
+
+ /**
+ * Wrapper to retain backwards compatibility
+ * (call this function to auto overwrite files)
+ */
+ public void saveChanges() {
+
+ saveChanges(true);
+ }
+
+ /**
+ *
+ */
+ public void saveChanges(boolean overwrite) {
+
+ ArrayList<WorldDataHolder> alreadyDone = new ArrayList<WorldDataHolder>();
+ Tasks.removeOldFiles(plugin, plugin.getBackupFolder());
+
+ // Write Global Groups
+ if (GroupManager.getGlobalGroups().haveGroupsChanged()) {
+ GroupManager.getGlobalGroups().writeGroups(overwrite);
+ } else {
+ if (GroupManager.getGlobalGroups().getTimeStampGroups() < GroupManager.getGlobalGroups().getGlobalGroupsFile().lastModified()) {
+ System.out.print("Newer GlobalGroups file found (Loading changes)!");
+ GroupManager.getGlobalGroups().load();
+ }
+ }
+
+ for (OverloadedWorldHolder w : worldsData.values()) {
+ if (alreadyDone.contains(w)) {
+ continue;
+ }
+ if (w == null) {
+ GroupManager.logger.severe("WHAT HAPPENED?");
+ continue;
+ }
+ if (!mirrorsGroup.containsKey(w.getName().toLowerCase()))
+ if (w.haveGroupsChanged()) {
+ if (overwrite || (!overwrite && (w.getTimeStampGroups() >= w.getGroupsFile().lastModified()))) {
+ // Backup Groups file
+ backupFile(w, true);
+
+ WorldDataHolder.writeGroups(w, w.getGroupsFile());
+ //w.removeGroupsChangedFlag();
+ } else {
+ // Newer file found.
+ GroupManager.logger.log(Level.WARNING, "Newer Groups file found for " + w.getName() + ", but we have local changes!");
+ throw new IllegalStateException("Unable to save unless you issue a '/mansave force'");
+ }
+ } else {
+ //Check for newer file as no local changes.
+ if (w.getTimeStampGroups() < w.getGroupsFile().lastModified()) {
+ System.out.print("Newer Groups file found (Loading changes)!");
+ // Backup Groups file
+ backupFile(w, true);
+ w.reloadGroups();
+ }
+ }
+ if (!mirrorsUser.containsKey(w.getName().toLowerCase()))
+ if (w.haveUsersChanged()) {
+ if (overwrite || (!overwrite && (w.getTimeStampUsers() >= w.getUsersFile().lastModified()))) {
+ // Backup Users file
+ backupFile(w, false);
+
+ WorldDataHolder.writeUsers(w, w.getUsersFile());
+ //w.removeUsersChangedFlag();
+ } else {
+ // Newer file found.
+ GroupManager.logger.log(Level.WARNING, "Newer Users file found for " + w.getName() + ", but we have local changes!");
+ throw new IllegalStateException("Unable to save unless you issue a '/mansave force'");
+ }
+ } else {
+ //Check for newer file as no local changes.
+ if (w.getTimeStampUsers() < w.getUsersFile().lastModified()) {
+ System.out.print("Newer Users file found (Loading changes)!");
+ // Backup Users file
+ backupFile(w, false);
+ w.reloadUsers();
+ }
+ }
+ alreadyDone.add(w);
+ }
+ }
+
+ /**
+ * Backup the Groups/Users file
+ *
+ * @param w
+ * @param groups
+ */
+ private void backupFile(OverloadedWorldHolder w, Boolean groups) {
+
+ File backupFile = new File(plugin.getBackupFolder(), "bkp_" + w.getName() + (groups ? "_g_" : "_u_") + Tasks.getDateString() + ".yml");
+ try {
+ Tasks.copy((groups ? w.getGroupsFile() : w.getUsersFile()), backupFile);
+ } catch (IOException ex) {
+ GroupManager.logger.log(Level.SEVERE, null, ex);
+ }
+ }
+
+ /**
+ * Returns the dataHolder for the given world.
+ * If the world is not on the worlds list, returns the default world
+ * holder.
+ *
+ * Mirrors return their parent world data.
+ * If no mirroring data it returns the default world.
+ *
+ * @param worldName
+ * @return OverloadedWorldHolder
+ */
+ public OverloadedWorldHolder getWorldData(String worldName) {
+
+ String worldNameLowered = worldName.toLowerCase();
+
+ // Find this worlds data
+ if (worldsData.containsKey(worldNameLowered))
+ 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) {
+
+ String worldNameLowered = worldName.toLowerCase();
+
+ if (worldsData.containsKey(worldNameLowered)) {
+ OverloadedWorldHolder data = worldsData.get(worldNameLowered);
+ data.updateDataSource();
+ return data;
+ }
+ return null;
+
+ }
+
+ /**
+ * Do a matching of playerName, if its found only one player, do
+ * getWorldData(player)
+ *
+ * @param playerName
+ * @return null if matching returned no player, or more than one.
+ */
+ public OverloadedWorldHolder getWorldDataByPlayerName(String playerName) {
+
+ List<Player> matchPlayer = plugin.getServer().matchPlayer(playerName);
+ if (matchPlayer.size() == 1) {
+ return getWorldData(matchPlayer.get(0));
+ }
+ return null;
+ }
+
+ /**
+ * Retrieves the field player.getWorld().getName() and do
+ * getWorld(worldName)
+ *
+ * @param player
+ * @return OverloadedWorldHolder
+ */
+ public OverloadedWorldHolder getWorldData(Player player) {
+
+ return getWorldData(player.getWorld().getName());
+ }
+
+ /**
+ * It does getWorld(worldName).getPermissionsHandler()
+ *
+ * @param worldName
+ * @return AnjoPermissionsHandler
+ */
+ public AnjoPermissionsHandler getWorldPermissions(String worldName) {
+
+ return getWorldData(worldName).getPermissionsHandler();
+ }
+
+ /**
+ * Returns the PermissionsHandler for this player data
+ *
+ * @param player
+ * @return AnjoPermissionsHandler
+ */
+ public AnjoPermissionsHandler getWorldPermissions(Player player) {
+
+ return getWorldData(player).getPermissionsHandler();
+ }
+
+ /**
+ * Id does getWorldDataByPlayerName(playerName).
+ * If it doesnt return null, it will return result.getPermissionsHandler()
+ *
+ * @param playerName
+ * @return null if the player matching gone wrong.
+ */
+ public AnjoPermissionsHandler getWorldPermissionsByPlayerName(String playerName) {
+
+ WorldDataHolder dh = getWorldDataByPlayerName(playerName);
+ if (dh != null) {
+ return dh.getPermissionsHandler();
+ }
+ return null;
+ }
+
+ private void verifyFirstRun() {
+
+ Properties server = new Properties();
+ try {
+ server.load(new FileInputStream(new File("server.properties")));
+ serverDefaultWorldName = server.getProperty("level-name").toLowerCase();
+ setupWorldFolder(serverDefaultWorldName);
+ } catch (IOException ex) {
+ GroupManager.logger.log(Level.SEVERE, null, ex);
+ }
+
+ }
+
+ public void setupWorldFolder(String worldName) {
+
+ String worldNameLowered = worldName.toLowerCase();
+
+ worldsFolder = new File(plugin.getDataFolder(), "worlds");
+ if (!worldsFolder.exists()) {
+ worldsFolder.mkdirs();
+ }
+
+ File defaultWorldFolder = new File(worldsFolder, worldNameLowered);
+ if ((!defaultWorldFolder.exists()) && ((!mirrorsGroup.containsKey(worldNameLowered))) || (!mirrorsUser.containsKey(worldNameLowered))) {
+
+ /*
+ * check and convert all old case sensitive folders to lower case
+ */
+ File casedWorldFolder = new File(worldsFolder, worldName);
+ if ((casedWorldFolder.exists()) && (casedWorldFolder.getName().toLowerCase().equals(worldNameLowered))) {
+ /*
+ * Rename the old folder to the new lower cased format
+ */
+ casedWorldFolder.renameTo(new File(worldsFolder, worldNameLowered));
+ } else {
+ /*
+ * Else we just create the folder
+ */
+ defaultWorldFolder.mkdirs();
+ }
+ }
+ if (defaultWorldFolder.exists()) {
+ if (!mirrorsGroup.containsKey(worldNameLowered)) {
+ File groupsFile = new File(defaultWorldFolder, "groups.yml");
+ if (!groupsFile.exists() || groupsFile.length() == 0) {
+
+ InputStream template = plugin.getResourceAsStream("groups.yml");
+ try {
+ Tasks.copy(template, groupsFile);
+ } catch (IOException ex) {
+ GroupManager.logger.log(Level.SEVERE, null, ex);
+ }
+ }
+ }
+
+ if (!mirrorsUser.containsKey(worldNameLowered)) {
+ File usersFile = new File(defaultWorldFolder, "users.yml");
+ if (!usersFile.exists() || usersFile.length() == 0) {
+
+ InputStream template = plugin.getResourceAsStream("users.yml");
+ try {
+ Tasks.copy(template, usersFile);
+ } catch (IOException ex) {
+ GroupManager.logger.log(Level.SEVERE, null, ex);
+ }
+
+ }
+ }
+ }
+ }
+
+ /**
+ * Copies the specified world data to another world
+ *
+ * @param fromWorld
+ * @param toWorld
+ * @return true if successfully copied.
+ */
+ public boolean cloneWorld(String fromWorld, String toWorld) {
+
+ File fromWorldFolder = new File(worldsFolder, fromWorld.toLowerCase());
+ File toWorldFolder = new File(worldsFolder, toWorld.toLowerCase());
+ if (toWorldFolder.exists() || !fromWorldFolder.exists()) {
+ return false;
+ }
+ File fromWorldGroups = new File(fromWorldFolder, "groups.yml");
+ File fromWorldUsers = new File(fromWorldFolder, "users.yml");
+ if (!fromWorldGroups.exists() || !fromWorldUsers.exists()) {
+ return false;
+ }
+ File toWorldGroups = new File(toWorldFolder, "groups.yml");
+ File toWorldUsers = new File(toWorldFolder, "users.yml");
+ toWorldFolder.mkdirs();
+ try {
+ Tasks.copy(fromWorldGroups, toWorldGroups);
+ Tasks.copy(fromWorldUsers, toWorldUsers);
+ } catch (IOException ex) {
+ Logger.getLogger(WorldsHolder.class.getName()).log(Level.SEVERE, null, ex);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * 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) {
+
+ String worldNameLowered = worldName.toLowerCase();
+
+ if (worldsData.containsKey(worldNameLowered)) {
+ worldsData.get(worldNameLowered).reload();
+ return;
+ }
+ GroupManager.logger.finest("Trying to load world " + worldName + "...");
+ File thisWorldFolder = new File(worldsFolder, worldNameLowered);
+ if ((isMirror) || (thisWorldFolder.exists() && thisWorldFolder.isDirectory())) {
+
+ // Setup file handles, if not mirrored
+ File groupsFile = (mirrorsGroup.containsKey(worldNameLowered)) ? null : new File(thisWorldFolder, "groups.yml");
+ File usersFile = (mirrorsUser.containsKey(worldNameLowered)) ? null : new File(thisWorldFolder, "users.yml");
+
+ if ((groupsFile != null) && (!groupsFile.exists())) {
+ throw new IllegalArgumentException("Groups file for world '" + worldName + "' doesnt exist: " + groupsFile.getPath());
+ }
+ if ((usersFile != null) && (!usersFile.exists())) {
+ throw new IllegalArgumentException("Users file for world '" + worldName + "' doesnt exist: " + usersFile.getPath());
+ }
+
+ WorldDataHolder tempHolder = new WorldDataHolder(worldName);
+
+ // Map the group object for any mirror
+ if (mirrorsGroup.containsKey(worldNameLowered))
+ tempHolder.setGroupsObject(this.getWorldData(mirrorsGroup.get(worldNameLowered)).getGroupsObject());
+ else
+ tempHolder.loadGroups(groupsFile);
+
+ // Map the user object for any mirror
+ if (mirrorsUser.containsKey(worldNameLowered))
+ tempHolder.setUsersObject(this.getWorldData(mirrorsUser.get(worldNameLowered)).getUsersObject());
+ else
+ tempHolder.loadUsers(usersFile);
+
+ OverloadedWorldHolder thisWorldData = new OverloadedWorldHolder(tempHolder);
+
+ // null the object so we don't keep file handles open where we shouldn't
+ tempHolder = null;
+
+ // Set the file TimeStamps as it will be default from the initial load.
+ thisWorldData.setTimeStamps();
+
+ if (thisWorldData != null) {
+ GroupManager.logger.finest("Successful load of world " + worldName + "...");
+ worldsData.put(worldNameLowered, thisWorldData);
+ return;
+ }
+
+ //GroupManager.logger.severe("Failed to load world " + worldName + "...");
+ }
+ }
+
+ /**
+ * Tells if the such world has been mapped.
+ *
+ * It will return true if world is a mirror.
+ *
+ * @param worldName
+ * @return true if world is loaded or mirrored. false if not listed
+ */
+ public boolean isInList(String worldName) {
+
+ if (worldsData.containsKey(worldName.toLowerCase()) || mirrorsGroup.containsKey(worldName.toLowerCase()) || mirrorsUser.containsKey(worldName.toLowerCase())) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Verify if world has it's own file permissions.
+ *
+ * @param worldName
+ * @return true if it has its own holder. false if not.
+ */
+ public boolean hasOwnData(String worldName) {
+
+ if (worldsData.containsKey(worldName.toLowerCase()) && (!mirrorsGroup.containsKey(worldName.toLowerCase()) || !mirrorsUser.containsKey(worldName.toLowerCase()))) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @return the defaultWorld
+ */
+ public OverloadedWorldHolder getDefaultWorld() {
+
+ return getUpdatedWorldData(serverDefaultWorldName);
+ }
+
+ /**
+ * Returns all physically loaded worlds which have at least
+ * one of their own data sets for users or groups.
+ *
+ * @return ArrayList<OverloadedWorldHolder> of all loaded worlds
+ */
+ public ArrayList<OverloadedWorldHolder> allWorldsDataList() {
+
+ ArrayList<OverloadedWorldHolder> list = new ArrayList<OverloadedWorldHolder>();
+ for (OverloadedWorldHolder data : worldsData.values()) {
+ 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);
+ }
+ }
+ return list;
+ }
+}
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMGroupEvent.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMGroupEvent.java
new file mode 100644
index 000000000..af3fb6135
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMGroupEvent.java
@@ -0,0 +1,87 @@
+package org.anjocaido.groupmanager.events;
+
+import org.anjocaido.groupmanager.GroupManager;
+import org.anjocaido.groupmanager.data.Group;
+import org.bukkit.Bukkit;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+/**
+ * @author ElgarL
+ *
+ */
+public class GMGroupEvent extends Event {
+
+ /**
+ *
+ */
+ private static final HandlerList handlers = new HandlerList();
+
+ @Override
+ public HandlerList getHandlers() {
+
+ return handlers;
+ }
+
+ public static HandlerList getHandlerList() {
+
+ return handlers;
+ }
+
+ //////////////////////////////
+
+ protected Group group;
+
+ protected String groupName;
+
+ protected Action action;
+
+ public GMGroupEvent(Group group, Action action) {
+
+ super();
+
+ this.group = group;
+ this.action = action;
+ this.groupName = group.getName();
+ }
+
+ public GMGroupEvent(String groupName, Action action) {
+
+ super();
+
+ this.groupName = groupName;
+ this.action = action;
+ }
+
+ public Action getAction() {
+
+ return this.action;
+ }
+
+ public Group getGroup() {
+
+ return group;
+ }
+
+ public String getGroupName() {
+
+ return groupName;
+ }
+
+ public enum Action {
+ GROUP_PERMISSIONS_CHANGED, GROUP_INHERITANCE_CHANGED, GROUP_INFO_CHANGED, GROUP_ADDED, GROUP_REMOVED,
+ }
+
+ public void schedule(final GMGroupEvent event) {
+
+ if (Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Bukkit.getPluginManager().getPlugin("GroupManager"), new Runnable() {
+
+ @Override
+ public void run() {
+
+ Bukkit.getServer().getPluginManager().callEvent(event);
+ }
+ }, 1) == -1)
+ GroupManager.logger.warning("Could not schedule GM Event.");
+ }
+} \ No newline at end of file
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMSystemEvent.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMSystemEvent.java
new file mode 100644
index 000000000..d11581356
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMSystemEvent.java
@@ -0,0 +1,62 @@
+package org.anjocaido.groupmanager.events;
+
+import org.anjocaido.groupmanager.GroupManager;
+import org.bukkit.Bukkit;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+/**
+ * @author ElgarL
+ *
+ */
+public class GMSystemEvent extends Event {
+
+ /**
+ *
+ */
+ private static final HandlerList handlers = new HandlerList();
+
+ @Override
+ public HandlerList getHandlers() {
+
+ return handlers;
+ }
+
+ public static HandlerList getHandlerList() {
+
+ return handlers;
+ }
+
+ //////////////////////////////
+
+ protected Action action;
+
+ public GMSystemEvent(Action action) {
+
+ super();
+
+ this.action = action;
+ }
+
+ public Action getAction() {
+
+ return this.action;
+ }
+
+ public enum Action {
+ RELOADED, SAVED, DEFAULT_GROUP_CHANGED, VALIDATE_TOGGLE,
+ }
+
+ public void schedule(final GMSystemEvent event) {
+
+ if (Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Bukkit.getPluginManager().getPlugin("GroupManager"), new Runnable() {
+
+ @Override
+ public void run() {
+
+ Bukkit.getServer().getPluginManager().callEvent(event);
+ }
+ }, 1) == -1)
+ GroupManager.logger.warning("Could not schedule GM Event.");
+ }
+} \ No newline at end of file
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMUserEvent.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMUserEvent.java
new file mode 100644
index 000000000..361e7d4cc
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMUserEvent.java
@@ -0,0 +1,87 @@
+package org.anjocaido.groupmanager.events;
+
+import org.anjocaido.groupmanager.GroupManager;
+import org.anjocaido.groupmanager.data.User;
+import org.bukkit.Bukkit;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+/**
+ * @author ElgarL
+ *
+ */
+public class GMUserEvent extends Event {
+
+ /**
+ *
+ */
+ private static final HandlerList handlers = new HandlerList();
+
+ @Override
+ public HandlerList getHandlers() {
+
+ return handlers;
+ }
+
+ public static HandlerList getHandlerList() {
+
+ return handlers;
+ }
+
+ //////////////////////////////
+
+ protected User user;
+
+ protected String userName;
+
+ protected Action action;
+
+ public GMUserEvent(User user, Action action) {
+
+ super();
+
+ this.user = user;
+ this.action = action;
+ this.userName = user.getName();
+ }
+
+ public GMUserEvent(String userName, Action action) {
+
+ super();
+
+ this.userName = userName;
+ this.action = action;
+ }
+
+ public Action getAction() {
+
+ return this.action;
+ }
+
+ public User getUser() {
+
+ return user;
+ }
+
+ public String getUserName() {
+
+ return userName;
+ }
+
+ public enum Action {
+ USER_PERMISSIONS_CHANGED, USER_INHERITANCE_CHANGED, USER_INFO_CHANGED, USER_GROUP_CHANGED, USER_SUBGROUP_CHANGED, USER_ADDED, USER_REMOVED,
+ }
+
+ public void schedule(final GMUserEvent event) {
+
+ if (Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Bukkit.getPluginManager().getPlugin("GroupManager"), new Runnable() {
+
+ @Override
+ public void run() {
+
+ Bukkit.getServer().getPluginManager().callEvent(event);
+ }
+ }, 1) == -1)
+ GroupManager.logger.warning("Could not schedule GM Event.");
+ }
+} \ No newline at end of file
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMWorldListener.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMWorldListener.java
new file mode 100644
index 000000000..f7a7109ab
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMWorldListener.java
@@ -0,0 +1,46 @@
+package org.anjocaido.groupmanager.events;
+
+import org.anjocaido.groupmanager.GroupManager;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.world.WorldInitEvent;
+
+/**
+ * @author ElgarL
+ *
+ * Handle new world creation from other plugins
+ *
+ */
+public class GMWorldListener implements Listener {
+
+ private final GroupManager plugin;
+
+ public GMWorldListener(GroupManager instance) {
+
+ plugin = instance;
+ registerEvents();
+ }
+
+ private void registerEvents() {
+
+ plugin.getServer().getPluginManager().registerEvents(this, plugin);
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ public void onWorldInit(WorldInitEvent event) {
+
+ String worldName = event.getWorld().getName();
+
+ if (GroupManager.isLoaded() && !plugin.getWorldsHolder().isInList(worldName)) {
+ GroupManager.logger.info("New world detected...");
+ GroupManager.logger.info("Creating data for: " + worldName);
+ plugin.getWorldsHolder().setupWorldFolder(worldName);
+ plugin.getWorldsHolder().loadWorld(worldName);
+ if (plugin.getWorldsHolder().isInList(worldName)) {
+ GroupManager.logger.info("Don't forget to configure/mirror this world in config.yml.");
+ } else
+ GroupManager.logger.severe("Failed to configure this world.");
+ }
+ }
+} \ No newline at end of file
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GroupManagerEventHandler.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GroupManagerEventHandler.java
new file mode 100644
index 000000000..5fc555cc4
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GroupManagerEventHandler.java
@@ -0,0 +1,53 @@
+package org.anjocaido.groupmanager.events;
+
+import org.anjocaido.groupmanager.data.Group;
+import org.anjocaido.groupmanager.data.User;
+
+/**
+ * @author ElgarL
+ *
+ * Handles all Event generation.
+ *
+ */
+public class GroupManagerEventHandler {
+
+ protected static void callEvent(GMGroupEvent event) {
+
+ event.schedule(event);
+ }
+
+ protected static void callEvent(GMUserEvent event) {
+
+ event.schedule(event);
+ }
+
+ protected static void callEvent(GMSystemEvent event) {
+
+ event.schedule(event);
+ }
+
+ public static void callEvent(Group group, GMGroupEvent.Action action) {
+
+ callEvent(new GMGroupEvent(group, action));
+ }
+
+ public static void callEvent(String groupName, GMGroupEvent.Action action) {
+
+ callEvent(new GMGroupEvent(groupName, action));
+ }
+
+ public static void callEvent(User user, GMUserEvent.Action action) {
+
+ callEvent(new GMUserEvent(user, action));
+ }
+
+ public static void callEvent(String userName, GMUserEvent.Action action) {
+
+ callEvent(new GMUserEvent(userName, action));
+ }
+
+ public static void callEvent(GMSystemEvent.Action action) {
+
+ callEvent(new GMSystemEvent(action));
+ }
+} \ No newline at end of file
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/AnjoPermissionsHandler.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/AnjoPermissionsHandler.java
new file mode 100644
index 000000000..efad11df4
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/AnjoPermissionsHandler.java
@@ -0,0 +1,1184 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anjocaido.groupmanager.permissions;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.anjocaido.groupmanager.GroupManager;
+import org.anjocaido.groupmanager.data.Group;
+import org.anjocaido.groupmanager.dataholder.WorldDataHolder;
+import org.anjocaido.groupmanager.data.User;
+import org.anjocaido.groupmanager.utils.PermissionCheckResult;
+import org.bukkit.entity.Player;
+
+/**
+ * Everything here maintains the model created by Nijikokun
+ *
+ * But implemented to use GroupManager system. Which provides instant changes,
+ * without file access.
+ *
+ * It holds permissions only for one single world.
+ *
+ * @author gabrielcouto, ElgarL
+ */
+public class AnjoPermissionsHandler extends PermissionsReaderInterface {
+
+ WorldDataHolder ph = null;
+
+ /**
+ * It needs a WorldDataHolder to work with.
+ *
+ * @param holder
+ */
+ public AnjoPermissionsHandler(WorldDataHolder holder) {
+
+ ph = holder;
+ }
+
+ /**
+ * A short name method, for permission method.
+ *
+ * @param player
+ * @param permission
+ * @return true if the player has the permission
+ */
+ @Override
+ public boolean has(Player player, String permission) {
+
+ return permission(player, permission);
+ }
+
+ /**
+ * Checks if a player can use that permission node.
+ *
+ * @param player
+ * @param permission
+ * @return true if the player has the permission
+ */
+ @Override
+ public boolean permission(Player player, String permission) {
+
+ return checkUserPermission(ph.getUser(player.getName()).updatePlayer(player), permission);
+ }
+
+ /**
+ * Checks if a player can use that permission node.
+ *
+ * @param playerName
+ * @param permission
+ * @return true if the player has the permission
+ */
+ public boolean permission(String playerName, String permission) {
+
+ return checkUserPermission(ph.getUser(playerName), permission);
+ }
+
+ /**
+ * Returns the name of the group of that player name.
+ *
+ * @param userName
+ * @return String of players group name.
+ */
+ @Override
+ public String getGroup(String userName) {
+
+ return ph.getUser(userName).getGroup().getName();
+ }
+
+ /**
+ * Returns All permissions (including inheritance and sub groups) for the
+ * player, including child nodes from Bukkit.
+ *
+ * @param userName
+ * @return List<String> of all players permissions.
+ */
+ @Override
+ public List<String> getAllPlayersPermissions(String userName) {
+
+ List<String> perms = new ArrayList<String>();
+
+ perms.addAll(getAllPlayersPermissions(userName, true));
+
+ return perms;
+ }
+
+ /**
+ * Returns All permissions (including inheritance and sub groups) for the
+ * player. With or without Bukkit child nodes.
+ *
+ * @param userName
+ * @return Set<String> of all players permissions.
+ */
+ @Override
+ public Set<String> getAllPlayersPermissions(String userName, Boolean includeChildren) {
+
+ Set<String> playerPermArray = new HashSet<String>();
+
+ // Add the players own permissions.
+ playerPermArray.addAll(populatePerms(ph.getUser(userName).getPermissionList(), includeChildren));
+
+ ArrayList<String> alreadyProcessed = new ArrayList<String>();
+
+ // fetch all group permissions
+ for (String group : getGroups(userName)) {
+ // Don't process a group more than once.
+ if (!alreadyProcessed.contains(group)) {
+ alreadyProcessed.add(group);
+
+ Set<String> groupPermArray = new HashSet<String>();
+
+ 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.contains("-" + perm)))
+ playerPermArray.add(perm);
+ }
+ }
+
+ }
+ // Collections.sort(playerPermArray, StringPermissionComparator.getInstance());
+
+ return playerPermArray;
+ }
+
+ private Set<String> populatePerms(List<String> permsList, boolean includeChildren) {
+
+ // Create a new array so it's modifiable.
+ List<String> perms = new ArrayList<String>(permsList);
+ Set<String> permArray = new HashSet<String>();
+ Boolean allPerms = false;
+
+ // Allow * node to populate ALL permissions to Bukkit.
+ if (perms.contains("*")) {
+ permArray.addAll(GroupManager.BukkitPermissions.getAllRegisteredPermissions(includeChildren));
+ allPerms = true;
+ perms.remove("*");
+ }
+
+ for (String perm : perms) {
+
+ /**
+ * all permission sets are passed here pre-sorted, alphabetically.
+ * This means negated nodes will be processed before all permissions
+ * other than *.
+ */
+ boolean negated = perm.startsWith("-");
+
+ if (!permArray.contains(perm)) {
+ permArray.add(perm);
+
+ if ((negated) && (permArray.contains(perm.substring(1))))
+ permArray.remove(perm.substring(1));
+
+ /**
+ * 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<String, Boolean> children = GroupManager.BukkitPermissions.getAllChildren((negated ? perm.substring(1) : perm), new HashSet<String>());
+
+ if (children != null) {
+ if (negated)
+ if (allPerms) {
+
+ // Remove children of negated nodes
+ for (String child : children.keySet())
+ if (children.get(child))
+ if (permArray.contains(child))
+ permArray.remove(child);
+
+ } else {
+
+ // Add child nodes
+ for (String child : children.keySet())
+ if (children.get(child))
+ if ((!permArray.contains(child)) && (!permArray.contains("-" + child)))
+ permArray.add(child);
+ }
+ }
+ }
+ }
+ }
+
+ return permArray;
+ }
+
+ /**
+ * Verify if player is in such group. It will check it's groups inheritance.
+ *
+ * So if you have a group Admin > Moderator
+ *
+ * And verify the player 'MyAdmin', which is Admin, it will return true for
+ * both Admin or Moderator groups.
+ *
+ * If you have a player 'MyModerator', which is Moderator, it will give
+ * false if you pass Admin in group parameter.
+ *
+ * @param name
+ * @param group
+ * @return true if in group (with inheritance)
+ */
+ @Override
+ public boolean inGroup(String name, String group) {
+
+ if (hasGroupInInheritance(ph.getUser(name).getGroup(), group)) {
+ return true;
+ }
+ for (Group subGroup : ph.getUser(name).subGroupListCopy()) {
+ if (hasGroupInInheritance(subGroup, group)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Gets the appropriate prefix for the user. This method is a utility method
+ * for chat plugins to get the user's prefix without having to look at every
+ * one of the user's ancestors. Returns an empty string if user has no
+ * parent groups.
+ *
+ * @param user
+ * Player's name
+ * @return Player's prefix
+ */
+ @Override
+ public String getUserPrefix(String user) {
+
+ String prefix = ph.getUser(user).getVariables().getVarString("prefix");
+ if (prefix.length() != 0) {
+ return prefix;
+ }
+
+ return getGroupPrefix(getGroup(user));
+ }
+
+ /**
+ * Gets the appropriate prefix for the user. This method is a utility method
+ * for chat plugins to get the user's prefix without having to look at every
+ * one of the user's ancestors. Returns an empty string if user has no
+ * parent groups.
+ *
+ * @param user
+ * Player's name
+ * @return Player's prefix
+ */
+ @Override
+ public String getUserSuffix(String user) {
+
+ String suffix = ph.getUser(user).getVariables().getVarString("suffix");
+ if (suffix.length() != 0) {
+ return suffix;
+ }
+
+ return getGroupSuffix(getGroup(user));
+
+ }
+
+ /**
+ * Gets name of the primary group of the user. Returns the name of the
+ * default group if user has no parent groups, or "Default" if there is no
+ * default group for that world.
+ *
+ * @param user
+ * Player's name
+ * @return Name of player's primary group
+ */
+ public String getPrimaryGroup(String user) {
+
+ return getGroup(user);
+
+ }
+
+ /**
+ * Check if user can build. Checks inheritance and subgroups.
+ *
+ * @param userName
+ * Player's name
+ * @return true if the user can build
+ */
+ public boolean canUserBuild(String userName) {
+
+ return getPermissionBoolean(userName, "build");
+
+ }
+
+ /**
+ * Returns the String prefix for the given group
+ *
+ * @param groupName
+ * @return empty string if found none.
+ */
+ @Override
+ public String getGroupPrefix(String groupName) {
+
+ Group g = ph.getGroup(groupName);
+ if (g == null) {
+ return "";
+ }
+ return g.getVariables().getVarString("prefix");
+ }
+
+ /**
+ * Return the suffix for the given group name
+ *
+ * @param groupName
+ * @return empty string if not found.
+ */
+ @Override
+ public String getGroupSuffix(String groupName) {
+
+ Group g = ph.getGroup(groupName);
+ if (g == null) {
+ return "";
+ }
+ return g.getVariables().getVarString("suffix");
+ }
+
+ /**
+ * Checks the specified group for the Info Build node. Does NOT check
+ * inheritance
+ *
+ * @param groupName
+ * @return true if can build
+ */
+ @Override
+ public boolean canGroupBuild(String groupName) {
+
+ Group g = ph.getGroup(groupName);
+ if (g == null) {
+ return false;
+ }
+ return g.getVariables().getVarBoolean("build");
+ }
+
+ /**
+ * It returns a string variable value, set in the INFO node of the group. It
+ * will harvest inheritance for value.
+ *
+ * @param groupName
+ * @param variable
+ * @return null if no group with that variable is found.
+ */
+ @Override
+ public String getGroupPermissionString(String groupName, String variable) {
+
+ Group start = ph.getGroup(groupName);
+ if (start == null) {
+ return null;
+ }
+ Group result = nextGroupWithVariable(start, variable);
+ if (result == null) {
+ return null;
+ }
+ return result.getVariables().getVarString(variable);
+ }
+
+ /**
+ * It returns a Integer variable value It will harvest inheritance for
+ * value.
+ *
+ * @param groupName
+ * @param variable
+ * @return -1 if none found or not parseable.
+ */
+ @Override
+ public int getGroupPermissionInteger(String groupName, String variable) {
+
+ Group start = ph.getGroup(groupName);
+ if (start == null) {
+ return -1;
+ }
+ Group result = nextGroupWithVariable(start, variable);
+ if (result == null) {
+ return -1;
+ }
+ return result.getVariables().getVarInteger(variable);
+ }
+
+ /**
+ * Returns a boolean for given variable in INFO node. It will harvest
+ * inheritance for value.
+ *
+ * @param group
+ * @param variable
+ * @return false if not found/not parseable.
+ */
+ @Override
+ public boolean getGroupPermissionBoolean(String group, String variable) {
+
+ Group start = ph.getGroup(group);
+ if (start == null) {
+ return false;
+ }
+ Group result = nextGroupWithVariable(start, variable);
+ if (result == null) {
+ return false;
+ }
+ return result.getVariables().getVarBoolean(variable);
+ }
+
+ /**
+ * Returns a double value for the given variable name in INFO node. It will
+ * harvest inheritance for value.
+ *
+ * @param group
+ * @param variable
+ * @return -1 if not found / not parseable.
+ */
+ @Override
+ public double getGroupPermissionDouble(String group, String variable) {
+
+ Group start = ph.getGroup(group);
+ if (start == null) {
+ return -1;
+ }
+ Group result = nextGroupWithVariable(start, variable);
+ if (result == null) {
+ return -1;
+ }
+ return result.getVariables().getVarDouble(variable);
+ }
+
+ /**
+ * Returns the variable value of the user, in INFO node.
+ *
+ * @param user
+ * @param variable
+ * @return empty string if not found
+ */
+ @Override
+ public String getUserPermissionString(String user, String variable) {
+
+ User auser = ph.getUser(user);
+ if (auser == null) {
+ return "";
+ }
+ return auser.getVariables().getVarString(variable);
+ }
+
+ /**
+ * Returns the variable value of the user, in INFO node.
+ *
+ * @param user
+ * @param variable
+ * @return -1 if not found
+ */
+ @Override
+ public int getUserPermissionInteger(String user, String variable) {
+
+ User auser = ph.getUser(user);
+ if (auser == null) {
+ return -1;
+ }
+ return auser.getVariables().getVarInteger(variable);
+ }
+
+ /**
+ * Returns the variable value of the user, in INFO node.
+ *
+ * @param user
+ * @param variable
+ * @return boolean value
+ */
+ @Override
+ public boolean getUserPermissionBoolean(String user, String variable) {
+
+ User auser = ph.getUser(user);
+ if (auser == null) {
+ return false;
+ }
+ return auser.getVariables().getVarBoolean(variable);
+ }
+
+ /**
+ * Returns the variable value of the user, in INFO node.
+ *
+ * @param user
+ * @param variable
+ * @return -1 if not found
+ */
+ @Override
+ public double getUserPermissionDouble(String user, String variable) {
+
+ User auser = ph.getUser(user);
+ if (auser == null) {
+ return -1;
+ }
+ return auser.getVariables().getVarDouble(variable);
+ }
+
+ /**
+ * Returns the variable value of the user, in INFO node. If not found, it
+ * will search for his Group variables. It will harvest the inheritance and
+ * subgroups.
+ *
+ * @param user
+ * @param variable
+ * @return empty string if not found
+ */
+ @Override
+ public String getPermissionString(String user, String variable) {
+
+ User auser = ph.getUser(user);
+ if (auser == null) {
+ return "";
+ }
+ if (auser.getVariables().hasVar(variable)) {
+ return auser.getVariables().getVarString(variable);
+ }
+ Group start = auser.getGroup();
+ if (start == null) {
+ return "";
+ }
+ Group result = nextGroupWithVariable(start, variable);
+ if (result == null) {
+ // Check sub groups
+ if (!auser.isSubGroupsEmpty())
+ for (Group subGroup : auser.subGroupListCopy()) {
+ result = nextGroupWithVariable(subGroup, variable);
+ // Found value?
+ if (result != null)
+ continue;
+ }
+ if (result == null)
+ return "";
+ }
+ return result.getVariables().getVarString(variable);
+ // return getUserPermissionString(user, variable);
+ }
+
+ /**
+ * Returns the variable value of the user, in INFO node. If not found, it
+ * will search for his Group variables. It will harvest the inheritance and
+ * subgroups.
+ *
+ * @param user
+ * @param variable
+ * @return -1 if not found
+ */
+ @Override
+ public int getPermissionInteger(String user, String variable) {
+
+ User auser = ph.getUser(user);
+ if (auser == null) {
+ return -1;
+ }
+ if (auser.getVariables().hasVar(variable)) {
+ return auser.getVariables().getVarInteger(variable);
+ }
+ Group start = auser.getGroup();
+ if (start == null) {
+ return -1;
+ }
+ Group result = nextGroupWithVariable(start, variable);
+ if (result == null) {
+ // Check sub groups
+ if (!auser.isSubGroupsEmpty())
+ for (Group subGroup : auser.subGroupListCopy()) {
+ result = nextGroupWithVariable(subGroup, variable);
+ // Found value?
+ if (result != null)
+ continue;
+ }
+ if (result == null)
+ return -1;
+ }
+ return result.getVariables().getVarInteger(variable);
+ // return getUserPermissionInteger(string, string1);
+ }
+
+ /**
+ * Returns the variable value of the user, in INFO node. If not found, it
+ * will search for his Group variables. It will harvest the inheritance and
+ * subgroups.
+ *
+ * @param user
+ * @param variable
+ * @return false if not found or not parseable to true.
+ */
+ @Override
+ public boolean getPermissionBoolean(String user, String variable) {
+
+ User auser = ph.getUser(user);
+ if (auser == null) {
+ return false;
+ }
+ if (auser.getVariables().hasVar(variable)) {
+ return auser.getVariables().getVarBoolean(variable);
+ }
+ Group start = auser.getGroup();
+ if (start == null) {
+ return false;
+ }
+ Group result = nextGroupWithVariable(start, variable);
+ if (result == null) {
+ // Check sub groups
+ if (!auser.isSubGroupsEmpty())
+ for (Group subGroup : auser.subGroupListCopy()) {
+ result = nextGroupWithVariable(subGroup, variable);
+ // Found value?
+ if (result != null)
+ continue;
+ }
+ if (result == null)
+ return false;
+ }
+ return result.getVariables().getVarBoolean(variable);
+ // return getUserPermissionBoolean(user, string1);
+ }
+
+ /**
+ * Returns the variable value of the user, in INFO node. If not found, it
+ * will search for his Group variables. It will harvest the inheritance and
+ * subgroups.
+ *
+ * @param user
+ * @param variable
+ * @return -1 if not found.
+ */
+ @Override
+ public double getPermissionDouble(String user, String variable) {
+
+ User auser = ph.getUser(user);
+ if (auser == null) {
+ return -1.0D;
+ }
+ if (auser.getVariables().hasVar(variable)) {
+ return auser.getVariables().getVarDouble(variable);
+ }
+ Group start = auser.getGroup();
+ if (start == null) {
+ return -1.0D;
+ }
+ Group result = nextGroupWithVariable(start, variable);
+ if (result == null) {
+ // Check sub groups
+ if (!auser.isSubGroupsEmpty())
+ for (Group subGroup : auser.subGroupListCopy()) {
+ result = nextGroupWithVariable(subGroup, variable);
+ // Found value?
+ if (result != null)
+ continue;
+ }
+ if (result == null)
+ return -1.0D;
+ }
+ return result.getVariables().getVarDouble(variable);
+ // return getUserPermissionDouble(string, string1);
+ }
+
+ /**
+ * Does not include User's group permission
+ *
+ * @param user
+ * @param permission
+ * @return PermissionCheckResult
+ */
+ public PermissionCheckResult checkUserOnlyPermission(User user, String permission) {
+
+ user.sortPermissions();
+ PermissionCheckResult result = new PermissionCheckResult();
+ result.askedPermission = permission;
+ result.owner = user;
+ for (String access : user.getPermissionList()) {
+ result.resultType = comparePermissionString(access, permission);
+ if (result.resultType != PermissionCheckResult.Type.NOTFOUND) {
+ return result;
+ }
+ }
+ result.resultType = PermissionCheckResult.Type.NOTFOUND;
+ return result;
+ }
+
+ /**
+ * Returns the node responsible for that permission. Does not include User's
+ * group permission.
+ *
+ * @param group
+ * @param permission
+ * @return the node if permission is found. if not found, return null
+ */
+ public PermissionCheckResult checkGroupOnlyPermission(Group group, String permission) {
+
+ group.sortPermissions();
+ PermissionCheckResult result = new PermissionCheckResult();
+ result.owner = group;
+ result.askedPermission = permission;
+ for (String access : group.getPermissionList()) {
+ result.resultType = comparePermissionString(access, permission);
+ if (result.resultType != PermissionCheckResult.Type.NOTFOUND) {
+ return result;
+ }
+ }
+ result.resultType = PermissionCheckResult.Type.NOTFOUND;
+ return result;
+ }
+
+ /**
+ * Check permissions, including it's group and inheritance.
+ *
+ * @param user
+ * @param permission
+ * @return true if permission was found. false if not, or was negated.
+ */
+ public boolean checkUserPermission(User user, String permission) {
+
+ PermissionCheckResult result = checkFullGMPermission(user, permission, true);
+ if (result.resultType == PermissionCheckResult.Type.EXCEPTION || result.resultType == PermissionCheckResult.Type.FOUND) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Do what checkUserPermission did before. But now returning a
+ * PermissionCheckResult.
+ *
+ * @param user
+ * @param targetPermission
+ * @return PermissionCheckResult
+ */
+ public PermissionCheckResult checkFullUserPermission(User user, String targetPermission) {
+
+ return checkFullGMPermission(user, targetPermission, true);
+ }
+
+ /**
+ * Check user and groups with inheritance and Bukkit if bukkit = true return
+ * a PermissionCheckResult.
+ *
+ * @param user
+ * @param targetPermission
+ * @param checkBukkit
+ * @return PermissionCheckResult
+ */
+ public PermissionCheckResult checkFullGMPermission(User user, String targetPermission, Boolean checkBukkit) {
+
+ PermissionCheckResult result = new PermissionCheckResult();
+ result.accessLevel = targetPermission;
+ result.resultType = PermissionCheckResult.Type.NOTFOUND;
+
+ if (user == null || targetPermission == null || targetPermission.isEmpty()) {
+ return result;
+ }
+
+ if (checkBukkit) {
+ // Check Bukkit perms to support plugins which add perms via code
+ // (Heroes).
+ final Player player = user.getBukkitPlayer();
+ //final Permission bukkitPerm = Bukkit.getPluginManager().getPermission(targetPermission);
+ if ((player != null) && player.hasPermission(targetPermission)) {
+ result.resultType = PermissionCheckResult.Type.FOUND;
+ result.owner = user;
+ return result;
+ }
+ }
+
+ PermissionCheckResult resultUser = checkUserOnlyPermission(user, targetPermission);
+ if (resultUser.resultType != PermissionCheckResult.Type.NOTFOUND) {
+ resultUser.accessLevel = targetPermission;
+ return resultUser;
+ }
+
+ // IT ONLY CHECKS GROUPS PERMISSIONS IF RESULT FOR USER IS NOT FOUND
+ PermissionCheckResult resultGroup = checkGroupPermissionWithInheritance(user.getGroup(), targetPermission);
+ if (resultGroup.resultType != PermissionCheckResult.Type.NOTFOUND) {
+ resultGroup.accessLevel = targetPermission;
+ return resultGroup;
+ }
+
+ // SUBGROUPS CHECK
+ for (Group subGroup : user.subGroupListCopy()) {
+ PermissionCheckResult resultSubGroup = checkGroupPermissionWithInheritance(subGroup, targetPermission);
+ if (resultSubGroup.resultType != PermissionCheckResult.Type.NOTFOUND) {
+ resultSubGroup.accessLevel = targetPermission;
+ return resultSubGroup;
+ }
+ }
+
+ // THEN IT RETURNS A NOT FOUND
+ return result;
+ }
+
+ /**
+ * Returns the next group, including inheritance, which contains that
+ * variable name.
+ *
+ * It does Breadth-first search
+ *
+ * @param start the starting group to look for
+ * @param targetVariable the variable name
+ * @return The group if found. Null if not.
+ */
+ public Group nextGroupWithVariable(Group start, String targetVariable) {
+
+ if (start == null || targetVariable == null) {
+ return null;
+ }
+ LinkedList<Group> stack = new LinkedList<Group>();
+ ArrayList<Group> alreadyVisited = new ArrayList<Group>();
+ stack.push(start);
+ alreadyVisited.add(start);
+ while (!stack.isEmpty()) {
+ Group now = stack.pop();
+ if (now.getVariables().hasVar(targetVariable)) {
+ return now;
+ }
+ for (String sonName : now.getInherits()) {
+ Group son = ph.getGroup(sonName);
+ if (son != null && !alreadyVisited.contains(son)) {
+ stack.push(son);
+ alreadyVisited.add(son);
+ }
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Check if given group inherits another group.
+ *
+ * It does Breadth-first search
+ *
+ * @param start The group to start the search.
+ * @param askedGroup Name of the group you're looking for
+ * @return true if it inherits the group.
+ */
+ public boolean hasGroupInInheritance(Group start, String askedGroup) {
+
+ if (start == null || askedGroup == null) {
+ return false;
+ }
+ LinkedList<Group> stack = new LinkedList<Group>();
+ ArrayList<Group> alreadyVisited = new ArrayList<Group>();
+ stack.push(start);
+ alreadyVisited.add(start);
+ while (!stack.isEmpty()) {
+ Group now = stack.pop();
+ if (now.getName().equalsIgnoreCase(askedGroup)) {
+ return true;
+ }
+ for (String sonName : now.getInherits()) {
+ Group son = ph.getGroup(sonName);
+ if (son != null && !alreadyVisited.contains(son)) {
+ stack.push(son);
+ alreadyVisited.add(son);
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the result of permission check. Including inheritance. If found
+ * anything, the PermissionCheckResult that retuns will include the Group
+ * name, and the result type. Result types will be EXCEPTION, NEGATION,
+ * FOUND.
+ *
+ * If returned type NOTFOUND, the owner will be null, and ownerType too.
+ *
+ * It does Breadth-first search
+ *
+ * @param start
+ * @param targetPermission
+ * @return PermissionCheckResult
+ */
+ public PermissionCheckResult checkGroupPermissionWithInheritance(Group start, String targetPermission) {
+
+ if (start == null || targetPermission == null) {
+ return null;
+ }
+ LinkedList<Group> stack = new LinkedList<Group>();
+ List<Group> alreadyVisited = new ArrayList<Group>();
+ stack.push(start);
+ alreadyVisited.add(start);
+ while (!stack.isEmpty()) {
+ Group now = stack.pop();
+ PermissionCheckResult resultNow = checkGroupOnlyPermission(now, targetPermission);
+ if (!resultNow.resultType.equals(PermissionCheckResult.Type.NOTFOUND)) {
+ return resultNow;
+ }
+ for (String sonName : now.getInherits()) {
+ Group son = ph.getGroup(sonName);
+ if (son != null && !alreadyVisited.contains(son)) {
+ // Add rather than push to retain inheritance order.
+ stack.add(son);
+ alreadyVisited.add(son);
+ }
+ }
+ }
+ PermissionCheckResult result = new PermissionCheckResult();
+ result.askedPermission = targetPermission;
+ result.resultType = PermissionCheckResult.Type.NOTFOUND;
+ return result;
+ }
+
+ /**
+ * Return whole list of names of groups in a inheritance chain. Including a
+ * starting group.
+ *
+ * It does Breadth-first search. So closer groups will appear first in list.
+ *
+ * @param start
+ * @return the group that passed on test. null if no group passed.
+ */
+ public ArrayList<String> listAllGroupsInherited(Group start) {
+
+ if (start == null) {
+ return null;
+ }
+ LinkedList<Group> stack = new LinkedList<Group>();
+ ArrayList<String> alreadyVisited = new ArrayList<String>();
+ stack.push(start);
+ alreadyVisited.add(start.getName());
+ while (!stack.isEmpty()) {
+ Group now = stack.pop();
+ for (String sonName : now.getInherits()) {
+ Group son = ph.getGroup(sonName);
+ if (son != null && !alreadyVisited.contains(son.getName())) {
+ stack.push(son);
+ alreadyVisited.add(son.getName());
+ }
+ }
+ }
+ return alreadyVisited;
+ }
+
+ /**
+ * Compare a user permission like 'myplugin.*' against a full plugin
+ * permission name, like 'myplugin.dosomething'. As the example above, will
+ * return true.
+ *
+ * Please sort permissions before sending them here. So negative tokens get
+ * priority.
+ *
+ * You must test if it start with negative outside this method. It will only
+ * tell if the nodes are matching or not.
+ *
+ * Every '-' or '+' in the beginning is ignored. It will match only node
+ * names.
+ *
+ * @param userAccessLevel
+ * @param fullPermissionName
+ * @return PermissionCheckResult.Type
+ */
+ public PermissionCheckResult.Type comparePermissionString(String userAccessLevel, String fullPermissionName) {
+
+ int userAccessLevelLength;
+ if (userAccessLevel == null || fullPermissionName == null || fullPermissionName.length() == 0 || (userAccessLevelLength = userAccessLevel.length()) == 0) {
+ return PermissionCheckResult.Type.NOTFOUND;
+ }
+
+ PermissionCheckResult.Type result = PermissionCheckResult.Type.FOUND;
+ int userAccessLevelOffset = 0;
+ if (userAccessLevel.charAt(0) == '+') {
+ userAccessLevelOffset = 1;
+ result = PermissionCheckResult.Type.EXCEPTION;
+ } else if (userAccessLevel.charAt(0) == '-') {
+ userAccessLevelOffset = 1;
+ result = PermissionCheckResult.Type.NEGATION;
+ }
+ if ("*".regionMatches(0, userAccessLevel, userAccessLevelOffset, userAccessLevelLength - userAccessLevelOffset)) {
+ return result;
+ }
+ int fullPermissionNameOffset;
+ if (fullPermissionName.charAt(0) == '+' || fullPermissionName.charAt(0) == '-') {
+ fullPermissionNameOffset = 1;
+ } else {
+ fullPermissionNameOffset = 0;
+ }
+
+ if (userAccessLevel.charAt(userAccessLevel.length() - 1) == '*') {
+ return userAccessLevel.regionMatches(true, userAccessLevelOffset, fullPermissionName, fullPermissionNameOffset, userAccessLevelLength - userAccessLevelOffset - 1) ? result : PermissionCheckResult.Type.NOTFOUND;
+ } else {
+ return userAccessLevel.regionMatches(true, userAccessLevelOffset, fullPermissionName, fullPermissionNameOffset, Math.max(userAccessLevelLength - userAccessLevelOffset, fullPermissionName.length() - fullPermissionNameOffset)) ? result : PermissionCheckResult.Type.NOTFOUND;
+ }
+ }
+
+ /**
+ * Returns a list of all groups.
+ *
+ * Including subgroups.
+ *
+ * @param userName
+ * @return String[] of all group names.
+ */
+ @Override
+ public String[] getGroups(String userName) {
+
+ ArrayList<String> allGroups = listAllGroupsInherited(ph.getUser(userName).getGroup());
+ for (Group subg : ph.getUser(userName).subGroupListCopy()) {
+ allGroups.addAll(listAllGroupsInherited(subg));
+ }
+
+ String[] arr = new String[allGroups.size()];
+ return allGroups.toArray(arr);
+ }
+
+ /**
+ * A Breadth-first search thru inheritance model.
+ *
+ * Just a model to copy and paste. This will guarantee the closer groups
+ * will be checked first.
+ *
+ * @param start
+ * @param targerPermission
+ * @return
+ */
+ @SuppressWarnings("unused")
+ private Group breadthFirstSearch(Group start, String targerPermission) {
+
+ if (start == null || targerPermission == null) {
+ return null;
+ }
+ LinkedList<Group> stack = new LinkedList<Group>();
+ ArrayList<Group> alreadyVisited = new ArrayList<Group>();
+ stack.push(start);
+ alreadyVisited.add(start);
+ while (!stack.isEmpty()) {
+ Group now = stack.pop();
+ PermissionCheckResult resultNow = checkGroupOnlyPermission(now, targerPermission);
+ if (resultNow.resultType.equals(PermissionCheckResult.Type.EXCEPTION) || resultNow.resultType.equals(PermissionCheckResult.Type.FOUND)) {
+ return now;
+ }
+ if (resultNow.resultType.equals(PermissionCheckResult.Type.NEGATION)) {
+ return null;
+ }
+ for (String sonName : now.getInherits()) {
+ Group son = ph.getGroup(sonName);
+ if (son != null && !alreadyVisited.contains(son)) {
+ stack.push(son);
+ alreadyVisited.add(son);
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Group getDefaultGroup() {
+
+ return ph.getDefaultGroup();
+ }
+
+ @Override
+ public String getInfoString(String entryName, String path, boolean isGroup) {
+
+ if (isGroup) {
+ Group data = ph.getGroup(entryName);
+ if (data == null) {
+ return null;
+ }
+ return data.getVariables().getVarString(path);
+ } else {
+ User data = ph.getUser(entryName);
+ if (data == null) {
+ return null;
+ }
+ return data.getVariables().getVarString(path);
+ }
+ }
+
+ @Override
+ public int getInfoInteger(String entryName, String path, boolean isGroup) {
+
+ if (isGroup) {
+ Group data = ph.getGroup(entryName);
+ if (data == null) {
+ return -1;
+ }
+ return data.getVariables().getVarInteger(path);
+ } else {
+ User data = ph.getUser(entryName);
+ if (data == null) {
+ return -1;
+ }
+ return data.getVariables().getVarInteger(path);
+ }
+ }
+
+ @Override
+ public double getInfoDouble(String entryName, String path, boolean isGroup) {
+
+ if (isGroup) {
+ Group data = ph.getGroup(entryName);
+ if (data == null) {
+ return -1;
+ }
+ return data.getVariables().getVarDouble(path);
+ } else {
+ User data = ph.getUser(entryName);
+ if (data == null) {
+ return -1;
+ }
+ return data.getVariables().getVarDouble(path);
+ }
+
+ }
+
+ @Override
+ public boolean getInfoBoolean(String entryName, String path, boolean isGroup) {
+
+ if (isGroup) {
+ Group data = ph.getGroup(entryName);
+ if (data == null) {
+ return false;
+ }
+ return data.getVariables().getVarBoolean(path);
+ } else {
+ User data = ph.getUser(entryName);
+ if (data == null) {
+ return false;
+ }
+ return data.getVariables().getVarBoolean(path);
+ }
+ }
+
+ @Override
+ public void addUserInfo(String name, String path, Object data) {
+
+ ph.getUser(name).getVariables().addVar(path, data);
+ }
+
+ @Override
+ public void removeUserInfo(String name, String path) {
+
+ ph.getUser(name).getVariables().removeVar(path);
+ }
+
+ @Override
+ public void addGroupInfo(String name, String path, Object data) {
+
+ ph.getGroup(name).getVariables().addVar(path, data);
+ }
+
+ @Override
+ public void removeGroupInfo(String name, String path) {
+
+ ph.getGroup(name).getVariables().removeVar(path);
+ }
+}
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/BukkitPermissions.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/BukkitPermissions.java
new file mode 100644
index 000000000..05e152286
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/BukkitPermissions.java
@@ -0,0 +1,491 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+package org.anjocaido.groupmanager.permissions;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import org.anjocaido.groupmanager.GroupManager;
+import org.anjocaido.groupmanager.data.User;
+
+import org.bukkit.Bukkit;
+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.PlayerQuitEvent;
+import org.bukkit.event.server.PluginDisableEvent;
+import org.bukkit.event.server.PluginEnableEvent;
+import org.bukkit.permissions.Permission;
+import org.bukkit.permissions.PermissionAttachment;
+import org.bukkit.permissions.PermissionAttachmentInfo;
+import org.bukkit.plugin.PluginManager;
+
+/**
+ *
+ * BukkitPermissions overrides to force GM reponses to Superperms
+ *
+ * @author ElgarL
+ */
+public class BukkitPermissions {
+
+ protected WeakHashMap<Player, PermissionAttachment> attachments = new WeakHashMap<Player, PermissionAttachment>();
+ protected LinkedHashMap<String, Permission> registeredPermissions = new LinkedHashMap<String, Permission>();
+ protected GroupManager plugin;
+ protected boolean dumpAllPermissions = true;
+ protected boolean dumpMatchedPermissions = true;
+ private boolean player_join = false;
+
+ /**
+ * @return the player_join
+ */
+ public boolean isPlayer_join() {
+
+ return player_join;
+ }
+
+ /**
+ * @param player_join the player_join to set
+ */
+ public void setPlayer_join(boolean player_join) {
+
+ this.player_join = player_join;
+ }
+
+ private static Field permissions;
+
+ // Setup reflection (Thanks to Codename_B for the reflection source)
+ static {
+ try {
+ permissions = PermissionAttachment.class.getDeclaredField("permissions");
+ permissions.setAccessible(true);
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public BukkitPermissions(GroupManager plugin) {
+
+ this.plugin = plugin;
+ this.reset();
+ this.registerEvents();
+
+
+ GroupManager.logger.info("Superperms support enabled.");
+ }
+
+ public void reset() {
+ this.collectPermissions();
+ this.updateAllPlayers();
+ }
+
+ private void registerEvents() {
+
+ PluginManager manager = plugin.getServer().getPluginManager();
+
+ manager.registerEvents(new PlayerEvents(), plugin);
+ manager.registerEvents(new BukkitEvents(), plugin);
+ }
+
+ public void collectPermissions() {
+
+ registeredPermissions.clear();
+
+ for (Permission perm : Bukkit.getPluginManager().getPermissions()) {
+ registeredPermissions.put(perm.getName().toLowerCase(), perm);
+ }
+
+ }
+
+ public void updatePermissions(Player player) {
+
+ this.updatePermissions(player, null);
+ }
+
+ /**
+ * Push all permissions which are registered with GM for this player, on
+ * this world to Bukkit
+ * and make it update for the child nodes.
+ *
+ * @param player
+ * @param world
+ */
+ public void updatePermissions(Player player, String world) {
+
+ if (player == null || !GroupManager.isLoaded()) {
+ return;
+ }
+
+ // Reset the User objects player reference.
+ User user = plugin.getWorldsHolder().getWorldData(player.getWorld().getName()).getUser(player.getName());
+ if (user != null)
+ user.updatePlayer(player);
+
+ PermissionAttachment attachment;
+
+ // Find the players current attachment, or add a new one.
+ if (this.attachments.containsKey(player)) {
+ attachment = this.attachments.get(player);
+ } else {
+ attachment = player.addAttachment(plugin);
+ this.attachments.put(player, attachment);
+ }
+
+ if (world == null) {
+ world = player.getWorld().getName();
+ }
+
+ // Add all permissions for this player (GM only)
+ // child nodes will be calculated by Bukkit.
+ List<String> playerPermArray = new ArrayList<String>(plugin.getWorldsHolder().getWorldData(world).getPermissionsHandler().getAllPlayersPermissions(player.getName(), false));
+ LinkedHashMap<String, Boolean> newPerms = new LinkedHashMap<String, Boolean>();
+
+ // Sort the perm list by parent/child, so it will push to superperms correctly.
+ playerPermArray = sort(playerPermArray);
+
+ Boolean value = false;
+ for (String permission : playerPermArray) {
+ value = (!permission.startsWith("-"));
+ newPerms.put((value ? permission : permission.substring(1)), value);
+ }
+
+ /**
+ * This is put in place until such a time as Bukkit pull 466 is
+ * implemented
+ * https://github.com/Bukkit/Bukkit/pull/466
+ */
+ try { // Codename_B source
+ @SuppressWarnings("unchecked")
+ Map<String, Boolean> orig = (Map<String, Boolean>) permissions.get(attachment);
+ // Clear the map (faster than removing the attachment and recalculating)
+ orig.clear();
+ // Then whack our map into there
+ orig.putAll(newPerms);
+ // That's all folks!
+ //attachment.getPermissible().recalculatePermissions();
+ player.recalculatePermissions();
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Sort a permission node list by parent/child
+ *
+ * @param permList
+ * @return List sorted for priority
+ */
+ private List<String> sort(List<String> permList) {
+
+ List<String> result = new ArrayList<String>();
+
+ for (String key : permList) {
+ String a = key.charAt(0) == '-' ? key.substring(1) : key;
+ Map<String, Boolean> allchildren = GroupManager.BukkitPermissions.getAllChildren(a, new HashSet<String>());
+ if (allchildren != null) {
+
+ ListIterator<String> itr = result.listIterator();
+
+ while (itr.hasNext()) {
+ String node = (String) itr.next();
+ String b = node.charAt(0) == '-' ? node.substring(1) : node;
+
+ // Insert the parent node before the child
+ if (allchildren.containsKey(b)) {
+ itr.set(key);
+ itr.add(node);
+ break;
+ }
+ }
+ }
+ if (!result.contains(key))
+ result.add(key);
+ }
+
+ return result;
+ }
+
+ /**
+ * Fetch all permissions which are registered with superperms.
+ * {can include child nodes)
+ *
+ * @param includeChildren
+ * @return List of all permission nodes
+ */
+ public List<String> getAllRegisteredPermissions(boolean includeChildren) {
+
+ List<String> perms = new ArrayList<String>();
+
+ for (String key : registeredPermissions.keySet()) {
+ if (!perms.contains(key)) {
+ perms.add(key);
+
+ if (includeChildren) {
+ Map<String, Boolean> children = getAllChildren(key, new HashSet<String>());
+ if (children != null) {
+ for (String node : children.keySet())
+ if (!perms.contains(node))
+ perms.add(node);
+ }
+ }
+ }
+
+ }
+ return perms;
+ }
+
+ /**
+ * Returns a map of ALL child permissions registered with bukkit
+ * null is empty
+ *
+ * @param node
+ * @param playerPermArray current list of perms to check against for
+ * negations
+ * @return Map of child permissions
+ */
+ public Map<String, Boolean> getAllChildren(String node, Set<String> playerPermArray) {
+
+ LinkedList<String> stack = new LinkedList<String>();
+ Map<String, Boolean> alreadyVisited = new HashMap<String, Boolean>();
+ stack.push(node);
+ alreadyVisited.put(node, true);
+
+ while (!stack.isEmpty()) {
+ String now = stack.pop();
+
+ Map<String, Boolean> children = getChildren(now);
+
+ if ((children != null) && (!playerPermArray.contains("-" + now))) {
+ for (String childName : children.keySet()) {
+ if (!alreadyVisited.containsKey(childName)) {
+ stack.push(childName);
+ alreadyVisited.put(childName, children.get(childName));
+ }
+ }
+ }
+ }
+ alreadyVisited.remove(node);
+ if (!alreadyVisited.isEmpty())
+ return alreadyVisited;
+
+ return null;
+ }
+
+ /**
+ * Returns a map of the child permissions (1 node deep) as registered with
+ * Bukkit.
+ * null is empty
+ *
+ * @param node
+ * @return Map of child permissions
+ */
+ public Map<String, Boolean> getChildren(String node) {
+
+ Permission perm = registeredPermissions.get(node.toLowerCase());
+ if (perm == null)
+ return null;
+
+ return perm.getChildren();
+
+ }
+
+ /**
+ * List all effective permissions for this player.
+ *
+ * @param player
+ * @return List<String> of permissions
+ */
+ public List<String> listPerms(Player player) {
+
+ List<String> perms = new ArrayList<String>();
+
+ /*
+ * // All permissions registered with Bukkit for this player
+ * PermissionAttachment attachment = this.attachments.get(player);
+ *
+ * // List perms for this player perms.add("Attachment Permissions:");
+ * for(Map.Entry<String, Boolean> entry :
+ * attachment.getPermissions().entrySet()){ perms.add(" " +
+ * entry.getKey() + " = " + entry.getValue()); }
+ */
+
+ perms.add("Effective Permissions:");
+ for (PermissionAttachmentInfo info : player.getEffectivePermissions()) {
+ if (info.getValue() == true)
+ perms.add(" " + info.getPermission() + " = " + info.getValue());
+ }
+ return perms;
+ }
+
+ /**
+ * force Bukkit to update every OnlinePlayers permissions.
+ */
+ public void updateAllPlayers() {
+
+ for (Player player : Bukkit.getServer().getOnlinePlayers()) {
+ updatePermissions(player);
+ }
+ }
+
+ /**
+ * force Bukkit to update this Players permissions.
+ */
+ public void updatePlayer(Player player) {
+
+ if (player != null)
+ this.updatePermissions(player, null);
+ }
+
+ /**
+ * Force remove any attachments
+ *
+ * @param player
+ */
+ private void removeAttachment(Player player) {
+
+ if (attachments.containsKey(player)) {
+ try {
+ player.removeAttachment(attachments.get(player));
+ } catch (IllegalArgumentException e) {
+ /*
+ * Failed to remove attachment
+ * This usually means Bukkit no longer knows of it.
+ */
+ }
+ attachments.remove(player);
+ }
+ }
+
+ /**
+ * Remove all attachments in case of a restart or reload.
+ */
+ public void removeAllAttachments() {
+
+ Iterator<Player> itr = attachments.keySet().iterator();
+
+ while (itr.hasNext()) {
+ Player player = itr.next();
+ try {
+ player.removeAttachment(attachments.get(player));
+ } catch (IllegalArgumentException e) {
+ /*
+ * Failed to remove attachment
+ * This usually means Bukkit no longer knows of it.
+ */
+ }
+ }
+ attachments.clear();
+ }
+
+ /**
+ * Player events tracked to cause Superperms updates
+ *
+ * @author ElgarL
+ *
+ */
+ protected class PlayerEvents implements Listener {
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ public void onPlayerJoin(PlayerJoinEvent event) {
+
+ setPlayer_join(true);
+ Player player = event.getPlayer();
+
+ /*
+ * Tidy up any lose ends
+ */
+ removeAttachment(player);
+
+ // force GM to create the player if they are not already listed.
+ if (plugin.getWorldsHolder().getWorldData(player.getWorld().getName()).getUser(player.getName()) != null) {
+ setPlayer_join(false);
+ updatePermissions(event.getPlayer());
+ }
+ setPlayer_join(false);
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ public void onPlayerChangeWorld(PlayerChangedWorldEvent event) { // has changed worlds
+
+ updatePermissions(event.getPlayer(), event.getPlayer().getWorld().getName());
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ public void onPlayerKick(PlayerKickEvent event) {
+
+ Player player = event.getPlayer();
+
+ /*
+ * force remove any attachments as bukkit may not
+ */
+ removeAttachment(player);
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ public void onPlayerQuit(PlayerQuitEvent event) {
+
+ if (!GroupManager.isLoaded())
+ return;
+
+ Player player = event.getPlayer();
+
+ /*
+ * force remove any attachments as bukkit may not
+ */
+ removeAttachment(player);
+ }
+ }
+
+ protected class BukkitEvents implements Listener {
+
+ @EventHandler(priority = EventPriority.NORMAL)
+ public void onPluginEnable(PluginEnableEvent event) {
+
+ if (!GroupManager.isLoaded())
+ return;
+
+ collectPermissions();
+ updateAllPlayers();
+ }
+
+ @EventHandler(priority = EventPriority.NORMAL)
+ public void onPluginDisable(PluginDisableEvent event) {
+
+ collectPermissions();
+ // updateAllPlayers();
+ }
+ }
+
+} \ No newline at end of file
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/PermissionsReaderInterface.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/PermissionsReaderInterface.java
new file mode 100644
index 000000000..69f098949
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/PermissionsReaderInterface.java
@@ -0,0 +1,252 @@
+package org.anjocaido.groupmanager.permissions;
+
+//import java.util.Collection;
+//import java.util.Map;
+//import java.util.Set;
+import java.util.List;
+import java.util.Set;
+
+import org.anjocaido.groupmanager.data.Group;
+//import org.anjocaido.groupmanager.data.User;
+import org.bukkit.entity.Player;
+
+/**
+ * Made by Nijikokun. Changed by Gabriel Couto
+ *
+ * This class is intended to *read* permissions from a single world.
+ *
+ * @author Nijikokun
+ * @author Gabriel Couto
+ * @author ElgarL
+ */
+public abstract class PermissionsReaderInterface {
+
+ /**
+ *
+ * @param player
+ * @param string
+ * @return true if has permission
+ */
+ public abstract boolean has(Player player, String string);
+
+ /**
+ *
+ * @param player
+ * @param string
+ * @return true if has permission
+ */
+ public abstract boolean permission(Player player, String string);
+
+ /**
+ *
+ * @param userName
+ * @return group name for this player.
+ */
+ public abstract String getGroup(String userName);
+
+ /**
+ *
+ * @param userName
+ * @param groupName
+ * @return true if in group
+ */
+ public abstract boolean inGroup(String userName, String groupName);
+
+ /**
+ *
+ * @param groupName
+ * @return String of prefix
+ */
+ public abstract String getGroupPrefix(String groupName);
+
+ /**
+ *
+ * @param groupName
+ * @return String of suffix
+ */
+ public abstract String getGroupSuffix(String groupName);
+
+ /**
+ *
+ * @param groupName
+ * @return true if can build
+ */
+ public abstract boolean canGroupBuild(String groupName);
+
+ /**
+ *
+ * @param groupName
+ * @param node
+ * @return String value
+ */
+ public abstract String getGroupPermissionString(String groupName, String node);
+
+ /**
+ *
+ * @param groupName
+ * @param node
+ * @return integer value
+ */
+ public abstract int getGroupPermissionInteger(String groupName, String node);
+
+ /**
+ *
+ * @param groupName
+ * @param node
+ * @return boolean value
+ */
+ public abstract boolean getGroupPermissionBoolean(String groupName, String node);
+
+ /**
+ *
+ * @param groupName
+ * @param node
+ * @return double value
+ */
+ public abstract double getGroupPermissionDouble(String groupName, String node);
+
+ /**
+ *
+ * @param userName
+ * @param node
+ * @return String value
+ */
+ public abstract String getUserPermissionString(String userName, String node);
+
+ /**
+ *
+ * @param userName
+ * @param node
+ * @return integer value
+ */
+ public abstract int getUserPermissionInteger(String userName, String node);
+
+ /**
+ *
+ * @param userName
+ * @param node
+ * @return boolean value
+ */
+ public abstract boolean getUserPermissionBoolean(String userName, String node);
+
+ /**
+ *
+ * @param userName
+ * @param node
+ * @return double value
+ */
+ public abstract double getUserPermissionDouble(String userName, String node);
+
+ /**
+ *
+ * @param userName
+ * @param node
+ * @return String value
+ */
+ public abstract String getPermissionString(String userName, String node);
+
+ /**
+ *
+ * @param userName
+ * @param node
+ * @return integer value
+ */
+ public abstract int getPermissionInteger(String userName, String node);
+
+ /**
+ *
+ * @param userName
+ * @param node
+ * @return boolean value
+ */
+ public abstract boolean getPermissionBoolean(String userName, String node);
+
+ /**
+ *
+ * @param userName
+ * @param node
+ * @return double value
+ */
+ public abstract double getPermissionDouble(String userName, String node);
+
+ /////////////////////////////
+ /**
+ * Gets the appropriate prefix for the user.
+ * This method is a utility method for chat plugins to get the user's prefix
+ * without having to look at every one of the user's ancestors.
+ * Returns an empty string if user has no parent groups.
+ *
+ * @param user Player's name
+ * @return Player's prefix
+ */
+ public abstract String getUserPrefix(String user);
+
+ /**
+ * Gets the appropriate suffix for the user.
+ * This method is a utility method for chat plugins to get the user's suffix
+ * without having to look at every one of the user's ancestors.
+ * Returns an empty string if user has no parent groups.
+ *
+ * @param user Player's name
+ * @return Player's suffix
+ */
+ public abstract String getUserSuffix(String user);
+
+ /**
+ * Returns the group object representing the default group of the given
+ * world.
+ * This method will return null if the object does not exist or the world
+ * has no default group.
+ *
+ * @return Group object representing default world, or null if it doesn't
+ * exist or is not defined.
+ */
+ public abstract Group getDefaultGroup();
+
+ /**
+ * Gets a array of the names of all parent groups in the same world.
+ *
+ * @param name Target user's name
+ * @return An array containing the names of all parent groups (including
+ * ancestors) that are in the same world
+ */
+ public abstract String[] getGroups(String name);
+
+ public abstract String getInfoString(String entryName, String path, boolean isGroup);
+
+ //public abstract String getInfoString(String entryName, String path, boolean isGroup, Comparator<String> comparator);
+
+ public abstract int getInfoInteger(String entryName, String path, boolean isGroup);
+
+ //public abstract int getInfoInteger(String entryName, String path, boolean isGroup, Comparator<Integer> comparator);
+
+ /**
+ * Gets a double from the Info node without inheritance.
+ *
+ * @param entryName
+ * @param path
+ * @param isGroup
+ * @return -1 if not found
+ */
+ public abstract double getInfoDouble(String entryName, String path, boolean isGroup);
+
+ //public abstract double getInfoDouble(String entryName, String path, boolean isGroup, Comparator<Double> comparator);
+
+ public abstract boolean getInfoBoolean(String entryName, String path, boolean isGroup);
+
+ //public abstract boolean getInfoBoolean(String entryName, String path, boolean isGroup, Comparator<Boolean> comparator);
+
+ public abstract void addUserInfo(String name, String path, Object data);
+
+ public abstract void removeUserInfo(String name, String path);
+
+ public abstract void addGroupInfo(String name, String path, Object data);
+
+ public abstract void removeGroupInfo(String name, String path);
+
+ //////////////////////////////
+
+ public abstract List<String> getAllPlayersPermissions(String userName);
+
+ public abstract Set<String> getAllPlayersPermissions(String userName, Boolean includeChildren);
+}
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/GMLoggerHandler.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/GMLoggerHandler.java
new file mode 100644
index 000000000..de5348b17
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/GMLoggerHandler.java
@@ -0,0 +1,27 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anjocaido.groupmanager.utils;
+
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+/**
+ *
+ * @author gabrielcouto
+ */
+public class GMLoggerHandler extends ConsoleHandler {
+
+ @Override
+ public void publish(LogRecord record) {
+
+ String message = "GroupManager - " + record.getLevel() + " - " + record.getMessage();
+ if (record.getLevel().equals(Level.SEVERE) || record.getLevel().equals(Level.WARNING)) {
+ System.err.println(message);
+ } else {
+ System.out.println(message);
+ }
+ }
+}
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/GroupManagerPermissions.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/GroupManagerPermissions.java
new file mode 100644
index 000000000..4a7298b9c
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/GroupManagerPermissions.java
@@ -0,0 +1,53 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anjocaido.groupmanager.utils;
+
+/**
+ * Just a list of commands for this plugin
+ *
+ * @author gabrielcouto
+ */
+public enum GroupManagerPermissions {
+
+ manuadd,
+ manudel,
+ manuaddsub,
+ manudelsub,
+ mangadd,
+ mangdel,
+ manuaddp,
+ manudelp,
+ manulistp,
+ manucheckp,
+ mangaddp,
+ mangdelp,
+ manglistp,
+ mangcheckp,
+ mangaddi,
+ mangdeli,
+ manuaddv,
+ manudelv,
+ manulistv,
+ manucheckv,
+ mangaddv,
+ mangdelv,
+ manglistv,
+ mangcheckv,
+ manwhois,
+ tempadd,
+ tempdel,
+ templist,
+ tempdelall,
+ mansave,
+ manload,
+ listgroups,
+ manpromote,
+ mandemote,
+ mantogglevalidate,
+ mantogglesave,
+ manworld,
+ manselect,
+ manclear
+}
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/PermissionCheckResult.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/PermissionCheckResult.java
new file mode 100644
index 000000000..eb6633863
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/PermissionCheckResult.java
@@ -0,0 +1,67 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anjocaido.groupmanager.utils;
+
+import org.anjocaido.groupmanager.data.DataUnit;
+
+/**
+ *
+ * @author gabrielcouto
+ */
+public class PermissionCheckResult {
+
+ /**
+ * It should be the owner of the access level found.
+ *
+ * Use instanceof to find the owner type
+ */
+ public DataUnit owner;
+ /**
+ * The permission node found in the DataUnit.
+ */
+ public String accessLevel;
+ /**
+ * The full name of the permission you are looking for
+ */
+ public String askedPermission;
+ /**
+ * The result conclusion of the search.
+ * It determines if the owner can do, or not.
+ *
+ * It even determines if it has an owner.
+ */
+ public Type resultType = Type.NOTFOUND;
+
+ /**
+ * The type of result the search can give.
+ */
+ public enum Type {
+
+ /**
+ * If found a matching node starting with '+'.
+ * It means the user CAN do the permission.
+ */
+ EXCEPTION,
+ /**
+ * If found a matching node starting with '-'.
+ * It means the user CANNOT do the permission.
+ */
+ NEGATION,
+ /**
+ * If just found a common matching node.
+ * IT means the user CAN do the permission.
+ */
+ FOUND,
+ /**
+ * If no matchin node was found.
+ * It means the user CANNOT do the permission.
+ *
+ * owner field and accessLevel field should not be considered,
+ * when type is
+ * NOTFOUND
+ */
+ NOTFOUND
+ }
+}
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/StringPermissionComparator.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/StringPermissionComparator.java
new file mode 100644
index 000000000..5a56cd9fc
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/StringPermissionComparator.java
@@ -0,0 +1,52 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anjocaido.groupmanager.utils;
+
+import java.util.Comparator;
+
+/**
+ *
+ * @author gabrielcouto
+ */
+public class StringPermissionComparator implements Comparator<String> {
+
+ @Override
+ public int compare(String permA, String permB) {
+
+ boolean ap = permA.startsWith("+");
+ boolean bp = permB.startsWith("+");
+ boolean am = permA.startsWith("-");
+ boolean bm = permB.startsWith("-");
+ if (ap && bp) {
+ return 0;
+ }
+ if (ap && !bp) {
+ return -1;
+ }
+ if (!ap && bp) {
+ return 1;
+ }
+ if (am && bm) {
+ return 0;
+ }
+ if (am && !bm) {
+ return -1;
+ }
+ if (!am && bm) {
+ return 1;
+ }
+ return permA.compareToIgnoreCase(permB);
+ }
+
+ private static StringPermissionComparator instance;
+
+ public static StringPermissionComparator getInstance() {
+
+ if (instance == null) {
+ instance = new StringPermissionComparator();
+ }
+ return instance;
+ }
+}
diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/Tasks.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/Tasks.java
new file mode 100644
index 000000000..d75737c66
--- /dev/null
+++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/Tasks.java
@@ -0,0 +1,175 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anjocaido.groupmanager.utils;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.List;
+
+import org.anjocaido.groupmanager.GroupManager;
+import org.anjocaido.groupmanager.data.Group;
+
+/**
+ *
+ * @author gabrielcouto
+ */
+public abstract class Tasks {
+
+ /**
+ * Gets the exception stack trace as a string.
+ *
+ * @param exception
+ * @return stack trace as a string
+ */
+ public static String getStackTraceAsString(Exception exception) {
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ exception.printStackTrace(pw);
+ return sw.toString();
+ }
+
+ public static void copy(InputStream src, File dst) throws IOException {
+
+ InputStream in = src;
+ OutputStream out = new FileOutputStream(dst);
+
+ // Transfer bytes from in to out
+ byte[] buf = new byte[1024];
+ int len;
+ while ((len = in.read(buf)) > 0) {
+ out.write(buf, 0, len);
+ }
+ out.close();
+ try {
+ in.close();
+ } catch (Exception e) {
+ }
+ }
+
+ public static void copy(File src, File dst) throws IOException {
+
+ InputStream in = new FileInputStream(src);
+ copy(in, dst);
+ }
+
+ /**
+ * Appends a string to a file
+ *
+ * @param data
+ * @param file
+ */
+ public static void appendStringToFile(String data, String file) throws IOException {
+
+ FileWriter outStream = new FileWriter("." + System.getProperty("file.separator") + file, true);
+
+ BufferedWriter out = new BufferedWriter(outStream);
+
+ data.replaceAll("\n", System.getProperty("line.separator"));
+
+ out.append(new SimpleDateFormat("yyyy-MM-dd HH-mm").format(System.currentTimeMillis()));
+ out.append(System.getProperty("line.separator"));
+ out.append(data);
+ out.append(System.getProperty("line.separator"));
+
+ out.close();
+ }
+
+ public static void removeOldFiles(GroupManager gm, File folder) {
+
+ if (folder.isDirectory()) {
+ long oldTime = System.currentTimeMillis() - (((long) gm.getGMConfig().getBackupDuration() * 60 * 60) * 1000);
+ for (File olds : folder.listFiles()) {
+ if (olds.isFile()) {
+ if (olds.lastModified() < oldTime) {
+ try {
+ olds.delete();
+ } catch (Exception e) {
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public static String getDateString() {
+
+ GregorianCalendar now = new GregorianCalendar();
+ String date = "";
+ date += now.get(Calendar.DAY_OF_MONTH);
+ date += "-";
+ date += now.get(Calendar.HOUR);
+ date += "-";
+ date += now.get(Calendar.MINUTE);
+ return date;
+ }
+
+ public static String getStringListInString(List<String> list) {
+
+ if (list == null) {
+ return "";
+ }
+ String result = "";
+ for (int i = 0; i < list.size(); i++) {
+ result += list.get(i);
+ if (i < list.size() - 1) {
+ result += ", ";
+ }
+ }
+ return result;
+ }
+
+ public static String getStringArrayInString(String[] list) {
+
+ if (list == null) {
+ return "";
+ }
+ String result = "";
+ for (int i = 0; i < list.length; i++) {
+ result += list[i];
+ if (i < ((list.length) - 1)) {
+ result += ", ";
+ }
+ }
+ return result;
+ }
+
+ public static String getGroupListInString(List<Group> list) {
+
+ if (list == null) {
+ return "";
+ }
+ String result = "";
+ for (int i = 0; i < list.size(); i++) {
+ result += list.get(i).getName();
+ if (i < list.size() - 1) {
+ result += ", ";
+ }
+ }
+ return result;
+ }
+
+ public static String join(String[] arr, String separator) {
+
+ if (arr.length == 0)
+ return "";
+ String out = arr[0].toString();
+ for (int i = 1; i < arr.length; i++)
+ out += separator + arr[i];
+ return out;
+ }
+
+}
diff --git a/EssentialsGroupManager/src/plugin.yml b/EssentialsGroupManager/src/plugin.yml
new file mode 100644
index 000000000..f7faa5896
--- /dev/null
+++ b/EssentialsGroupManager/src/plugin.yml
@@ -0,0 +1,171 @@
+name: GroupManager
+version: GMBuildVer (Phoenix)
+main: org.anjocaido.groupmanager.GroupManager
+website: http://ess.khhq.net/wiki/Group_Manager
+description: Provides on-the-fly system for permissions system created by Nijikokun. But all in memory, and with flat-file saving schedule.
+authors:
+ - AnjoCaido
+ - Gabriel Couto
+ - ElgarL
+commands:
+ manuadd:
+ description: Move a player to desired group.(Adds to the file if not exists)
+ usage: /<command> <player> <group> | optional [world]
+ permissions: groupmanager.manuadd
+ manudel:
+ description: Remove any user specific configuration. Make him default group.
+ usage: /<command> <player>
+ permissions: groupmanager.manudel
+ manuaddsub:
+ description: Add a group to a player's subgroup list.
+ usage: /<command> <player> <group>
+ permissions: groupmanager.manuaddsub
+ manudelsub:
+ description: Remove a group to a player's subgroup list.
+ usage: /<command> <player> <group>
+ permissions: groupmanager.manudelsub
+ mangadd:
+ description: Add group to the system.
+ usage: /<command> <group>
+ permissions: groupmanager.mangadd
+ mangdel:
+ description: Removes group from the system(all it's users become default)
+ usage: /<command> <group>
+ permissions: groupmanager.mangdel
+ manuaddp:
+ description: Add permissions diretly to the player.
+ usage: /<command> <player> <permissions>
+ permissions: groupmanager.manuaddp
+ manudelp:
+ description: Removes permissions diretly from the player.
+ usage: /<command> <player> <permissions>
+ permissions: groupmanager.manudelp
+ manulistp:
+ description: List all permissionss from a player.
+ usage: /<command> <player>
+ permissions: groupmanager.manulistp
+ manucheckp:
+ description: Verify if user has a permissions, and where it comes from.
+ usage: /<command> <player> <permissions>
+ permissions: groupmanager.manucheckp
+ mangaddp:
+ description: Add permissions to a group.
+ usage: /<command> <group> <permissions>
+ permissions: groupmanager.mangaddp
+ mangdelp:
+ description: Removes permissions from a group.
+ usage: /<command> <group> <permissions>
+ permissions: groupmanager.mangdelp
+ manglistp:
+ description: Lists all permissionss from a group.
+ usage: /<command> <group>
+ permissions: groupmanager.manglistp
+ mangcheckp:
+ description: Check if group has a permissions, and where it comes from.
+ usage: /<command> <group> <permissions>
+ permissions: groupmanager.mangcheckp
+ mangaddi:
+ description: Add a group to another group inheritance list.
+ usage: /<command> <group1> <group2>
+ permissions: groupmanager.mangaddi
+ mangdeli:
+ description: Remove a group from another group inheritance list.
+ usage: /<command> <group1> <group2>
+ permissions: groupmanager.mangdeli
+ manuaddv:
+ description: Add, or replaces, a variable to a user (like prefix or suffix).
+ usage: /<command> <user> <variable> <value>
+ permissions: groupmanager.manuaddv
+ manudelv:
+ description: Remove a variable from a user.
+ usage: /<command> <user> <variable>
+ permissions: groupmanager.manudelv
+ manulistv:
+ description: List variables a user has (like prefix or suffix).
+ usage: /<command> <user>
+ permissions: groupmanager.manulistv
+ manucheckv:
+ description: Verify a value of a variable of user, and where it comes from.
+ usage: /<command> <user> <variable>
+ permissions: groupmanager.manucheckv
+ mangaddv:
+ description: Add, or replaces, a variable to a group (like prefix or suffix).
+ usage: /<command> <group> <variable> <value>
+ permissions: groupmanager.mangaddv
+ mangdelv:
+ description: Remove a variable from a group.
+ usage: /<command> <group> <variable>
+ permissions: groupmanager.mangdelv
+ manglistv:
+ description: List variables a group has (like prefix or suffix).
+ usage: /<command> <group>
+ permissions: groupmanager.manglistv
+ mangcheckv:
+ description: Verify a value of a variable of group, and where it comes from.
+ usage: /<command> <group> <variable>
+ permissions: groupmanager.mangckeckv
+ manwhois:
+ description: Tell the group that user belongs.
+ usage: /<command> <player>
+ permissions: groupmanager.manwhois
+ tempadd:
+ description: Creates a temporary permissions copy for that user.
+ usage: /<command> <player>
+ permissions: groupmanager.tempadd
+ tempdel:
+ description: Remove the temporary permissions copy for player.
+ usage: /<command> <player>
+ permissions: groupmanager.tempdel
+ templist:
+ description: List players in overload-permissionss mode made by /tempadd.
+ usage: /<command>
+ permissions: groupmanager.templist
+ tempdelall:
+ description: Remove all overrides made by command /tempadd.
+ usage: /<command>
+ permissions: groupmanager.tempdelall
+ mansave:
+ description: Save all permissionss on file.
+ usage: /<command>
+ permissions: groupmanager.mansave
+ manload:
+ description: Reload current world and config.yml. Or load given world.
+ usage: /<command> [world]
+ permissions: groupmanager.manload
+ listgroups:
+ description: List the groups available.
+ usage: /<command>
+ permissions: groupmanager.listgroups
+ manpromote:
+ description: Promote a player in the same heritage line to a higher rank.
+ usage: /<command> <player> <group>
+ permissions: groupmanager.manpromote
+ mandemote:
+ description: Demote a player in the same heritage line to a lower rank.
+ usage: /<command> <player> <group>
+ permissions: groupmanager.mandemote
+ mantogglevalidate:
+ description: Toggle on/off the validating if player is online.
+ usage: /<command>
+ permissions: groupmanager.mantogglevalidate
+ mantogglesave:
+ description: Toggle on/ff the autosave.
+ usage: /<command>
+ permissions: groupmanager.mantogglesave
+ manworld:
+ description: Prints the selected world name
+ usage: /<command>
+ permissions: groupmanager.manworld
+ manselect:
+ description: Select a world to work with next commands.
+ usage: /<command> <world>
+ permissions: groupmanager.manselect
+ manclear:
+ description: Clear world selection. Next commands will work on your world.
+ usage: /<command>
+ permissions: groupmanager.manclear
+
+Permissions:
+ groupmanager.op:
+ description: User is treated as an op when using the GroupManager commands.
+ default: false \ No newline at end of file
diff --git a/EssentialsGroupManager/src/users.yml b/EssentialsGroupManager/src/users.yml
new file mode 100644
index 000000000..72a7b652f
--- /dev/null
+++ b/EssentialsGroupManager/src/users.yml
@@ -0,0 +1,15 @@
+# "For a more advanced configuration example utilizing the advanced features of GroupManager, see http://pastebin.com/a8ZA0j5G"
+users:
+ snowleo:
+ subgroups: []
+ permissions: []
+ group: Builder
+ KHobbits:
+ subgroups: []
+ permissions: []
+ group: Moderator
+ ElgarL:
+ subgroups: []
+ permissions: []
+ group: Moderator
+