mirror of
https://github.com/EssentialsX/Essentials.git
synced 2024-12-22 00:58:50 +01:00
Add GroupManager
This doesn't mean we are actively supporting it, just means I wanted to appease people begging for a binary that works on 1.9.
This commit is contained in:
parent
7967f62131
commit
10eed23430
2
.gitignore
vendored
2
.gitignore
vendored
@ -46,4 +46,4 @@ dependency-reduced-pom.xml
|
||||
/Essentials/userdata/testplayer1.yml
|
||||
/Essentials/usermap.csv
|
||||
/Essentials/userdata
|
||||
/EssentialsGroupManager/
|
||||
/EssentialsGroupManager/target/
|
||||
|
44
EssentialsGroupManager/pom.xml
Normal file
44
EssentialsGroupManager/pom.xml
Normal file
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||
|
||||
<groupId>org.anjocaido</groupId>
|
||||
<artifactId>EssentialsGroupManager</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>net.ess3</groupId>
|
||||
<artifactId>EssentialsXParent</artifactId>
|
||||
<version>2.0.1</version>
|
||||
</parent>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>GPLv3</name>
|
||||
<url>http://www.gnu.org/copyleft/gpl.html</url>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>net.milkbowl.vault</groupId>
|
||||
<artifactId>VaultAPI</artifactId>
|
||||
<version>1.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>vault-repo</id>
|
||||
<url>http://nexus.theyeticave.net/content/repositories/pub_releases</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
</project>
|
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.anjocaido.groupmanager;
|
||||
|
||||
import org.anjocaido.groupmanager.utils.Tasks;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||
import org.yaml.snakeyaml.reader.UnicodeReader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* @author gabrielcouto
|
||||
*/
|
||||
public class GMConfiguration {
|
||||
|
||||
private boolean allowCommandBlocks = false;
|
||||
private boolean opOverride = true;
|
||||
private boolean toggleValidate = true;
|
||||
private Integer saveInterval = 10;
|
||||
private Integer backupDuration = 24;
|
||||
private String loggerLevel = "OFF";
|
||||
private Map<String, Object> mirrorsMap;
|
||||
|
||||
|
||||
private GroupManager plugin;
|
||||
private Map<String, Object> GMconfig;
|
||||
|
||||
public GMConfiguration(GroupManager plugin) {
|
||||
|
||||
this.plugin = plugin;
|
||||
|
||||
/*
|
||||
* Set defaults
|
||||
*/
|
||||
allowCommandBlocks = false;
|
||||
opOverride = true;
|
||||
toggleValidate = true;
|
||||
saveInterval = 10;
|
||||
backupDuration = 24;
|
||||
loggerLevel = "OFF";
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void load() {
|
||||
|
||||
if (!plugin.getDataFolder().exists()) {
|
||||
plugin.getDataFolder().mkdirs();
|
||||
}
|
||||
|
||||
File 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, "Error creating a new config.yml", ex);
|
||||
}
|
||||
}
|
||||
|
||||
Yaml configYAML = new Yaml(new SafeConstructor());
|
||||
|
||||
try {
|
||||
FileInputStream configInputStream = new FileInputStream(configFile);
|
||||
GMconfig = (Map<String, Object>) configYAML.load(new UnicodeReader(configInputStream));
|
||||
configInputStream.close();
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalArgumentException("The following file couldn't pass on Parser.\n" + configFile.getPath(), ex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read our config settings and store them for reading later.
|
||||
*/
|
||||
try {
|
||||
Map<String, Object> config = getElement("config", getElement("settings", GMconfig));
|
||||
|
||||
try {
|
||||
allowCommandBlocks = (Boolean) config.get("allow_commandblocks");
|
||||
} catch (Exception ex) {
|
||||
GroupManager.logger.log(Level.SEVERE, "Missing or corrupt 'allow_commandblocks' node. Using default settings", ex);
|
||||
}
|
||||
|
||||
try {
|
||||
opOverride = (Boolean) config.get("opOverrides");
|
||||
} catch (Exception ex) {
|
||||
GroupManager.logger.log(Level.SEVERE, "Missing or corrupt 'opOverrides' node. Using default settings", ex);
|
||||
}
|
||||
|
||||
try {
|
||||
toggleValidate = (Boolean) config.get("validate_toggle");
|
||||
} catch (Exception ex) {
|
||||
GroupManager.logger.log(Level.SEVERE, "Missing or corrupt 'validate_toggle' node. Using default settings", ex);
|
||||
}
|
||||
|
||||
/*
|
||||
* data node for save/backup timers.
|
||||
*/
|
||||
try {
|
||||
Map<String, Object> save = getElement("save", getElement("data", getElement("settings", GMconfig)));
|
||||
|
||||
try {
|
||||
saveInterval = (Integer) save.get("minutes");
|
||||
} catch (Exception ex) {
|
||||
GroupManager.logger.log(Level.SEVERE, "Missing or corrupt 'minutes' node. Using default setting", ex);
|
||||
}
|
||||
|
||||
try {
|
||||
backupDuration = (Integer) save.get("hours");
|
||||
} catch (Exception ex) {
|
||||
GroupManager.logger.log(Level.SEVERE, "Missing or corrupt 'hours' node. Using default setting", ex);
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
GroupManager.logger.log(Level.SEVERE, "Missing or corrupt 'data' node. Using default settings", ex);
|
||||
}
|
||||
|
||||
|
||||
Object level = ((Map<String, String>) getElement("settings", GMconfig).get("logging")).get("level");
|
||||
if (level instanceof String) {
|
||||
loggerLevel = (String) level;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store our mirrors map for parsing later.
|
||||
*/
|
||||
mirrorsMap = (Map<String, Object>) ((Map<String, Object>) GMconfig.get("settings")).get("mirrors");
|
||||
|
||||
if (mirrorsMap == null) {
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
/*
|
||||
* Flag the error and use defaults
|
||||
*/
|
||||
GroupManager.logger.log(Level.SEVERE, "There are errors in your config.yml. Using default settings", ex);
|
||||
|
||||
mirrorsMap = new HashMap<String, Object>();
|
||||
}
|
||||
// Setup defaults
|
||||
adjustLoggerLevel();
|
||||
plugin.setValidateOnlinePlayer(isToggleValidate());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, Object> getElement(String element, Map<String, Object> map) {
|
||||
|
||||
if (!map.containsKey(element)) {
|
||||
throw new IllegalArgumentException("The config.yml has no '" + element + ".\n");
|
||||
}
|
||||
|
||||
return (Map<String, Object>) map.get(element);
|
||||
|
||||
}
|
||||
|
||||
public boolean isAllowCommandBlocks() {
|
||||
|
||||
return allowCommandBlocks;
|
||||
}
|
||||
|
||||
public boolean isOpOverride() {
|
||||
|
||||
return opOverride;
|
||||
}
|
||||
|
||||
public boolean isToggleValidate() {
|
||||
|
||||
return toggleValidate;
|
||||
}
|
||||
|
||||
public Integer getSaveInterval() {
|
||||
|
||||
return saveInterval;
|
||||
}
|
||||
|
||||
public Integer getBackupDuration() {
|
||||
|
||||
return backupDuration;
|
||||
}
|
||||
|
||||
public void adjustLoggerLevel() {
|
||||
|
||||
try {
|
||||
GroupManager.logger.setLevel(Level.parse(loggerLevel));
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
GroupManager.logger.setLevel(Level.INFO);
|
||||
}
|
||||
|
||||
public Map<String, Object> getMirrorsMap() {
|
||||
|
||||
if (!mirrorsMap.isEmpty()) {
|
||||
return mirrorsMap;
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,486 @@
|
||||
package org.anjocaido.groupmanager;
|
||||
|
||||
import org.anjocaido.groupmanager.data.Group;
|
||||
import org.anjocaido.groupmanager.events.GMGroupEvent;
|
||||
import org.anjocaido.groupmanager.utils.PermissionCheckResult;
|
||||
import org.anjocaido.groupmanager.utils.Tasks;
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||
import org.yaml.snakeyaml.reader.UnicodeReader;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* @author ElgarL
|
||||
*/
|
||||
public class GlobalGroups {
|
||||
|
||||
private GroupManager plugin;
|
||||
//private Yaml GGroups;
|
||||
|
||||
private final Map<String, Group> groups = Collections.synchronizedMap(new HashMap<String, Group>());
|
||||
|
||||
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;
|
||||
}
|
||||
synchronized (groups) {
|
||||
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() {
|
||||
|
||||
Yaml GGroupYAML = new Yaml(new SafeConstructor());
|
||||
Map<String, Object> GGroups;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Load the YAML file.
|
||||
*/
|
||||
try {
|
||||
FileInputStream groupsInputStream = new FileInputStream(GlobalGroupsFile);
|
||||
GGroups = (Map<String, Object>) GGroupYAML.load(new UnicodeReader(groupsInputStream));
|
||||
groupsInputStream.close();
|
||||
} 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.keySet().isEmpty()) {
|
||||
// Read all global groups
|
||||
Map<String, Object> allGroups = new HashMap<String, Object>();
|
||||
|
||||
try {
|
||||
allGroups = (Map<String, Object>) GGroups.get("groups");
|
||||
} 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
|
||||
try {
|
||||
element = ((Map<String, Object>) allGroups.get(groupName)).get("permissions");
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalArgumentException("The GlobalGroup ' " + groupName + "' is formatted incorrectly: ", ex);
|
||||
}
|
||||
|
||||
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
|
||||
// try {
|
||||
// element = ((Map<String, Object>)allGroups.get(groupName)).get("info");
|
||||
// } catch ( Exception ex) {
|
||||
// throw new IllegalArgumentException("The GlobalGroup ' " + groupName + "' is formatted incorrectly: ", ex);
|
||||
// }
|
||||
//
|
||||
// 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);
|
||||
synchronized (groups) {
|
||||
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()) {
|
||||
GroupManager.getGMEventHandler().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()) {
|
||||
GroupManager.getGMEventHandler().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.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a collection of the groups
|
||||
*/
|
||||
public Group[] getGroupList() {
|
||||
synchronized (groups) {
|
||||
return groups.values().toArray(new Group[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
synchronized (groups) {
|
||||
for (Group g : groups.values()) {
|
||||
g.flagAsSaved();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -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!");
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* 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.utils.StringPermissionComparator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author gabrielcouto
|
||||
*/
|
||||
public abstract class DataUnit {
|
||||
|
||||
private WorldDataHolder dataSource;
|
||||
private String uUID;
|
||||
private String lastName;
|
||||
private boolean changed, sorted = false;
|
||||
private List<String> permissions = Collections.unmodifiableList(Collections.<String>emptyList());
|
||||
|
||||
public DataUnit(WorldDataHolder dataSource, String name) {
|
||||
|
||||
this.dataSource = dataSource;
|
||||
this.uUID = name;
|
||||
}
|
||||
|
||||
public DataUnit(String name) {
|
||||
|
||||
this.uUID = 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.getUUID().equalsIgnoreCase(go.getUUID())) {
|
||||
// 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.uUID != null ? this.uUID.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;
|
||||
}
|
||||
|
||||
public String getUUID() {
|
||||
|
||||
return uUID;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
|
||||
if (uUID.length() < 36) {
|
||||
return this.uUID;
|
||||
}
|
||||
|
||||
return this.lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
|
||||
if (!lastName.equals(this.lastName)) {
|
||||
|
||||
this.lastName = lastName;
|
||||
dataSource.putUUIDLookup(lastName, uUID);
|
||||
|
||||
changed = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void flagAsChanged() {
|
||||
|
||||
WorldDataHolder testSource = getDataSource();
|
||||
String source = "";
|
||||
|
||||
if (testSource == null) {
|
||||
source = "GlobalGroups";
|
||||
} else {
|
||||
source = testSource.getName();
|
||||
}
|
||||
|
||||
GroupManager.logger.finest("DataSource: " + source + " - DataUnit: " + getUUID() + " 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: " + getUUID() + " flagged as saved!");
|
||||
changed = false;
|
||||
}
|
||||
|
||||
public boolean hasSamePermissionNode(String permission) {
|
||||
|
||||
return permissions.contains(permission);
|
||||
}
|
||||
|
||||
public void addPermission(String permission) {
|
||||
|
||||
if (!hasSamePermissionNode(permission)) {
|
||||
List<String> clone = new ArrayList<String>(permissions);
|
||||
clone.add(permission);
|
||||
permissions = Collections.unmodifiableList(clone);
|
||||
}
|
||||
flagAsChanged();
|
||||
}
|
||||
|
||||
public boolean removePermission(String permission) {
|
||||
|
||||
flagAsChanged();
|
||||
List<String> clone = new ArrayList<String>(permissions);
|
||||
boolean ret = clone.remove(permission);
|
||||
permissions = Collections.unmodifiableList(clone);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
sortPermissions();
|
||||
return permissions;
|
||||
}
|
||||
|
||||
public boolean isSorted() {
|
||||
|
||||
return this.sorted;
|
||||
}
|
||||
|
||||
public void sortPermissions() {
|
||||
|
||||
if (!isSorted()) {
|
||||
List<String> clone = new ArrayList<String>(permissions);
|
||||
Collections.sort(clone, StringPermissionComparator.getInstance());
|
||||
permissions = Collections.unmodifiableList(clone);
|
||||
sorted = true;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* 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 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 List<String> inherits = Collections.unmodifiableList(Collections.<String>emptyList());
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
|
||||
return this.getUUID();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = this.getInherits().isEmpty() ? Collections.unmodifiableList(Collections.<String>emptyList()) : Collections.unmodifiableList(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 = this.getInherits().isEmpty() ? Collections.unmodifiableList(Collections.<String>emptyList()) : Collections.unmodifiableList(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 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())) {
|
||||
List<String> clone = new ArrayList<String>(inherits);
|
||||
clone.add(inherit.getName().toLowerCase());
|
||||
inherits = Collections.unmodifiableList(clone);
|
||||
}
|
||||
flagAsChanged();
|
||||
if (GroupManager.isLoaded()) {
|
||||
GroupManager.BukkitPermissions.updateAllPlayers();
|
||||
GroupManager.getGMEventHandler().callEvent(this, Action.GROUP_INHERITANCE_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean removeInherits(String inherit) {
|
||||
|
||||
if (!isGlobal()) {
|
||||
if (this.inherits.contains(inherit.toLowerCase())) {
|
||||
List<String> clone = new ArrayList<String>(inherits);
|
||||
clone.remove(inherit.toLowerCase());
|
||||
inherits = Collections.unmodifiableList(clone);
|
||||
flagAsChanged();
|
||||
GroupManager.getGMEventHandler().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();
|
||||
GroupManager.getGMEventHandler().callEvent(this, Action.GROUP_INFO_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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.clear();
|
||||
variables.putAll(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);
|
||||
synchronized (variables) {
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,327 @@
|
||||
/*
|
||||
* 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 org.anjocaido.groupmanager.GroupManager;
|
||||
import org.anjocaido.groupmanager.dataholder.WorldDataHolder;
|
||||
import org.anjocaido.groupmanager.events.GMUserEvent.Action;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author gabrielcouto/ElgarL
|
||||
*/
|
||||
public class User extends DataUnit implements Cloneable {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private String group = null;
|
||||
private final List<String> subGroups = Collections.synchronizedList(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.getLastName());
|
||||
clone.group = this.group;
|
||||
|
||||
// Clone all subgroups.
|
||||
clone.subGroups.addAll(this.subGroupListStringCopy());
|
||||
|
||||
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.getUUID())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
User clone = dataSource.createUser(this.getUUID());
|
||||
|
||||
if (dataSource.getGroup(group) == null) {
|
||||
clone.setGroup(dataSource.getDefaultGroup());
|
||||
} else {
|
||||
clone.setGroup(dataSource.getGroup(this.getGroupName()));
|
||||
}
|
||||
|
||||
// Clone all subgroups.
|
||||
clone.subGroups.addAll(this.subGroupListStringCopy());
|
||||
|
||||
for (String perm : this.getPermissionList()) {
|
||||
clone.addPermission(perm);
|
||||
}
|
||||
|
||||
clone.variables = this.variables.clone(this);
|
||||
clone.flagAsChanged();
|
||||
return clone;
|
||||
}
|
||||
|
||||
public User clone(String uUID, String CurrentName) {
|
||||
|
||||
User clone = this.getDataSource().createUser(uUID);
|
||||
|
||||
clone.setLastName(CurrentName);
|
||||
|
||||
// Set the group silently.
|
||||
clone.setGroup(this.getDataSource().getGroup(this.getGroupName()), false);
|
||||
|
||||
// Clone all subgroups.
|
||||
clone.subGroups.addAll(this.subGroupListStringCopy());
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Place holder to let people know to stop using this method.
|
||||
*
|
||||
* @return a string containing the players last known name.
|
||||
*
|
||||
* @deprecated use {@link #getLastName()} and {@link #getUUID()}.
|
||||
*/
|
||||
@Deprecated
|
||||
public String getName() {
|
||||
|
||||
return this.getLastName();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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.getLastName(), String.format(" moved to the group %s in %s.", group.getName(), this.getDataSource().getName()));
|
||||
}
|
||||
|
||||
if (updatePerms) {
|
||||
GroupManager.getGMEventHandler().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());
|
||||
}
|
||||
GroupManager.getGMEventHandler().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());
|
||||
}
|
||||
}
|
||||
GroupManager.getGMEventHandler().callEvent(this, Action.USER_SUBGROUP_CHANGED);
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public ArrayList<Group> subGroupListCopy() {
|
||||
|
||||
ArrayList<Group> val = new ArrayList<Group>();
|
||||
synchronized (subGroups) {
|
||||
for (String gstr : subGroups) {
|
||||
Group g = getDataSource().getGroup(gstr);
|
||||
if (g == null) {
|
||||
removeSubGroup(g);
|
||||
continue;
|
||||
}
|
||||
val.add(g);
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
public ArrayList<String> subGroupListStringCopy() {
|
||||
synchronized (subGroups) {
|
||||
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());
|
||||
GroupManager.getGMEventHandler().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.getLastName());
|
||||
}
|
||||
return bukkitPlayer;
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.clear();
|
||||
this.variables.putAll(varList);
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* A clone of all vars here.
|
||||
*
|
||||
* @return UserVariables clone
|
||||
*/
|
||||
protected UserVariables clone(User newOwner) {
|
||||
|
||||
UserVariables clone = new UserVariables(newOwner);
|
||||
synchronized (variables) {
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.anjocaido.groupmanager.data;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 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 final Map<String, Object> variables = Collections.synchronizedMap(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 String[] getVarKeyList() {
|
||||
synchronized (variables) {
|
||||
return variables.keySet().toArray(new String[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
package org.anjocaido.groupmanager.dataholder;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
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 final Map<String, Group> groups = Collections.synchronizedMap(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.
|
||||
synchronized(groups) {
|
||||
for (Group group : groups.values())
|
||||
group.setDataSource(this.dataSource);
|
||||
}
|
||||
}
|
||||
|
||||
public WorldDataHolder getDataSource() {
|
||||
|
||||
return this.dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the defaultGroup
|
||||
*/
|
||||
public Group getDefaultGroup() {
|
||||
|
||||
return defaultGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param defaultGroup the defaultGroup to set
|
||||
*/
|
||||
public void setDefaultGroup(Group defaultGroup) {
|
||||
|
||||
this.defaultGroup = defaultGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: Iteration over this object has to be synchronized!
|
||||
* @return the groups
|
||||
*/
|
||||
public Map<String, Group> getGroups() {
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the Groups
|
||||
*/
|
||||
public void resetGroups() {
|
||||
this.groups.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,217 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.anjocaido.groupmanager.dataholder;
|
||||
|
||||
import org.anjocaido.groupmanager.data.User;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author gabrielcouto
|
||||
*/
|
||||
public class OverloadedWorldHolder extends WorldDataHolder {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected final Map<String, User> overloadedUsers = Collections.synchronizedMap(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 userId) {
|
||||
|
||||
//OVERLOADED CODE
|
||||
String userNameLowered = userId.toLowerCase();
|
||||
if (overloadedUsers.containsKey(userNameLowered)) {
|
||||
return overloadedUsers.get(userNameLowered);
|
||||
}
|
||||
//END CODE
|
||||
|
||||
return super.getUser(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @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.getUUID().toLowerCase())) {
|
||||
overloadedUsers.remove(theUser.getUUID().toLowerCase());
|
||||
overloadedUsers.put(theUser.getUUID().toLowerCase(), theUser);
|
||||
return;
|
||||
}
|
||||
//END CODE
|
||||
removeUser(theUser.getUUID());
|
||||
getUsers().put(theUser.getUUID().toLowerCase(), theUser);
|
||||
setUsersChanged(true);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param userId
|
||||
* @return true if removed/false if not found.
|
||||
*/
|
||||
@Override
|
||||
public boolean removeUser(String userId) {
|
||||
|
||||
//OVERLOADED CODE
|
||||
if (overloadedUsers.containsKey(userId.toLowerCase())) {
|
||||
overloadedUsers.remove(userId.toLowerCase());
|
||||
return true;
|
||||
}
|
||||
//END CODE
|
||||
if (getUsers().containsKey(userId.toLowerCase())) {
|
||||
getUsers().remove(userId.toLowerCase());
|
||||
setUsersChanged(true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeGroup(String groupName) {
|
||||
|
||||
if (groupName.equals(getDefaultGroup())) {
|
||||
return false;
|
||||
}
|
||||
synchronized(getGroups()) {
|
||||
for (String key : getGroups().keySet()) {
|
||||
if (groupName.equalsIgnoreCase(key)) {
|
||||
getGroups().remove(key);
|
||||
synchronized(getUsers()) {
|
||||
for (String userKey : getUsers().keySet()) {
|
||||
User user = getUsers().get(userKey);
|
||||
if (user.getGroupName().equalsIgnoreCase(key)) {
|
||||
user.setGroup(getDefaultGroup());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
//OVERLOADED CODE
|
||||
synchronized(overloadedUsers) {
|
||||
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>();
|
||||
synchronized(getUsers()) {
|
||||
Collection<User> normalList = getUsers().values();
|
||||
for (User u : normalList) {
|
||||
if (overloadedUsers.containsKey(u.getUUID().toLowerCase())) {
|
||||
overloadedList.add(overloadedUsers.get(u.getUUID().toLowerCase()));
|
||||
} else {
|
||||
overloadedList.add(u);
|
||||
}
|
||||
}
|
||||
}
|
||||
return overloadedList;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param userId
|
||||
* @return true if user is overloaded.
|
||||
*/
|
||||
public boolean isOverloaded(String userId) {
|
||||
|
||||
return overloadedUsers.containsKey(userId.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param userId
|
||||
*/
|
||||
public void overloadUser(String userId) {
|
||||
|
||||
if (!isOverloaded(userId)) {
|
||||
User theUser = getUser(userId);
|
||||
theUser = theUser.clone();
|
||||
if (overloadedUsers.containsKey(theUser.getUUID().toLowerCase())) {
|
||||
overloadedUsers.remove(theUser.getUUID().toLowerCase());
|
||||
}
|
||||
overloadedUsers.put(theUser.getUUID().toLowerCase(), theUser);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param userId
|
||||
*/
|
||||
public void removeOverload(String userId) {
|
||||
|
||||
User theUser = getUser(userId);
|
||||
overloadedUsers.remove(theUser.getUUID().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 userId
|
||||
* @return user object
|
||||
*/
|
||||
public User surpassOverload(String userId) {
|
||||
|
||||
if (!isOverloaded(userId)) {
|
||||
return getUser(userId);
|
||||
}
|
||||
if (getUsers().containsKey(userId.toLowerCase())) {
|
||||
return getUsers().get(userId.toLowerCase());
|
||||
}
|
||||
User newUser = createUser(userId);
|
||||
return newUser;
|
||||
}
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
package org.anjocaido.groupmanager.dataholder;
|
||||
|
||||
import org.anjocaido.groupmanager.data.User;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 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 final Map<String, User> users = Collections.synchronizedMap(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.
|
||||
synchronized (users) {
|
||||
for (User user : users.values()) {
|
||||
user.setDataSource(this.dataSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: Iteration over this object has to be synchronized!
|
||||
*
|
||||
* @return the users
|
||||
*/
|
||||
public Map<String, User> getUsers() {
|
||||
|
||||
return users;
|
||||
}
|
||||
|
||||
public WorldDataHolder getDataSource() {
|
||||
|
||||
return this.dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the Users
|
||||
*/
|
||||
public void resetUsers() {
|
||||
this.users.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,815 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.anjocaido.groupmanager.dataholder.worlds;
|
||||
|
||||
import org.anjocaido.groupmanager.GroupManager;
|
||||
import org.anjocaido.groupmanager.dataholder.OverloadedWorldHolder;
|
||||
import org.anjocaido.groupmanager.dataholder.WorldDataHolder;
|
||||
import org.anjocaido.groupmanager.permissions.AnjoPermissionsHandler;
|
||||
import org.anjocaido.groupmanager.utils.Tasks;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* @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.
|
||||
* <p/>
|
||||
* 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the mirrorsGroup
|
||||
*/
|
||||
public Map<String, String> getMirrorsGroup() {
|
||||
|
||||
return mirrorsGroup;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the mirrorsUser
|
||||
*/
|
||||
public Map<String, String> getMirrorsUser() {
|
||||
|
||||
return mirrorsUser;
|
||||
}
|
||||
|
||||
public boolean isWorldKnown(String name) {
|
||||
|
||||
return worldsData.containsKey(name.toLowerCase());
|
||||
}
|
||||
|
||||
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()) {
|
||||
GroupManager.logger.log(Level.FINE, "Checking data for " + world.getName() + ".");
|
||||
if ((!worldsData.containsKey(world.getName().toLowerCase())) && ((!mirrorsGroup.containsKey(world.getName().toLowerCase())) || (!mirrorsUser.containsKey(world.getName().toLowerCase())))) {
|
||||
|
||||
if (worldsData.containsKey("all_unnamed_worlds")) {
|
||||
|
||||
String usersMirror = mirrorsUser.get("all_unnamed_worlds");
|
||||
String groupsMirror = mirrorsGroup.get("all_unnamed_worlds");
|
||||
|
||||
if (usersMirror != null) {
|
||||
mirrorsUser.put(world.getName().toLowerCase(), usersMirror);
|
||||
}
|
||||
|
||||
if (groupsMirror != null) {
|
||||
mirrorsGroup.put(world.getName().toLowerCase(), groupsMirror);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GroupManager.logger.log(Level.FINE, "Creating folders for " + world.getName() + ".");
|
||||
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() && !folder.getName().startsWith(".")) {
|
||||
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.equalsIgnoreCase(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 Map) {
|
||||
Map subSection = (Map) mirrorsMap.get(source);
|
||||
|
||||
for (Object key : subSection.keySet()) {
|
||||
|
||||
if (!((String) key).equalsIgnoreCase(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(((String) key).toLowerCase());
|
||||
}
|
||||
|
||||
if (type.equals("users")) {
|
||||
mirrorsUser.remove(((String) key).toLowerCase());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
}
|
||||
if (type.equals("groups")) {
|
||||
mirrorsGroup.put(((String) key).toLowerCase(), getWorldData(source).getName());
|
||||
GroupManager.logger.log(Level.FINE, "Adding groups mirror for " + key + ".");
|
||||
}
|
||||
|
||||
if (type.equals("users")) {
|
||||
mirrorsUser.put(((String) key).toLowerCase(), getWorldData(source).getName());
|
||||
GroupManager.logger.log(Level.FINE, "Adding users mirror for " + key + ".");
|
||||
}
|
||||
}
|
||||
|
||||
// Track this world so we can create a datasource for it later
|
||||
mirroredWorlds.add((String) key);
|
||||
|
||||
} else {
|
||||
throw new IllegalStateException("Unknown mirroring format for " + (String) key);
|
||||
}
|
||||
|
||||
} else {
|
||||
GroupManager.logger.log(Level.WARNING, "Mirroring error with " + (String) key + ". Recursive loop detected!");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a datasource for any worlds not already loaded
|
||||
for (String world : mirroredWorlds) {
|
||||
if (!worldsData.containsKey(world.toLowerCase())) {
|
||||
GroupManager.logger.log(Level.FINE, "No data for " + world + ".");
|
||||
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 boolean saveChanges(boolean overwrite) {
|
||||
|
||||
boolean changed = false;
|
||||
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());
|
||||
changed = true;
|
||||
//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();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
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());
|
||||
changed = true;
|
||||
//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();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
alreadyDone.add(w);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* <p/>
|
||||
* 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 attempt to return the global mirror.
|
||||
if (worldsData.containsKey("all_unnamed_worlds")) {
|
||||
GroupManager.logger.finest("Requested world " + worldName + " not found or badly mirrored. Returning all_unnamed_worlds world...");
|
||||
return getUpdatedWorldData("all_unnamed_worlds");
|
||||
}
|
||||
|
||||
// Oddly no data source or global mirror 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() {
|
||||
|
||||
/* Do not use the folder name if this
|
||||
* is a Bukkit Forge server.
|
||||
*/
|
||||
if (plugin.getServer().getName().equalsIgnoreCase("BukkitForge")) {
|
||||
serverDefaultWorldName = "overworld";
|
||||
|
||||
} else {
|
||||
Properties server = new Properties();
|
||||
try {
|
||||
server.load(new FileInputStream(new File("server.properties")));
|
||||
serverDefaultWorldName = server.getProperty("level-name").toLowerCase();
|
||||
} catch (IOException ex) {
|
||||
GroupManager.logger.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
setupWorldFolder(serverDefaultWorldName);
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
* <p/>
|
||||
* 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(worldNameLowered);
|
||||
|
||||
// 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.
|
||||
* <p/>
|
||||
* 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 which isn't an identical mirror.
|
||||
*
|
||||
* @return ArrayList<OverloadedWorldHolder> of all loaded worlds
|
||||
*/
|
||||
public ArrayList<OverloadedWorldHolder> allWorldsDataList() {
|
||||
|
||||
ArrayList<OverloadedWorldHolder> list = new ArrayList<OverloadedWorldHolder>();
|
||||
|
||||
for (String world : worldsData.keySet()) {
|
||||
|
||||
if (!world.equalsIgnoreCase("all_unnamed_worlds")) {
|
||||
|
||||
// Fetch the relevant world object
|
||||
OverloadedWorldHolder data = getWorldData(world);
|
||||
|
||||
if (!list.contains(data)) {
|
||||
|
||||
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) {
|
||||
data = getWorldData(usersMirror.toLowerCase());
|
||||
|
||||
// Only add the parent if it's not already listed.
|
||||
if (!list.contains(data)) {
|
||||
list.add(data);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
package org.anjocaido.groupmanager.events;
|
||||
|
||||
import org.anjocaido.groupmanager.GroupManager;
|
||||
import org.anjocaido.groupmanager.data.Group;
|
||||
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) {
|
||||
|
||||
synchronized (GroupManager.getGMEventHandler().getServer()) {
|
||||
if (GroupManager.getGMEventHandler().getServer().getScheduler().scheduleSyncDelayedTask(GroupManager.getGMEventHandler().getPlugin(), new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
GroupManager.getGMEventHandler().getServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
}, 1) == -1) {
|
||||
GroupManager.logger.warning("Could not schedule GM Event.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package org.anjocaido.groupmanager.events;
|
||||
|
||||
import org.anjocaido.groupmanager.GroupManager;
|
||||
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) {
|
||||
|
||||
synchronized (GroupManager.getGMEventHandler().getServer()) {
|
||||
if (GroupManager.getGMEventHandler().getServer().getScheduler().scheduleSyncDelayedTask(GroupManager.getGMEventHandler().getPlugin(), new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
GroupManager.getGMEventHandler().getServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
}, 1) == -1) {
|
||||
GroupManager.logger.warning("Could not schedule GM Event.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
package org.anjocaido.groupmanager.events;
|
||||
|
||||
import org.anjocaido.groupmanager.GroupManager;
|
||||
import org.anjocaido.groupmanager.data.User;
|
||||
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.getLastName();
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
synchronized (GroupManager.getGMEventHandler().getServer()) {
|
||||
if (GroupManager.getGMEventHandler().getServer().getScheduler().scheduleSyncDelayedTask(GroupManager.getGMEventHandler().getPlugin(), new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
GroupManager.getGMEventHandler().getServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
}, 1) == -1) {
|
||||
GroupManager.logger.warning("Could not schedule GM Event.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
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
|
||||
* <p/>
|
||||
* 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);
|
||||
|
||||
if (plugin.getWorldsHolder().isWorldKnown("all_unnamed_worlds")) {
|
||||
|
||||
String usersMirror = plugin.getWorldsHolder().getMirrorsUser().get("all_unnamed_worlds");
|
||||
String groupsMirror = plugin.getWorldsHolder().getMirrorsGroup().get("all_unnamed_worlds");
|
||||
|
||||
if (usersMirror != null) {
|
||||
plugin.getWorldsHolder().getMirrorsUser().put(worldName.toLowerCase(), usersMirror);
|
||||
}
|
||||
|
||||
if (groupsMirror != null) {
|
||||
plugin.getWorldsHolder().getMirrorsGroup().put(worldName.toLowerCase(), groupsMirror);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package org.anjocaido.groupmanager.events;
|
||||
|
||||
import org.anjocaido.groupmanager.GroupManager;
|
||||
import org.anjocaido.groupmanager.data.Group;
|
||||
import org.anjocaido.groupmanager.data.User;
|
||||
import org.bukkit.Server;
|
||||
|
||||
/**
|
||||
* @author ElgarL
|
||||
* <p/>
|
||||
* Handles all Event generation.
|
||||
*/
|
||||
public class GroupManagerEventHandler {
|
||||
|
||||
private final Server server;
|
||||
private final GroupManager plugin;
|
||||
|
||||
|
||||
public GroupManagerEventHandler(GroupManager plugin) {
|
||||
|
||||
this.plugin = plugin;
|
||||
this.server = plugin.getServer();
|
||||
|
||||
}
|
||||
|
||||
protected void callEvent(GMGroupEvent event) {
|
||||
|
||||
event.schedule(event);
|
||||
}
|
||||
|
||||
protected void callEvent(GMUserEvent event) {
|
||||
|
||||
event.schedule(event);
|
||||
}
|
||||
|
||||
protected void callEvent(GMSystemEvent event) {
|
||||
|
||||
event.schedule(event);
|
||||
}
|
||||
|
||||
public void callEvent(Group group, GMGroupEvent.Action action) {
|
||||
|
||||
callEvent(new GMGroupEvent(group, action));
|
||||
}
|
||||
|
||||
public void callEvent(String groupName, GMGroupEvent.Action action) {
|
||||
|
||||
callEvent(new GMGroupEvent(groupName, action));
|
||||
}
|
||||
|
||||
public void callEvent(User user, GMUserEvent.Action action) {
|
||||
|
||||
callEvent(new GMUserEvent(user, action));
|
||||
}
|
||||
|
||||
public void callEvent(String userName, GMUserEvent.Action action) {
|
||||
|
||||
callEvent(new GMUserEvent(userName, action));
|
||||
}
|
||||
|
||||
public void callEvent(GMSystemEvent.Action action) {
|
||||
|
||||
callEvent(new GMSystemEvent(action));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the plugin
|
||||
*/
|
||||
public GroupManager getPlugin() {
|
||||
|
||||
return plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the server
|
||||
*/
|
||||
public Server getServer() {
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,756 @@
|
||||
/*
|
||||
* 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.*;
|
||||
import java.net.Proxy;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.*;
|
||||
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().size();
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,508 @@
|
||||
/*
|
||||
* 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 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.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;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* BukkitPermissions overrides to force GM reponses to Superperms
|
||||
*
|
||||
* @author ElgarL
|
||||
*/
|
||||
public class BukkitPermissions {
|
||||
|
||||
protected LinkedHashMap<String, PermissionAttachment> attachments = new LinkedHashMap<String, 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() {
|
||||
|
||||
/*
|
||||
* collect new permissions
|
||||
* and register all attachments.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
String uuid = player.getUniqueId().toString();
|
||||
|
||||
// Reset the User objects player reference.
|
||||
User user = plugin.getWorldsHolder().getWorldData(player.getWorld().getName()).getUser(uuid, player.getName());
|
||||
|
||||
if (user != null) {
|
||||
user.updatePlayer(player);
|
||||
}
|
||||
|
||||
PermissionAttachment attachment;
|
||||
|
||||
// Find the players current attachment, or add a new one.
|
||||
if (this.attachments.containsKey(uuid)) {
|
||||
attachment = this.attachments.get(uuid);
|
||||
} else {
|
||||
attachment = player.addAttachment(plugin);
|
||||
this.attachments.put(uuid, 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(uuid, 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do not push any perms to bukkit if...
|
||||
* We are in offline mode
|
||||
* and the player has the 'groupmanager.noofflineperms' permission.
|
||||
*/
|
||||
if (!Bukkit.getServer().getOnlineMode() && (newPerms.containsKey("groupmanager.noofflineperms") && (newPerms.get("groupmanager.noofflineperms") == true))) {
|
||||
removeAttachment(uuid);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
synchronized (attachment.getPermissible()) {
|
||||
|
||||
@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();
|
||||
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
GroupManager.logger.finest("Attachment updated for: " + player.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
/*
|
||||
* Ignore stupid plugins which add empty permission nodes.
|
||||
*/
|
||||
if (!key.isEmpty()) {
|
||||
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(String uuid) {
|
||||
|
||||
if (attachments.containsKey(uuid)) {
|
||||
attachments.get(uuid).remove();
|
||||
attachments.remove(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all attachments in case of a restart or reload.
|
||||
*/
|
||||
public void removeAllAttachments() {
|
||||
|
||||
/*
|
||||
* Remove all attachments.
|
||||
*/
|
||||
for (String key : attachments.keySet()) {
|
||||
attachments.get(key).remove();
|
||||
}
|
||||
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();
|
||||
|
||||
GroupManager.logger.finest("Player Join event: " + player.getName());
|
||||
|
||||
/*
|
||||
* Tidy up any lose ends
|
||||
*/
|
||||
removeAttachment(player.getUniqueId().toString());
|
||||
|
||||
// force GM to create the player if they are not already listed.
|
||||
plugin.getWorldsHolder().getWorldData(player.getWorld().getName()).getUser(player.getUniqueId().toString(), player.getName());
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
/*
|
||||
* Trigger at highest so we tidy up last.
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
|
||||
if (!GroupManager.isLoaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
String uuid = player.getUniqueId().toString();
|
||||
|
||||
// Reset the User objects player reference.
|
||||
User user = plugin.getWorldsHolder().getWorldData(player.getWorld().getName()).getUser(uuid, player.getName());
|
||||
|
||||
user.updatePlayer(null);
|
||||
|
||||
/*
|
||||
* force remove any attachments as bukkit may not
|
||||
*/
|
||||
removeAttachment(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,259 @@
|
||||
package org.anjocaido.groupmanager.permissions;
|
||||
|
||||
//import java.util.Collection;
|
||||
//import java.util.Map;
|
||||
//import java.util.Set;
|
||||
|
||||
import org.anjocaido.groupmanager.data.Group;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
//import org.anjocaido.groupmanager.data.User;
|
||||
|
||||
/**
|
||||
* Made by Nijikokun. Changed by Gabriel Couto
|
||||
* <p/>
|
||||
* 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);
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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,
|
||||
manuclearp,
|
||||
manulistp,
|
||||
manucheckp,
|
||||
mangaddp,
|
||||
mangdelp,
|
||||
mangclearp,
|
||||
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,
|
||||
mancheckw
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.
|
||||
* <p/>
|
||||
* 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.
|
||||
* <p/>
|
||||
* 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.
|
||||
* <p/>
|
||||
* owner field and accessLevel field should not be considered,
|
||||
* when type is
|
||||
* NOTFOUND
|
||||
*/
|
||||
NOTFOUND
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.anjocaido.groupmanager.utils;
|
||||
|
||||
import org.anjocaido.groupmanager.GroupManager;
|
||||
import org.anjocaido.groupmanager.data.Group;
|
||||
|
||||
import java.io.*;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
}
|
240
EssentialsGroupManager/src/main/resources/Changelog.txt
Normal file
240
EssentialsGroupManager/src/main/resources/Changelog.txt
Normal file
@ -0,0 +1,240 @@
|
||||
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.
|
||||
- Only output a Data update message if something has changed.
|
||||
- Fix loading users with only numerals in their names to be seen as strings.
|
||||
- Ignore any sub folders in the Worlds folder which start with a period (fix for storing data in svn respoitories).
|
||||
- Throw a better error than 'null' when someone removes all groups from a yml.
|
||||
- Stop force removing attachments and let Bukkit handle it's own mess.
|
||||
- Change to our own Yaml parsing for globalgroups instead of using the YAMLConfiguration class in bukkit.
|
||||
- Fix a cases sensitivity bug in world loading.
|
||||
- Stop using the YamlConfiguration in bukkit for our config handling. We can now support periods in world names.
|
||||
- Fix GlobalGroups not loading permission nodes.
|
||||
- Fix an error with Logging set to 'OFF' triggering a cast exception.
|
||||
- No more null errors from corrupt config.yml's.
|
||||
- Give a better error when a subgroup is null.
|
||||
- Include the GM version when logging errors.
|
||||
- Fix Synchronization on adding subgroups (thanks snowleo).
|
||||
- Remove info node support from GlobalGroups. It should not have them as GlobalGroups are only permission collections.
|
||||
- Change order of data in Users.yml to [name, Group, SubGroup, Permissions, Info nodes].
|
||||
- Add alphabetically sorted user lists.
|
||||
- allWorldsDataList now returns fully mirrored worlds which are not identical mirrors (fixes the /manselect list).
|
||||
- Add support for Rcon.
|
||||
- Prevent GM commands from being used on CommandBlocks.
|
||||
- Clear our attachment map upon a manload so we correctly reconfigure a players new permissions.
|
||||
- Synchronize the raising of GroupManager events to Bukkit.getServer() (should prevent deadlocks).
|
||||
- Synchronize pushing to Bukkit perms to prevent any ConcurrentModificationException.
|
||||
- Do not grant any permissions (nor update Bukkit) if the server is in offline mode and the player has the permission node 'groupmanager.noofflineperms'.
|
||||
- Negate 'groupmanager.noofflineperms' by default in the owner group.
|
||||
- Add support for BukkitForge using 'overworld' as the main world name.
|
||||
- Prevent '*' permissions granting the 'groupmanager.noofflineperms' permission.
|
||||
- Added '/mancheckw <world>' to inspect which permission files a world is referencing.
|
||||
- Add config potion to set if GM commands should be allowed on CommnandBlocks.
|
||||
- Catch the error when using an out of date config for 'allow_commandblocks' So it doesn't kill the whole config.
|
||||
- '/manselect' will no longer list duplicate worlds.
|
||||
- Added a new mirroring option in the config of 'all_unnamed_worlds'. This will cause all new or unnamed worlds to use this mirroring.
|
||||
- Don't allow adding a node with '/manuaddp' and '/mangaddp' which is already negated.
|
||||
- Warn when adding a node where an exception already exist.
|
||||
- Only prevent adding nodes with '/manuaddp' and '/mangaddp' if they are exact matches (not wildcards).
|
||||
- Store worldSelection indexed on the senders name rather than the object (fixes commandblocks using manselect).
|
||||
- Check subgroup permissions with an equal priority so no one subgroup is higher ranked than another.
|
||||
- add recursive permission adding/deleting
|
||||
- Prevent adding sub groups for ranks the granting player doesn't have access to.
|
||||
- Allow Exceptions in any inherited group to override negation of permissions.
|
||||
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.
|
||||
- Set a default mirror map if none is found in the config.
|
||||
- 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.
|
50
EssentialsGroupManager/src/main/resources/config.yml
Normal file
50
EssentialsGroupManager/src/main/resources/config.yml
Normal file
@ -0,0 +1,50 @@
|
||||
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 'mantogglevalidate'
|
||||
# true will cause GroupManager to attempt name matching by default.
|
||||
validate_toggle: true
|
||||
# ************************************************************************************************************************************************************
|
||||
# *** NOTE: Having this feature enabled can allow improper use of Command Blocks which may lead to undesireable permission changes. You have been warned! ***
|
||||
# ************************************************************************************************************************************************************
|
||||
allow_commandblocks: false
|
||||
|
||||
data:
|
||||
save:
|
||||
# How often GroupManager will save it's data back to groups.yml 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, and is the parent world.
|
||||
# subsequent elements 'world_nether' and 'world_the_end' are worlds which will use
|
||||
# the same user/groups files as the parent.
|
||||
# the element 'all_unnamed_worlds' specifies all worlds that aren't listed, and automatically mirrors them to it's parent.
|
||||
# Each child world can be configured to mirror the 'groups', 'users' or both files from its parent.
|
||||
world:
|
||||
world_nether:
|
||||
- users
|
||||
- groups
|
||||
world_the_end:
|
||||
- users
|
||||
- groups
|
||||
all_unnamed_worlds:
|
||||
- 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)
|
328
EssentialsGroupManager/src/main/resources/globalgroups.yml
Normal file
328
EssentialsGroupManager/src/main/resources/globalgroups.yml
Normal file
@ -0,0 +1,328 @@
|
||||
# These groups only contain permission nodes.
|
||||
#
|
||||
# **** You can NOT add anything other than permission nodes ****
|
||||
# **** This is NOT where you set up the groups which you give to users! ****
|
||||
# **** goto groupmanager/worlds/worldname/groups.yml if you want to set the actual groups! ****
|
||||
#
|
||||
# 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 your needs.
|
||||
|
||||
groups:
|
||||
|
||||
# Permission nodes for GroupManager
|
||||
# by ElgarL, snowleo, continued from gabrielcouto's original
|
||||
# http://wiki.ess3.net
|
||||
|
||||
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
|
||||
- essentials.jail.allow.help
|
||||
- essentials.jail.allow.helpop
|
||||
- essentials.jail.allow.rules
|
||||
|
||||
g:essentials_builder:
|
||||
permissions:
|
||||
- essentials.afk
|
||||
- essentials.afk.auto
|
||||
- essentials.back
|
||||
- essentials.back.ondeath
|
||||
- essentials.balance
|
||||
- essentials.balance.others
|
||||
- essentials.balancetop
|
||||
- essentials.book
|
||||
- essentials.chat.color
|
||||
- essentials.chat.format
|
||||
- essentials.chat.shout
|
||||
- essentials.chat.question
|
||||
- essentials.compass
|
||||
- essentials.delhome
|
||||
- essentials.depth
|
||||
- essentials.exp
|
||||
- essentials.getpos
|
||||
- essentials.hat
|
||||
- essentials.home
|
||||
- essentials.ignore
|
||||
- essentials.itemdb
|
||||
- essentials.kit
|
||||
- essentials.kits.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.recipe
|
||||
- essentials.seen
|
||||
- essentials.sethome
|
||||
- essentials.sethome.bed
|
||||
- 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
|
||||
- essentials.jail.allow.mail
|
||||
- essentials.jail.allow.ping
|
||||
- essentials.jail.allow.seen
|
||||
|
||||
g:essentials_moderator:
|
||||
permissions:
|
||||
- -essentials.spawner.enderdragon
|
||||
- essentials.afk.kickexempt
|
||||
- essentials.ban
|
||||
- essentials.ban.notify
|
||||
- essentials.banip
|
||||
- essentials.book.title
|
||||
- essentials.book.others
|
||||
- essentials.broadcast
|
||||
- essentials.chat.url
|
||||
- essentials.chat.magic
|
||||
- essentials.clearinventory
|
||||
- essentials.delwarp
|
||||
- essentials.eco.loan
|
||||
- essentials.exp.others
|
||||
- essentials.ext
|
||||
- essentials.fly
|
||||
- essentials.fly.safelogin
|
||||
- essentials.getpos
|
||||
- essentials.getpos.others
|
||||
- essentials.helpop.receive
|
||||
- essentials.home.others
|
||||
- essentials.invsee
|
||||
- essentials.jails
|
||||
- essentials.jump
|
||||
- essentials.kick
|
||||
- essentials.kick.notify
|
||||
- essentials.kill
|
||||
- essentials.kits.*
|
||||
- essentials.msg.magic
|
||||
- essentials.mute
|
||||
- essentials.mute.notify
|
||||
- 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.vanish
|
||||
- essentials.vanish.effect
|
||||
- essentials.warps.*
|
||||
- essentials.weather
|
||||
- essentials.whois
|
||||
- essentials.workbench
|
||||
- essentials.world
|
||||
- essentials.worlds.*
|
||||
- essentials.jail.allow.jails
|
||||
- essentials.jail.allow.togglejail
|
||||
|
||||
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.local
|
||||
|
||||
g:towny_builder:
|
||||
permissions:
|
||||
- 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.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
|
75
EssentialsGroupManager/src/main/resources/groups.yml
Normal file
75
EssentialsGroupManager/src/main/resources/groups.yml
Normal file
@ -0,0 +1,75 @@
|
||||
# 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.effects.*
|
||||
- +vanish.effects.toggle.all
|
||||
inheritance:
|
||||
- admin
|
||||
info:
|
||||
prefix: '&4'
|
||||
build: true
|
||||
suffix: ''
|
184
EssentialsGroupManager/src/main/resources/plugin.yml
Normal file
184
EssentialsGroupManager/src/main/resources/plugin.yml
Normal file
@ -0,0 +1,184 @@
|
||||
name: GroupManager
|
||||
version: ${project.version}-b${BUILD_NUMBER}
|
||||
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: Moves a player to desired group (Adds to the file if does not exist).
|
||||
usage: /<command> <player> <group> | optional [world]
|
||||
permissions: groupmanager.manuadd
|
||||
manudel:
|
||||
description: Removes any user specific configuration and make them default group.
|
||||
usage: /<command> <player>
|
||||
permissions: groupmanager.manudel
|
||||
manuaddsub:
|
||||
description: Adds a group to a user's subgroup list.
|
||||
usage: /<command> <player> <group>
|
||||
permissions: groupmanager.manuaddsub
|
||||
manudelsub:
|
||||
description: Removes a group from a user's subgroup list.
|
||||
usage: /<command> <player> <group>
|
||||
permissions: groupmanager.manudelsub
|
||||
mangadd:
|
||||
description: Adds a group to the system.
|
||||
usage: /<command> <group>
|
||||
permissions: groupmanager.mangadd
|
||||
mangdel:
|
||||
description: Removes a group from the system (all its users become default).
|
||||
usage: /<command> <group>
|
||||
permissions: groupmanager.mangdel
|
||||
manuaddp:
|
||||
description: Adds permissions directly to the user.
|
||||
usage: /<command> <player> <permission> [permission2] [permission3]..
|
||||
permissions: groupmanager.manuaddp
|
||||
manudelp:
|
||||
description: Removes permissions directly from the user.
|
||||
usage: /<command> <player> <permission> [permission2] [permission3]..
|
||||
permissions: groupmanager.manudelp
|
||||
manuclearp:
|
||||
description: Removes all permissions from a user.
|
||||
usage: /<command> <player>
|
||||
permissions: groupmanager.manuclearp
|
||||
manulistp:
|
||||
description: Lists all permissions of a user.
|
||||
usage: /<command> <player>
|
||||
permissions: groupmanager.manulistp
|
||||
manucheckp:
|
||||
description: Verifies if user has a permission, and where it comes from.
|
||||
usage: /<command> <player> <permissions>
|
||||
permissions: groupmanager.manucheckp
|
||||
mangaddp:
|
||||
description: Adds permissions to a group.
|
||||
usage: /<command> <group> <permission> [permission2] [permission3]..
|
||||
permissions: groupmanager.mangaddp
|
||||
mangdelp:
|
||||
description: Removes permissions from a group.
|
||||
usage: /<command> <group> <permission> [permission2] [permission3]..
|
||||
permissions: groupmanager.mangdelp
|
||||
mangclearp:
|
||||
description: Removes all permissions from a group.
|
||||
usage: /<command> <group> <permissions>
|
||||
permissions: groupmanager.mangclearp
|
||||
manglistp:
|
||||
description: Lists all permissions of a group.
|
||||
usage: /<command> <group>
|
||||
permissions: groupmanager.manglistp
|
||||
mangcheckp:
|
||||
description: Checks if group has a permission and where it comes from.
|
||||
usage: /<command> <group> <permissions>
|
||||
permissions: groupmanager.mangcheckp
|
||||
mangaddi:
|
||||
description: Adds a group to another group inheritance list.
|
||||
usage: /<command> <group1> <group2>
|
||||
permissions: groupmanager.mangaddi
|
||||
mangdeli:
|
||||
description: Removes a group from another group inheritance list.
|
||||
usage: /<command> <group1> <group2>
|
||||
permissions: groupmanager.mangdeli
|
||||
manuaddv:
|
||||
description: Adds or replaces a variable of a user (like prefix or suffix).
|
||||
usage: /<command> <user> <variable> <value>
|
||||
permissions: groupmanager.manuaddv
|
||||
manudelv:
|
||||
description: Removes a variable from a user.
|
||||
usage: /<command> <user> <variable>
|
||||
permissions: groupmanager.manudelv
|
||||
manulistv:
|
||||
description: Lists variables of a user (like prefix or suffix).
|
||||
usage: /<command> <user>
|
||||
permissions: groupmanager.manulistv
|
||||
manucheckv:
|
||||
description: Verifies a value of a variable of a user, and where it comes from.
|
||||
usage: /<command> <user> <variable>
|
||||
permissions: groupmanager.manucheckv
|
||||
mangaddv:
|
||||
description: Adds or replaces a variable of a group (like prefix or suffix).
|
||||
usage: /<command> <group> <variable> <value>
|
||||
permissions: groupmanager.mangaddv
|
||||
mangdelv:
|
||||
description: Removes a variable from a group.
|
||||
usage: /<command> <group> <variable>
|
||||
permissions: groupmanager.mangdelv
|
||||
manglistv:
|
||||
description: Lists variables of a group (like prefix or suffix).
|
||||
usage: /<command> <group>
|
||||
permissions: groupmanager.manglistv
|
||||
mangcheckv:
|
||||
description: Verifies a value of a variable of a group, and where it comes from.
|
||||
usage: /<command> <group> <variable>
|
||||
permissions: groupmanager.mangckeckv
|
||||
manwhois:
|
||||
description: Lists groups and other data of a user.
|
||||
usage: /<command> <player>
|
||||
permissions: groupmanager.manwhois
|
||||
tempadd:
|
||||
description: Creates a temporary permissions copy for a user.
|
||||
usage: /<command> <player>
|
||||
permissions: groupmanager.tempadd
|
||||
tempdel:
|
||||
description: Removes the temporary permissions copy for a user.
|
||||
usage: /<command> <player>
|
||||
permissions: groupmanager.tempdel
|
||||
templist:
|
||||
description: Lists users in overload-permissions mode made by command /tempadd.
|
||||
usage: /<command>
|
||||
permissions: groupmanager.templist
|
||||
tempdelall:
|
||||
description: Removes all overrides made by command /tempadd.
|
||||
usage: /<command>
|
||||
permissions: groupmanager.tempdelall
|
||||
mansave:
|
||||
description: Saves all permissions from server to file.
|
||||
usage: /<command>
|
||||
permissions: groupmanager.mansave
|
||||
manload:
|
||||
description: Reloads current world and config.yml, or loads given world from file to server.
|
||||
usage: /<command> [world]
|
||||
permissions: groupmanager.manload
|
||||
listgroups:
|
||||
aliases: [manlistg]
|
||||
description: Lists the groups available.
|
||||
usage: /<command>
|
||||
permissions: groupmanager.listgroups
|
||||
manpromote:
|
||||
description: Promotes a user in the same heritage line to a higher rank.
|
||||
usage: /<command> <player> <group>
|
||||
permissions: groupmanager.manpromote
|
||||
mandemote:
|
||||
description: Demotes a user in the same heritage line to a lower rank.
|
||||
usage: /<command> <player> <group>
|
||||
permissions: groupmanager.mandemote
|
||||
mantogglevalidate:
|
||||
description: Toggles on/off the validating if user is online.
|
||||
usage: /<command>
|
||||
permissions: groupmanager.mantogglevalidate
|
||||
mantogglesave:
|
||||
description: Toggles on/off the autosave.
|
||||
usage: /<command>
|
||||
permissions: groupmanager.mantogglesave
|
||||
manworld:
|
||||
description: Prints the selected world name.
|
||||
usage: /<command>
|
||||
permissions: groupmanager.manworld
|
||||
manselect:
|
||||
description: Selects a world to work with commands.
|
||||
usage: /<command> <world>
|
||||
permissions: groupmanager.manselect
|
||||
manclear:
|
||||
description: Clears world selection. Commands will work on your current world.
|
||||
usage: /<command>
|
||||
permissions: groupmanager.manclear
|
||||
mancheckw:
|
||||
description: Obtains the path to each file a world is storing its data in (users/groups).
|
||||
usage: /<command> <world>
|
||||
permissions: groupmanager.mancheckw
|
||||
|
||||
Permissions:
|
||||
groupmanager.op:
|
||||
description: User is treated as an op when using the GroupManager commands.
|
||||
default: false
|
18
EssentialsGroupManager/src/main/resources/users.yml
Normal file
18
EssentialsGroupManager/src/main/resources/users.yml
Normal file
@ -0,0 +1,18 @@
|
||||
# "For a more advanced configuration example utilizing the advanced features of GroupManager, see http://pastebin.com/a8ZA0j5G"
|
||||
users:
|
||||
snowleo:
|
||||
group: Builder
|
||||
subgroups: []
|
||||
permissions:
|
||||
- groupmanager.noofflineperms
|
||||
KHobbits:
|
||||
group: Moderator
|
||||
subgroups: []
|
||||
permissions:
|
||||
- groupmanager.noofflineperms
|
||||
ElgarL:
|
||||
group: Moderator
|
||||
subgroups: []
|
||||
permissions:
|
||||
- groupmanager.noofflineperms
|
||||
|
Loading…
Reference in New Issue
Block a user