1
0
mirror of https://e.coding.net/circlecloud/GroupManager.git synced 2024-11-24 02:09:07 +00:00

使用YUMC统计系统...

Signed-off-by: 502647092 <jtb1@163.com>
This commit is contained in:
502647092 2016-03-01 11:15:02 +08:00
commit ae31156f72
38 changed files with 10717 additions and 0 deletions

31
.classpath Normal file
View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

38
.gitignore vendored Normal file
View File

@ -0,0 +1,38 @@
# Eclipse stuff
/.settings
# netbeans
/nbproject
# we use maven!
/build.xml
# maven
/target
/repo
# vim
.*.sw[a-p]
# various other potential build files
/build
/bin
/dist
/manifest.mf
/world
# Mac filesystem dust
*.DS_Store
# intellij
*.iml
*.ipr
*.iws
.idea/
# Project Stuff
/src/main/resources/Soulbound
# Atlassian Stuff
/atlassian-ide-plugin.xml

23
.project Normal file
View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>GroupManager</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

78
pom.xml Normal file
View File

@ -0,0 +1,78 @@
<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>GroupManager</artifactId>
<version>2.3</version>
<build>
<finalName>${project.name}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<minimizeJar>true</minimizeJar>
<artifactSet>
<includes>
<include>cn.citycraft:PluginHelper</include>
</includes>
</artifactSet>
<relocations>
<relocation>
<pattern>cn.citycraft.PluginHelper</pattern>
<shadedPattern>${project.groupId}.${project.artifactId}</shadedPattern>
</relocation>
</relocations>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
</repository>
<repository>
<id>citycraft-repo</id>
<url>${jenkins.url}/plugin/repository/everything/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<type>jar</type>
<version>1.8.8-R0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.citycraft</groupId>
<artifactId>PluginHelper</artifactId>
<type>jar</type>
<version>1.0</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,208 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.anjocaido.groupmanager;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import org.anjocaido.groupmanager.utils.Tasks;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import org.yaml.snakeyaml.reader.UnicodeReader;
/**
*
* @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;
}
}

View File

@ -0,0 +1,483 @@
package org.anjocaido.groupmanager;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
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;
/**
* @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

View File

@ -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!");
}
}

View File

@ -0,0 +1,205 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.anjocaido.groupmanager.data;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.anjocaido.groupmanager.GroupManager;
import org.anjocaido.groupmanager.dataholder.WorldDataHolder;
import org.anjocaido.groupmanager.utils.StringPermissionComparator;
/**
*
* @author gabrielcouto
*/
public abstract class DataUnit {
private WorldDataHolder dataSource;
private String 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;
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;
}
}
}

View File

@ -0,0 +1,197 @@
/*
* 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);
}
}
}
}

View File

@ -0,0 +1,97 @@
/*
* 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;
}
}

View File

@ -0,0 +1,323 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.anjocaido.groupmanager.data;
// import com.sun.org.apache.bcel.internal.generic.AALOAD;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.anjocaido.groupmanager.GroupManager;
import org.anjocaido.groupmanager.dataholder.WorldDataHolder;
import org.anjocaido.groupmanager.events.GMUserEvent.Action;
import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
/**
*
* @author gabrielcouto/ElgarL
*/
public class User extends DataUnit implements Cloneable {
/**
*
*/
private String group = null;
private 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.
*
* @deprecated use {@link #getLastName()} and {@link #getUUID()}.
* @return a string containing the players last known name.
*/
@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;
}
}

View File

@ -0,0 +1,56 @@
/*
* 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;
}
}

View File

@ -0,0 +1,213 @@
/*
* 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();
}
}

View File

@ -0,0 +1,136 @@
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;
}
}

View File

@ -0,0 +1,220 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.anjocaido.groupmanager.dataholder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.anjocaido.groupmanager.data.User;
/**
*
* @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 userName) {
// OVERLOADED CODE
String userNameLowered = userName.toLowerCase();
if (overloadedUsers.containsKey(userNameLowered)) {
return overloadedUsers.get(userNameLowered);
}
// END CODE
return super.getUser(userName);
}
/**
*
* @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;
}
}

View File

@ -0,0 +1,118 @@
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.User;
/**
* This container holds all Users loaded from the relevant usersFile.
*
* @author ElgarL
*
*/
public class UsersDataHolder {
private WorldDataHolder dataSource;
private File usersFile;
private boolean haveUsersChanged = false;
private long timeStampUsers = 0;
/**
* The actual groups holder
*/
private 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

View File

@ -0,0 +1,794 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.anjocaido.groupmanager.dataholder.worlds;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.anjocaido.groupmanager.GroupManager;
import org.anjocaido.groupmanager.dataholder.WorldDataHolder;
import org.anjocaido.groupmanager.dataholder.OverloadedWorldHolder;
import org.anjocaido.groupmanager.permissions.AnjoPermissionsHandler;
import org.anjocaido.groupmanager.utils.Tasks;
import org.bukkit.World;
import org.bukkit.entity.Player;
/**
*
* @author gabrielcouto
*/
public class WorldsHolder {
/**
* Map with instances of loaded worlds.
*/
private Map<String, OverloadedWorldHolder> worldsData = new HashMap<String, OverloadedWorldHolder>();
/**
* Map of mirrors: <nonExistingWorldName, existingAndLoadedWorldName>
* The key is the mirror.
* The object is the mirrored.
*
* Mirror shows the same data of mirrored.
*/
private Map<String, String> mirrorsGroup = new HashMap<String, String>();
private Map<String, String> mirrorsUser = new HashMap<String, String>();
private String serverDefaultWorldName;
private GroupManager plugin;
private File worldsFolder;
/**
*
* @param plugin
*/
public WorldsHolder(GroupManager plugin) {
this.plugin = plugin;
resetWorldsHolder();
}
/**
* @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.
*
* 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
*
* 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.
*
* 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;
}
}

View File

@ -0,0 +1,92 @@
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();
protected Group group;
protected String groupName;
//////////////////////////////
protected Action action;
public GMGroupEvent(final Group group, final Action action) {
super();
this.group = group;
this.action = action;
this.groupName = group.getName();
}
public GMGroupEvent(final String groupName, final Action action) {
super();
this.groupName = groupName;
this.action = action;
}
public static HandlerList getHandlerList() {
return handlers;
}
public Action getAction() {
return this.action;
}
public Group getGroup() {
return group;
}
public String getGroupName() {
return groupName;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
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.");
}
}
public enum Action {
GROUP_PERMISSIONS_CHANGED,
GROUP_INHERITANCE_CHANGED,
GROUP_INFO_CHANGED,
GROUP_ADDED,
GROUP_REMOVED,
}
}

View File

@ -0,0 +1,66 @@
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.");
}
}
}

View File

@ -0,0 +1,94 @@
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.");
}
}
}

View File

@ -0,0 +1,61 @@
package org.anjocaido.groupmanager.events;
import org.anjocaido.groupmanager.GroupManager;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldInitEvent;
/**
* @author ElgarL
*
* Handle new world creation from other plugins
*
*/
public class GMWorldListener implements Listener {
private final GroupManager plugin;
public GMWorldListener(GroupManager instance) {
plugin = instance;
registerEvents();
}
private void registerEvents() {
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@EventHandler(priority = EventPriority.LOWEST)
public void onWorldInit(WorldInitEvent event) {
String worldName = event.getWorld().getName();
if (GroupManager.isLoaded() && !plugin.getWorldsHolder().isInList(worldName)) {
GroupManager.logger.info("New world detected...");
GroupManager.logger.info("Creating data for: " + worldName);
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.");
}
}
}

View File

@ -0,0 +1,82 @@
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
*
* 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;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,497 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
package org.anjocaido.groupmanager.permissions;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import org.anjocaido.groupmanager.GroupManager;
import org.anjocaido.groupmanager.data.User;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.PluginManager;
/**
*
* BukkitPermissions overrides to force GM reponses to Superperms
*
* @author ElgarL
*/
public class BukkitPermissions {
protected WeakHashMap<String, PermissionAttachment> attachments = new WeakHashMap<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 name = player.getName();
// Reset the User objects player reference.
User user = plugin.getWorldsHolder().getWorldData(player.getWorld().getName()).getUser(name);
if (user != null)
user.updatePlayer(player);
PermissionAttachment attachment;
// Find the players current attachment, or add a new one.
if (this.attachments.containsKey(name)) {
attachment = this.attachments.get(name);
} else {
attachment = player.addAttachment(plugin);
this.attachments.put(name, 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(name, 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(name);
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: " + name);
}
/**
* 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 playerName) {
if (attachments.containsKey(playerName)) {
attachments.get(playerName).remove();
attachments.remove(playerName);
}
}
/**
* 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.getName());
// 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();
/*
* force remove any attachments as bukkit may not
*/
removeAttachment(player.getName());
}
}
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();
}
}
}

View File

@ -0,0 +1,255 @@
package org.anjocaido.groupmanager.permissions;
// import java.util.Collection;
// import java.util.Map;
// import java.util.Set;
import java.util.List;
import java.util.Set;
import org.anjocaido.groupmanager.data.Group;
// import org.anjocaido.groupmanager.data.User;
import org.bukkit.entity.Player;
/**
* Made by Nijikokun. Changed by Gabriel Couto
*
* This class is intended to *read* permissions from a single world.
*
* @author Nijikokun
* @author Gabriel Couto
* @author ElgarL
*/
public abstract class PermissionsReaderInterface {
/**
*
* @param player
* @param string
* @return true if has permission
*/
public abstract boolean has(Player player, String string);
/**
*
* @param player
* @param string
* @return true if has permission
*/
public abstract boolean permission(Player player, String string);
/**
*
* @param userName
* @return group name for this player.
*/
public abstract String getGroup(String userName);
/**
*
* @param userName
* @param groupName
* @return true if in group
*/
public abstract boolean inGroup(String userName, String groupName);
/**
*
* @param groupName
* @return String of prefix
*/
public abstract String getGroupPrefix(String groupName);
/**
*
* @param groupName
* @return String of suffix
*/
public abstract String getGroupSuffix(String groupName);
/**
*
* @param groupName
* @return true if can build
*/
public abstract boolean canGroupBuild(String groupName);
/**
*
* @param groupName
* @param node
* @return String value
*/
public abstract String getGroupPermissionString(String groupName, String node);
/**
*
* @param groupName
* @param node
* @return integer value
*/
public abstract int getGroupPermissionInteger(String groupName, String node);
/**
*
* @param groupName
* @param node
* @return boolean value
*/
public abstract boolean getGroupPermissionBoolean(String groupName, String node);
/**
*
* @param groupName
* @param node
* @return double value
*/
public abstract double getGroupPermissionDouble(String groupName, String node);
/**
*
* @param userName
* @param node
* @return String value
*/
public abstract String getUserPermissionString(String userName, String node);
/**
*
* @param userName
* @param node
* @return integer value
*/
public abstract int getUserPermissionInteger(String userName, String node);
/**
*
* @param userName
* @param node
* @return boolean value
*/
public abstract boolean getUserPermissionBoolean(String userName, String node);
/**
*
* @param userName
* @param node
* @return double value
*/
public abstract double getUserPermissionDouble(String userName, String node);
/**
*
* @param userName
* @param node
* @return String value
*/
public abstract String getPermissionString(String userName, String node);
/**
*
* @param userName
* @param node
* @return integer value
*/
public abstract int getPermissionInteger(String userName, String node);
/**
*
* @param userName
* @param node
* @return boolean value
*/
public abstract boolean getPermissionBoolean(String userName, String node);
/**
*
* @param userName
* @param node
* @return double value
*/
public abstract double getPermissionDouble(String userName, String node);
/////////////////////////////
/**
* Gets the appropriate prefix for the user.
* This method is a utility method for chat plugins to get the user's prefix
* without having to look at every one of the user's ancestors.
* Returns an empty string if user has no parent groups.
*
* @param user
* Player's name
* @return Player's prefix
*/
public abstract String getUserPrefix(String user);
/**
* Gets the appropriate suffix for the user.
* This method is a utility method for chat plugins to get the user's suffix
* without having to look at every one of the user's ancestors.
* Returns an empty string if user has no parent groups.
*
* @param user
* Player's name
* @return Player's suffix
*/
public abstract String getUserSuffix(String user);
/**
* Returns the group object representing the default group of the given
* world.
* This method will return null if the object does not exist or the world
* has no default group.
*
* @return Group object representing default world, or null if it doesn't
* exist or is not defined.
*/
public abstract Group getDefaultGroup();
/**
* Gets a array of the names of all parent groups in the same world.
*
* @param name
* Target user's name
* @return An array containing the names of all parent groups (including
* ancestors) that are in the same world
*/
public abstract String[] getGroups(String name);
public abstract String getInfoString(String entryName, String path, boolean isGroup);
// public abstract String getInfoString(String entryName, String path, boolean isGroup, Comparator<String> comparator);
public abstract int getInfoInteger(String entryName, String path, boolean isGroup);
// public abstract int getInfoInteger(String entryName, String path, boolean isGroup, Comparator<Integer> comparator);
/**
* Gets a double from the Info node without inheritance.
*
* @param entryName
* @param path
* @param isGroup
* @return -1 if not found
*/
public abstract double getInfoDouble(String entryName, String path, boolean isGroup);
// public abstract double getInfoDouble(String entryName, String path, boolean isGroup, Comparator<Double> comparator);
public abstract boolean getInfoBoolean(String entryName, String path, boolean isGroup);
// public abstract boolean getInfoBoolean(String entryName, String path, boolean isGroup, Comparator<Boolean> comparator);
public abstract void addUserInfo(String name, String path, Object data);
public abstract void removeUserInfo(String name, String path);
public abstract void addGroupInfo(String name, String path, Object data);
public abstract void removeGroupInfo(String name, String path);
//////////////////////////////
public abstract List<String> getAllPlayersPermissions(String userName);
public abstract Set<String> getAllPlayersPermissions(String userName, Boolean includeChildren);
}

View File

@ -0,0 +1,27 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.anjocaido.groupmanager.utils;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
/**
*
* @author gabrielcouto
*/
public class GMLoggerHandler extends ConsoleHandler {
@Override
public void publish(LogRecord record) {
String message = "GroupManager - " + record.getLevel() + " - " + record.getMessage();
if (record.getLevel().equals(Level.SEVERE) || record.getLevel().equals(Level.WARNING)) {
System.err.println(message);
} else {
System.out.println(message);
}
}
}

View File

@ -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
}

View File

@ -0,0 +1,67 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.anjocaido.groupmanager.utils;
import org.anjocaido.groupmanager.data.DataUnit;
/**
*
* @author gabrielcouto
*/
public class PermissionCheckResult {
/**
* It should be the owner of the access level found.
*
* Use instanceof to find the owner type
*/
public DataUnit owner;
/**
* The permission node found in the DataUnit.
*/
public String accessLevel;
/**
* The full name of the permission you are looking for
*/
public String askedPermission;
/**
* The result conclusion of the search.
* It determines if the owner can do, or not.
*
* It even determines if it has an owner.
*/
public Type resultType = Type.NOTFOUND;
/**
* The type of result the search can give.
*/
public enum Type {
/**
* If found a matching node starting with '+'.
* It means the user CAN do the permission.
*/
EXCEPTION,
/**
* If found a matching node starting with '-'.
* It means the user CANNOT do the permission.
*/
NEGATION,
/**
* If just found a common matching node.
* IT means the user CAN do the permission.
*/
FOUND,
/**
* If no matchin node was found.
* It means the user CANNOT do the permission.
*
* owner field and accessLevel field should not be considered,
* when type is
* NOTFOUND
*/
NOTFOUND
}
}

View File

@ -0,0 +1,52 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.anjocaido.groupmanager.utils;
import java.util.Comparator;
/**
*
* @author gabrielcouto
*/
public class StringPermissionComparator implements Comparator<String> {
@Override
public int compare(String permA, String permB) {
boolean ap = permA.startsWith("+");
boolean bp = permB.startsWith("+");
boolean am = permA.startsWith("-");
boolean bm = permB.startsWith("-");
if (ap && bp) {
return 0;
}
if (ap && !bp) {
return -1;
}
if (!ap && bp) {
return 1;
}
if (am && bm) {
return 0;
}
if (am && !bm) {
return -1;
}
if (!am && bm) {
return 1;
}
return permA.compareToIgnoreCase(permB);
}
private static StringPermissionComparator instance;
public static StringPermissionComparator getInstance() {
if (instance == null) {
instance = new StringPermissionComparator();
}
return instance;
}
}

View File

@ -0,0 +1,175 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.anjocaido.groupmanager.utils;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import org.anjocaido.groupmanager.GroupManager;
import org.anjocaido.groupmanager.data.Group;
/**
*
* @author gabrielcouto
*/
public abstract class Tasks {
/**
* Gets the exception stack trace as a string.
*
* @param exception
* @return stack trace as a string
*/
public static String getStackTraceAsString(Exception exception) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
exception.printStackTrace(pw);
return sw.toString();
}
public static void copy(InputStream src, File dst) throws IOException {
InputStream in = src;
OutputStream out = new FileOutputStream(dst);
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
out.close();
try {
in.close();
} catch (Exception e) {
}
}
public static void copy(File src, File dst) throws IOException {
InputStream in = new FileInputStream(src);
copy(in, dst);
}
/**
* Appends a string to a file
*
* @param data
* @param file
*/
public static void appendStringToFile(String data, String file) throws IOException {
FileWriter outStream = new FileWriter("." + System.getProperty("file.separator") + file, true);
BufferedWriter out = new BufferedWriter(outStream);
data.replaceAll("\n", System.getProperty("line.separator"));
out.append(new SimpleDateFormat("yyyy-MM-dd HH-mm").format(System.currentTimeMillis()));
out.append(System.getProperty("line.separator"));
out.append(data);
out.append(System.getProperty("line.separator"));
out.close();
}
public static void removeOldFiles(GroupManager gm, File folder) {
if (folder.isDirectory()) {
long oldTime = System.currentTimeMillis() - (((long) gm.getGMConfig().getBackupDuration() * 60 * 60) * 1000);
for (File olds : folder.listFiles()) {
if (olds.isFile()) {
if (olds.lastModified() < oldTime) {
try {
olds.delete();
} catch (Exception e) {
}
}
}
}
}
}
public static String getDateString() {
GregorianCalendar now = new GregorianCalendar();
String date = "";
date += now.get(Calendar.DAY_OF_MONTH);
date += "-";
date += now.get(Calendar.HOUR);
date += "-";
date += now.get(Calendar.MINUTE);
return date;
}
public static String getStringListInString(List<String> list) {
if (list == null) {
return "";
}
String result = "";
for (int i = 0; i < list.size(); i++) {
result += list.get(i);
if (i < list.size() - 1) {
result += ", ";
}
}
return result;
}
public static String getStringArrayInString(String[] list) {
if (list == null) {
return "";
}
String result = "";
for (int i = 0; i < list.length; i++) {
result += list[i];
if (i < ((list.length) - 1)) {
result += ", ";
}
}
return result;
}
public static String getGroupListInString(List<Group> list) {
if (list == null) {
return "";
}
String result = "";
for (int i = 0; i < list.size(); i++) {
result += list.get(i).getName();
if (i < list.size() - 1) {
result += ", ";
}
}
return result;
}
public static String join(String[] arr, String separator) {
if (arr.length == 0)
return "";
String out = arr[0].toString();
for (int i = 1; i < arr.length; i++)
out += separator + arr[i];
return out;
}
}

View File

@ -0,0 +1,233 @@
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.

View 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)

View File

@ -0,0 +1,329 @@
# 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
- 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

View File

@ -0,0 +1,74 @@
# Group inheritance
#
# Any inherited groups prefixed with a g: are global groups
# and are inherited from the GlobalGroups.yml.
#
# Groups without the g: prefix are groups local to this world
# and are defined in the this groups.yml file.
#
# Local group inheritances define your promotion tree when using 'manpromote/mandemote'
groups:
Default:
default: true
permissions:
- -bukkit.command.kill
inheritance:
- g:groupmanager_default
- g:bukkit_default
- g:essentials_default
- g:towny_default
info:
prefix: '&e'
build: false
suffix: ''
Builder:
default: false
permissions: []
inheritance:
- default
- g:essentials_builder
- g:towny_builder
info:
prefix: '&2'
build: true
suffix: ''
Moderator:
default: false
permissions: []
inheritance:
- builder
- g:groupmanager_moderator
- g:bukkit_moderator
- g:essentials_moderator
- g:towny_moderator
- g:vanish_moderator
info:
prefix: '&5'
build: true
suffix: ''
Admin:
default: false
permissions: []
inheritance:
- moderator
- g:groupmanager_admin
- g:bukkit_admin
- g:essentials_admin
- g:towny_admin
- g:vanish_admin
info:
prefix: '&c'
build: true
suffix: ''
Owner:
default: false
permissions:
- '*'
- -vanish.*
inheritance:
- admin
info:
prefix: '&4'
build: true
suffix: ''

View File

@ -0,0 +1,184 @@
name: GroupManager
version: ${project.version} (YUMC)
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

View 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