1
0
mirror of https://github.com/essentials/Essentials.git synced 2025-09-06 20:50:46 +02:00

Compare commits

...

64 Commits

Author SHA1 Message Date
ElgarL
02c6780476 Release the Player object reference on quit. 2014-10-15 09:39:23 +01:00
ElgarL
2526f559ff Merge pull request #766 from necrodoom/patch-133
Fix error message typo
2014-10-03 08:42:46 +01:00
Necrodoom
9818df3039 Fix error message typo 2014-10-03 10:30:53 +03:00
ElgarL
c843a329bd Update WorldDataHolder.java
Set Primary group before sub group on loading else the subgroup tests default.
2014-10-03 08:25:04 +01:00
ElgarL
4fb96aa586 Merge pull request #740 from necrodoom/patch-119
Remove null check
2014-07-24 13:38:00 +01:00
Necrodoom
a11daafb0d Remove null check
Match can never be null
2014-07-24 12:58:23 +03:00
ElgarL
c6dfa741c1 Case sensitive works, so make all Users names case insensitive as no duplicate names will be allowed. 2014-07-20 13:46:59 +01:00
ElgarL
e36f26e185 All User lookups should be case sensitive. 2014-07-19 04:10:35 +01:00
ElgarL
4b20b6a93a Perform case sensitive name checks on plugin requests. 2014-07-19 04:04:20 +01:00
ElgarL
cdd5df0c0a Debug logging on Name to UUID lookup. 2014-07-19 02:21:34 +01:00
ElgarL
d3be04c81a Merge branch 'groupmanager' of https://github.com/essentials/Essentials into groupmanager 2014-07-19 00:08:00 +01:00
ElgarL
e6049b0818 Add FINE debug on user login. 2014-07-19 00:05:50 +01:00
ElgarL
2e04dbf7be Merge pull request #736 from necrodoom/patch-117
Remove unneeded negation
2014-07-17 11:25:04 +01:00
Necrodoom
bd210309b2 Add exception node example
Readd toggle effect options
2014-07-17 12:49:40 +03:00
Necrodoom
d7c9a8742d Change vanish negation in groups.yml
Instead of negating all vanish perms, negate forced effects
2014-07-17 12:48:08 +03:00
Necrodoom
7b63aab562 Remove unneeded negation
No vanish perms are default given
2014-07-17 12:45:32 +03:00
ElgarL
2c9feadf1d Fix 'manudel' so it correctly deletes the user. 2014-07-17 10:40:28 +01:00
ElgarL
bd72eee559 Prevent inherited group permission negations overriding higher level group perms. 2014-07-17 10:37:58 +01:00
ElgarL
d32c692b66 Fix Overloaded and non-overloaded users to report correctly for group tests. 2014-07-08 18:03:21 +01:00
ElgarL
4097ef4939 Remove debug spam.
Stop using WeakHashMap in BukkitPermissions as using it with string keys results in unreliable removal.
2014-06-21 09:09:20 +01:00
ElgarL
3137c9ae10 Ensure GM reports the same permissions as Bukkit. 2014-06-20 22:33:25 +01:00
ElgarL
194de920cf Fix attachments not being reset between worlds. 2014-06-20 21:48:44 +01:00
ElgarL
9a55d32b75 Convert all User lookups and commands to use UUIDs where possible. 2014-06-20 10:56:52 +01:00
ElgarL
d86d72eeb7 Prevent NPEs on new user creation. 2014-06-20 08:51:41 +01:00
ElgarL
f336e54b67 Prevent plugins which run their PlayerJoinEvent too early from breaking the name to UUID lookups.
No plugin bar permission plugins shoud be running on Lowest for the PlayerJoinEvent
2014-06-19 21:40:01 +01:00
ElgarL
2e0a1dde85 Fix NPE when adding name to UUID key before the name has been set. 2014-06-19 17:29:20 +01:00
ElgarL
e862e3c87b Add internal name to UUID resolution to speed data lookups. 2014-06-19 07:59:20 +01:00
ElgarL
d9fdf3bdf6 Merge pull request #708 from necrodoom/patch-105
[REPULL] Fix successful message color
2014-05-28 11:56:11 +01:00
ElgarL
34a323125f Prevent GM's own permission tests from allowing inherited permissions to override inherited negations (caused when we added the exception override for sub groups). 2014-05-28 02:03:51 +01:00
ElgarL
f03e41536b Added metrics. 2014-05-15 19:07:04 +01:00
ElgarL
9c3d965371 Error in logic 2014-05-04 17:10:37 +01:00
ElgarL
578aec35eb Prevent players who have never logged in before from taking over existing accounts. 2014-05-04 16:17:31 +01:00
ElgarL
a8ad83fb0b Merge branch 'groupmanager' of https://github.com/essentials/Essentials into groupmanager 2014-05-04 16:13:02 +01:00
Necrodoom
6779c9f0d3 [REPULL] Fix successful message color 2014-05-04 16:33:20 +03:00
ElgarL
69faf87866 Fix clones forgetting sub groups. 2014-04-29 00:22:51 +01:00
ElgarL
e1631b2af8 Set a default mirror map if none is found in the config. 2014-04-27 23:55:20 +01:00
ElgarL
50d3486d35 Fix overloadedWorldHolder so it correctly calls the new WorldHolder code when the user is not overloaded. 2014-04-14 23:40:04 +01:00
ElgarL
4f2ed6fe11 Fixup javadocs 2014-04-14 22:23:47 +01:00
ElgarL
6cc0edb89a v2.1:
- Update for CraftBukkit 1.7.8-R0.1(3050).
	- Add UUID support.
	  Plugins can still query by player name but a UUID is faster and preferable.
2014-04-14 22:19:14 +01:00
ElgarL
e00ee62f75 Do not override higher level permissions with negations. 2014-03-27 12:55:01 +00:00
ElgarL
22ff49a0b8 Merge pull request #689 from necrodoom/patch-102
Fix a /mangcheckp message
2014-03-27 12:35:38 +00:00
Necrodoom
14c764e049 Fix a /mangcheckp message 2014-03-27 13:02:34 +02:00
ElgarL
ec5496ad18 Update mangcheckp to understand Exception nodes. 2014-03-27 03:55:58 +00:00
ElgarL
020f0b2ad6 Fix manucheckp to understand and report correctly on Exception nodes. 2014-03-27 03:48:20 +00:00
ElgarL
8e59c47200 Allow Exceptions in any inherited group to override negation of permissions. 2014-03-27 01:50:00 +00:00
ElgarL
3440a22d6d Merge pull request #626 from necrodoom/patch-76
Update plugin.yml
2014-01-07 07:18:25 -08:00
Necrodoom
bca9bf5099 Update plugin.yml 2013-12-25 20:25:10 +02:00
ElgarL
69e1583bac Merge pull request #606 from necrodoom/patch-66
fix typo in node
2013-12-08 06:32:47 -08:00
Necrodoom
752cec8f13 fix typo in node 2013-12-08 15:02:48 +02:00
ElgarL
a66b9a3ee4 Prevent adding sub groups for ranks the granting player doesn't have access to. 2013-10-31 11:40:12 +00:00
ElgarL
ea824b26f4 Fix Typo. 2013-07-28 09:10:23 +01:00
ElgarL
7b0d3d49f1 Allow Exception permission to override negations when in the same group. 2013-07-22 13:29:06 +01:00
ElgarL
00cc13ce1a Change to use LinkedHashSets to preserve ordering.
Fixes an issue with populating bukkit perms in the wrong order.
Fix wildcard negation in parent groups.
2013-07-22 13:02:24 +01:00
ElgarL
132d56760b Fix Cyclic mirroring test (silly me) 2013-07-08 16:01:34 +01:00
ElgarL
32b466bb3b Tidy imports 2013-06-14 08:47:10 +01:00
ElgarL
0041492f42 Merge pull request #487 from necrodoom/patch-20
add recursive permission adding/removing
2013-06-14 00:39:58 -07:00
Necrodoom
27d88a6c56 remove excess return false lines since elgarl doesnt like them 2013-06-14 10:38:54 +03:00
Necrodoom
981d620349 fix javadoc 2013-06-14 10:34:55 +03:00
Necrodoom
c902155d6e change checkPermissionExists to how Elgarl wants it 2013-06-14 10:30:03 +03:00
Necrodoom
6ea835e96f change ' strip checks 2013-06-14 10:25:41 +03:00
Necrodoom
5fdac7588e Update Changelog.txt 2013-06-14 10:01:39 +03:00
Necrodoom
9e7320ad16 Update plugin.yml 2013-06-14 10:00:43 +03:00
Necrodoom
8dc79c2d37 add recursive permission adding/removing
also other minor fixes
2013-06-14 10:00:11 +03:00
ElgarL
4da70254ff Check subgroup permissions with an equal priority so no one subgroup is higher ranked than another. 2013-05-22 10:37:24 +01:00
10 changed files with 1492 additions and 600 deletions

View File

@@ -229,4 +229,12 @@ v2.1:
- Add UUID support. - Add UUID support.
Plugins can still query by player name but a UUID is faster and preferable. Plugins can still query by player name but a UUID is faster and preferable.
- Set a default mirror map if none is found in the config. - Set a default mirror map if none is found in the config.
- Fix clones forgetting sub groups. - Fix clones forgetting sub groups.
- Prevent players who have never logged in before from taking over existing accounts.
- Added metrics.
- Prevent GM's own permission tests from allowing inherited permissions to override inherited negations (caused when we added the exception override for sub groups).
- Add internal name to UUID resolution to speed data lookups.
- Convert all User lookups and commands to use UUIDs where possible.
- Fix Overloaded and non-overloaded users to report correctly for group tests.
- Prevent inherited group permission negations overriding higher level group perms.
- Fix 'manudel' so it correctly deletes the user.

View File

@@ -313,7 +313,6 @@ groups:
g:vanish_moderator: g:vanish_moderator:
permissions: permissions:
- -vanish.*
- vanish.vanish - vanish.vanish
- vanish.smokin - vanish.smokin
- vanish.nofollow - vanish.nofollow
@@ -326,4 +325,4 @@ groups:
permissions: permissions:
- vanish.silentjoin - vanish.silentjoin
- vanish.silentquit - vanish.silentquit
- vanish.silentchests - vanish.silentchests

View File

@@ -65,7 +65,8 @@ groups:
default: false default: false
permissions: permissions:
- '*' - '*'
- -vanish.* - -vanish.effects.*
- +vanish.effects.toggle.all
inheritance: inheritance:
- admin - admin
info: info:

View File

@@ -12,6 +12,7 @@ import org.anjocaido.groupmanager.data.Variables;
import org.anjocaido.groupmanager.data.User; import org.anjocaido.groupmanager.data.User;
import org.anjocaido.groupmanager.data.Group; import org.anjocaido.groupmanager.data.Group;
import org.anjocaido.groupmanager.dataholder.OverloadedWorldHolder; import org.anjocaido.groupmanager.dataholder.OverloadedWorldHolder;
import org.anjocaido.groupmanager.metrics.Metrics;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@@ -84,6 +85,17 @@ public class GroupManager extends JavaPlugin {
@Override @Override
public void onEnable() { public void onEnable() {
/*
* Register Metrics
*/
try {
Metrics metrics = new Metrics(this);
metrics.start();
} catch (IOException e) {
System.err.println("[GroupManager] Error setting up metrics");
}
/* /*
* Initialize the event handler * Initialize the event handler
*/ */
@@ -405,7 +417,7 @@ public class GroupManager extends JavaPlugin {
return true; return true;
} }
senderUser = worldsHolder.getWorldData(senderPlayer).getUser(senderPlayer.getName()); senderUser = worldsHolder.getWorldData(senderPlayer).getUser(senderPlayer.getUniqueId().toString());
senderGroup = senderUser.getGroup(); senderGroup = senderUser.getGroup();
isOpOverride = (isOpOverride && (senderPlayer.isOp() || worldsHolder.getWorldPermissions(senderPlayer).has(senderPlayer, "groupmanager.op"))); isOpOverride = (isOpOverride && (senderPlayer.isOp() || worldsHolder.getWorldPermissions(senderPlayer).has(senderPlayer, "groupmanager.op")));
@@ -522,7 +534,7 @@ public class GroupManager extends JavaPlugin {
} }
// Validating permissions // Validating permissions
if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getUUID(), senderGroup.getName()) : false)) {
sender.sendMessage(ChatColor.RED + "Can't modify a player with the same permissions as you, or higher."); sender.sendMessage(ChatColor.RED + "Can't modify a player with the same permissions as you, or higher.");
return true; return true;
} }
@@ -530,7 +542,7 @@ public class GroupManager extends JavaPlugin {
sender.sendMessage(ChatColor.RED + "The destination group can't be the same as yours, or higher."); sender.sendMessage(ChatColor.RED + "The destination group can't be the same as yours, or higher.");
return true; return true;
} }
if (!isConsole && !isOpOverride && (!permissionHandler.inGroup(senderUser.getLastName(), auxUser.getGroupName()) || !permissionHandler.inGroup(senderUser.getLastName(), auxGroup.getName()))) { if (!isConsole && !isOpOverride && (!permissionHandler.inGroup(senderUser.getUUID(), auxUser.getGroupName()) || !permissionHandler.inGroup(senderUser.getUUID(), auxGroup.getName()))) {
sender.sendMessage(ChatColor.RED + "You can't modify a player involving a group that you don't inherit."); sender.sendMessage(ChatColor.RED + "You can't modify a player involving a group that you don't inherit.");
return true; return true;
} }
@@ -563,12 +575,12 @@ public class GroupManager extends JavaPlugin {
auxUser = dataHolder.getUser(args[0]); auxUser = dataHolder.getUser(args[0]);
} }
// Validating permission // Validating permission
if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getUUID(), senderGroup.getName()) : false)) {
sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher."); sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher.");
return true; return true;
} }
// Seems OK // Seems OK
dataHolder.removeUser(auxUser.getLastName()); dataHolder.removeUser(auxUser.getUUID());
sender.sendMessage(ChatColor.YELLOW + "You changed player '" + auxUser.getLastName() + "' to default settings."); sender.sendMessage(ChatColor.YELLOW + "You changed player '" + auxUser.getLastName() + "' to default settings.");
// If the player is online, this will create new data for the user. // If the player is online, this will create new data for the user.
@@ -607,7 +619,7 @@ public class GroupManager extends JavaPlugin {
return true; return true;
} }
// Validating permission // Validating permission
if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getUUID(), senderGroup.getName()) : false)) {
sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher."); sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher.");
return true; return true;
} }
@@ -615,7 +627,7 @@ public class GroupManager extends JavaPlugin {
sender.sendMessage(ChatColor.RED + "The sub-group can't be the same as yours, or higher."); sender.sendMessage(ChatColor.RED + "The sub-group can't be the same as yours, or higher.");
return true; return true;
} }
if (!isConsole && !isOpOverride && (!permissionHandler.inGroup(senderUser.getLastName(), auxUser.getGroupName()) || !permissionHandler.inGroup(senderUser.getLastName(), auxGroup.getName()))) { if (!isConsole && !isOpOverride && (!permissionHandler.inGroup(senderUser.getUUID(), auxUser.getGroupName()) || !permissionHandler.inGroup(senderUser.getUUID(), auxGroup.getName()))) {
sender.sendMessage(ChatColor.RED + "You can't modify a player involving a group that you don't inherit."); sender.sendMessage(ChatColor.RED + "You can't modify a player involving a group that you don't inherit.");
return true; return true;
} }
@@ -654,7 +666,7 @@ public class GroupManager extends JavaPlugin {
} }
// Validating permission // Validating permission
if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getUUID(), senderGroup.getName()) : false)) {
sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher."); sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher.");
return true; return true;
} }
@@ -737,7 +749,7 @@ public class GroupManager extends JavaPlugin {
} }
// Validating your permissions // Validating your permissions
if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getUUID(), senderGroup.getName()) : false)) {
sender.sendMessage(ChatColor.RED + "Can't modify player with same group than you, or higher."); sender.sendMessage(ChatColor.RED + "Can't modify player with same group than you, or higher.");
return true; return true;
} }
@@ -795,7 +807,7 @@ public class GroupManager extends JavaPlugin {
{ {
auxString = args[i].replace("'", ""); auxString = args[i].replace("'", "");
if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getUUID(), senderGroup.getName()) : false)) {
sender.sendMessage(ChatColor.RED + "You can't modify a player with same group as you, or higher."); sender.sendMessage(ChatColor.RED + "You can't modify a player with same group as you, or higher.");
continue; continue;
} }
@@ -849,7 +861,7 @@ public class GroupManager extends JavaPlugin {
auxUser = dataHolder.getUser(args[0]); auxUser = dataHolder.getUser(args[0]);
} }
// Validating your permissions // Validating your permissions
if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getUUID(), senderGroup.getName()) : false)) {
sender.sendMessage(ChatColor.RED + "You can't modify a player with same group as you, or higher."); sender.sendMessage(ChatColor.RED + "You can't modify a player with same group as you, or higher.");
return true; return true;
} }
@@ -1247,7 +1259,7 @@ public class GroupManager extends JavaPlugin {
} }
// Seems OK // Seems OK
auxGroup.addInherits(auxGroup2); auxGroup.addInherits(auxGroup2);
sender.sendMessage(ChatColor.RED + "Group " + auxGroup2.getName() + " is now in " + auxGroup.getName() + " inheritance list."); sender.sendMessage(ChatColor.YELLOW + "Group " + auxGroup2.getName() + " is now in " + auxGroup.getName() + " inheritance list.");
BukkitPermissions.updateAllPlayers(); BukkitPermissions.updateAllPlayers();
@@ -1281,16 +1293,16 @@ public class GroupManager extends JavaPlugin {
// Validating permission // Validating permission
if (!permissionHandler.hasGroupInInheritance(auxGroup, auxGroup2.getName())) { if (!permissionHandler.hasGroupInInheritance(auxGroup, auxGroup2.getName())) {
sender.sendMessage(ChatColor.RED + "Group " + auxGroup.getName() + " does not inherits " + auxGroup2.getName() + "."); sender.sendMessage(ChatColor.RED + "Group " + auxGroup.getName() + " does not inherit " + auxGroup2.getName() + ".");
return true; return true;
} }
if (!auxGroup.getInherits().contains(auxGroup2.getName())) { if (!auxGroup.getInherits().contains(auxGroup2.getName())) {
sender.sendMessage(ChatColor.RED + "Group " + auxGroup.getName() + " does not inherits " + auxGroup2.getName() + " directly."); sender.sendMessage(ChatColor.RED + "Group " + auxGroup.getName() + " does not inherit " + auxGroup2.getName() + " directly.");
return true; return true;
} }
// Seems OK // Seems OK
auxGroup.removeInherits(auxGroup2.getName()); auxGroup.removeInherits(auxGroup2.getName());
sender.sendMessage(ChatColor.RED + "Group " + auxGroup2.getName() + " was removed from " + auxGroup.getName() + " inheritance list."); sender.sendMessage(ChatColor.YELLOW + "Group " + auxGroup2.getName() + " was removed from " + auxGroup.getName() + " inheritance list.");
BukkitPermissions.updateAllPlayers(); BukkitPermissions.updateAllPlayers();
@@ -1620,8 +1632,8 @@ public class GroupManager extends JavaPlugin {
sender.sendMessage(ChatColor.YELLOW + "subgroups: " + auxString); sender.sendMessage(ChatColor.YELLOW + "subgroups: " + auxString);
} }
sender.sendMessage(ChatColor.YELLOW + "Overloaded: " + ChatColor.GREEN + dataHolder.isOverloaded(auxUser.getLastName())); sender.sendMessage(ChatColor.YELLOW + "Overloaded: " + ChatColor.GREEN + dataHolder.isOverloaded(auxUser.getUUID()));
auxGroup = dataHolder.surpassOverload(auxUser.getLastName()).getGroup(); auxGroup = dataHolder.surpassOverload(auxUser.getUUID()).getGroup();
if (!auxGroup.equals(auxUser.getGroup())) { if (!auxGroup.equals(auxUser.getGroup())) {
sender.sendMessage(ChatColor.YELLOW + "Original Group: " + ChatColor.GREEN + auxGroup.getName()); sender.sendMessage(ChatColor.YELLOW + "Original Group: " + ChatColor.GREEN + auxGroup.getName());
} }
@@ -1648,7 +1660,7 @@ public class GroupManager extends JavaPlugin {
auxUser = dataHolder.getUser(args[0]); auxUser = dataHolder.getUser(args[0]);
} }
// Validating permission // Validating permission
if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getUUID(), senderGroup.getName()) : false)) {
sender.sendMessage(ChatColor.RED + "Can't modify player with same permissions than you, or higher."); sender.sendMessage(ChatColor.RED + "Can't modify player with same permissions than you, or higher.");
return true; return true;
} }
@@ -1656,8 +1668,8 @@ public class GroupManager extends JavaPlugin {
if (overloadedUsers.get(dataHolder.getName().toLowerCase()) == null) { if (overloadedUsers.get(dataHolder.getName().toLowerCase()) == null) {
overloadedUsers.put(dataHolder.getName().toLowerCase(), new ArrayList<User>()); overloadedUsers.put(dataHolder.getName().toLowerCase(), new ArrayList<User>());
} }
dataHolder.overloadUser(auxUser.getLastName()); dataHolder.overloadUser(auxUser.getUUID());
overloadedUsers.get(dataHolder.getName().toLowerCase()).add(dataHolder.getUser(auxUser.getLastName())); overloadedUsers.get(dataHolder.getName().toLowerCase()).add(dataHolder.getUser(auxUser.getUUID()));
sender.sendMessage(ChatColor.YELLOW + "Player set to overload mode!"); sender.sendMessage(ChatColor.YELLOW + "Player set to overload mode!");
return true; return true;
@@ -1682,7 +1694,7 @@ public class GroupManager extends JavaPlugin {
auxUser = dataHolder.getUser(args[0]); auxUser = dataHolder.getUser(args[0]);
} }
// Validating permission // Validating permission
if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getUUID(), senderGroup.getName()) : false)) {
sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher."); sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher.");
return true; return true;
} }
@@ -1690,7 +1702,7 @@ public class GroupManager extends JavaPlugin {
if (overloadedUsers.get(dataHolder.getName().toLowerCase()) == null) { if (overloadedUsers.get(dataHolder.getName().toLowerCase()) == null) {
overloadedUsers.put(dataHolder.getName().toLowerCase(), new ArrayList<User>()); overloadedUsers.put(dataHolder.getName().toLowerCase(), new ArrayList<User>());
} }
dataHolder.removeOverload(auxUser.getLastName()); dataHolder.removeOverload(auxUser.getUUID());
if (overloadedUsers.get(dataHolder.getName().toLowerCase()).contains(auxUser)) { if (overloadedUsers.get(dataHolder.getName().toLowerCase()).contains(auxUser)) {
overloadedUsers.get(dataHolder.getName().toLowerCase()).remove(auxUser); overloadedUsers.get(dataHolder.getName().toLowerCase()).remove(auxUser);
} }
@@ -1709,7 +1721,7 @@ public class GroupManager extends JavaPlugin {
removeList = new ArrayList<User>(); removeList = new ArrayList<User>();
count = 0; count = 0;
for (User u : overloadedUsers.get(dataHolder.getName().toLowerCase())) { for (User u : overloadedUsers.get(dataHolder.getName().toLowerCase())) {
if (!dataHolder.isOverloaded(u.getLastName())) { if (!dataHolder.isOverloaded(u.getUUID())) {
removeList.add(u); removeList.add(u);
} else { } else {
auxString += u.getLastName() + ", "; auxString += u.getLastName() + ", ";
@@ -1739,8 +1751,8 @@ public class GroupManager extends JavaPlugin {
removeList = new ArrayList<User>(); removeList = new ArrayList<User>();
count = 0; count = 0;
for (User u : overloadedUsers.get(dataHolder.getName().toLowerCase())) { for (User u : overloadedUsers.get(dataHolder.getName().toLowerCase())) {
if (dataHolder.isOverloaded(u.getLastName())) { if (dataHolder.isOverloaded(u.getUUID())) {
dataHolder.removeOverload(u.getLastName()); dataHolder.removeOverload(u.getUUID());
count++; count++;
} }
} }
@@ -1880,7 +1892,7 @@ public class GroupManager extends JavaPlugin {
return true; return true;
} }
// Validating permission // Validating permission
if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getUUID(), senderGroup.getName()) : false)) {
sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher."); sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher.");
return true; return true;
} }
@@ -1888,7 +1900,7 @@ public class GroupManager extends JavaPlugin {
sender.sendMessage(ChatColor.RED + "The destination group can't be the same as yours, or higher."); sender.sendMessage(ChatColor.RED + "The destination group can't be the same as yours, or higher.");
return true; return true;
} }
if (!isConsole && !isOpOverride && (!permissionHandler.inGroup(senderUser.getLastName(), auxUser.getGroupName()) || !permissionHandler.inGroup(senderUser.getLastName(), auxGroup.getName()))) { if (!isConsole && !isOpOverride && (!permissionHandler.inGroup(senderUser.getUUID(), auxUser.getGroupName()) || !permissionHandler.inGroup(senderUser.getUUID(), auxGroup.getName()))) {
sender.sendMessage(ChatColor.RED + "You can't modify a player involving a group that you don't inherit."); sender.sendMessage(ChatColor.RED + "You can't modify a player involving a group that you don't inherit.");
return true; return true;
} }
@@ -1936,7 +1948,7 @@ public class GroupManager extends JavaPlugin {
return true; return true;
} }
// Validating permission // Validating permission
if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getUUID(), senderGroup.getName()) : false)) {
sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher."); sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher.");
return true; return true;
} }
@@ -1944,7 +1956,7 @@ public class GroupManager extends JavaPlugin {
sender.sendMessage(ChatColor.RED + "The destination group can't be the same as yours, or higher."); sender.sendMessage(ChatColor.RED + "The destination group can't be the same as yours, or higher.");
return true; return true;
} }
if (!isConsole && !isOpOverride && (!permissionHandler.inGroup(senderUser.getLastName(), auxUser.getGroupName()) || !permissionHandler.inGroup(senderUser.getLastName(), auxGroup.getName()))) { if (!isConsole && !isOpOverride && (!permissionHandler.inGroup(senderUser.getUUID(), auxUser.getGroupName()) || !permissionHandler.inGroup(senderUser.getUUID(), auxGroup.getName()))) {
sender.sendMessage(ChatColor.RED + "You can't modify a player involving a group that you don't inherit."); sender.sendMessage(ChatColor.RED + "You can't modify a player involving a group that you don't inherit.");
return true; return true;
} }
@@ -2196,22 +2208,22 @@ public class GroupManager extends JavaPlugin {
if (players.isEmpty()) { if (players.isEmpty()) {
// Check for an offline player (exact match). // Check for an offline player (exact match).
if (Arrays.asList(this.getServer().getOfflinePlayers()).contains(Bukkit.getOfflinePlayer(playerName))) { if (Arrays.asList(this.getServer().getOfflinePlayers()).contains(Bukkit.getOfflinePlayer(playerName))) {
match.add(playerName); match.add(Bukkit.getOfflinePlayer(playerName).getName()); //.getUniqueId().toString());
} else { } else {
// look for partial matches // look for partial matches
for (OfflinePlayer offline : this.getServer().getOfflinePlayers()) { for (OfflinePlayer offline : this.getServer().getOfflinePlayers()) {
if (offline.getName().toLowerCase().startsWith(playerName.toLowerCase())) if (offline.getName().toLowerCase().startsWith(playerName.toLowerCase()))
match.add(offline.getName()); match.add(offline.getName()); //.getUniqueId().toString());
} }
} }
} else { } else {
for (Player player : players) { for (Player player : players) {
match.add(player.getName()); match.add(player.getUniqueId().toString());
} }
} }
if (match.isEmpty() || match == null) { if (match.isEmpty()) {
sender.sendMessage(ChatColor.RED + "Player not found!"); sender.sendMessage(ChatColor.RED + "Player not found!");
return null; return null;
} else if (match.size() > 1) { } else if (match.size() > 1) {

View File

@@ -110,6 +110,8 @@ public abstract class DataUnit {
if (!lastName.equals(this.lastName)) { if (!lastName.equals(this.lastName)) {
this.lastName = lastName; this.lastName = lastName;
dataSource.putUUIDLookup(lastName, uUID);
changed = true; changed = true;
} }

View File

@@ -41,16 +41,16 @@ public class OverloadedWorldHolder extends WorldDataHolder {
* @return user object or a new user if none exists. * @return user object or a new user if none exists.
*/ */
@Override @Override
public User getUser(String userName) { public User getUser(String userId) {
//OVERLOADED CODE //OVERLOADED CODE
String userNameLowered = userName.toLowerCase(); String userNameLowered = userId.toLowerCase();
if (overloadedUsers.containsKey(userNameLowered)) { if (overloadedUsers.containsKey(userNameLowered)) {
return overloadedUsers.get(userNameLowered); return overloadedUsers.get(userNameLowered);
} }
//END CODE //END CODE
return super.getUser(userName); return super.getUser(userId);
} }
/** /**

View File

@@ -18,6 +18,8 @@ import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -58,6 +60,11 @@ public class WorldDataHolder {
* The actual users holder * The actual users holder
*/ */
protected UsersDataHolder users = new UsersDataHolder(); protected UsersDataHolder users = new UsersDataHolder();
/**
* List of UUID's associated with this user name.
*/
protected static Map<String, Set<String>> nameToUUIDLookup = new TreeMap<String, Set<String>>();
/** /**
* *
*/ */
@@ -101,8 +108,10 @@ public class WorldDataHolder {
} }
/** /**
* Search for a user. If it doesn't exist, create a new one with default * Search for a user. If it doesn't exist, create a new one with default group.
* group. *
* If this is called passing a player name with mantogglevalidate off
* it can return the wrong user object (offline/online UUID match).
* *
* @param userId the UUID String or name of the user * @param userId the UUID String or name of the user
* @return class that manage that user permission * @return class that manage that user permission
@@ -114,21 +123,26 @@ public class WorldDataHolder {
} }
// Legacy name matching // Legacy name matching
if (userId.length() < 36) { if ((userId.length() < 36) && nameToUUIDLookup.containsKey(userId.toLowerCase())) {
// Search for a LastName match // Search for a name to UUID match
for (User user : getUserList()) { for (String uid : getUUIDLookup(userId.toLowerCase())) {
if (user.getLastName().equalsIgnoreCase(userId)) { User user = getUsers().get(uid.toLowerCase());
if ((user != null) && user.getLastName().equalsIgnoreCase(userId)) {
return user; return user;
} }
} }
} }
if (!nameToUUIDLookup.containsKey(userId.toLowerCase())) {
GroupManager.logger.fine("ERROR: No lookup for: " + userId);
}
// No user account found so create a new one. // No user account found so create a new one.
User newUser = createUser(userId); User newUser = createUser(userId);
return newUser; return newUser;
} }
@@ -147,33 +161,39 @@ public class WorldDataHolder {
if (user != null) { if (user != null) {
GroupManager.logger.fine("User record found for UUID: " + uUID + ":" + currentName);
user.setLastName(currentName); user.setLastName(currentName);
return user; return user;
} }
// Search for a LastName match // Search for a LastName match
for (User usr : getUserList()) { user = getUsers().get(currentName.toLowerCase());
if ((user != null) && user.getLastName().equalsIgnoreCase(currentName) && user.getUUID().equalsIgnoreCase(user.getLastName())) {
if (usr.getLastName().equalsIgnoreCase(currentName)) { // Clone this user so we can set it's uUID
User usr = user.clone(uUID, currentName);
// Clone this user so we can set it's uUID
user = usr.clone(uUID, currentName);
// Delete it and replace with the new clone.
this.removeUser(usr.getUUID());
this.addUser(user);
return getUsers().get(uUID.toLowerCase());
}
// Delete it and replace with the new clone.
this.removeUser(user.getUUID().toLowerCase());
this.addUser(usr);
GroupManager.logger.fine("Updating User record for UUID: " + uUID + ":" + currentName);
return getUsers().get(uUID.toLowerCase());
}
if (user != null) {
GroupManager.logger.fine("User record found but UUID mismatch for: " + currentName);
} }
// No user account found so create a new one. // No user account found so create a new one.
User newUser = createUser(uUID); User newUser = createUser(uUID.toLowerCase());
newUser.setLastName(currentName); newUser.setLastName(currentName);
GroupManager.logger.fine("New User record created: " + uUID + ":" + currentName);
return newUser; return newUser;
} }
@@ -193,8 +213,12 @@ public class WorldDataHolder {
if ((theUser.getGroup() == null)) { if ((theUser.getGroup() == null)) {
theUser.setGroup(groups.getDefaultGroup()); theUser.setGroup(groups.getDefaultGroup());
} }
removeUser(theUser.getUUID()); removeUser(theUser.getUUID().toLowerCase());
getUsers().put(theUser.getUUID().toLowerCase(), theUser); getUsers().put(theUser.getUUID().toLowerCase(), theUser);
// Store for name to UUID lookups.
//putUUIDLookup(theUser.getLastName(), theUser.getUUID().toLowerCase());
setUsersChanged(true); setUsersChanged(true);
if (GroupManager.isLoaded()) if (GroupManager.isLoaded())
GroupManager.getGMEventHandler().callEvent(theUser, Action.USER_ADDED); GroupManager.getGMEventHandler().callEvent(theUser, Action.USER_ADDED);
@@ -209,10 +233,19 @@ public class WorldDataHolder {
public boolean removeUser(String userId) { public boolean removeUser(String userId) {
if (getUsers().containsKey(userId.toLowerCase())) { if (getUsers().containsKey(userId.toLowerCase())) {
User user = getUser(userId.toLowerCase());
// Remove the name to UUID lookup for this user object.
removeUUIDLookup(user.getLastName().toLowerCase(), user.getUUID());
getUsers().remove(userId.toLowerCase()); getUsers().remove(userId.toLowerCase());
setUsersChanged(true); setUsersChanged(true);
if (GroupManager.isLoaded()) if (GroupManager.isLoaded())
GroupManager.getGMEventHandler().callEvent(userId, GMUserEvent.Action.USER_REMOVED); GroupManager.getGMEventHandler().callEvent(userId, GMUserEvent.Action.USER_REMOVED);
return true; return true;
} }
return false; return false;
@@ -877,7 +910,7 @@ public class WorldDataHolder {
nodeData = thisUserNode.get("lastname"); nodeData = thisUserNode.get("lastname");
} catch (Exception ex) { } catch (Exception ex) {
throw new IllegalArgumentException("Bad format found in 'subgroups' for user: " + usersKey + " in file: " + usersFile.getPath()); throw new IllegalArgumentException("Bad format found in 'lastname' for user: " + usersKey + " in file: " + usersFile.getPath());
} }
if ((nodeData != null) && (nodeData instanceof String)) { if ((nodeData != null) && (nodeData instanceof String)) {
@@ -926,42 +959,6 @@ public class WorldDataHolder {
} }
thisUser.sortPermissions(); 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)) {
if (o == null) {
GroupManager.logger.warning("Invalid Subgroup data for user: " + thisUser.getLastName() + ". Ignoring entry in file: " + usersFile.getPath());
} else {
Group subGrp = ph.getGroup(o.toString());
if (subGrp != null) {
thisUser.addSubGroup(subGrp);
} else {
GroupManager.logger.warning("Subgroup '" + o.toString() + "' not found for user: " + thisUser.getLastName() + ". 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.getLastName() + ". Ignoring entry in file: " + usersFile.getPath());
}
}
// USER INFO NODE // USER INFO NODE
@@ -1003,6 +1000,41 @@ public class WorldDataHolder {
} else { } else {
thisUser.setGroup(ph.getDefaultGroup()); thisUser.setGroup(ph.getDefaultGroup());
} }
// 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)) {
if (o == null) {
GroupManager.logger.warning("Invalid Subgroup data for user: " + thisUser.getLastName() + ". Ignoring entry in file: " + usersFile.getPath());
} else {
Group subGrp = ph.getGroup(o.toString());
if (subGrp != null) {
thisUser.addSubGroup(subGrp);
} else {
GroupManager.logger.warning("Subgroup '" + o.toString() + "' not found for user: " + thisUser.getLastName() + ". 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.getLastName() + ". Ignoring entry in file: " + usersFile.getPath());
}
}
} }
} }
@@ -1351,6 +1383,7 @@ public class WorldDataHolder {
public void resetUsers() { public void resetUsers() {
users.resetUsers(); users.resetUsers();
this.clearUUIDLookup();
} }
/** /**
@@ -1444,5 +1477,69 @@ public class WorldDataHolder {
if (getUsersFile() != null) if (getUsersFile() != null)
setTimeStampUsers(getUsersFile().lastModified()); setTimeStampUsers(getUsersFile().lastModified());
} }
/** Name to UUID lookups **/
/**
* Add a new name to UUID lookup.
*
* @param name the User name key to index on.
* @param UUID the User object UUID (same as name if there is no UUID).
*/
public void putUUIDLookup(String name, String UUID) {
Set<String> lookup = getUUIDLookup(name.toLowerCase());
if (lookup == null)
lookup = new TreeSet<String>();
lookup.add(UUID);
nameToUUIDLookup.put(name.toLowerCase(), lookup);
}
/**
* Delete a name lookup.
* Allows for multiple UUID's assigned to a single name (offline/online)
*
* @param name
* @param UUID
*/
public void removeUUIDLookup(String name, String UUID) {
if (nameToUUIDLookup.containsKey(name.toLowerCase())) {
Set<String> lookup = getUUIDLookup(name.toLowerCase());
lookup.remove(UUID);
if (lookup.isEmpty()) {
nameToUUIDLookup.remove(name.toLowerCase());
return;
}
nameToUUIDLookup.put(name.toLowerCase(), lookup);
}
}
/**
*
* @param name
* @return a Set of strings containing the User objects UUID (or name if they don't have a UUID)
*/
public Set<String> getUUIDLookup(String name) {
return nameToUUIDLookup.get(name.toLowerCase());
}
/**
* Reset the UUID Lookup cache
*/
protected void clearUUIDLookup() {
nameToUUIDLookup.clear();
}
} }

View File

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

View File

@@ -67,7 +67,7 @@ public class AnjoPermissionsHandler extends PermissionsReaderInterface {
@Override @Override
public boolean permission(Player player, String permission) { public boolean permission(Player player, String permission) {
return checkUserPermission(ph.getUser(player.getName()).updatePlayer(player), permission); return checkUserPermission(ph.getUser(player.getUniqueId().toString()).updatePlayer(player), permission);
} }
/** /**
@@ -1069,12 +1069,20 @@ public class AnjoPermissionsHandler extends PermissionsReaderInterface {
if (resultNow.resultType.equals(PermissionCheckResult.Type.EXCEPTION)) { if (resultNow.resultType.equals(PermissionCheckResult.Type.EXCEPTION)) {
resultNow.accessLevel = targetPermission; resultNow.accessLevel = targetPermission;
GroupManager.logger.fine("Found an " + resultNow.resultType + " for " + targetPermission + " in group " + resultNow.owner.getLastName());
return resultNow; return resultNow;
} }
// Negation found so store for later /*
// as we need to continue looking for an Exception. * Store the first found permission only.
result = resultNow; * This will prevent inherited permission negations overriding higher level perms.
*/
if (result.resultType.equals(PermissionCheckResult.Type.NOTFOUND)) {
// No Negation found so store for later
// as we need to continue looking for an Exception.
GroupManager.logger.fine("Found an " + resultNow.resultType + " for " + targetPermission + " in group " + resultNow.owner.getLastName());
result = resultNow;
}
} }
for (String sonName : now.getInherits()) { for (String sonName : now.getInherits()) {