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
This commit is contained in:
ElgarL 2012-02-05 16:30:58 +00:00
parent 76ba5caeec
commit e93e50f6d2
7 changed files with 216 additions and 77 deletions

View file

@ -135,4 +135,6 @@ v 1.9:
- 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.
- 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

View file

@ -1485,7 +1485,7 @@ public class GroupManager extends JavaPlugin {
try {
worldsHolder.saveChanges(forced);
sender.sendMessage(ChatColor.YELLOW + " The changes were saved.");
sender.sendMessage(ChatColor.YELLOW + " All changes were saved.");
} catch (IllegalStateException ex) {
sender.sendMessage(ChatColor.RED + ex.getMessage());
}
@ -1522,6 +1522,7 @@ public class GroupManager extends JavaPlugin {
}
// WORKING
config.load();
globalGroups.load();
worldsHolder.mirrorSetUp();
isLoaded = false;
@ -1538,7 +1539,7 @@ public class GroupManager extends JavaPlugin {
sender.sendMessage("The request to world '" + auxString + "' was sent.");
} else {
worldsHolder.reloadAll();
sender.sendMessage(ChatColor.YELLOW + " The current world was reloaded.");
sender.sendMessage(ChatColor.YELLOW + " All worlds were reloaded.");
}
isLoaded = true;

View file

@ -65,6 +65,15 @@ public abstract class DataUnit {
hash = 71 * hash + (this.name != null ? this.name.toLowerCase().hashCode() : 0);
return hash;
}
/**
* Set the data source to point to a new worldDataHolder
*
* @param source
*/
public void setDataSource(WorldDataHolder source) {
this.dataSource = source;
}
/**
* @return the dataSource

View file

@ -17,7 +17,8 @@ public class GroupsDataHolder {
/**
* Root World name this set of groups is associated with.
*/
private String name;
//private String name;
private WorldDataHolder dataSource;
private Group defaultGroup = null;
private File groupsFile;
private boolean haveGroupsChanged = false;
@ -33,17 +34,24 @@ public class GroupsDataHolder {
*/
protected GroupsDataHolder() {
}
protected void setWorldName(String worldName) {
name = worldName;
public void setDataSource(WorldDataHolder dataSource) {
this.dataSource = dataSource;
//push this data source to the users, so they pull the correct groups data.
for (Group group : groups.values())
group.setDataSource(this.dataSource);
}
//protected void setWorldName(String worldName) {
// name = worldName;
//}
/**
* @return the name
*/
public String getWorldName() {
return name;
}
//public String getWorldName() {
// return name;
//}
/**
* @return the defaultGroup

View file

@ -17,7 +17,8 @@ public class UsersDataHolder {
/**
* Root World name this set of groups is associated with.
*/
private String name;
//private String name;
private WorldDataHolder dataSource;
private File usersFile;
private boolean haveUsersChanged = false;
private long timeStampUsers = 0;
@ -32,20 +33,28 @@ public class UsersDataHolder {
*/
protected UsersDataHolder() {
}
public void setDataSource(WorldDataHolder dataSource) {
this.dataSource = dataSource;
//push this data source to the users, so they pull the correct groups data.
for (User user : users.values())
user.setDataSource(this.dataSource);
}
/**
* @param worldName
*/
public void setWorldName(String worldName) {
this.name = worldName;
}
//public void setWorldName(String worldName) {
// this.name = worldName;
//}
/**
* @return the name
*/
public String getWorldName() {
return this.name;
}
//public String getWorldName() {
// return this.name;
//}
/**
* @return the users

View file

@ -80,6 +80,16 @@ public class WorldDataHolder {
//this.defaultGroup = defaultGroup;
}
/**
* update the dataSource to point to this object.
*
* This should be called whenever a set of world data is fetched.
*/
public void updateDataSource() {
this.groups.setDataSource(this);
this.users.setDataSource(this);
}
/**
* Search for a user. If it doesn't exist, create a new one with
@ -465,54 +475,66 @@ public class WorldDataHolder {
}
//PERMISSIONS NODE
if (thisGroupNode.get("permissions") == null) {
thisGroupNode.put("permissions", new ArrayList<String>());
} else {
if (thisGroupNode.get("permissions") instanceof List) {
for (Object o : ((List) thisGroupNode.get("permissions"))) {
try {
thisGrp.addPermission(o.toString());
} catch (NullPointerException e) {
// Ignore this entry as it's null.
//throw new IllegalArgumentException("Invalid permission node in group: " + thisGrp.getName() + " in file: " + groupsFile.getPath());
}
}
} else if (thisGroupNode.get("permissions") instanceof String) {
thisGrp.addPermission((String) thisGroupNode.get("permissions"));
try {
if (thisGroupNode.get("permissions") == null) {
thisGroupNode.put("permissions", new ArrayList<String>());
} else {
throw new IllegalArgumentException("Unknown type of permissions node(Should be String or List<String>) for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath());
if (thisGroupNode.get("permissions") instanceof List) {
for (Object o : ((List) thisGroupNode.get("permissions"))) {
try {
thisGrp.addPermission(o.toString());
} catch (NullPointerException e) {
// Ignore this entry as it's null.
//throw new IllegalArgumentException("Invalid permission node in group: " + thisGrp.getName() + " in file: " + groupsFile.getPath());
}
}
} else if (thisGroupNode.get("permissions") instanceof String) {
thisGrp.addPermission((String) thisGroupNode.get("permissions"));
} else {
throw new IllegalArgumentException("Unknown type of permissions node(Should be String or List<String>) for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath());
}
thisGrp.sortPermissions();
}
thisGrp.sortPermissions();
} catch (Exception e) {
throw new IllegalArgumentException("Invalid formatting found in permissions section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath());
}
//INFO NODE
if (thisGroupNode.get("info") instanceof Map) {
Map<String, Object> infoNode = (Map<String, Object>) thisGroupNode.get("info");
if (infoNode != null) {
thisGrp.setVariables(infoNode);
}
} else
throw new IllegalArgumentException("Unknown entry found in Info section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath());
try {
if (thisGroupNode.get("info") instanceof Map) {
Map<String, Object> infoNode = (Map<String, Object>) thisGroupNode.get("info");
if (infoNode != null) {
thisGrp.setVariables(infoNode);
}
} else
throw new IllegalArgumentException("Unknown entry found in Info section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath());
} catch (Exception e1) {
throw new IllegalArgumentException("Invalid formatting found in info section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath());
}
//END INFO NODE
if (thisGroupNode.get("inheritance") == null || thisGroupNode.get("inheritance") instanceof List) {
Object inheritNode = thisGroupNode.get("inheritance");
if (inheritNode == null) {
thisGroupNode.put("inheritance", new ArrayList<String>());
} else if (inheritNode instanceof List) {
List<String> groupsInh = (List<String>) inheritNode;
for (String grp : groupsInh) {
if (inheritance.get(groupKey) == null) {
List<String> thisInherits = new ArrayList<String>();
inheritance.put(groupKey, thisInherits);
}
inheritance.get(groupKey).add(grp);
}
}
}else
throw new IllegalArgumentException("Unknown entry found in inheritance section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath());
try {
if (thisGroupNode.get("inheritance") == null || thisGroupNode.get("inheritance") instanceof List) {
Object inheritNode = thisGroupNode.get("inheritance");
if (inheritNode == null) {
thisGroupNode.put("inheritance", new ArrayList<String>());
} else if (inheritNode instanceof List) {
List<String> groupsInh = (List<String>) inheritNode;
for (String grp : groupsInh) {
if (inheritance.get(groupKey) == null) {
List<String> thisInherits = new ArrayList<String>();
inheritance.put(groupKey, thisInherits);
}
inheritance.get(groupKey).add(grp);
}
}
}else
throw new IllegalArgumentException("Unknown entry found in inheritance section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath());
} catch (Exception e2) {
throw new IllegalArgumentException("Invalid formatting found in inheritance section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath());
}
}
} catch (Exception ex) {
ex.printStackTrace();

View file

@ -10,6 +10,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@ -45,7 +46,7 @@ public class WorldsHolder {
private Map<String, String> mirrorsGroup = new HashMap<String, String>();
private Map<String, String> mirrorsUser = new HashMap<String, String>();
private OverloadedWorldHolder defaultWorld;
//private OverloadedWorldHolder defaultWorld;
private String serverDefaultWorldName;
private GroupManager plugin;
private File worldsFolder;
@ -59,7 +60,7 @@ public class WorldsHolder {
// Setup folders and check files exist for the primary world
verifyFirstRun();
initialLoad();
if (defaultWorld == null) {
if (serverDefaultWorldName == null) {
throw new IllegalStateException("There is no default group! OMG!");
}
}
@ -76,7 +77,7 @@ public class WorldsHolder {
private void initialWorldLoading() {
//Load the default world
loadWorld(serverDefaultWorldName);
defaultWorld = worldsData.get(serverDefaultWorldName);
//defaultWorld = getUpdatedWorldData(serverDefaultWorldName);
}
private void loadAllSearchedWorlds() {
@ -117,6 +118,8 @@ public class WorldsHolder {
mirrorsGroup.clear();
mirrorsUser.clear();
Map<String, Object> mirrorsMap = plugin.getGMConfig().getMirrorsMap();
HashSet<String> mirroredWorlds = new HashSet<String>();
if (mirrorsMap != null) {
for (String source : mirrorsMap.keySet()) {
@ -140,6 +143,10 @@ public class WorldsHolder {
}
mirrorsGroup.put(world, getWorldData(source).getName());
mirrorsUser.put(world, getWorldData(source).getName());
// Track this world so we can create a datasource for it later
mirroredWorlds.add(o.toString());
} else
GroupManager.logger.log(Level.WARNING, "Mirroring error with " + o.toString() + ". Recursive loop detected!");
}
@ -171,11 +178,13 @@ public class WorldsHolder {
if (type.equals("users"))
mirrorsUser.put(key.toLowerCase(), getWorldData(source).getName());
}
// Track this world so we can create a datasource for it later
mirroredWorlds.add(key);
} else
GroupManager.logger.log(Level.WARNING, "Mirroring error with " + key + ". Recursive loop detected!");
} else {
throw new IllegalStateException("Unknown mirroring format for " + key);
}
@ -183,6 +192,14 @@ public class WorldsHolder {
}
}
}
// Create a datasource for any worlds not already loaded
for (String world : mirroredWorlds){
if (!worldsData.containsKey(world.toLowerCase())) {
setupWorldFolder(world);
loadWorld(world, true);
}
}
}
}
@ -329,21 +346,55 @@ public class WorldsHolder {
public OverloadedWorldHolder getWorldData(String worldName) {
String worldNameLowered = worldName.toLowerCase();
// Return this worlds data
if (worldsData.containsKey(worldNameLowered))
return worldsData.get(worldNameLowered);
// Find this worlds data
if (worldsData.containsKey(worldNameLowered)) {
String usersMirror = mirrorsUser.get(worldNameLowered);
String groupsMirror = mirrorsGroup.get(worldNameLowered);
if (usersMirror != null) {
// If both are mirrored
if (groupsMirror != null) {
// if the data sources are the same, return the parent
if (usersMirror == groupsMirror)
return getUpdatedWorldData(usersMirror.toLowerCase());
// Both data sources are mirrors, but they are from different parents
// so we return the actual data object.
return getUpdatedWorldData(worldNameLowered);
}
// Groups isn't a mirror so return this this worlds data source
return getUpdatedWorldData(worldNameLowered);
}
// users isn't mirrored so we need to return this worlds data source
return getUpdatedWorldData(worldNameLowered);
}
// If groups mirrored return the parent worlds data
if (mirrorsGroup.containsKey(worldNameLowered))
return worldsData.get(mirrorsGroup.get(worldNameLowered).toLowerCase());
// If users mirrored return the parent worlds data
if (mirrorsUser.containsKey(worldNameLowered))
return worldsData.get(mirrorsUser.get(worldNameLowered).toLowerCase());
// Oddly no data source was found for this world so return the default.
GroupManager.logger.finest("Requested world " + worldName + " not found or badly mirrored. Returning default world...");
return getDefaultWorld();
}
/**
* Get the requested world data and update it's dataSource to be relevant for this world
*
* @param worldName
* @return updated world holder
*/
private OverloadedWorldHolder getUpdatedWorldData(String worldName) {
if (worldsData.containsKey(worldName.toLowerCase())) {
OverloadedWorldHolder data = worldsData.get(worldName.toLowerCase());
data.updateDataSource();
return data;
}
return null;
}
/**
* Do a matching of playerName, if its found only one player, do
@ -487,18 +538,29 @@ public class WorldsHolder {
}
/**
* Wrapper for LoadWorld(String,Boolean) for backwards compatibility
*
* Load a world from file.
* If it already been loaded, summon reload method from dataHolder.
* @param worldName
*/
public void loadWorld(String worldName) {
loadWorld(worldName, false);
}
/**
* Load a world from file.
* If it already been loaded, summon reload method from dataHolder.
* @param worldName
*/
public void loadWorld(String worldName, Boolean isMirror) {
if (worldsData.containsKey(worldName.toLowerCase())) {
worldsData.get(worldName.toLowerCase()).reload();
return;
}
GroupManager.logger.finest("Trying to load world " + worldName + "...");
File thisWorldFolder = new File(worldsFolder, worldName);
if (thisWorldFolder.exists() && thisWorldFolder.isDirectory()) {
if ((isMirror) || (thisWorldFolder.exists() && thisWorldFolder.isDirectory())) {
// Setup file handles, if not mirrored
File groupsFile = (mirrorsGroup.containsKey(worldName.toLowerCase()))? null : new File(thisWorldFolder, "groups.yml");
@ -575,17 +637,43 @@ public class WorldsHolder {
* @return the defaultWorld
*/
public OverloadedWorldHolder getDefaultWorld() {
return defaultWorld;
return getUpdatedWorldData(serverDefaultWorldName);
}
/**
* Returns all physically loaded worlds.
* Returns all physically loaded worlds which have at least
* one of their own data sets for users or groups.
*
* @return ArrayList<OverloadedWorldHolder> of all loaded worlds
*/
public ArrayList<OverloadedWorldHolder> allWorldsDataList() {
ArrayList<OverloadedWorldHolder> list = new ArrayList<OverloadedWorldHolder>();
for (OverloadedWorldHolder data : worldsData.values()) {
if (!list.contains(data)) {
if ((!list.contains(data)) && (!mirrorsGroup.containsKey(data.getName().toLowerCase()) || !mirrorsUser.containsKey(data.getName().toLowerCase()))) {
String worldNameLowered = data.getName().toLowerCase();
String usersMirror = mirrorsUser.get(worldNameLowered);
String groupsMirror = mirrorsGroup.get(worldNameLowered);
// is users mirrored?
if (usersMirror != null) {
// If both are mirrored
if (groupsMirror != null) {
// if the data sources are the same, return the parent
if (usersMirror == groupsMirror) {
if (!list.contains(usersMirror.toLowerCase()))
list.add(worldsData.get(usersMirror.toLowerCase()));
continue;
}
// Both data sources are mirrors, but they are from different parents
// so fall through to add the actual data object.
}
// Groups isn't a mirror so fall through to add this this worlds data source
}
// users isn't mirrored so we need to add this worlds data source
list.add(data);
}
}