Synchronized all access to worlds map in WorldManager.

This commit is contained in:
Jeremy Wood 2012-08-05 00:00:46 -04:00
parent 16e42f6469
commit b2f3b74062

View File

@ -45,10 +45,10 @@ import java.util.logging.Logger;
* Public facing API to add/remove Multiverse worlds. * Public facing API to add/remove Multiverse worlds.
*/ */
public class WorldManager implements MVWorldManager { public class WorldManager implements MVWorldManager {
private MultiverseCore plugin; private final MultiverseCore plugin;
private WorldPurger worldPurger; private final WorldPurger worldPurger;
private final Map<String, MultiverseWorld> worlds;
private Map<String, MVWorld> worldsFromTheConfig; private Map<String, MVWorld> worldsFromTheConfig;
private Map<String, MultiverseWorld> worlds;
private FileConfiguration configWorlds = null; private FileConfiguration configWorlds = null;
private Map<String, String> defaultGens; private Map<String, String> defaultGens;
private String firstSpawn; private String firstSpawn;
@ -225,7 +225,9 @@ public class WorldManager implements MVWorldManager {
} }
// set generator (special case because we can't read it from org.bukkit.World) // set generator (special case because we can't read it from org.bukkit.World)
this.worlds.get(name).setGenerator(generator); synchronized (worlds) {
this.worlds.get(name).setGenerator(generator);
}
this.saveWorldsConfig(); this.saveWorldsConfig();
return true; return true;
@ -304,23 +306,25 @@ public class WorldManager implements MVWorldManager {
*/ */
@Override @Override
public boolean unloadWorld(String name) { public boolean unloadWorld(String name) {
if (this.worlds.containsKey(name)) { synchronized (worlds) {
if (this.unloadWorldFromBukkit(name, true)) { if (this.worlds.containsKey(name)) {
this.worlds.remove(name); if (this.unloadWorldFromBukkit(name, true)) {
this.plugin.log(Level.INFO, "World '" + name + "' was unloaded from memory."); this.worlds.remove(name);
this.plugin.log(Level.INFO, "World '" + name + "' was unloaded from memory.");
this.worldsFromTheConfig.get(name).tearDown(); this.worldsFromTheConfig.get(name).tearDown();
return true; return true;
} else {
this.plugin.log(Level.WARNING, "World '" + name + "' could not be unloaded. Is it a default world?");
}
} else if (this.plugin.getServer().getWorld(name) != null) {
this.plugin.log(Level.WARNING, "Hmm Multiverse does not know about this world but it's loaded in memory.");
this.plugin.log(Level.WARNING, "To let Multiverse know about it, use:");
this.plugin.log(Level.WARNING, String.format("/mv import %s %s", name, this.plugin.getServer().getWorld(name).getEnvironment().toString()));
} else { } else {
this.plugin.log(Level.WARNING, "World '" + name + "' could not be unloaded. Is it a default world?"); this.plugin.log(Level.INFO, "Multiverse does not know about " + name + " and it's not loaded by Bukkit.");
} }
} else if (this.plugin.getServer().getWorld(name) != null) {
this.plugin.log(Level.WARNING, "Hmm Multiverse does not know about this world but it's loaded in memory.");
this.plugin.log(Level.WARNING, "To let Multiverse know about it, use:");
this.plugin.log(Level.WARNING, String.format("/mv import %s %s", name, this.plugin.getServer().getWorld(name).getEnvironment().toString()));
} else {
this.plugin.log(Level.INFO, "Multiverse does not know about " + name + " and it's not loaded by Bukkit.");
} }
return false; return false;
} }
@ -331,8 +335,10 @@ public class WorldManager implements MVWorldManager {
@Override @Override
public boolean loadWorld(String name) { public boolean loadWorld(String name) {
// Check if the World is already loaded // Check if the World is already loaded
if (this.worlds.containsKey(name)) { synchronized (worlds) {
return true; if (this.worlds.containsKey(name)) {
return true;
}
} }
// Check that the world is in the config // Check that the world is in the config
@ -367,8 +373,10 @@ public class WorldManager implements MVWorldManager {
String worldName = creator.name(); String worldName = creator.name();
if (!worldsFromTheConfig.containsKey(worldName)) if (!worldsFromTheConfig.containsKey(worldName))
throw new IllegalArgumentException("That world doesn't exist!"); throw new IllegalArgumentException("That world doesn't exist!");
if (worlds.containsKey(worldName)) synchronized (worlds) {
throw new IllegalArgumentException("That world is already loaded!"); if (worlds.containsKey(worldName))
throw new IllegalArgumentException("That world is already loaded!");
}
MVWorld mvworld = worldsFromTheConfig.get(worldName); MVWorld mvworld = worldsFromTheConfig.get(worldName);
World cbworld; World cbworld;
try { try {
@ -380,7 +388,9 @@ public class WorldManager implements MVWorldManager {
} }
mvworld.init(cbworld, plugin); mvworld.init(cbworld, plugin);
this.worldPurger.purgeWorld(mvworld); this.worldPurger.purgeWorld(mvworld);
this.worlds.put(worldName, mvworld); synchronized (worlds) {
this.worlds.put(worldName, mvworld);
}
return true; return true;
} }
@ -477,7 +487,9 @@ public class WorldManager implements MVWorldManager {
*/ */
@Override @Override
public Collection<MultiverseWorld> getMVWorlds() { public Collection<MultiverseWorld> getMVWorlds() {
return this.worlds.values(); synchronized (worlds) {
return this.worlds.values();
}
} }
/** /**
@ -485,8 +497,10 @@ public class WorldManager implements MVWorldManager {
*/ */
@Override @Override
public MultiverseWorld getMVWorld(String name) { public MultiverseWorld getMVWorld(String name) {
if (this.worlds.containsKey(name)) { synchronized (worlds) {
return this.worlds.get(name); if (this.worlds.containsKey(name)) {
return this.worlds.get(name);
}
} }
return this.getMVWorldByAlias(name); return this.getMVWorldByAlias(name);
} }
@ -509,9 +523,11 @@ public class WorldManager implements MVWorldManager {
* @return A {@link MVWorld} or null. * @return A {@link MVWorld} or null.
*/ */
private MultiverseWorld getMVWorldByAlias(String alias) { private MultiverseWorld getMVWorldByAlias(String alias) {
for (MultiverseWorld w : this.worlds.values()) { synchronized (worlds) {
if (w.getAlias().equalsIgnoreCase(alias)) { for (MultiverseWorld w : this.worlds.values()) {
return w; if (w.getAlias().equalsIgnoreCase(alias)) {
return w;
}
} }
} }
return null; return null;
@ -522,7 +538,9 @@ public class WorldManager implements MVWorldManager {
*/ */
@Override @Override
public boolean isMVWorld(String name) { public boolean isMVWorld(String name) {
return (this.worlds.containsKey(name) || isMVWorldAlias(name)); synchronized (worlds) {
return (this.worlds.containsKey(name) || isMVWorldAlias(name));
}
} }
/** /**
@ -540,9 +558,11 @@ public class WorldManager implements MVWorldManager {
* @return True if the world exists, false if not. * @return True if the world exists, false if not.
*/ */
private boolean isMVWorldAlias(String alias) { private boolean isMVWorldAlias(String alias) {
for (MultiverseWorld w : this.worlds.values()) { synchronized (worlds) {
if (w.getAlias().equalsIgnoreCase(alias)) { for (MultiverseWorld w : this.worlds.values()) {
return true; if (w.getAlias().equalsIgnoreCase(alias)) {
return true;
}
} }
} }
return false; return false;
@ -589,28 +609,34 @@ public class WorldManager implements MVWorldManager {
// Remove all world permissions. // Remove all world permissions.
Permission allAccess = this.plugin.getServer().getPluginManager().getPermission("multiverse.access.*"); Permission allAccess = this.plugin.getServer().getPluginManager().getPermission("multiverse.access.*");
Permission allExempt = this.plugin.getServer().getPluginManager().getPermission("multiverse.exempt.*"); Permission allExempt = this.plugin.getServer().getPluginManager().getPermission("multiverse.exempt.*");
for (MultiverseWorld w : this.worlds.values()) { synchronized (worlds) {
// Remove this world from the master list for (MultiverseWorld w : this.worlds.values()) {
if (allAccess != null) { // Remove this world from the master list
allAccess.getChildren().remove(w.getAccessPermission().getName()); if (allAccess != null) {
allAccess.getChildren().remove(w.getAccessPermission().getName());
}
if (allExempt != null) {
allExempt.getChildren().remove(w.getAccessPermission().getName());
}
this.plugin.getServer().getPluginManager().removePermission(w.getAccessPermission().getName());
this.plugin.getServer().getPluginManager().removePermission(w.getExemptPermission().getName());
// Special namespace for gamemodes
this.plugin.getServer().getPluginManager().removePermission("mv.bypass.gamemode." + w.getName());
} }
if (allExempt != null) {
allExempt.getChildren().remove(w.getAccessPermission().getName());
}
this.plugin.getServer().getPluginManager().removePermission(w.getAccessPermission().getName());
this.plugin.getServer().getPluginManager().removePermission(w.getExemptPermission().getName());
// Special namespace for gamemodes
this.plugin.getServer().getPluginManager().removePermission("mv.bypass.gamemode." + w.getName());
} }
// Recalc the all permission // Recalc the all permission
this.plugin.getServer().getPluginManager().recalculatePermissionDefaults(allAccess); this.plugin.getServer().getPluginManager().recalculatePermissionDefaults(allAccess);
this.plugin.getServer().getPluginManager().recalculatePermissionDefaults(allExempt); this.plugin.getServer().getPluginManager().recalculatePermissionDefaults(allExempt);
this.worlds.clear(); synchronized (worlds) {
this.worlds.clear();
}
} }
for (Map.Entry<String, MVWorld> entry : worldsFromTheConfig.entrySet()) { for (Map.Entry<String, MVWorld> entry : worldsFromTheConfig.entrySet()) {
if (worlds.containsKey(entry.getKey())) synchronized (worlds) {
continue; if (worlds.containsKey(entry.getKey()))
continue;
}
if (!entry.getValue().getAutoLoad()) if (!entry.getValue().getAutoLoad())
continue; continue;
@ -676,9 +702,11 @@ public class WorldManager implements MVWorldManager {
String worldName = key.replaceAll(String.valueOf(SEPARATOR), "."); String worldName = key.replaceAll(String.valueOf(SEPARATOR), ".");
if (this.worldsFromTheConfig.containsKey(worldName)) { if (this.worldsFromTheConfig.containsKey(worldName)) {
// Object-Recycling :D // Object-Recycling :D
MVWorld oldMVWorld = (MVWorld) this.worlds.get(worldName); synchronized (worlds) {
oldMVWorld.copyValues((MVWorld) obj); MVWorld oldMVWorld = (MVWorld) this.worlds.get(worldName);
newWorldsFromTheConfig.put(worldName, oldMVWorld); oldMVWorld.copyValues((MVWorld) obj);
newWorldsFromTheConfig.put(worldName, oldMVWorld);
}
} else { } else {
// we have to use a new one // we have to use a new one
World cbworld = this.plugin.getServer().getWorld(worldName); World cbworld = this.plugin.getServer().getWorld(worldName);
@ -696,7 +724,9 @@ public class WorldManager implements MVWorldManager {
} }
} }
this.worldsFromTheConfig = newWorldsFromTheConfig; this.worldsFromTheConfig = newWorldsFromTheConfig;
this.worlds.keySet().retainAll(this.worldsFromTheConfig.keySet()); synchronized (worlds) {
this.worlds.keySet().retainAll(this.worldsFromTheConfig.keySet());
}
return this.configWorlds; return this.configWorlds;
} }
@ -733,7 +763,9 @@ public class WorldManager implements MVWorldManager {
@Override @Override
public List<String> getUnloadedWorlds() { public List<String> getUnloadedWorlds() {
List<String> allNames = new ArrayList<String>(this.worldsFromTheConfig.keySet()); List<String> allNames = new ArrayList<String>(this.worldsFromTheConfig.keySet());
allNames.removeAll(worlds.keySet()); synchronized (worlds) {
allNames.removeAll(worlds.keySet());
}
return allNames; return allNames;
} }