diff --git a/config/mv_checks.xml b/config/mv_checks.xml index 73be9841..54710f7b 100644 --- a/config/mv_checks.xml +++ b/config/mv_checks.xml @@ -76,7 +76,10 @@ - + + + + diff --git a/pom.xml b/pom.xml index 0f364d57..4d7b82d2 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.onarandombox.multiversecore Multiverse-Core - 2.4 + 2.5 Multiverse-Core World Management Plugin @@ -25,6 +25,16 @@ DynMap TBD --> + + + mcstats + http://repo.mcstats.org/content/repositories/snapshots + + + + herocraft + http://ci.herocraftonline.com/plugin/repository/everything/ + @@ -106,12 +116,6 @@ - - - org.apache.maven.plugins - maven-source-plugin - 2.1.2 - org.apache.maven.plugins maven-surefire-plugin @@ -141,6 +145,33 @@ ${project.basedir}/config/mv_checks.xml + + org.apache.maven.plugins + maven-source-plugin + 2.1.2 + + + attach-sources + package + + jar-no-fork + + + + + + maven-javadoc-plugin + 2.8.1 + + + javadoc-jar + verify + + jar + + + + org.apache.maven.plugins maven-shade-plugin @@ -155,8 +186,11 @@ me.main__.util:SerializationConfig - com.fernferret.allpay:AllPay com.pneumaticraft.commandhandler:CommandHandler + com.dumptruckman.minecraft:buscript + org.mcstats:metrics + com.dumptruckman.minecraft:Logging + com.fernferret.allpay:AllPay @@ -172,6 +206,22 @@ com.pneumaticraft.commandhandler com.pneumaticraft.commandhandler.multiverse + + buscript + buscript.multiverse + + + org.mcstats + org.mcstats.multiverse + + + com.dumptruckman.minecraft.util.Logging + com.onarandombox.MultiverseCore.utils.CoreLogging + + + com.dumptruckman.minecraft.util.DebugLog + com.onarandombox.MultiverseCore.utils.DebugFileLogger + @@ -185,38 +235,45 @@ org.bukkit bukkit - 1.2.3-R0.2-SNAPSHOT + 1.3.2-R2.1-SNAPSHOT jar compile - + + End of Spout --> me.main__.util SerializationConfig - 1.3 + 1.6b jar compile - + com.fernferret.allpay AllPay - 9 + 10 jar compile - + + net.milkbowl.vault + Vault + 1.2.19-SNAPSHOT + jar + compile + + com.pneumaticraft.commandhandler @@ -242,6 +299,33 @@ compile + + + com.dumptruckman.minecraft + buscript + 1.0 + jar + compile + + + + + org.mcstats + metrics + 1.2-SNAPSHOT + jar + compile + + + + + com.dumptruckman.minecraft + Logging + 1.0.6 + jar + compile + + junit diff --git a/src/main/java/com/onarandombox/MultiverseCore/MVWorld.java b/src/main/java/com/onarandombox/MultiverseCore/MVWorld.java index 3d376a39..5a59f5db 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/MVWorld.java +++ b/src/main/java/com/onarandombox/MultiverseCore/MVWorld.java @@ -9,14 +9,23 @@ package com.onarandombox.MultiverseCore; import com.onarandombox.MultiverseCore.api.BlockSafety; import com.onarandombox.MultiverseCore.api.MultiverseWorld; -import com.onarandombox.MultiverseCore.configuration.ConfigPropertyFactory; -import com.onarandombox.MultiverseCore.configuration.MVActiveConfigProperty; -import com.onarandombox.MultiverseCore.configuration.MVConfigProperty; +import com.onarandombox.MultiverseCore.api.SafeTTeleporter; +import com.onarandombox.MultiverseCore.configuration.EntryFee; +import com.onarandombox.MultiverseCore.configuration.SpawnLocation; +import com.onarandombox.MultiverseCore.configuration.SpawnSettings; +import com.onarandombox.MultiverseCore.configuration.WorldPropertyValidator; import com.onarandombox.MultiverseCore.enums.AllowedPortalType; import com.onarandombox.MultiverseCore.enums.EnglishChatColor; -import com.onarandombox.MultiverseCore.event.MVWorldPropertyChangeEvent; +import com.onarandombox.MultiverseCore.enums.EnglishChatStyle; import com.onarandombox.MultiverseCore.exceptions.PropertyDoesNotExistException; -import com.onarandombox.MultiverseCore.api.SafeTTeleporter; +import me.main__.util.SerializationConfig.ChangeDeniedException; +import me.main__.util.SerializationConfig.IllegalPropertyValueException; +import me.main__.util.SerializationConfig.NoSuchPropertyException; +import me.main__.util.SerializationConfig.Property; +import me.main__.util.SerializationConfig.SerializationConfig; +import me.main__.util.SerializationConfig.Serializor; +import me.main__.util.SerializationConfig.ValidateAllWith; +import me.main__.util.SerializationConfig.VirtualProperty; import org.bukkit.ChatColor; import org.bukkit.Difficulty; import org.bukkit.GameMode; @@ -25,15 +34,15 @@ import org.bukkit.World; import org.bukkit.World.Environment; import org.bukkit.WorldType; import org.bukkit.command.CommandSender; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.serialization.SerializableAs; import org.bukkit.entity.Player; import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionDefault; +import org.bukkit.util.Vector; +import org.json.simple.JSONObject; -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Method; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -46,157 +55,520 @@ import java.util.regex.Pattern; /** * The implementation of a Multiverse handled world. */ -public class MVWorld implements MultiverseWorld { +@SerializableAs("MVWorld") +@ValidateAllWith(WorldPropertyValidator.class) +public class MVWorld extends SerializationConfig implements MultiverseWorld { + private static final int SPAWN_LOCATION_SEARCH_TOLERANCE = 16; + private static final int SPAWN_LOCATION_SEARCH_RADIUS = 16; + + private static final Map PROPERTY_ALIASES; + + static { + PROPERTY_ALIASES = new HashMap(); + PROPERTY_ALIASES.put("curr", "currency"); + PROPERTY_ALIASES.put("scaling", "scale"); + PROPERTY_ALIASES.put("aliascolor", "color"); + PROPERTY_ALIASES.put("heal", "autoHeal"); + PROPERTY_ALIASES.put("storm", "allowWeather"); + PROPERTY_ALIASES.put("weather", "allowWeather"); + PROPERTY_ALIASES.put("spawnmemory", "keepSpawnInMemory"); + PROPERTY_ALIASES.put("memory", "keepSpawnInMemory"); + PROPERTY_ALIASES.put("mode", "gameMode"); + PROPERTY_ALIASES.put("diff", "difficulty"); + PROPERTY_ALIASES.put("spawnlocation", "spawn"); + PROPERTY_ALIASES.put("animals", "spawning.animals.spawn"); + PROPERTY_ALIASES.put("monsters", "spawning.monsters.spawn"); + } + /* + * We have to use setCBWorld(), setPlugin() and initPerms() to prepare this object for use. + */ + public MVWorld(Map values) { + super(values); + } private MultiverseCore plugin; // Hold the Plugin Instance. - private FileConfiguration config; // Hold the Configuration File. - private ConfigurationSection worldSection; // Holds the section of the config file for this world. - private World world; // The World Instance. - private Environment environment; // Hold the Environment type EG Environment.NETHER / Environment.NORMAL - private Long seed; // The world seed + private volatile Reference world = new WeakReference(null); // A reference to the World Instance. private String name; // The Worlds Name, EG its folder name. - private Map> masterList; - private Map> propertyList; + /** + * Validates the scale-property. + */ + private final class ScalePropertyValidator extends WorldPropertyValidator { + @Override + public Double validateChange(String property, Double newValue, Double oldValue, + MVWorld object) throws ChangeDeniedException { + if (newValue <= 0) { + plugin.log(Level.FINE, "Someone tried to set a scale <= 0, aborting!"); + throw new ChangeDeniedException(); + } + return super.validateChange(property, newValue, oldValue, object); + } + } + + /** + * Validates the respawnWorld-property. + */ + private final class RespawnWorldPropertyValidator extends WorldPropertyValidator { + @Override + public String validateChange(String property, String newValue, String oldValue, + MVWorld object) throws ChangeDeniedException { + if (!plugin.getMVWorldManager().isMVWorld(newValue)) + throw new ChangeDeniedException(); + return super.validateChange(property, newValue, oldValue, object); + } + } + + /** + * Serializor for the time-property. + */ + private static final class TimePropertySerializor implements Serializor { + // BEGIN CHECKSTYLE-SUPPRESSION: MagicNumberCheck + private static final String TIME_REGEX = "(\\d\\d?):?(\\d\\d)(a|p)?m?"; + private static final Map TIME_ALIASES; + static { + Map staticTimes = new HashMap(); + staticTimes.put("morning", "8:00"); + staticTimes.put("day", "12:00"); + staticTimes.put("noon", "12:00"); + staticTimes.put("midnight", "0:00"); + staticTimes.put("night", "20:00"); + + // now set TIME_ALIASES to a "frozen" map + TIME_ALIASES = Collections.unmodifiableMap(staticTimes); + } + + @Override + public String serialize(Long from) { + // I'm tired, so they get time in 24 hour for now. + // Someone else can add 12 hr format if they want :P + + int hours = (int) ((from / 1000 + 8) % 24); + int minutes = (int) (60 * (from % 1000) / 1000); + + return String.format("%d:%02d", hours, minutes); + } + + @Override + public Long deserialize(String serialized, Class wanted) throws IllegalPropertyValueException { + if (TIME_ALIASES.containsKey(serialized.toLowerCase())) { + serialized = TIME_ALIASES.get(serialized.toLowerCase()); + } + // Regex that extracts a time in the following formats: + // 11:11pm, 11:11, 23:11, 1111, 1111p, and the aliases at the top of this file. + Pattern pattern = Pattern.compile(TIME_REGEX, Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(serialized); + matcher.find(); + int hour = 0; + double minute = 0; + int count = matcher.groupCount(); + if (count >= 2) { + hour = Integer.parseInt(matcher.group(1)); + minute = Integer.parseInt(matcher.group(2)); + } + // If there were 4 matches (all, hour, min, am/pm) + if (count == 4) { + // We want 24 hour time for calcs, but if they + // added a p[m], turn it into a 24 hr one. + if (matcher.group(3).equals("p")) { + hour += 12; + } + } + // Translate 24th hour to 0th hour. + if (hour == 24) { + hour = 0; + } + // Clamp the hour + if (hour > 23 || hour < 0) { + throw new IllegalPropertyValueException("Illegal hour!"); + } + // Clamp the minute + if (minute > 59 || minute < 0) { + throw new IllegalPropertyValueException("Illegal minute!"); + } + // 60 seconds in a minute, time needs to be in hrs * 1000, per + // the bukkit docs. + double totaltime = (hour + (minute / 60.0)) * 1000; + // Somehow there's an 8 hour offset... + totaltime -= 8000; + if (totaltime < 0) { + totaltime = 24000 + totaltime; + } + + return (long) totaltime; + } + // END CHECKSTYLE-SUPPRESSION: MagicNumberCheck + } + + /** + * Used to apply the allowWeather-property. + */ + private final class AllowWeatherPropertyValidator extends WorldPropertyValidator { + @Override + public Boolean validateChange(String property, Boolean newValue, Boolean oldValue, + MVWorld object) throws ChangeDeniedException { + if (!newValue) { + world.get().setStorm(false); + world.get().setThundering(false); + } + return super.validateChange(property, newValue, oldValue, object); + } + } + + /** + * Used to apply the spawning-property. + */ + private final class SpawningPropertyValidator extends WorldPropertyValidator { + @Override + public Boolean validateChange(String property, Boolean newValue, Boolean oldValue, + MVWorld object) throws ChangeDeniedException { + boolean allowMonsters, allowAnimals; + if (getAnimalList().isEmpty()) { + allowAnimals = canAnimalsSpawn(); + } else { + allowAnimals = true; + } + if (getMonsterList().isEmpty()) { + allowMonsters = canMonstersSpawn(); + } else { + allowMonsters = true; + } + world.get().setSpawnFlags(allowMonsters, allowAnimals); + plugin.getMVWorldManager().getTheWorldPurger().purgeWorld(MVWorld.this); + return super.validateChange(property, newValue, oldValue, object); + } + } + + /** + * Serializor for the difficulty-property. + */ + private static final class DifficultyPropertySerializor implements Serializor { + @Override + public String serialize(Difficulty from) { + return from.toString(); + } + + @Override + public Difficulty deserialize(String serialized, Class wanted) throws IllegalPropertyValueException { + try { + return Difficulty.getByValue(Integer.parseInt(serialized)); + } catch (Exception e) { + } + try { + return Difficulty.valueOf(serialized.toUpperCase()); + } catch (Exception e) { + } + throw new IllegalPropertyValueException(); + } + } + + /** + * Serializor for the gameMode-property. + */ + private static final class GameModePropertySerializor implements Serializor { + @Override + public String serialize(GameMode from) { + return from.toString(); + } + + @Override + public GameMode deserialize(String serialized, Class wanted) throws IllegalPropertyValueException { + try { + return GameMode.getByValue(Integer.parseInt(serialized)); + } catch (NumberFormatException nfe) { + } + try { + return GameMode.valueOf(serialized.toUpperCase()); + } catch (Exception e) { + } + throw new IllegalPropertyValueException(); + } + } + + + /** + * Used to apply the gameMode-property. + */ + private final class GameModePropertyValidator extends WorldPropertyValidator { + @Override + public GameMode validateChange(String property, GameMode newValue, GameMode oldValue, + MVWorld object) throws ChangeDeniedException { + for (Player p : plugin.getServer().getWorld(getName()).getPlayers()) { + plugin.log(Level.FINER, String.format("Setting %s's GameMode to %s", + p.getName(), newValue.toString())); + plugin.getPlayerListener().handleGameMode(p, MVWorld.this); + } + return super.validateChange(property, newValue, oldValue, object); + } + } + + /** + * Validator for the spawnLocation-property. + */ + private final class SpawnLocationPropertyValidator extends WorldPropertyValidator { + @Override + public Location validateChange(String property, Location newValue, Location oldValue, + MVWorld object) throws ChangeDeniedException { + if (newValue == null) + throw new ChangeDeniedException(); + if (adjustSpawn) { + BlockSafety bs = plugin.getBlockSafety(); + // verify that the location is safe + if (!bs.playerCanSpawnHereSafely(newValue)) { + // it's not ==> find a better one! + plugin.log(Level.WARNING, String.format("Somebody tried to set the spawn location for '%s' to an unsafe value! Adjusting...", getAlias())); + plugin.log(Level.WARNING, "Old Location: " + plugin.getLocationManipulation().strCoordsRaw(oldValue)); + plugin.log(Level.WARNING, "New (unsafe) Location: " + plugin.getLocationManipulation().strCoordsRaw(newValue)); + SafeTTeleporter teleporter = plugin.getSafeTTeleporter(); + newValue = teleporter.getSafeLocation(newValue, SPAWN_LOCATION_SEARCH_TOLERANCE, SPAWN_LOCATION_SEARCH_RADIUS); + if (newValue == null) { + plugin.log(Level.WARNING, "Couldn't fix the location. I have to abort the spawn location-change :/"); + throw new ChangeDeniedException(); + } + plugin.log(Level.WARNING, "New (safe) Location: " + plugin.getLocationManipulation().strCoordsRaw(newValue)); + } + } + return super.validateChange(property, newValue, oldValue, object); + } + } + + /** + * Serializor for the color-property. + */ + private static final class EnumPropertySerializor> implements Serializor { + @Override + public String serialize(T from) { + return from.toString(); + } + + @Override + public T deserialize(String serialized, Class wanted) throws IllegalPropertyValueException { + try { + return Enum.valueOf(wanted, serialized.toUpperCase()); + } catch (IllegalArgumentException e) { + throw new IllegalPropertyValueException(e); + } + } + } + + // -------------------------------------------------------------- + // Begin properties + @Property(description = "Sorry, 'hidden' must either be: true or false.") + private volatile boolean hidden; + @Property(description = "Alias must be a valid string.") + private volatile String alias; + @Property(serializor = EnumPropertySerializor.class, description = "Sorry, 'color' must be a valid color-name.") + private volatile EnglishChatColor color; + @Property(serializor = EnumPropertySerializor.class, description = "Sorry, 'style' must be a valid style-name.") + private volatile EnglishChatStyle style; + @Property(description = "Sorry, 'pvp' must either be: true or false.", virtualType = Boolean.class, persistVirtual = true) + private volatile VirtualProperty pvp = new VirtualProperty() { + @Override + public void set(Boolean newValue) { + world.get().setPVP(newValue); + } + + @Override + public Boolean get() { + return world.get().getPVP(); + } + }; + @Property(validator = ScalePropertyValidator.class, description = "Scale must be a positive double value. ex: 2.3") + private volatile double scale; + @Property(validator = RespawnWorldPropertyValidator.class, description = "You must set this to the NAME not alias of a world.") + private volatile String respawnWorld; + @Property(validator = AllowWeatherPropertyValidator.class, description = "Sorry, this must either be: true or false.") + private volatile boolean allowWeather; + @Property(serializor = DifficultyPropertySerializor.class, virtualType = Difficulty.class, persistVirtual = true, + description = "Difficulty must be set as one of the following: peaceful easy normal hard") + private volatile VirtualProperty difficulty = new VirtualProperty() { + @Override + public void set(Difficulty newValue) { + world.get().setDifficulty(newValue); + } + + @Override + public Difficulty get() { + return world.get().getDifficulty(); + } + }; + @Property(validator = SpawningPropertyValidator.class, description = "Sorry, 'animals' must either be: true or false.") + private volatile SpawnSettings spawning; + @Property + private volatile EntryFee entryfee; + @Property(description = "Sorry, 'hunger' must either be: true or false.") + private volatile boolean hunger; + @Property(description = "Sorry, 'autoheal' must either be: true or false.") + private volatile boolean autoHeal; + @Property(description = "Sorry, 'adjustspawn' must either be: true or false.") + private volatile boolean adjustSpawn; + @Property(serializor = EnumPropertySerializor.class, description = "Allow portal forming must be NONE, ALL, NETHER or END.") + private volatile AllowedPortalType portalForm; + @Property(serializor = GameModePropertySerializor.class, validator = GameModePropertyValidator.class, + description = "GameMode must be set as one of the following: survival creative") + private volatile GameMode gameMode; + @Property(description = "Sorry, this must either be: true or false.", virtualType = Boolean.class, persistVirtual = true) + private volatile VirtualProperty keepSpawnInMemory = new VirtualProperty() { + @Override + public void set(Boolean newValue) { + world.get().setKeepSpawnInMemory(newValue); + } + + @Override + public Boolean get() { + return world.get().getKeepSpawnInMemory(); + } + }; + @Property + private volatile SpawnLocation spawnLocation; + @Property(validator = SpawnLocationPropertyValidator.class, virtualType = Location.class, + description = "There is no help available for this variable. Go bug Rigby90 about it.") + private volatile VirtualProperty spawn = new VirtualProperty() { + @Override + public void set(Location newValue) { + if (getCBWorld() != null) + getCBWorld().setSpawnLocation(newValue.getBlockX(), newValue.getBlockY(), newValue.getBlockZ()); + + spawnLocation = new SpawnLocation(newValue); + } + + @Override + public Location get() { + spawnLocation.setWorld(getCBWorld()); + // basically, everybody should accept our "SpawnLocation", right? + // so just returning it should be fine + return spawnLocation; + } + }; + @Property(description = "Set this to false ONLY if you don't want this world to load itself on server restart.") + private volatile boolean autoLoad; + @Property(description = "If a player dies in this world, shoudld they go to their bed?") + private volatile boolean bedRespawn; + @Property + private volatile List worldBlacklist; + @Property(serializor = TimePropertySerializor.class, virtualType = Long.class, + description = "Set the time to whatever you want! (Will NOT freeze time)") + private volatile VirtualProperty time = new VirtualProperty() { + @Override + public void set(Long newValue) { + world.get().setTime(newValue); + } + + @Override + public Long get() { + return world.get().getTime(); + } + }; + @Property + private volatile Environment environment; + @Property + private volatile long seed; + @Property + private volatile String generator; + // End of properties + // -------------------------------------------------------------- private Permission permission; private Permission exempt; - - private boolean canSave = false; // Prevents all the setters from constantly saving to the config when being called from the constructor. - private Map propertyAliases; private Permission ignoreperm; - private static final Map TIME_ALIASES; - private WorldType type; - - static { - Map staticTimes = new HashMap(); - staticTimes.put("morning", "8:00"); - staticTimes.put("day", "12:00"); - staticTimes.put("noon", "12:00"); - staticTimes.put("midnight", "0:00"); - staticTimes.put("night", "20:00"); - - // now set TIME_ALIASES to a "frozen" map - TIME_ALIASES = Collections.unmodifiableMap(staticTimes); + public MVWorld(boolean fixSpawn) { + super(); + if (!fixSpawn) { + this.adjustSpawn = false; + } } - public MVWorld(World world, FileConfiguration config, MultiverseCore instance, Long seed, String generatorString, boolean fixSpawn) { - this.config = config; - this.plugin = instance; + /** + * {@inheritDoc} + */ + @Override + public void copyValues(SerializationConfig other) { + super.copyValues(other); + } - // Set local values that CANNOT be changed by user - this.world = world; - this.name = world.getName(); - this.seed = seed; - this.environment = world.getEnvironment(); - this.type = world.getWorldType(); - - // Initialize our lists - this.initLists(); - worldSection = config.getConfigurationSection("worlds." + this.name); - if (worldSection == null) { - config.createSection("worlds." + this.name); - worldSection = config.getConfigurationSection("worlds." + this.name); + /** + * Null-location. + */ + @SerializableAs("MVNullLocation (It's a bug if you see this in your config file)") + public static final class NullLocation extends SpawnLocation { + public NullLocation() { + super(0, -1, 0); } - // Write these files to the config (once it's saved) - if (generatorString != null) { - worldSection.set("generator", generatorString); + + @Override + public Location clone() { + throw new UnsupportedOperationException(); + }; + + @Override + public Map serialize() { + return Collections.EMPTY_MAP; } - if (seed != null) { - worldSection.set("seed", this.seed); + + /** + * Let Bukkit be able to deserialize this. + * @param args The map. + * @return The deserialized object. + */ + public static NullLocation deserialize(Map args) { + return new NullLocation(); } - worldSection.set("environment", this.environment.toString()); - worldSection.set("type", this.type.toString()); - - // Start NEW config awesomeness. - ConfigPropertyFactory fac = new ConfigPropertyFactory(this.worldSection); - this.propertyList = new HashMap>(); - // The format of these are either: - // getNewProperty(name, defaultValue, helpText) - // or - // getNewProperty(name, defaultValue, yamlConfigNode, helpText) - // - // If the first type is used, name is used as the yamlConfigNode - this.propertyList.put("hidden", fac.getNewProperty("hidden", false, - "Sorry, 'hidden' must either be:" + ChatColor.GREEN + " true " + ChatColor.WHITE + "or" + ChatColor.RED + " false" + ChatColor.WHITE + ".")); - this.propertyList.put("alias", fac.getNewProperty("alias", "", "alias.name", - "Alias must be a valid string.")); - this.propertyList.put("color", fac.getNewProperty("color", EnglishChatColor.WHITE, "alias.color", - "Sorry, 'color' must either one of: " + EnglishChatColor.getAllColors())); - this.propertyList.put("pvp", fac.getNewProperty("pvp", true, "pvp", - "Sorry, 'pvp' must either be:" + ChatColor.GREEN + " true " + ChatColor.WHITE - + "or" + ChatColor.RED + " false" + ChatColor.WHITE + ".", "setActualPVP")); - this.propertyList.put("scale", fac.getNewProperty("scale", this.getDefaultScale(this.environment), "scale", - "Scale must be a positive double value. ex: " + ChatColor.GOLD + "2.3", "verifyScaleSetProperly")); - this.propertyList.put("respawn", fac.getNewProperty("respawn", "", "respawnworld", - "You must set this to the " + ChatColor.GOLD + " NAME" + ChatColor.RED + " not alias of a world.")); - this.propertyList.put("weather", fac.getNewProperty("weather", true, "allowweather", - "Sorry, 'weather' must either be:" + ChatColor.GREEN + " true " + ChatColor.WHITE - + "or" + ChatColor.RED + " false" + ChatColor.WHITE + ".", "setActualWeather")); - this.propertyList.put("difficulty", fac.getNewProperty("difficulty", Difficulty.EASY, - "Difficulty must be set as one of the following: " + ChatColor.GREEN + "peaceful " - + ChatColor.AQUA + "easy " + ChatColor.GOLD + "normal " + ChatColor.RED + "hard")); - this.propertyList.put("animals", fac.getNewProperty("animals", true, "animals.spawn", - "Sorry, 'animals' must either be:" + ChatColor.GREEN + " true " + ChatColor.WHITE - + "or" + ChatColor.RED + " false" + ChatColor.WHITE + ".", "syncMobs")); - this.propertyList.put("monsters", fac.getNewProperty("monsters", true, "monsters.spawn", - "Sorry, 'monsters' must either be:" + ChatColor.GREEN + " true " + ChatColor.WHITE - + "or" + ChatColor.RED + " false" + ChatColor.WHITE + ".", "syncMobs")); - this.propertyList.put("currency", fac.getNewProperty("currency", -1, "entryfee.currency", - "Currency must be an integer between -1 and the highest Minecraft item ID.")); - this.propertyList.put("price", fac.getNewProperty("price", 0.0, "entryfee.price", - "Price must be a double value. ex: " + ChatColor.GOLD + "1.2" + ChatColor.WHITE - + ". Set to a negative value to give players money for entering this world.")); - this.propertyList.put("hunger", fac.getNewProperty("hunger", true, - "Sorry, 'hunger' must either be:" + ChatColor.GREEN + " true " + ChatColor.WHITE + "or" + ChatColor.RED + " false" + ChatColor.WHITE + ".")); - this.propertyList.put("autoheal", fac.getNewProperty("autoheal", true, - "Sorry, 'autoheal' must either be:" + ChatColor.GREEN + " true " + ChatColor.WHITE + "or" + ChatColor.RED + " false" + ChatColor.WHITE + ".")); - this.propertyList.put("adjustspawn", fac.getNewProperty("adjustspawn", true, - "Sorry, 'adjustspawn' must either be:" + ChatColor.GREEN + " true " + ChatColor.WHITE - + "or" + ChatColor.RED + " false" + ChatColor.WHITE + ".")); - this.propertyList.put("portalform", fac.getNewProperty("portalform", AllowedPortalType.ALL, - "Allow portal forming must be NONE, ALL, NETHER or END.")); - if (!fixSpawn) { - this.setAdjustSpawn(false); + @Override + public Vector toVector() { + throw new UnsupportedOperationException(); } - this.propertyList.put("gamemode", fac.getNewProperty("gamemode", GameMode.SURVIVAL, - "GameMode must be set as one of the following: " + ChatColor.RED + "survival " + ChatColor.GREEN + "creative ")); - this.propertyList.put("memory", fac.getNewProperty("keepspawninmemory", true, "keepspawninmemory", - "Sorry, 'memory' must either be:" + ChatColor.GREEN + " true " - + ChatColor.WHITE + "or" + ChatColor.RED + " false" + ChatColor.WHITE + ".", "setActualKeepSpawnInMemory")); - this.propertyList.put("spawn", fac.getNewProperty("spawn", this.world.getSpawnLocation(), "spawn", - "There is no help available for this variable. Go bug Rigby90 about it.", "setActualKeepSpawnInMemory")); - this.propertyList.put("autoload", fac.getNewProperty("autoload", true, - "Set this to false ONLY if you don't want this world to load itself on server restart.")); - this.propertyList.put("bedrespawn", fac.getNewProperty("bedrespawn", true, "If a player dies in this world, shoudld they go to their bed?")); - this.propertyList.put("time", fac.getNewProperty("time", "", "Set the time to whatever you want! (Will NOT freeze time)", "setActualTime", true)); - this.getKnownProperty("spawn", Location.class).setValue(this.readSpawnFromConfig(this.getCBWorld())); + @Override + public int hashCode() { + return -1; + }; - // Set aliases - this.propertyAliases = new HashMap(); - this.propertyAliases.put("curr", "currency"); - this.propertyAliases.put("scaling", "scale"); - this.propertyAliases.put("aliascolor", "color"); - this.propertyAliases.put("heal", "autoheal"); - this.propertyAliases.put("storm", "weather"); - this.propertyAliases.put("spawnmemory", "memory"); - this.propertyAliases.put("mode", "gamemode"); - this.propertyAliases.put("diff", "difficulty"); + @Override + public String toString() { + return "NULL LOCATION"; + }; + } - // Things I haven't converted yet. - this.getMobExceptions(); - List tempWorldBlacklist = worldSection.getStringList("worldblacklist"); - if (tempWorldBlacklist != null) - this.getWorldBlacklist().addAll(tempWorldBlacklist); + /** + * Sets the CB-World. + *

+ * This is used to set some values after deserialization. + * @param cbWorld The new world. + * @param thePlugin The reference to the plugin. + */ + public void init(World cbWorld, MultiverseCore thePlugin) { + this.plugin = thePlugin; - // Enable and do the save. - this.canSave = true; - this.saveConfig(); + // Weak reference so the CB-World can be unloaded even if this object still exists! + this.world = new WeakReference(cbWorld); + this.environment = cbWorld.getEnvironment(); + this.seed = cbWorld.getSeed(); + this.name = cbWorld.getName(); + if (this.spawnLocation instanceof NullLocation) + this.spawnLocation = new SpawnLocation(readSpawnFromWorld(cbWorld)); + this.initPerms(); + + this.flushPendingVPropChanges(); + } + + /** + * This prepares the MVWorld for unloading. + */ + public void tearDown() { + try { + this.buildVPropChanges(); + } catch (IllegalStateException e) { + // do nothing + } + } + + /** + * Initializes permissions. + */ + private void initPerms() { this.permission = new Permission("multiverse.access." + this.getName(), "Allows access to " + this.getName(), PermissionDefault.OP); // This guy is special. He shouldn't be added to any parent perms. this.ignoreperm = new Permission("mv.bypass.gamemode." + this.getName(), @@ -216,79 +588,93 @@ public class MVWorld implements MultiverseWorld { } catch (IllegalArgumentException e) { this.plugin.log(Level.FINER, "Permissions nodes were already added for " + this.name); } - - // Sync all active settings. - this.setActualPVP(); - this.verifyScaleSetProperly(); - this.setActualKeepSpawnInMemory(); - this.setActualDifficulty(); - this.setActualGameMode(); - this.setActualSpawn(); - this.syncMobs(); } - /** - * Used by the active PVP-property to set the "actual" PVP-property. - * @return True if the property was successfully set. - */ - public boolean setActualPVP() { - // Set the PVP mode - this.world.setPVP(this.getKnownProperty("pvp", Boolean.class).getValue()); - return true; - } - - /** - * Used by the active scale-property to set the "actual" scale-property. - * @return True if the property was successfully set. - */ - public boolean verifyScaleSetProperly() { - // Ensure the scale is above 0 - if (this.getKnownProperty("scale", Double.class).getValue() <= 0) { - // Disallow negative or 0 scalings. - this.getKnownProperty("scale", Double.class).setValue(1.0); - this.plugin.log(Level.WARNING, "Someone tried to set a scale <= 0, defaulting to 1."); + private Location readSpawnFromWorld(World w) { + Location location = w.getSpawnLocation(); + // Set the worldspawn to our configspawn + BlockSafety bs = this.plugin.getBlockSafety(); + // Verify that location was safe + if (!bs.playerCanSpawnHereSafely(location)) { + if (!this.getAdjustSpawn()) { + this.plugin.log(Level.FINE, "Spawn location from world.dat file was unsafe!!"); + this.plugin.log(Level.FINE, "NOT adjusting spawn for '" + this.getAlias() + "' because you told me not to."); + this.plugin.log(Level.FINE, "To turn on spawn adjustment for this world simply type:"); + this.plugin.log(Level.FINE, "/mvm set adjustspawn true " + this.getAlias()); + return location; + } + // If it's not, find a better one. + SafeTTeleporter teleporter = this.plugin.getSafeTTeleporter(); + this.plugin.log(Level.WARNING, "Spawn location from world.dat file was unsafe. Adjusting..."); + this.plugin.log(Level.WARNING, "Original Location: " + plugin.getLocationManipulation().strCoordsRaw(location)); + Location newSpawn = teleporter.getSafeLocation(location, + SPAWN_LOCATION_SEARCH_TOLERANCE, SPAWN_LOCATION_SEARCH_RADIUS); + // I think we could also do this, as I think this is what Notch does. + // Not sure how it will work in the nether... + //Location newSpawn = this.spawnLocation.getWorld().getHighestBlockAt(this.spawnLocation).getLocation(); + if (newSpawn != null) { + this.plugin.log(Level.INFO, String.format("New Spawn for '%s' is located at: %s", + this.getName(), plugin.getLocationManipulation().locationToString(newSpawn))); + return newSpawn; + } else { + // If it's a standard end world, let's check in a better place: + Location newerSpawn; + newerSpawn = bs.getTopBlock(new Location(w, 0, 0, 0)); + if (newerSpawn != null) { + this.plugin.log(Level.INFO, String.format("New Spawn for '%s' is located at: %s", + this.getName(), plugin.getLocationManipulation().locationToString(newerSpawn))); + return newerSpawn; + } else { + this.plugin.log(Level.SEVERE, "Safe spawn NOT found!!!"); + } + } } - return true; + return location; } /** - * Used by the active keepSpawnInMemory-property to set the "actual" property. - * @return True if the property was successfully set. + * {@inheritDoc} */ - public boolean setActualKeepSpawnInMemory() { - // Ensure the memory setting is correct - this.getCBWorld().setKeepSpawnInMemory(this.getKnownProperty("memory", Boolean.class).getValue()); - return true; + @Override + protected void setDefaults() { + this.hidden = false; + this.alias = new String(); + this.color = EnglishChatColor.WHITE; + this.style = EnglishChatStyle.NORMAL; + this.scale = getDefaultScale(environment); + this.respawnWorld = new String(); + this.allowWeather = true; + this.spawning = new SpawnSettings(); + this.entryfee = new EntryFee(); + this.hunger = true; + this.autoHeal = true; + this.adjustSpawn = true; + this.portalForm = AllowedPortalType.ALL; + this.gameMode = GameMode.SURVIVAL; + this.spawnLocation = (world != null) ? new SpawnLocation(world.get().getSpawnLocation()) : new NullLocation(); + this.autoLoad = true; + this.bedRespawn = true; + this.worldBlacklist = new ArrayList(); + this.generator = null; } /** - * Used by the active difficulty-property to set the "actual" property. - * @return True if the property was successfully set. + * getAliases(). + * @return The alias-map. + * @see SerializationConfig */ - public boolean setActualDifficulty() { - this.getCBWorld().setDifficulty(this.getKnownProperty("difficulty", Difficulty.class).getValue()); - return true; + protected static Map getAliases() { + return PROPERTY_ALIASES; } - /** - * Used by the active spawn-property to set the "actual" property. - * @return True if the property was successfully set. - */ - public boolean setActualSpawn() { - // Set the spawn location - Location spawnLocation = this.getKnownProperty("spawn", Location.class).getValue(); - this.getCBWorld().setSpawnLocation(spawnLocation.getBlockX(), spawnLocation.getBlockY(), spawnLocation.getBlockZ()); - return true; - } - - private double getDefaultScale(Environment environment) { + private static double getDefaultScale(Environment environment) { if (environment == Environment.NETHER) { return 8.0; // SUPPRESS CHECKSTYLE: MagicNumberCheck } return 1.0; } - private void addToUpperLists(Permission permission) { + private void addToUpperLists(Permission perm) { Permission all = this.plugin.getServer().getPluginManager().getPermission("multiverse.*"); Permission allWorlds = this.plugin.getServer().getPluginManager().getPermission("multiverse.access.*"); Permission allExemption = this.plugin.getServer().getPluginManager().getPermission("multiverse.exempt.*"); @@ -297,7 +683,7 @@ public class MVWorld implements MultiverseWorld { allWorlds = new Permission("multiverse.access.*"); this.plugin.getServer().getPluginManager().addPermission(allWorlds); } - allWorlds.getChildren().put(permission.getName(), true); + allWorlds.getChildren().put(perm.getName(), true); if (allExemption == null) { allExemption = new Permission("multiverse.exempt.*"); this.plugin.getServer().getPluginManager().addPermission(allExemption); @@ -314,289 +700,178 @@ public class MVWorld implements MultiverseWorld { this.plugin.getServer().getPluginManager().recalculatePermissionDefaults(allWorlds); } + /** + * {@inheritDoc} + */ + @Override + public World getCBWorld() { + return this.world.get(); + } + /** * {@inheritDoc} */ @Override public String getColoredWorldString() { - EnglishChatColor worldColor = this.getKnownProperty("color", EnglishChatColor.class).getValue(); - String alias = this.getKnownProperty("alias", String.class).getValue(); - if (worldColor == null) { - this.setKnownProperty("color", "WHITE", null); - return alias + ChatColor.WHITE; - } else if (worldColor.getColor() == null) { - return alias + ChatColor.WHITE; - } if (alias.length() == 0) { alias = this.getName(); } - return worldColor.getColor() + alias + ChatColor.WHITE; - } - // TODO: Migrate this method. - private void getMobExceptions() { - List temp; - temp = this.worldSection.getStringList("animals.exceptions"); - // Add Animals to the exclusion list - if (temp != null) { - for (String s : temp) { - this.masterList.get("animals").add(s.toUpperCase()); - } - } - temp = this.worldSection.getStringList("monsters.exceptions"); - // Add Monsters to the exclusion list - if (temp != null) { - for (String s : temp) { - this.masterList.get("monsters").add(s.toUpperCase()); - } + if ((color == null) || (color.getColor() == null)) { + this.setPropertyValueUnchecked("color", EnglishChatColor.WHITE); } + + StringBuilder nameBuilder = new StringBuilder().append(color.getColor()); + if (style.getColor() != null) + nameBuilder.append(style.getColor()); + nameBuilder.append(alias).append(ChatColor.WHITE).toString(); + + return nameBuilder.toString(); } /** * {@inheritDoc} + * + * @deprecated This is deprecated. */ @Override - public World getCBWorld() { - return this.world; - } - - private void initLists() { - this.masterList = new HashMap>(); - this.masterList.put("worldblacklist", new ArrayList()); - this.masterList.put("animals", new ArrayList()); - this.masterList.put("monsters", new ArrayList()); + @Deprecated + public boolean clearList(String property) { + return clearVariable(property); } /** * {@inheritDoc} + * + * @deprecated This is deprecated. */ @Override + @Deprecated public boolean clearVariable(String property) { - if (this.masterList.keySet().contains(property)) { - this.masterList.get(property).clear(); - } else { + List list = getOldAndEvilList(property); + if (list == null) return false; - } - this.worldSection.set(property.toLowerCase(), new ArrayList()); - this.saveConfig(); + list.clear(); return true; } - /** - * {@inheritDoc} - */ - @Override - public boolean addToVariable(String property, String value) { - property = property.toLowerCase(); - if (this.masterList.keySet().contains(property)) { - - if (property.equals("animals") || property.equals("monsters")) { - this.masterList.get(property).add(value.toUpperCase()); - this.worldSection.set(property.toLowerCase() + ".exceptions", this.masterList.get(property)); - this.syncMobs(); - } else { - this.masterList.get(property).add(value); - this.worldSection.set(property.toLowerCase(), this.masterList.get(property)); - } - saveConfig(); - return true; - } - return false; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean removeFromVariable(String property, String value) { - property = property.toLowerCase(); - if (this.masterList.keySet().contains(property)) { - - if (property.equals("animals") || property.equals("monsters")) { - this.masterList.get(property).remove(value.toUpperCase()); - this.worldSection.set(property + ".exceptions", this.masterList.get(property)); - this.syncMobs(); - } else { - this.masterList.get(property).remove(value); - this.worldSection.set(property, this.masterList.get(property)); - } - saveConfig(); - return true; - } - return false; - } - - /** - * Ensure that the value of the animals and monsters config - * properties are set in accordance with the current animals - * and monsters in the world, respectively. - */ - public void syncMobs() { - - if (this.getAnimalList().isEmpty()) { - this.world.setSpawnFlags(this.world.getAllowMonsters(), this.getKnownProperty("animals", Boolean.class).getValue()); - } else { - this.world.setSpawnFlags(this.world.getAllowMonsters(), true); - } - if (this.getMonsterList().isEmpty()) { - this.world.setSpawnFlags(this.getKnownProperty("monsters", Boolean.class).getValue(), this.world.getAllowAnimals()); - } else { - this.world.setSpawnFlags(true, this.world.getAllowAnimals()); - } - this.plugin.getMVWorldManager().getTheWorldPurger().purgeWorld(this); - } - - /** - * {@inheritDoc} - */ - @Override - public void setKeepSpawnInMemory(boolean value) { - this.getKnownProperty("memory", Boolean.class).setValue(value); - saveConfig(); - } - - /** - * {@inheritDoc} - */ - @Override - // TODO: Provide better feedback - public boolean setProperty(String name, String value, CommandSender sender) throws PropertyDoesNotExistException { - if (!this.isValidPropertyName(name)) { - throw new PropertyDoesNotExistException(name); - } - return this.setKnownProperty(name, value, sender) || this.setKnownProperty(this.propertyAliases.get(name), value, sender); - - } - - private boolean isValidPropertyName(String name) { - return this.propertyList.containsKey(name) || this.propertyAliases.containsKey(name); - } - - /** - * {@inheritDoc} - */ - @Override - public String getPropertyValue(String name) throws PropertyDoesNotExistException { - if (this.propertyList.containsKey(name)) { - return this.getKnownProperty(name, Object.class).toString(); - } - throw new PropertyDoesNotExistException(name); - } - /** * {@inheritDoc} * - * @deprecated Use {@link #getProperty(String, Class)} instead + * @deprecated This is deprecated. */ @Override @Deprecated - public MVConfigProperty getProperty(String property) throws PropertyDoesNotExistException { - return getProperty(property, Object.class); + public boolean addToVariable(String property, String value) { + List list = getOldAndEvilList(property); + if (list == null) + return false; + list.add(value); + return true; } /** * {@inheritDoc} + * + * @deprecated This is deprecated. */ @Override - public MVConfigProperty getProperty(String name, Class expected) throws PropertyDoesNotExistException { - MVConfigProperty p = this.getKnownProperty(name, expected); - if (p == null) { - throw new PropertyDoesNotExistException(name); - } - return p; + @Deprecated + public boolean removeFromVariable(String property, String value) { + List list = getOldAndEvilList(property); + if (list == null) + return false; + list.remove(value); + return true; } /** - * This method should only be used from inside this class when it is KNOWN that the property exists. - * - * @param name The known name of a property - * @param expected The Type of the expected value - * @return The property object. + * @deprecated This is deprecated. */ - @SuppressWarnings("unchecked") - private MVConfigProperty getKnownProperty(String name, Class expected) { - try { - if (this.propertyList.containsKey(name)) { - return (MVConfigProperty) this.propertyList.get(name); - } else if (this.propertyAliases.containsKey(name)) { - // If the property was defined in the alias table, make sure to grab the actual name - return (MVConfigProperty) this.propertyList.get(this.propertyAliases.get(name)); - } - } catch (ClassCastException e) { - return null; - } + @Deprecated + private List getOldAndEvilList(String property) { + if (property.equalsIgnoreCase("worldblacklist")) + return this.worldBlacklist; + else if (property.equalsIgnoreCase("animals")) + return this.spawning.getAnimalSettings().getExceptions(); + else if (property.equalsIgnoreCase("monsters")) + return this.spawning.getMonsterSettings().getExceptions(); return null; } /** - * This method should only be used from inside this class when it is KNOWN that the property exists. + * {@inheritDoc} * - * @param name The known name of a property. - * @param value The value that is trying to be set. - * @param sender The person sending the command, MAY BE NULL. - * @return True if the property was saved, false if not. + * @deprecated This is deprecated. */ - private boolean setKnownProperty(String name, String value, CommandSender sender) { - MVConfigProperty property; - if (this.propertyList.containsKey(name)) { - property = this.getKnownProperty(name, Object.class); - } else if (this.propertyAliases.containsKey(name)) { - return this.setKnownProperty(this.propertyAliases.get(name), value, sender); - } else { - return false; - } - // Only allow people to cancel events when they're not the initializations. - if (this.canSave) { - MVWorldPropertyChangeEvent propertyChangeEvent = new MVWorldPropertyChangeEvent(this, sender, name, value); - this.plugin.getServer().getPluginManager().callEvent(propertyChangeEvent); - if (propertyChangeEvent.isCancelled()) { - this.plugin.log(Level.FINE, "Someone else cancelled the WorldPropertyChanged Event!!!"); - return false; - } - value = propertyChangeEvent.getNewValue(); - } - if (property.parseValue(value)) { - if (property instanceof MVActiveConfigProperty) { - return this.setActiveProperty((MVActiveConfigProperty) property); - } - this.saveConfig(); - return true; - } - return false; + @Override + @Deprecated + public com.onarandombox.MultiverseCore.configuration.MVConfigProperty getProperty(String property, + Class expected) throws PropertyDoesNotExistException { + throw new UnsupportedOperationException("'MVConfigProperty getProperty(String,Class)' is no longer supported!"); } - private boolean setActiveProperty(MVActiveConfigProperty property) { + /** + * {@inheritDoc} + * + * @deprecated This is deprecated. + */ + @Override + @Deprecated + public boolean setProperty(String name, String value, CommandSender sender) throws PropertyDoesNotExistException { + return this.setPropertyValue(name, value); + } + + /** + * {@inheritDoc} + */ + @Override + public String getPropertyValue(String property) throws PropertyDoesNotExistException { try { - if (property.getMethod() == null) { - // This property did not have a method. - this.saveConfig(); - return true; - } - Method method = this.getClass().getMethod(property.getMethod()); - Object returnVal = method.invoke(this); - if (returnVal instanceof Boolean) { - if ((Boolean) returnVal) { - this.saveConfig(); - } - return (Boolean) returnVal; - } else { - this.saveConfig(); - return true; - } - } catch (Exception e) { - // TODO: I don't care about 3 catches, - // TODO: I hate pokemon errors :/ - FernFerret - e.printStackTrace(); - return false; + return this.getProperty(property, true); + } catch (NoSuchPropertyException e) { + throw new PropertyDoesNotExistException(property, e); } } + /** + * {@inheritDoc} + */ + @Override + public boolean setPropertyValue(String property, String value) throws PropertyDoesNotExistException { + try { + return this.setProperty(property, value, true); + } catch (NoSuchPropertyException e) { + throw new PropertyDoesNotExistException(property, e); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getPropertyHelp(String property) throws PropertyDoesNotExistException { + try { + return this.getPropertyDescription(property, true); + } catch (NoSuchPropertyException e) { + throw new PropertyDoesNotExistException(property, e); + } + } + + /** + * {@inheritDoc} + */ + @Override + public WorldType getWorldType() { + // This variable is not settable in-game, therefore does not get a property. + return world.get().getWorldType(); + } + /** * {@inheritDoc} */ @Override public Environment getEnvironment() { - // This variable is not settable in-game, therefore does not get a property. return this.environment; } @@ -605,16 +880,14 @@ public class MVWorld implements MultiverseWorld { */ @Override public void setEnvironment(Environment environment) { - // This variable is not settable in-game, therefore does not get a property. - this.environment = environment; + this.setPropertyValueUnchecked("environment", environment); } /** * {@inheritDoc} */ @Override - public Long getSeed() { - // This variable is not settable in-game, therefore does not get a property. + public long getSeed() { return this.seed; } @@ -622,9 +895,24 @@ public class MVWorld implements MultiverseWorld { * {@inheritDoc} */ @Override - public void setSeed(Long seed) { - // This variable is not settable in-game, therefore does not get a property. - this.seed = seed; + public void setSeed(long seed) { + this.setPropertyValueUnchecked("seed", seed); + } + + /** + * {@inheritDoc} + */ + @Override + public String getGenerator() { + return this.generator; + } + + /** + * {@inheritDoc} + */ + @Override + public void setGenerator(String generator) { + this.setPropertyValueUnchecked("generator", generator); } /** @@ -649,12 +937,10 @@ public class MVWorld implements MultiverseWorld { */ @Override public String getAlias() { - String alias = this.getKnownProperty("alias", String.class).getValue(); - if (alias == null || alias.length() == 0) { + if (this.alias == null || this.alias.length() == 0) { return this.name; } - return alias; - + return this.alias; } /** @@ -662,7 +948,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public void setAlias(String alias) { - this.setKnownProperty("alias", alias, null); + this.setPropertyValueUnchecked("alias", alias); } /** @@ -670,7 +956,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public boolean canAnimalsSpawn() { - return this.getKnownProperty("animals", Boolean.class).getValue(); + return this.spawning.getAnimalSettings().doSpawn(); } /** @@ -678,7 +964,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public void setAllowAnimalSpawn(boolean animals) { - this.setKnownProperty("animals", animals + "", null); + this.setPropertyValueUnchecked("spawning.animals.spawn", animals); } /** @@ -686,7 +972,8 @@ public class MVWorld implements MultiverseWorld { */ @Override public List getAnimalList() { - return this.masterList.get("animals"); + // These don't fire events at the moment. Should they? + return this.spawning.getAnimalSettings().getExceptions(); } /** @@ -694,7 +981,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public boolean canMonstersSpawn() { - return this.getKnownProperty("monsters", Boolean.class).getValue(); + return this.spawning.getMonsterSettings().doSpawn(); } /** @@ -702,7 +989,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public void setAllowMonsterSpawn(boolean monsters) { - this.setKnownProperty("monsters", monsters + "", null); + this.setPropertyValueUnchecked("spawning.monsters.spawn", monsters); } /** @@ -710,7 +997,8 @@ public class MVWorld implements MultiverseWorld { */ @Override public List getMonsterList() { - return this.masterList.get("monsters"); + // These don't fire events at the moment. Should they? + return this.spawning.getMonsterSettings().getExceptions(); } /** @@ -718,7 +1006,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public boolean isPVPEnabled() { - return this.getKnownProperty("pvp", Boolean.class).getValue(); + return this.pvp.get(); } /** @@ -726,7 +1014,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public void setPVPMode(boolean pvp) { - this.setKnownProperty("pvp", pvp + "", null); + this.setPropertyValueUnchecked("pvp", pvp); } /** @@ -734,7 +1022,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public boolean isHidden() { - return this.getKnownProperty("hidden", Boolean.class).getValue(); + return this.hidden; } /** @@ -742,7 +1030,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public void setHidden(boolean hidden) { - this.setKnownProperty("hidden", hidden + "", null); + this.setPropertyValueUnchecked("hidden", hidden); } /** @@ -750,7 +1038,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public List getWorldBlacklist() { - return this.masterList.get("worldblacklist"); + return this.worldBlacklist; } /** @@ -758,7 +1046,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public double getScaling() { - return this.getKnownProperty("scale", Double.class).getValue(); + return this.scale; } /** @@ -766,7 +1054,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public boolean setScaling(double scaling) { - return this.setKnownProperty("scale", scaling + "", null); + return this.setPropertyValueUnchecked("scale", scaling); } /** @@ -774,13 +1062,16 @@ public class MVWorld implements MultiverseWorld { */ @Override public boolean setColor(String aliasColor) { - return this.setKnownProperty("color", aliasColor, null); + return this.setPropertyUnchecked("color", aliasColor); } /** * {@inheritDoc} + * + * @deprecated This is deprecated. */ - @Override // TODO This method should be static. (Maybe EnglishChatColor would be a good place?) + @Override + @Deprecated public boolean isValidAliasColor(String aliasColor) { return (EnglishChatColor.fromString(aliasColor) != null); } @@ -790,22 +1081,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public ChatColor getColor() { - return this.getKnownProperty("color", EnglishChatColor.class).getValue().getColor(); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean clearList(String property) { - if (this.masterList.containsKey(property)) { - this.masterList.get(property).clear(); - this.worldSection.set(property.toLowerCase(), this.masterList.get(property)); - this.syncMobs(); - saveConfig(); - return true; - } - return false; + return this.color.getColor(); } /** @@ -824,7 +1100,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public World getRespawnToWorld() { - return (this.plugin.getServer().getWorld(this.getKnownProperty("respawn", String.class).getValue())); + return this.plugin.getServer().getWorld(respawnWorld); } /** @@ -833,7 +1109,7 @@ public class MVWorld implements MultiverseWorld { @Override public boolean setRespawnToWorld(String respawnToWorld) { if (!this.plugin.getMVWorldManager().isMVWorld(respawnToWorld)) return false; - return this.setKnownProperty("respawn", respawnToWorld, null); + return this.setPropertyValueUnchecked("respawnWorld", respawnToWorld); } /** @@ -849,7 +1125,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public int getCurrency() { - return this.getKnownProperty("curr", Integer.class).getValue(); + return this.entryfee.getCurrency(); } /** @@ -857,7 +1133,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public void setCurrency(int currency) { - this.setKnownProperty("curr", currency + "", null); + this.setPropertyValueUnchecked("entryfee.currency", currency); } /** @@ -865,7 +1141,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public double getPrice() { - return this.getKnownProperty("price", Double.class).getValue(); + return this.entryfee.getAmount(); } /** @@ -873,7 +1149,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public void setPrice(double price) { - this.setKnownProperty("price", price + "", null); + this.setPropertyValueUnchecked("entryfee.amount", price); } /** @@ -884,40 +1160,17 @@ public class MVWorld implements MultiverseWorld { return this.exempt; } - private void saveConfig() { - if (this.canSave) { - try { - this.config.save(new File(this.plugin.getDataFolder(), "worlds.yml")); - } catch (IOException e) { - this.plugin.log(Level.SEVERE, "Could not save worlds.yml. Please check your filesystem permissions."); - } - } - } - /** * {@inheritDoc} */ @Override - public boolean setGameMode(String gameMode) { - return this.setKnownProperty("mode", gameMode, null); + public boolean setGameMode(String mode) { + return this.setPropertyUnchecked("gameMode", mode); } - /** - * Sets the actual gamemode by iterating through players. - * - * gameMode is not used, but it's in the reflection template. - * - * Needs a bit o' refactoring. - * - * @return True if the gamemodes of players were set successfully. (always) - */ - public boolean setActualGameMode() { - for (Player p : this.plugin.getServer().getWorld(this.getName()).getPlayers()) { - this.plugin.log(Level.FINER, String.format("Setting %s's GameMode to %s", - p.getName(), this.getKnownProperty("mode", GameMode.class).getValue().toString())); - this.plugin.getPlayerListener().handleGameMode(p, this); - } - return true; + @Override + public boolean setGameMode(GameMode mode) { + return this.setPropertyValueUnchecked("gameMode", mode); } /** @@ -925,7 +1178,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public GameMode getGameMode() { - return this.getKnownProperty("mode", GameMode.class).getValue(); + return this.gameMode; } /** @@ -933,20 +1186,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public void setEnableWeather(boolean weather) { - this.setKnownProperty("weather", weather + "", null); - } - - /** - * Used by the active weather-property to set the "actual" property. - * @return True if the property was successfully set. - */ - public boolean setActualWeather() { - // Disable any current weather - if (!this.getKnownProperty("weather", Boolean.class).getValue()) { - this.getCBWorld().setStorm(false); - this.getCBWorld().setThundering(false); - } - return true; + this.setPropertyValueUnchecked("allowWeather", weather); } /** @@ -954,7 +1194,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public boolean isWeatherEnabled() { - return this.getKnownProperty("weather", Boolean.class).getValue(); + return this.allowWeather; } /** @@ -962,15 +1202,15 @@ public class MVWorld implements MultiverseWorld { */ @Override public boolean isKeepingSpawnInMemory() { - return this.getKnownProperty("memory", Boolean.class).getValue(); + return this.keepSpawnInMemory.get(); } /** * {@inheritDoc} */ @Override - public void setHunger(boolean hunger) { - this.setKnownProperty("hunger", hunger + "", null); + public void setKeepSpawnInMemory(boolean value) { + this.setPropertyValueUnchecked("keepSpawnInMemory", value); } /** @@ -978,69 +1218,15 @@ public class MVWorld implements MultiverseWorld { */ @Override public boolean getHunger() { - return this.getKnownProperty("hunger", Boolean.class).getValue(); + return this.hunger; } /** * {@inheritDoc} */ @Override - public void setSpawnLocation(Location l) { - this.getCBWorld().setSpawnLocation(l.getBlockX(), l.getBlockY(), l.getBlockZ()); - this.getKnownProperty("spawn", Location.class).setValue(l); - this.saveConfig(); - } - - private static final int SPAWN_LOCATION_SEARCH_TOLERANCE = 16; - private static final int SPAWN_LOCATION_SEARCH_RADIUS = 16; - - private Location readSpawnFromConfig(World w) { - Location spawnLocation = w.getSpawnLocation(); - Location configLocation = this.getSpawnLocation(); - - // Set the worldspawn to our configspawn - w.setSpawnLocation(configLocation.getBlockX(), configLocation.getBlockY(), configLocation.getBlockZ()); - SafeTTeleporter teleporter = this.plugin.getSafeTTeleporter(); - BlockSafety bs = this.plugin.getBlockSafety(); - // Verify that location was safe - if (!bs.playerCanSpawnHereSafely(configLocation)) { - if (!this.getAdjustSpawn()) { - this.plugin.log(Level.FINE, "Spawn location from world.dat file was unsafe!!"); - this.plugin.log(Level.FINE, "NOT adjusting spawn for '" + this.getAlias() + "' because you told me not to."); - this.plugin.log(Level.FINE, "To turn on spawn adjustment for this world simply type:"); - this.plugin.log(Level.FINE, "/mvm set adjustspawn true " + this.getAlias()); - return configLocation; - } - // If it's not, find a better one. - this.plugin.log(Level.WARNING, "Spawn location from world.dat file was unsafe. Adjusting..."); - this.plugin.log(Level.WARNING, "Original Location: " + plugin.getLocationManipulation().strCoordsRaw(spawnLocation)); - Location newSpawn = teleporter.getSafeLocation(spawnLocation, - SPAWN_LOCATION_SEARCH_TOLERANCE, SPAWN_LOCATION_SEARCH_RADIUS); - // I think we could also do this, as I think this is what Notch does. - // Not sure how it will work in the nether... - //Location newSpawn = this.spawnLocation.getWorld().getHighestBlockAt(this.spawnLocation).getLocation(); - if (newSpawn != null) { - this.setSpawnLocation(newSpawn); - configLocation = this.getSpawnLocation(); - this.plugin.log(Level.INFO, "New Spawn for '" + this.getName() - + "' is Located at: " + plugin.getLocationManipulation().locationToString(configLocation)); - } else { - // If it's a standard end world, let's check in a better place: - Location newerSpawn; - newerSpawn = bs.getTopBlock(new Location(w, 0, 0, 0)); - if (newerSpawn != null) { - this.setSpawnLocation(newerSpawn); - configLocation = this.getSpawnLocation(); - this.plugin.log(Level.INFO, "New Spawn for '" + this.getName() - + "' is Located at: " + plugin.getLocationManipulation().locationToString(configLocation)); - } else { - this.plugin.log(Level.SEVERE, "New safe spawn NOT found!!!"); - } - - - } - } - return configLocation; + public void setHunger(boolean hunger) { + this.setPropertyValueUnchecked("hunger", hunger); } /** @@ -1048,7 +1234,15 @@ public class MVWorld implements MultiverseWorld { */ @Override public Location getSpawnLocation() { - return this.getKnownProperty("spawn", Location.class).getValue(); + return this.spawn.get(); + } + + /** + * {@inheritDoc} + */ + @Override + public void setSpawnLocation(Location l) { + this.setPropertyValueUnchecked("spawn", l); } /** @@ -1056,20 +1250,23 @@ public class MVWorld implements MultiverseWorld { */ @Override public Difficulty getDifficulty() { - return this.getCBWorld().getDifficulty(); + return this.difficulty.get(); } /** * {@inheritDoc} + * + * @deprecated This is deprecated. */ @Override + @Deprecated public boolean setDifficulty(String difficulty) { - if (this.setKnownProperty("diff", difficulty, null)) { - // Set the difficulty - this.getCBWorld().setDifficulty(this.getKnownProperty("diff", Difficulty.class).getValue()); - return true; - } - return false; + return this.setPropertyUnchecked("difficulty", difficulty); + } + + @Override + public boolean setDifficulty(Difficulty difficulty) { + return this.setPropertyValueUnchecked("difficulty", difficulty); } /** @@ -1077,7 +1274,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public boolean getAutoHeal() { - return this.getKnownProperty("autoheal", Boolean.class).getValue(); + return this.autoHeal; } /** @@ -1085,7 +1282,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public void setAutoHeal(boolean heal) { - this.setKnownProperty("autoheal", heal + "", null); + this.setPropertyValueUnchecked("autoHeal", heal); } /** @@ -1093,7 +1290,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public void setAdjustSpawn(boolean adjust) { - this.setKnownProperty("adjustspawn", adjust + "", null); + this.setPropertyValueUnchecked("adjustSpawn", adjust); } /** @@ -1101,15 +1298,15 @@ public class MVWorld implements MultiverseWorld { */ @Override public boolean getAdjustSpawn() { - return this.getKnownProperty("adjustspawn", Boolean.class).getValue(); + return this.adjustSpawn; } /** * {@inheritDoc} */ @Override - public void setAutoLoad(boolean autoLoad) { - this.setKnownProperty("autoload", autoLoad + "", null); + public void setAutoLoad(boolean load) { + this.setPropertyValueUnchecked("autoLoad", load); } /** @@ -1117,7 +1314,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public boolean getAutoLoad() { - return this.getKnownProperty("autoload", Boolean.class).getValue(); + return this.autoLoad; } /** @@ -1125,7 +1322,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public void setBedRespawn(boolean respawn) { - this.setKnownProperty("bedrespawn", respawn + "", null); + this.setPropertyValueUnchecked("bedRespawn", respawn); } /** @@ -1133,7 +1330,7 @@ public class MVWorld implements MultiverseWorld { */ @Override public boolean getBedRespawn() { - return this.getKnownProperty("bedrespawn", Boolean.class).getValue(); + return this.bedRespawn; } /** @@ -1141,13 +1338,14 @@ public class MVWorld implements MultiverseWorld { */ @Override public String getAllPropertyNames() { - ChatColor color = ChatColor.AQUA; - String result = ""; - for (String propertyNames : this.propertyList.keySet()) { - result += color + propertyNames + " "; - color = (color == ChatColor.AQUA) ? ChatColor.GOLD : ChatColor.AQUA; + ChatColor myColor = ChatColor.AQUA; + StringBuilder result = new StringBuilder(); + Map serialized = this.serialize(); + for (String key : serialized.keySet()) { + result.append(myColor).append(key).append(' '); + myColor = (myColor == ChatColor.AQUA) ? ChatColor.GOLD : ChatColor.AQUA; } - return result; + return result.toString(); } /** @@ -1155,32 +1353,15 @@ public class MVWorld implements MultiverseWorld { */ @Override public String getTime() { - long time = this.getCBWorld().getTime(); - // I'm tired, so they get time in 24 hour for now. - // Someone else can add 12 hr format if they want :P - - // BEGIN CHECKSTYLE-SUPPRESSION: MagicNumberCheck - int hours = (int) ((time / 1000 + 8) % 24); - int minutes = (int) (60 * (time % 1000) / 1000); - // END CHECKSTYLE-SUPPRESSION: MagicNumberCheck - - return String.format("%d:%02d", hours, minutes); + return this.getPropertyUnchecked("time"); } /** * {@inheritDoc} */ @Override - public WorldType getWorldType() { - return this.type; - } - - /** - * {@inheritDoc} - */ - @Override - public void allowPortalMaking(AllowedPortalType type) { - this.setKnownProperty("portalform", type.toString(), null); + public boolean setTime(String timeAsString) { + return this.setPropertyUnchecked("time", timeAsString); } /** @@ -1188,80 +1369,42 @@ public class MVWorld implements MultiverseWorld { */ @Override public AllowedPortalType getAllowedPortals() { - return this.getKnownProperty("portalform", AllowedPortalType.class).getValue(); - } - - /** - * Used by the active time-property to set the "actual" property. - * @return True if the property was successfully set. - */ - public boolean setActualTime() { - return this.setTime(this.getKnownProperty("time", String.class).toString()); + return portalForm; } /** * {@inheritDoc} */ @Override - // BEGIN CHECKSTYLE-SUPPRESSION: MagicNumberCheck - public boolean setTime(String timeAsString) { - if (TIME_ALIASES.containsKey(timeAsString.toLowerCase())) { - return this.setTime(TIME_ALIASES.get(timeAsString.toLowerCase())); - } - // Regex that extracts a time in the following formats: - // 11:11pm, 11:11, 23:11, 1111, 1111p, and the aliases at the top of this file. - String timeRegex = "(\\d\\d?):?(\\d\\d)(a|p)?m?"; - Pattern pattern = Pattern.compile(timeRegex, Pattern.CASE_INSENSITIVE); - Matcher matcher = pattern.matcher(timeAsString); - matcher.find(); - int hour = 0; - double minute = 0; - int count = matcher.groupCount(); - if (count >= 2) { - hour = Integer.parseInt(matcher.group(1)); - minute = Integer.parseInt(matcher.group(2)); - } - // If there were 4 matches (all, hour, min, ampm) - if (count == 4) { - // We want 24 hour time for calcs, but if they - // added a p[m], turn it into a 24 hr one. - if (matcher.group(3).equals("p")) { - hour += 12; - } - } - // Translate 24th hour to 0th hour. - if (hour == 24) { // SUPPRESS CHECKSTYLE MagicNumberCheck - hour = 0; - } - // Clamp the hour - if (hour > 23 || hour < 0) { - return false; - } - // Clamp the minute - if (minute > 59 || minute < 0) { - return false; - } - // 60 seconds in a minute, time needs to be in hrs * 1000, per - // the bukkit docs. - double totaltime = (hour + (minute / 60.0)) * 1000; - // Somehow there's an 8 hour offset... - totaltime -= 8000; - if (totaltime < 0) { - totaltime = 24000 + totaltime; - } - - this.getCBWorld().setTime((long) totaltime); - return true; + public void allowPortalMaking(AllowedPortalType portalType) { + this.setPropertyValueUnchecked("portalForm", portalType); + } + + /** + * {@inheritDoc} + */ + @Override + public ChatColor getStyle() { + return style.getColor(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean setStyle(String style) { + return this.setPropertyUnchecked("style", style); } - // END CHECKSTYLE-SUPPRESSION: MagicNumberCheck @Override public String toString() { - StringBuilder toStringBuilder = new StringBuilder(); - toStringBuilder.append(this.getClass().getSimpleName()); - toStringBuilder.append('@'); - toStringBuilder.append(this.hashCode()); - toStringBuilder.append(" (Name: '").append(this.getName()).append("')"); - return toStringBuilder.toString(); + final JSONObject jsonData = new JSONObject(); + jsonData.put("Name", getName()); + jsonData.put("Env", getEnvironment().toString()); + jsonData.put("Type", getWorldType().toString()); + jsonData.put("Gen", getGenerator()); + final JSONObject topLevel = new JSONObject(); + topLevel.put(getClass().getSimpleName() + "@" + hashCode(), jsonData); + return topLevel.toString(); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/MultiverseCore.java b/src/main/java/com/onarandombox/MultiverseCore/MultiverseCore.java index f7881a3e..b7f648fc 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/MultiverseCore.java +++ b/src/main/java/com/onarandombox/MultiverseCore/MultiverseCore.java @@ -7,6 +7,8 @@ package com.onarandombox.MultiverseCore; +import buscript.Buscript; +import com.dumptruckman.minecraft.util.Logging; import com.fernferret.allpay.AllPay; import com.fernferret.allpay.GenericBank; import com.onarandombox.MultiverseCore.api.BlockSafety; @@ -18,7 +20,38 @@ import com.onarandombox.MultiverseCore.api.MultiverseCoreConfig; import com.onarandombox.MultiverseCore.api.MultiverseMessaging; import com.onarandombox.MultiverseCore.api.MultiverseWorld; import com.onarandombox.MultiverseCore.api.SafeTTeleporter; -import com.onarandombox.MultiverseCore.commands.*; +import com.onarandombox.MultiverseCore.commands.AnchorCommand; +import com.onarandombox.MultiverseCore.commands.CheckCommand; +import com.onarandombox.MultiverseCore.commands.CloneCommand; +import com.onarandombox.MultiverseCore.commands.ConfigCommand; +import com.onarandombox.MultiverseCore.commands.ConfirmCommand; +import com.onarandombox.MultiverseCore.commands.CoordCommand; +import com.onarandombox.MultiverseCore.commands.CreateCommand; +import com.onarandombox.MultiverseCore.commands.DebugCommand; +import com.onarandombox.MultiverseCore.commands.DeleteCommand; +import com.onarandombox.MultiverseCore.commands.EnvironmentCommand; +import com.onarandombox.MultiverseCore.commands.GeneratorCommand; +import com.onarandombox.MultiverseCore.commands.HelpCommand; +import com.onarandombox.MultiverseCore.commands.ImportCommand; +import com.onarandombox.MultiverseCore.commands.InfoCommand; +import com.onarandombox.MultiverseCore.commands.ListCommand; +import com.onarandombox.MultiverseCore.commands.LoadCommand; +import com.onarandombox.MultiverseCore.commands.ModifyAddCommand; +import com.onarandombox.MultiverseCore.commands.ModifyClearCommand; +import com.onarandombox.MultiverseCore.commands.ModifyCommand; +import com.onarandombox.MultiverseCore.commands.ModifyRemoveCommand; +import com.onarandombox.MultiverseCore.commands.ModifySetCommand; +import com.onarandombox.MultiverseCore.commands.PurgeCommand; +import com.onarandombox.MultiverseCore.commands.RegenCommand; +import com.onarandombox.MultiverseCore.commands.ReloadCommand; +import com.onarandombox.MultiverseCore.commands.RemoveCommand; +import com.onarandombox.MultiverseCore.commands.ScriptCommand; +import com.onarandombox.MultiverseCore.commands.SetSpawnCommand; +import com.onarandombox.MultiverseCore.commands.SpawnCommand; +import com.onarandombox.MultiverseCore.commands.TeleportCommand; +import com.onarandombox.MultiverseCore.commands.UnloadCommand; +import com.onarandombox.MultiverseCore.commands.VersionCommand; +import com.onarandombox.MultiverseCore.commands.WhoCommand; import com.onarandombox.MultiverseCore.destination.AnchorDestination; import com.onarandombox.MultiverseCore.destination.BedDestination; import com.onarandombox.MultiverseCore.destination.CannonDestination; @@ -27,52 +60,73 @@ import com.onarandombox.MultiverseCore.destination.ExactDestination; import com.onarandombox.MultiverseCore.destination.PlayerDestination; import com.onarandombox.MultiverseCore.destination.WorldDestination; import com.onarandombox.MultiverseCore.event.MVVersionEvent; +import com.onarandombox.MultiverseCore.exceptions.PropertyDoesNotExistException; +import com.onarandombox.MultiverseCore.listeners.MVAsyncPlayerChatListener; +import com.onarandombox.MultiverseCore.listeners.MVChatListener; import com.onarandombox.MultiverseCore.listeners.MVEntityListener; +import com.onarandombox.MultiverseCore.listeners.MVPlayerChatListener; import com.onarandombox.MultiverseCore.listeners.MVPlayerListener; import com.onarandombox.MultiverseCore.listeners.MVPluginListener; -import com.onarandombox.MultiverseCore.listeners.MVWeatherListener; import com.onarandombox.MultiverseCore.listeners.MVPortalListener; import com.onarandombox.MultiverseCore.plugins.DynmapConnector; -import com.onarandombox.MultiverseCore.utils.*; +import com.onarandombox.MultiverseCore.listeners.MVWeatherListener; +import com.onarandombox.MultiverseCore.utils.AnchorManager; +import com.onarandombox.MultiverseCore.utils.MVMessaging; +import com.onarandombox.MultiverseCore.utils.MVPermissions; +import com.onarandombox.MultiverseCore.utils.MVPlayerSession; +import com.onarandombox.MultiverseCore.utils.SimpleBlockSafety; +import com.onarandombox.MultiverseCore.utils.SimpleLocationManipulation; +import com.onarandombox.MultiverseCore.utils.SimpleSafeTTeleporter; +import com.onarandombox.MultiverseCore.utils.WorldManager; import com.pneumaticraft.commandhandler.CommandHandler; - import me.main__.util.SerializationConfig.SerializationConfig; - +import net.milkbowl.vault.economy.Economy; +import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; +import org.bukkit.World.Environment; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.configuration.Configuration; +import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.server.PluginDisableEvent; +import org.bukkit.event.server.PluginEnableEvent; import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.java.JavaPlugin; +import org.mcstats.Metrics; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Random; +import java.util.Set; import java.util.logging.Level; -import java.util.logging.Logger; /** * The implementation of the Multiverse-{@link Core}. */ -public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { - private static final int PROTOCOL = 14; +public class MultiverseCore extends JavaPlugin implements MVPlugin, Core, Listener { + private static final int PROTOCOL = 18; // TODO: Investigate if this one is really needed to be static. // Doubt it. -- FernFerret private static Map teleportQueue = new HashMap(); private AnchorManager anchorManager = new AnchorManager(this); - // TODO please let's make this non-static private MultiverseCoreConfiguration config; private DynmapConnector dynmapConnecter; + private volatile MultiverseCoreConfiguration config; /** * This method is used to find out who is teleporting a player. @@ -95,7 +149,7 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { * @param teleportee The name of the player that was teleported. */ public static void addPlayerToTeleportQueue(String teleporter, String teleportee) { - staticLog(Level.FINEST, "Adding mapping '" + teleporter + "' => '" + teleportee + "' to teleport queue"); + Logging.finest( "Adding mapping '%s' => '%s' to teleport queue", teleporter, teleportee); teleportQueue.put(teleportee, teleporter); } @@ -131,10 +185,6 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { return MultiverseCore.PROTOCOL; } - // Useless stuff to keep us going. - private static final Logger LOGGER = Logger.getLogger("Minecraft"); - private static DebugLog debugLog; - // Setup our Map for our Commands using the CommandHandler. private CommandHandler commandHandler; @@ -146,22 +196,25 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { // Configurations private FileConfiguration multiverseConfig = null; - private MVWorldManager worldManager = new WorldManager(this); + private final MVWorldManager worldManager = new WorldManager(this); // Setup the block/player/entity listener. - private MVPlayerListener playerListener = new MVPlayerListener(this); - private MVEntityListener entityListener = new MVEntityListener(this); - private MVPluginListener pluginListener = new MVPluginListener(this); - private MVWeatherListener weatherListener = new MVWeatherListener(this); - private MVPortalListener portalListener = new MVPortalListener(this); + private final MVPlayerListener playerListener = new MVPlayerListener(this); + private final MVEntityListener entityListener = new MVEntityListener(this); + private final MVPluginListener pluginListener = new MVPluginListener(this); + private final MVWeatherListener weatherListener = new MVWeatherListener(this); + private final MVPortalListener portalListener = new MVPortalListener(this); + private MVChatListener chatListener; // HashMap to contain information relating to the Players. private HashMap playerSessions; + private Economy vaultEco = null; private GenericBank bank = null; private AllPay banker; + private Buscript buscript; private int pluginCount; private DestinationFactory destFactory; - private SpoutInterface spoutInterface = null; + //private SpoutInterface spoutInterface = null; private MultiverseMessaging messaging; private BlockSafety blockSafety; private LocationManipulation locationManipulation; @@ -173,10 +226,13 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { public void onLoad() { // Register our config SerializationConfig.registerAll(MultiverseCoreConfiguration.class); + // Register our world + SerializationConfig.registerAll(MVWorld.class); // Create our DataFolder getDataFolder().mkdirs(); // Setup our Debug Log - debugLog = new DebugLog("Multiverse-Core", getDataFolder() + File.separator + "debug.log"); + Logging.init(this); + SerializationConfig.initLogging(Logging.getLogger()); // Setup our BlockSafety this.blockSafety = new SimpleBlockSafety(this); // Setup our LocationManipulation @@ -199,10 +255,19 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { * {@inheritDoc} */ @Override + @Deprecated public GenericBank getBank() { return this.bank; } + /** + * {@inheritDoc} + */ + @Override + public Economy getVaultEconomy() { + return vaultEco; + } + /** * {@inheritDoc} */ @@ -242,19 +307,33 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { if (this.multiverseConfig != null) { this.worldManager.loadDefaultWorlds(); this.worldManager.loadWorlds(true); + Logging.setDebugLevel(getMVConfig().getGlobalDebug()); } else { this.log(Level.SEVERE, "Your configs were not loaded. Very little will function in Multiverse."); } this.anchorManager.loadAnchors(); // Now set the firstspawnworld (after the worlds are loaded): - this.worldManager.setFirstSpawnWorld(config.getFirstSpawnWorld()); + this.worldManager.setFirstSpawnWorld(getMVConfig().getFirstSpawnWorld()); try { - config.setFirstSpawnWorld(this.worldManager.getFirstSpawnWorld().getName()); + getMVConfig().setFirstSpawnWorld(this.worldManager.getFirstSpawnWorld().getName()); } catch (NullPointerException e) { // A test that had no worlds loaded was being run. This should never happen in production } this.saveMVConfig(); + // Register async or sync player chat according to config + try { + Class.forName("org.bukkit.event.player.AsyncPlayerChatEvent"); + } catch (ClassNotFoundException e) { + getMVConfig().setUseAsyncChat(false); + } + if (getMVConfig().getUseAsyncChat()) { + this.chatListener = new MVAsyncPlayerChatListener(this, this.playerListener); + } else { + this.chatListener = new MVPlayerChatListener(this, this.playerListener); + } + getServer().getPluginManager().registerEvents(this.chatListener, this); + /* // Check to see if spout was already loaded (most likely): if (this.getServer().getPluginManager().getPlugin("Spout") != null) { this.setSpout(); @@ -265,6 +344,146 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { if (this.getServer().getPluginManager().getPlugin("dynmap") != null) { this.getDynmap(); this.log(Level.INFO, "Dynmap integration enabled."); + */ + + this.initializeBuscript(); + this.setupMetrics(); + // Listen out for vault. + getServer().getPluginManager().registerEvents(this, this); + this.setupVaultEconomy(); + } + + private boolean setupVaultEconomy() { + if (Bukkit.getPluginManager().getPlugin("Vault") != null) { + final RegisteredServiceProvider economyProvider + = getServer().getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class); + if (economyProvider != null) { + Logging.fine("Vault economy enabled."); + vaultEco = economyProvider.getProvider(); + } else { + Logging.finer("Vault economy not detected."); + vaultEco = null; + } + } else { + Logging.finer("Vault was not found."); + vaultEco = null; + } + + return (vaultEco != null); + } + + @EventHandler + private void vaultEnabled(PluginEnableEvent event) { + if (event.getPlugin() != null && event.getPlugin().getName().equals("Vault")) { + setupVaultEconomy(); + } + } + + @EventHandler + private void vaultDisabled(PluginDisableEvent event) { + if (event.getPlugin() != null && event.getPlugin().getName().equals("Vault")) { + Logging.fine("Vault economy disabled"); + setupVaultEconomy(); + } + } + + /** + * Initializes the buscript javascript library. + */ + private void initializeBuscript() { + buscript = new Buscript(this); + // Add global variable "multiverse" to javascript environment + buscript.getGlobalScope().put("multiverse", buscript.getGlobalScope(), this); + } + + /** + * Plotter for Environment-Values. + */ + private static final class EnvironmentPlotter extends Metrics.Plotter { + private MultiverseCore core; + private final Environment env; + + public EnvironmentPlotter(MultiverseCore core, Environment env) { + super(envToString(env)); + this.core = core; + this.env = env; + } + + private static String envToString(Environment env) { + return new StringBuilder().append(env.name().toUpperCase().charAt(0)) + .append(env.name().toLowerCase().substring(1)).toString(); + } + + @Override + public int getValue() { + int count = 0; + for (MultiverseWorld w : core.getMVWorldManager().getMVWorlds()) + if (w.getEnvironment() == env) + count++; + core.log(Level.FINE, String.format("Tracking %d worlds of type %s", count, env)); + return count; + } + } + + /** + * Plotter for Generator-Values. + */ + private static final class GeneratorPlotter extends Metrics.Plotter { + private MultiverseCore core; + private final String gen; + + public GeneratorPlotter(MultiverseCore core, String gen) { + super(gen); + this.core = core; + this.gen = gen; + } + + @Override + public int getValue() { + int count = 0; + for (MultiverseWorld w : core.getMVWorldManager().getMVWorlds()) + if (gen.equals(w.getGenerator())) + count++; + core.log(Level.FINE, String.format("Tracking %d worlds of type %s", count, gen)); + return count; + } + } + + private void setupMetrics() { + try { + Metrics m = new Metrics(this); + + Metrics.Graph envGraph = m.createGraph("worlds_by_env"); + for (Environment env : Environment.values()) + envGraph.addPlotter(new EnvironmentPlotter(this, env)); + + m.addCustomData(new Metrics.Plotter("Loaded worlds") { + @Override + public int getValue() { + return getMVWorldManager().getMVWorlds().size(); + } + }); + m.addCustomData(new Metrics.Plotter("Total number of worlds") { + @Override + public int getValue() { + return getMVWorldManager().getMVWorlds().size() + + getMVWorldManager().getUnloadedWorlds().size(); + } + }); + + Set gens = new HashSet(); + for (MultiverseWorld w : this.getMVWorldManager().getMVWorlds()) + gens.add(w.getGenerator()); + gens.remove(null); + gens.remove("null"); + Metrics.Graph genGraph = m.createGraph("custom_gens"); + for (String gen : gens) + genGraph.addPlotter(new GeneratorPlotter(this, gen)); + + m.start(); + log(Level.FINE, "Metrics have run!"); + } catch (IOException e) { + log(Level.WARNING, "There was an issue while enabling metrics: " + e.getMessage()); } } @@ -303,18 +522,18 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { this.multiverseConfig.setDefaults(coreDefaults); this.multiverseConfig.options().copyDefaults(false); this.multiverseConfig.options().copyHeader(true); - this.worldManager.loadWorldConfig(new File(getDataFolder(), "worlds.yml")); MultiverseCoreConfiguration wantedConfig = null; try { wantedConfig = (MultiverseCoreConfiguration) multiverseConfig.get("multiverse-configuration"); - } catch (Exception e) { - // We're just thinking "no risk no fun" and therefore have to catch and forget this exception + } catch (Exception ignore) { } finally { config = ((wantedConfig == null) ? new MultiverseCoreConfiguration() : wantedConfig); } + this.migrateWorldConfig(); + this.worldManager.loadWorldConfig(new File(getDataFolder(), "worlds.yml")); - this.messaging.setCooldown(config.getMessageCooldown()); + this.messaging.setCooldown(getMVConfig().getMessageCooldown()); // Remove old values. this.multiverseConfig.set("enforcegamemodes", null); @@ -333,42 +552,42 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { private void migrate22Values() { if (this.multiverseConfig.isSet("worldnameprefix")) { this.log(Level.INFO, "Migrating 'worldnameprefix'..."); - this.config.setPrefixChat(this.multiverseConfig.getBoolean("worldnameprefix")); + this.getMVConfig().setPrefixChat(this.multiverseConfig.getBoolean("worldnameprefix")); this.multiverseConfig.set("worldnameprefix", null); } if (this.multiverseConfig.isSet("firstspawnworld")) { this.log(Level.INFO, "Migrating 'firstspawnworld'..."); - this.config.setFirstSpawnWorld(this.multiverseConfig.getString("firstspawnworld")); + this.getMVConfig().setFirstSpawnWorld(this.multiverseConfig.getString("firstspawnworld")); this.multiverseConfig.set("firstspawnworld", null); } if (this.multiverseConfig.isSet("enforceaccess")) { this.log(Level.INFO, "Migrating 'enforceaccess'..."); - this.config.setEnforceAccess(this.multiverseConfig.getBoolean("enforceaccess")); + this.getMVConfig().setEnforceAccess(this.multiverseConfig.getBoolean("enforceaccess")); this.multiverseConfig.set("enforceaccess", null); } if (this.multiverseConfig.isSet("displaypermerrors")) { this.log(Level.INFO, "Migrating 'displaypermerrors'..."); - this.config.setDisplayPermErrors(this.multiverseConfig.getBoolean("displaypermerrors")); + this.getMVConfig().setDisplayPermErrors(this.multiverseConfig.getBoolean("displaypermerrors")); this.multiverseConfig.set("displaypermerrors", null); } if (this.multiverseConfig.isSet("teleportintercept")) { this.log(Level.INFO, "Migrating 'teleportintercept'..."); - this.config.setTeleportIntercept(this.multiverseConfig.getBoolean("teleportintercept")); + this.getMVConfig().setTeleportIntercept(this.multiverseConfig.getBoolean("teleportintercept")); this.multiverseConfig.set("teleportintercept", null); } if (this.multiverseConfig.isSet("firstspawnoverride")) { this.log(Level.INFO, "Migrating 'firstspawnoverride'..."); - this.config.setFirstSpawnOverride(this.multiverseConfig.getBoolean("firstspawnoverride")); + this.getMVConfig().setFirstSpawnOverride(this.multiverseConfig.getBoolean("firstspawnoverride")); this.multiverseConfig.set("firstspawnoverride", null); } if (this.multiverseConfig.isSet("messagecooldown")) { this.log(Level.INFO, "Migrating 'messagecooldown'..."); - this.config.setMessageCooldown(this.multiverseConfig.getInt("messagecooldown")); + this.getMVConfig().setMessageCooldown(this.multiverseConfig.getInt("messagecooldown")); this.multiverseConfig.set("messagecooldown", null); } if (this.multiverseConfig.isSet("debug")) { this.log(Level.INFO, "Migrating 'debug'..."); - this.config.setGlobalDebug(this.multiverseConfig.getInt("debug")); + this.getMVConfig().setGlobalDebug(this.multiverseConfig.getInt("debug")); this.multiverseConfig.set("debug", null); } if (this.multiverseConfig.isSet("version")) { @@ -377,6 +596,216 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { } } + /** + * Migrate the worlds.yml to SerializationConfig. + */ + private void migrateWorldConfig() { // SUPPRESS CHECKSTYLE: MethodLength + FileConfiguration wconf = YamlConfiguration + .loadConfiguration(new File(getDataFolder(), "worlds.yml")); + + if (!wconf.isConfigurationSection("worlds")) { // empty config + this.log(Level.FINE, "No worlds to migrate!"); + return; + } + + Map values = wconf.getConfigurationSection("worlds").getValues(false); + + boolean wasChanged = false; + Map newValues = new LinkedHashMap(values.size()); + for (Map.Entry entry : values.entrySet()) { + if (entry.getValue() instanceof MVWorld) { + // fine + newValues.put(entry.getKey(), entry.getValue()); + } else if (entry.getValue() instanceof ConfigurationSection) { + this.log(Level.FINE, "Migrating: " + entry.getKey()); + // we have to migrate this + MVWorld world = new MVWorld(Collections.EMPTY_MAP); + ConfigurationSection section = (ConfigurationSection) entry.getValue(); + + // migrate animals and monsters + if (section.isConfigurationSection("animals")) { + ConfigurationSection animalSection = section.getConfigurationSection("animals"); + if (animalSection.contains("spawn")) { + if (animalSection.isBoolean("spawn")) + world.setAllowAnimalSpawn(animalSection.getBoolean("spawn")); + else + world.setAllowAnimalSpawn(Boolean.parseBoolean(animalSection.getString("spawn"))); + } + if (animalSection.isList("exceptions")) { + world.getAnimalList().clear(); + world.getAnimalList().addAll(animalSection.getStringList("exceptions")); + } + } + if (section.isConfigurationSection("monsters")) { + ConfigurationSection monsterSection = section.getConfigurationSection("monsters"); + if (monsterSection.contains("spawn")) { + if (monsterSection.isBoolean("spawn")) + world.setAllowMonsterSpawn(monsterSection.getBoolean("spawn")); + else + world.setAllowMonsterSpawn(Boolean.parseBoolean(monsterSection.getString("spawn"))); + } + if (monsterSection.isList("exceptions")) { + world.getMonsterList().clear(); + world.getMonsterList().addAll(monsterSection.getStringList("exceptions")); + } + } + + // migrate entryfee + if (section.isConfigurationSection("entryfee")) { + ConfigurationSection feeSection = section.getConfigurationSection("entryfee"); + if (feeSection.isInt("currency")) + world.setCurrency(feeSection.getInt("currency")); + + if (feeSection.isDouble("amount")) + world.setPrice(feeSection.getDouble("amount")); + else if (feeSection.isInt("amount")) + world.setPrice(feeSection.getInt("amount")); + } + + // migrate pvp + if (section.isBoolean("pvp")) { + world.setPVPMode(section.getBoolean("pvp")); + } + + // migrate alias + if (section.isConfigurationSection("alias")) { + ConfigurationSection aliasSection = section.getConfigurationSection("alias"); + if (aliasSection.isString("color")) + world.setColor(aliasSection.getString("color")); + if (aliasSection.isString("name")) + world.setAlias(aliasSection.getString("name")); + } + + // migrate worldblacklist + if (section.isList("worldblacklist")) { + world.getWorldBlacklist().clear(); + world.getWorldBlacklist().addAll(section.getStringList("worldblacklist")); + } + + // migrate scale + if (section.isDouble("scale")) { + world.setScaling(section.getDouble("scale")); + } + + // migrate gamemode + if (section.isString("gamemode")) { + try { + world.setPropertyValue("gamemode", section.getString("gamemode")); + } catch (PropertyDoesNotExistException e) { + throw new RuntimeException("Who forgot to update the migrator?", e); + } + } + + // migrate hunger + if (section.isBoolean("hunger")) { + world.setHunger(section.getBoolean("hunger")); + } + + // migrate hidden + if (section.isBoolean("hidden")) { + world.setHidden(section.getBoolean("hidden")); + } + + // migrate autoheal + if (section.isBoolean("autoheal")) { + world.setAutoHeal(section.getBoolean("autoheal")); + } + + // migrate portalform + if (section.isString("portalform")) { + try { + world.setPropertyValue("portalform", section.getString("portalform")); + } catch (PropertyDoesNotExistException e) { + throw new RuntimeException("Who forgot to update the migrator?", e); + } + } + + // migrate environment + if (section.isString("environment")) { + try { + world.setPropertyValue("environment", section.getString("environment")); + } catch (PropertyDoesNotExistException e) { + throw new RuntimeException("Who forgot to update the migrator?", e); + } + } + + // migrate generator + if (section.isString("generator")) { + world.setGenerator(section.getString("generator")); + } + + // migrate seed + if (section.isLong("seed")) { + world.setSeed(section.getLong("seed")); + } + + // migrate weather + if (section.isBoolean("allowweather")) { + world.setEnableWeather(section.getBoolean("allowweather")); + } + + // migrate adjustspawn + if (section.isBoolean("adjustspawn")) { + world.setAdjustSpawn(section.getBoolean("adjustspawn")); + } + + // migrate autoload + if (section.isBoolean("autoload")) { + world.setAutoLoad(section.getBoolean("autoload")); + } + + // migrate bedrespawn + if (section.isBoolean("bedrespawn")) { + world.setBedRespawn(section.getBoolean("bedrespawn")); + } + + // migrate spawn + if (section.isConfigurationSection("spawn")) { + ConfigurationSection spawnSect = section.getConfigurationSection("spawn"); + Location spawnLoc = world.getSpawnLocation(); + if (spawnSect.isDouble("yaw")) + spawnLoc.setYaw((float) spawnSect.getDouble("yaw")); + if (spawnSect.isDouble("pitch")) + spawnLoc.setPitch((float) spawnSect.getDouble("pitch")); + if (spawnSect.isDouble("x")) + spawnLoc.setX(spawnSect.getDouble("x")); + if (spawnSect.isDouble("y")) + spawnLoc.setY(spawnSect.getDouble("y")); + if (spawnSect.isDouble("z")) + spawnLoc.setZ(spawnSect.getDouble("z")); + + world.setSpawnLocation(spawnLoc); + } + + newValues.put(entry.getKey(), world); + wasChanged = true; + } else { + // huh? + this.log(Level.WARNING, "Removing unknown entry in the config: " + entry); + // just don't add to newValues + wasChanged = true; + } + } + + if (wasChanged) { + // clear config + wconf.set("worlds", null); + + // and rebuild it + ConfigurationSection rootSection = wconf.createSection("worlds"); + for (Map.Entry entry : newValues.entrySet()) { + rootSection.set(entry.getKey(), entry.getValue()); + } + + try { + wconf.save(new File(getDataFolder(), "worlds.yml")); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + /** * {@inheritDoc} */ @@ -395,6 +824,7 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { this.commandHandler.registerCommand(new ListCommand(this)); this.commandHandler.registerCommand(new InfoCommand(this)); this.commandHandler.registerCommand(new CreateCommand(this)); + this.commandHandler.registerCommand(new CloneCommand(this)); this.commandHandler.registerCommand(new ImportCommand(this)); this.commandHandler.registerCommand(new ReloadCommand(this)); this.commandHandler.registerCommand(new SetSpawnCommand(this)); @@ -423,6 +853,7 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { this.commandHandler.registerCommand(new DebugCommand(this)); this.commandHandler.registerCommand(new GeneratorCommand(this)); this.commandHandler.registerCommand(new CheckCommand(this)); + this.commandHandler.registerCommand(new ScriptCommand(this)); } /** @@ -430,10 +861,11 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { */ @Override public void onDisable() { - debugLog.close(); + this.saveMVConfigs(); this.banker = null; this.bank = null; log(Level.INFO, "- Disabled"); + Logging.shutdown(); } /** @@ -444,7 +876,7 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { if (this.playerSessions.containsKey(player.getName())) { return this.playerSessions.get(player.getName()); } else { - this.playerSessions.put(player.getName(), new MVPlayerSession(player, config)); + this.playerSessions.put(player.getName(), new MVPlayerSession(player, getMVConfig())); return this.playerSessions.get(player.getName()); } } @@ -479,7 +911,17 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { } ArrayList allArgs = new ArrayList(Arrays.asList(args)); allArgs.add(0, command.getName()); - return this.commandHandler.locateAndRunCommand(sender, allArgs, config.getDisplayPermErrors()); + try { + return this.commandHandler.locateAndRunCommand(sender, allArgs, getMVConfig().getDisplayPermErrors()); + } catch (Exception e) { + e.printStackTrace(); + sender.sendMessage(ChatColor.RED + "An internal error occurred when attempting to perform this command."); + if (sender.isOp()) + sender.sendMessage(ChatColor.RED + "Details were printed to the server console and logs, please add that to your bug report."); + else + sender.sendMessage(ChatColor.RED + "Try again and contact the server owner or an admin if this problem persists."); + return true; + } } /** @@ -487,7 +929,7 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { */ @Override public void log(Level level, String msg) { - staticLog(level, msg); + Logging.log(level, msg); } /** @@ -495,33 +937,28 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { * * @param level The Log-{@link Level}. * @param msg The message to log. + * + * @deprecated Replaced by {@link Logging}. Please refrain from using this from a third party plugin as the + * messages will appear to originate from Multiverse-Core. */ + @Deprecated public static void staticLog(Level level, String msg) { - if (level == Level.FINE && MultiverseCoreConfiguration.getInstance().getGlobalDebug() >= 1) { - staticDebugLog(Level.INFO, msg); - return; - } else if (level == Level.FINER && MultiverseCoreConfiguration.getInstance().getGlobalDebug() >= 2) { - staticDebugLog(Level.INFO, msg); - return; - } else if (level == Level.FINEST && MultiverseCoreConfiguration.getInstance().getGlobalDebug() >= 3) { - staticDebugLog(Level.INFO, msg); - return; - } else if (level != Level.FINE && level != Level.FINER && level != Level.FINEST) { - LOGGER.log(level, String.format("%s %s", LOG_TAG, msg)); - debugLog.log(level, String.format("%s %s", LOG_TAG, msg)); - } + Logging.log(level, msg); } /** - * Print messages to the Debug Log, if the servers in Debug Mode then we also wan't to print the messages to the + * Print messages to the Debug Log, if the servers in Debug Mode then we also want to print the messages to the * standard Server Console. * * @param level The Log-{@link Level} * @param msg The message + * + * @deprecated Replaced by {@link Logging}. Please refrain from using this from a third party plugin as the + * messages will appear to originate from Multiverse-Core. */ + @Deprecated public static void staticDebugLog(Level level, String msg) { - LOGGER.log(level, "[MVCore-Debug] " + msg); - debugLog.log(level, "[MVCore-Debug] " + msg); + Logging.log(level, msg); } /** @@ -617,6 +1054,7 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { * {@inheritDoc} */ @Override + @Deprecated public AllPay getBanker() { return this.banker; } @@ -625,6 +1063,7 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { * {@inheritDoc} */ @Override + @Deprecated public void setBank(GenericBank bank) { this.bank = bank; } @@ -670,9 +1109,10 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { this.serverFolder = newServerFolder; } + /* /** * Initializes Spout. - */ + * / public void setSpout() { this.spoutInterface = new SpoutInterface(); this.commandHandler.registerCommand(new SpoutCommand(this)); @@ -682,10 +1122,11 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { * Gets our {@link SpoutInterface}. * * @return The {@link SpoutInterface} we're using. - */ + * / public SpoutInterface getSpout() { return this.spoutInterface; } + */ /** * {@inheritDoc} @@ -704,6 +1145,15 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { return this.playerListener; } + /** + * Gets the {@link MVChatListener}. + * + * @return The {@link MVChatListener}. + */ + public MVChatListener getChatListener() { + return this.chatListener; + } + /** * Gets the {@link MVEntityListener}. * @@ -729,7 +1179,7 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { */ public boolean saveMVConfig() { try { - this.multiverseConfig.set("multiverse-configuration", config); + this.multiverseConfig.set("multiverse-configuration", getMVConfig()); this.multiverseConfig.save(new File(getDataFolder(), "config.yml")); return true; } catch (IOException e) { @@ -766,38 +1216,27 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { return this.worldManager.deleteWorld(name); } + /** + * NOT deprecated for the time as queued commands use this. + * However, this is not in the API and other plugins should therefore not use it. + * + * @param oldName World to copy + * @param newName World to create + * @param generator The Custom generator plugin to use. + * @return True if success, false if fail. + */ + public Boolean cloneWorld(String oldName, String newName, String generator) { + return this.worldManager.cloneWorld(oldName, newName, generator); + } + /** * {@inheritDoc} + * @deprecated This is deprecated! */ @Override + @Deprecated public Boolean regenWorld(String name, Boolean useNewSeed, Boolean randomSeed, String seed) { - MultiverseWorld world = this.worldManager.getMVWorld(name); - if (world == null) { - return false; - } - - List ps = world.getCBWorld().getPlayers(); - - if (useNewSeed) { - // Set the worldseed. - if (randomSeed) { - Random random = new Random(); - Long newseed = random.nextLong(); - seed = newseed.toString(); - } - ((WorldManager) this.worldManager).getConfigWorlds().set("worlds." + name + ".seed", seed); - } - if (this.worldManager.deleteWorld(name, false)) { - this.worldManager.loadWorlds(false); - SafeTTeleporter teleporter = this.getSafeTTeleporter(); - Location newSpawn = this.getServer().getWorld(name).getSpawnLocation(); - // Send all players that were in the old world, BACK to it! - for (Player p : ps) { - teleporter.safelyTeleport(null, p, newSpawn, true); - } - return true; - } - return false; + return this.worldManager.regenWorld(name, useNewSeed, randomSeed, seed); } /** @@ -889,5 +1328,9 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core { public void setDynmap() { this.dynmapConnecter = new DynmapConnector(this.getServer().getPluginManager().getPlugin("dynmap"), this); + + @Override + public Buscript getScriptAPI() { + return buscript; } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/MultiverseCoreConfiguration.java b/src/main/java/com/onarandombox/MultiverseCore/MultiverseCoreConfiguration.java index 25e95cfc..29f8a471 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/MultiverseCoreConfiguration.java +++ b/src/main/java/com/onarandombox/MultiverseCore/MultiverseCoreConfiguration.java @@ -1,12 +1,13 @@ package com.onarandombox.MultiverseCore; -import java.util.Map; - +import com.dumptruckman.minecraft.util.Logging; import com.onarandombox.MultiverseCore.api.MultiverseCoreConfig; - +import me.main__.util.SerializationConfig.NoSuchPropertyException; import me.main__.util.SerializationConfig.Property; import me.main__.util.SerializationConfig.SerializationConfig; +import java.util.Map; + /** * Our configuration. */ @@ -21,6 +22,13 @@ public class MultiverseCoreConfiguration extends SerializationConfig implements MultiverseCoreConfiguration.instance = instance; } + /** + * @return True if the static instance of config is set. + */ + public static boolean isSet() { + return instance != null; + } + /** * Gets the statically saved instance. * @return The statically saved instance. @@ -32,25 +40,27 @@ public class MultiverseCoreConfiguration extends SerializationConfig implements } @Property - private boolean enforceaccess; + private volatile boolean enforceaccess; @Property - private boolean prefixchat; + private volatile boolean prefixchat; @Property - private boolean teleportintercept; + private volatile boolean useasyncchat; @Property - private boolean firstspawnoverride; + private volatile boolean teleportintercept; @Property - private boolean displaypermerrors; + private volatile boolean firstspawnoverride; @Property - private int globaldebug; + private volatile boolean displaypermerrors; @Property - private int messagecooldown; + private volatile int globaldebug; @Property - private double version; + private volatile int messagecooldown; @Property - private String firstspawnworld; + private volatile double version; @Property - private int teleportcooldown; + private volatile String firstspawnworld; + @Property + private volatile int teleportcooldown; public MultiverseCoreConfiguration() { super(); @@ -66,9 +76,10 @@ public class MultiverseCoreConfiguration extends SerializationConfig implements * {@inheritDoc} */ @Override - public void setDefaults() { + protected void setDefaults() { // BEGIN CHECKSTYLE-SUPPRESSION: MagicNumberCheck enforceaccess = false; + useasyncchat = true; prefixchat = true; teleportintercept = true; firstspawnoverride = true; @@ -80,6 +91,18 @@ public class MultiverseCoreConfiguration extends SerializationConfig implements // END CHECKSTYLE-SUPPRESSION: MagicNumberCheck } + /** + * {@inheritDoc} + */ + @Override + public boolean setConfigProperty(String property, String value) { + try { + return this.setProperty(property, value, true); + } catch (NoSuchPropertyException e) { + return false; + } + } + // And here we go: /** @@ -176,6 +199,7 @@ public class MultiverseCoreConfiguration extends SerializationConfig implements @Override public void setGlobalDebug(int globalDebug) { this.globaldebug = globalDebug; + Logging.setDebugLevel(globalDebug); } /** @@ -241,4 +265,14 @@ public class MultiverseCoreConfiguration extends SerializationConfig implements public void setTeleportCooldown(int teleportCooldown) { this.teleportcooldown = teleportCooldown; } + + @Override + public void setUseAsyncChat(boolean useAsyncChat) { + this.useasyncchat = useAsyncChat; + } + + @Override + public boolean getUseAsyncChat() { + return this.useasyncchat; + } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/api/BlockSafety.java b/src/main/java/com/onarandombox/MultiverseCore/api/BlockSafety.java index db25a17e..5dc4f7eb 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/api/BlockSafety.java +++ b/src/main/java/com/onarandombox/MultiverseCore/api/BlockSafety.java @@ -35,6 +35,13 @@ public interface BlockSafety { */ boolean playerCanSpawnHereSafely(Location l); + /** + * Gets a safe bed spawn location OR null if the bed is invalid. + * @param l The location of the bead head (block with the pillow on it). + * @return Safe location around the bed or null if no location was found. + */ + Location getSafeBedSpawn(Location l); + /** * Gets the location of the top block at the specified {@link Location}. * @param l Any {@link Location}. diff --git a/src/main/java/com/onarandombox/MultiverseCore/api/Core.java b/src/main/java/com/onarandombox/MultiverseCore/api/Core.java index 01c684d0..f8c59283 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/api/Core.java +++ b/src/main/java/com/onarandombox/MultiverseCore/api/Core.java @@ -7,11 +7,19 @@ package com.onarandombox.MultiverseCore.api; +import buscript.Buscript; import com.fernferret.allpay.AllPay; import com.fernferret.allpay.GenericBank; import com.onarandombox.MultiverseCore.destination.DestinationFactory; -import com.onarandombox.MultiverseCore.utils.*; +import com.onarandombox.MultiverseCore.utils.AnchorManager; +import com.onarandombox.MultiverseCore.utils.MVPermissions; +import com.onarandombox.MultiverseCore.utils.MVPlayerSession; +import com.onarandombox.MultiverseCore.utils.SimpleBlockSafety; +import com.onarandombox.MultiverseCore.utils.SimpleLocationManipulation; +import com.onarandombox.MultiverseCore.utils.SimpleSafeTTeleporter; +import com.onarandombox.MultiverseCore.utils.WorldManager; import com.pneumaticraft.commandhandler.CommandHandler; +import net.milkbowl.vault.economy.Economy; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; @@ -35,9 +43,18 @@ public interface Core { * Gets the Banking system that Multiverse-Core has hooked into. * * @return A {@link GenericBank} that can be used for payments. + * @deprecated Now using vault, see {@link #getVaultEconomy} */ + @Deprecated GenericBank getBank(); + /** + * Returns the Vault economy system if Vault is present and has an economy system enabled. + * + * @return The vault economy system or null if not configured. + */ + Economy getVaultEconomy(); + /** * Reloads the Multiverse Configuration files: * worlds.yml and config.yml. @@ -128,21 +145,28 @@ public interface Core { * @param seed The seed of the world. * * @return True if success, false if fail. + * + * @deprecated Use {@link MVWorldManager#regenWorld(String, boolean, boolean, String)} instead. */ + @Deprecated Boolean regenWorld(String name, Boolean useNewSeed, Boolean randomSeed, String seed); /** * Sets the {@link GenericBank}-Bank AllPay is using. * * @param bank The new {@link GenericBank} + * @deprecated Now using vault, see {@link #getVaultEconomy} */ + @Deprecated void setBank(GenericBank bank); /** * Gets this plugin's {@link AllPay}-Banker. * * @return An {@link AllPay}-Banker + * @deprecated Now using vault, see {@link #getVaultEconomy} */ + @Deprecated AllPay getBanker(); /** @@ -222,4 +246,11 @@ public interface Core { * @return The configuration. */ MultiverseCoreConfig getMVConfig(); + + /** + * Gets the buscript object for Multiverse. This is what handles Javascript processing. + * + * @return The Multiverse buscript object. + */ + Buscript getScriptAPI(); } diff --git a/src/main/java/com/onarandombox/MultiverseCore/api/MVWorldManager.java b/src/main/java/com/onarandombox/MultiverseCore/api/MVWorldManager.java index f13da921..597ee32b 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/api/MVWorldManager.java +++ b/src/main/java/com/onarandombox/MultiverseCore/api/MVWorldManager.java @@ -60,6 +60,16 @@ public interface MVWorldManager { boolean addWorld(String name, Environment env, String seedString, WorldType type, Boolean generateStructures, String generator, boolean useSpawnAdjust); + /** + * Make a copy of a world. + * + * @param oldName Name of world to be copied + * @param newName Name of world to be created + * @param generator The Custom generator plugin to use. + * @return True if the world is copied successfully, false if not. + */ + boolean cloneWorld(String oldName, String newName, String generator); + /** * Remove the world from the Multiverse list, from the * config and deletes the folder. @@ -245,4 +255,16 @@ public interface MVWorldManager { * @return The {@link MultiverseWorld} new players should spawn in. */ MultiverseWorld getFirstSpawnWorld(); + + /** + * Regenerates a world. + * + * @param name Name of the world to regenerate + * @param useNewSeed If a new seed should be used + * @param randomSeed IF the new seed should be random + * @param seed The seed of the world. + * + * @return True if success, false if fail. + */ + boolean regenWorld(String name, boolean useNewSeed, boolean randomSeed, String seed); } diff --git a/src/main/java/com/onarandombox/MultiverseCore/api/MultiverseCoreConfig.java b/src/main/java/com/onarandombox/MultiverseCore/api/MultiverseCoreConfig.java index 25f6fad4..abd9ace0 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/api/MultiverseCoreConfig.java +++ b/src/main/java/com/onarandombox/MultiverseCore/api/MultiverseCoreConfig.java @@ -12,7 +12,7 @@ public interface MultiverseCoreConfig extends ConfigurationSerializable { * @param value The value. * @return True on success, false if the operation failed. */ - boolean setProperty(String property, String value); + boolean setConfigProperty(String property, String value); /** * Sets portalCooldown. @@ -133,4 +133,16 @@ public interface MultiverseCoreConfig extends ConfigurationSerializable { * @return enforceAccess. */ boolean getEnforceAccess(); + + /** + * Sets useasyncchat. + * @param useAsyncChat The new value. + */ + void setUseAsyncChat(boolean useAsyncChat); + + /** + * Gets useasyncchat. + * @return useasyncchat. + */ + boolean getUseAsyncChat(); } diff --git a/src/main/java/com/onarandombox/MultiverseCore/api/MultiversePlugin.java b/src/main/java/com/onarandombox/MultiverseCore/api/MultiversePlugin.java new file mode 100644 index 00000000..a6a064b8 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/api/MultiversePlugin.java @@ -0,0 +1,161 @@ +package com.onarandombox.MultiverseCore.api; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.java.JavaPlugin; + +import com.onarandombox.MultiverseCore.MultiverseCore; +import com.onarandombox.MultiverseCore.utils.DebugLog; +import com.pneumaticraft.commandhandler.CommandHandler; + +/** + * Make things easier for MV-Plugins! + */ +public abstract class MultiversePlugin extends JavaPlugin implements MVPlugin { + private MultiverseCore core; + /** + * Prefix for standard log entrys. + */ + protected String logTag; + private DebugLog debugLog; + + /** + * {@inheritDoc} + * + * Note: You can't override this, use {@link #onPluginEnable()} instead! + * @see #onPluginEnable() + */ + @Override + public final void onEnable() { + MultiverseCore theCore = (MultiverseCore) this.getServer().getPluginManager().getPlugin("Multiverse-Core"); + if (theCore == null) { + this.getLogger().severe("Core not found! The plugin dev needs to add a dependency!"); + this.getLogger().severe("Disabling!"); + this.getServer().getPluginManager().disablePlugin(this); + return; + } + if (theCore.getProtocolVersion() < this.getProtocolVersion()) { + this.getLogger().severe("You need a newer version of Multiverse-Core!"); + this.getLogger().severe("Disabling!"); + this.getServer().getPluginManager().disablePlugin(this); + return; + } + this.setCore(theCore); + + this.getServer().getLogger().info(String.format("%s - Version %s enabled - By %s", + this.getDescription().getName(), this.getDescription().getVersion(), getAuthors())); + getDataFolder().mkdirs(); + File debugLogFile = new File(getDataFolder(), "debug.log"); + try { + debugLogFile.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + debugLog = new DebugLog(this.getDescription().getName(), getDataFolder() + File.separator + "debug.log"); + debugLog.setTag(String.format("[%s-Debug]", this.getDescription().getName())); + + this.onPluginEnable(); + } + + /** + * Parse the Authors Array into a readable String with ',' and 'and'. + * + * @return The readable authors-{@link String} + */ + protected String getAuthors() { + String authors = ""; + List auths = this.getDescription().getAuthors(); + if (auths.size() == 0) { + return ""; + } + + if (auths.size() == 1) { + return auths.get(0); + } + + for (int i = 0; i < auths.size(); i++) { + if (i == this.getDescription().getAuthors().size() - 1) { + authors += " and " + this.getDescription().getAuthors().get(i); + } else { + authors += ", " + this.getDescription().getAuthors().get(i); + } + } + return authors.substring(2); + } + + /** + * Called when the plugin is enabled. + * @see #onEnable() + */ + protected abstract void onPluginEnable(); + + /** + * You can register commands here. + * @param handler The CommandHandler. + */ + protected abstract void registerCommands(CommandHandler handler); + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!this.isEnabled()) { + sender.sendMessage("This plugin is Disabled!"); + return true; + } + + ArrayList allArgs = new ArrayList(args.length + 1); + allArgs.add(command.getName()); + allArgs.addAll(Arrays.asList(args)); + return this.getCore().getCommandHandler().locateAndRunCommand(sender, allArgs); + } + + @Override + public void log(Level level, String msg) { + int debugLevel = this.getCore().getMVConfig().getGlobalDebug(); + if ((level == Level.FINE && debugLevel >= 1) || (level == Level.FINER && debugLevel >= 2) + || (level == Level.FINEST && debugLevel >= 3)) { + debugLog.log(level, msg); + } else if (level != Level.FINE && level != Level.FINER && level != Level.FINEST) { + String message = new StringBuilder(getLogTag()).append(msg).toString(); + this.getServer().getLogger().log(level, message); + debugLog.log(level, message); + } + } + + private String getLogTag() { + if (logTag == null) + logTag = String.format("[%s]", this.getDescription().getName()); + return logTag; + } + + /** + * Sets the debug log-tag. + * @param tag The new tag. + */ + protected final void setDebugLogTag(String tag) { + this.debugLog.setTag(tag); + } + + @Override + public final String dumpVersionInfo(String buffer) { + throw new UnsupportedOperationException("This is gone."); + } + + @Override + public final MultiverseCore getCore() { + if (this.core == null) + throw new IllegalStateException("Core is null!"); + return this.core; + } + + @Override + public final void setCore(MultiverseCore core) { + this.core = core; + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/api/MultiverseWorld.java b/src/main/java/com/onarandombox/MultiverseCore/api/MultiverseWorld.java index 46961803..2266594c 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/api/MultiverseWorld.java +++ b/src/main/java/com/onarandombox/MultiverseCore/api/MultiverseWorld.java @@ -7,7 +7,6 @@ package com.onarandombox.MultiverseCore.api; -import com.onarandombox.MultiverseCore.configuration.MVConfigProperty; import com.onarandombox.MultiverseCore.enums.AllowedPortalType; import com.onarandombox.MultiverseCore.exceptions.PropertyDoesNotExistException; @@ -26,7 +25,6 @@ import java.util.List; * The API for a Multiverse Handled World. */ public interface MultiverseWorld { - /** * Returns the Bukkit world object that this world describes. * @@ -35,79 +33,24 @@ public interface MultiverseWorld { World getCBWorld(); /** - * Adds the property to the given value. - * It will throw a PropertyDoesNotExistException if the property is not found. + * Gets the name of this world. The name cannot be changed. + *

+ * Note for plugin developers: Usually {@link #getAlias()} + * is what you want to use instead of this method. * - * @param property The name of a world property to set. - * @param value A value in string representation, it will be parsed to the correct type. - * @param sender The sender who wants this value to be set. - * @return True if the value was set, false if not. - * @throws PropertyDoesNotExistException Thrown if the property was not found in the world. + * @return The name of the world as a String. */ - boolean setProperty(String property, String value, CommandSender sender) throws PropertyDoesNotExistException; + String getName(); /** - * Gets the actual MVConfigProperty from this world. - * It will throw a PropertyDoesNotExistException if the property is not found. + * Gets the type of this world. As of 1.2 this will be: + * FLAT, NORMAL or VERSION_1_1 + *

+ * This is not the generator. * - * @param property The name of a world property to get. - * @return A valid MVWorldProperty. - * @throws PropertyDoesNotExistException Thrown if the property was not found in the world. - * @deprecated Use {@link #getProperty(String, Class)} instead + * @return The Type of this world. */ - @Deprecated - MVConfigProperty getProperty(String property) throws PropertyDoesNotExistException; - - /** - * Gets the string representation of a property. - * It will throw a PropertyDoesNotExistException if the property is not found. - * - * @param property The name of a world property to get. - * @return A valid MVWorldProperty. - * @throws PropertyDoesNotExistException Thrown if the property was not found in the world. - */ - String getPropertyValue(String property) throws PropertyDoesNotExistException; - - /** - * Gets the actual MVConfigProperty from this world. - * It will throw a PropertyDoesNotExistException if the property is not found. - * - * @param property The name of a world property to get. - * @param expected The type of the expected property. Use Object.class if this doesn't matter for you. - * @param The type of the expected property. - * - * @return A valid MVWorldProperty. - * - * @throws PropertyDoesNotExistException Thrown if the property was not found in the world. - */ - MVConfigProperty getProperty(String property, Class expected) throws PropertyDoesNotExistException; - - /** - * Removes all values from the given property. The property must be a {@link com.onarandombox.MultiverseCore.enums.AddProperties}. - * - * @param property The name of a {@link com.onarandombox.MultiverseCore.enums.AddProperties} to clear. - * @return True if it was cleared, false if not. - */ - boolean clearVariable(String property); - - /** - * Adds a value to the given property. The property must be a {@link com.onarandombox.MultiverseCore.enums.AddProperties}. - * - * @param property The name of a {@link com.onarandombox.MultiverseCore.enums.AddProperties} to add a value to. - * @param value A value in string representation, it will be parsed to the correct type. - * @return True if the value was added, false if not. - */ - boolean addToVariable(String property, String value); - - /** - * Removes a value from the given property. The property must be a {@link com.onarandombox.MultiverseCore.enums.AddProperties}. - * - * @param property The name of a {@link com.onarandombox.MultiverseCore.enums.AddProperties} to remove a value - * from. - * @param value A value in string representation, it will be parsed to the correct type. - * @return True if the value was removed, false if not. - */ - boolean removeFromVariable(String property, String value); + WorldType getWorldType(); /** * Gets the environment of this world. @@ -125,27 +68,168 @@ public interface MultiverseWorld { */ void setEnvironment(World.Environment environment); + /** + * Gets the difficulty of this world. + * + * @return The difficulty of this world. + */ + Difficulty getDifficulty(); + + /** + * Sets the difficulty of this world and returns true if success. + * Valid string values are either an integer of difficulty(0-3) or + * the name that resides in the Bukkit enum, ex. {@code PEACEFUL} + * + * @param difficulty The difficulty to set the world to as a string. + * @return True if success, false if the provided string + * could not be translated to a difficulty. + * @deprecated Use {@link #setDifficulty(Difficulty)} or, if you have to + * pass a string, use {@link #setPropertyValue(String, String)} instead. + */ + @Deprecated + boolean setDifficulty(String difficulty); + + /** + * Sets the difficulty of this world and returns {@code true} on success. + * Valid string values are either an integer of difficulty(0-3) or + * the name that resides in the Bukkit enum, ex. PEACEFUL + * + * @param difficulty The new difficulty. + * @return True if success, false if the operation failed... for whatever reason. + */ + boolean setDifficulty(Difficulty difficulty); + /** * Gets the world seed of this world. * * @return The Long version of the seed. */ - Long getSeed(); + long getSeed(); /** * Sets the seed of this world. * * @param seed A Long that is the seed. */ - void setSeed(Long seed); + void setSeed(long seed); /** - * Gets the name of this world. This cannot be changed. + * Gets the generator of this world. * - * @return The name of the world as a String. + * @return The name of the generator. */ - String getName(); + String getGenerator(); + /** + * Sets the generator of this world. + * + * @param generator The new generator's name. + */ + void setGenerator(String generator); + + /** + * Gets the help-message for a property. + * @param property The name of the property. + * @return The help-message. + * @throws PropertyDoesNotExistException Thrown if the property was not found. + */ + String getPropertyHelp(String property) throws PropertyDoesNotExistException; + + /** + * Gets a property as {@link String}. + * + * @param property The name of a world property to get. + * @return The string-representation of that property. + * @throws PropertyDoesNotExistException Thrown if the property was not found in the world. + */ + String getPropertyValue(String property) throws PropertyDoesNotExistException; + + /** + * Sets a property to a given value. + * + * @param property The name of a world property to set. + * @param value A value in string representation, it will be parsed to the correct type. + * @return True if the value was set, false if not. + * @throws PropertyDoesNotExistException Thrown if the property was not found in the world. + */ + boolean setPropertyValue(String property, String value) throws PropertyDoesNotExistException; + + /** + * Gets the actual MVConfigProperty from this world. + * It will throw a PropertyDoesNotExistException if the property is not found. + * + * @param property The name of a world property to get. + * @param expected The type of the expected property. Use Object.class if this doesn't matter for you. + * @param The type of the expected property. + * + * @return A valid MVWorldProperty. + * + * @throws PropertyDoesNotExistException Thrown if the property was not found in the world. + * @deprecated We don't use {@link com.onarandombox.MultiverseCore.configuration.MVConfigProperty} any longer! + */ + @Deprecated + com.onarandombox.MultiverseCore.configuration.MVConfigProperty getProperty(String property, Class expected) throws PropertyDoesNotExistException; + + // old config + /** + * Adds the property to the given value. + * It will throw a PropertyDoesNotExistException if the property is not found. + * + * @param property The name of a world property to set. + * @param value A value in string representation, it will be parsed to the correct type. + * @param sender The sender who wants this value to be set. + * @return True if the value was set, false if not. + * @throws PropertyDoesNotExistException Thrown if the property was not found in the world. + * @deprecated Use {@link #setPropertyValue(String, String)} instead. + */ + @Deprecated + boolean setProperty(String property, String value, CommandSender sender) throws PropertyDoesNotExistException; + + /** + * Adds a value to the given property. The property must be a {@link com.onarandombox.MultiverseCore.enums.AddProperties}. + * + * @param property The name of a {@link com.onarandombox.MultiverseCore.enums.AddProperties} to add a value to. + * @param value A value in string representation, it will be parsed to the correct type. + * @return True if the value was added, false if not. + * @deprecated We changed the entire world-config-system. This is not compatible any more. + */ + @Deprecated + boolean addToVariable(String property, String value); + + /** + * Removes a value from the given property. The property must be a {@link com.onarandombox.MultiverseCore.enums.AddProperties}. + * + * @param property The name of a {@link com.onarandombox.MultiverseCore.enums.AddProperties} to remove a value + * from. + * @param value A value in string representation, it will be parsed to the correct type. + * @return True if the value was removed, false if not. + * @deprecated We changed the entire world-config-system. This is not compatible any more. + */ + @Deprecated + boolean removeFromVariable(String property, String value); + + /** + * Removes all values from the given property. The property must be a {@link com.onarandombox.MultiverseCore.enums.AddProperties}. + * + * @param property The name of a {@link com.onarandombox.MultiverseCore.enums.AddProperties} to clear. + * @return True if it was cleared, false if not. + * @deprecated We changed the entire world-config-system. This is not compatible any more. + */ + @Deprecated + boolean clearVariable(String property); + + /** + * Clears a list property (sets it to []). + * + * @param property The property to clear. + * @return True if success, false if fail. + * @deprecated We changed the entire world-config-system. This is not compatible any more. + */ + @Deprecated + boolean clearList(String property); + // end of old config stuff + + // permission stuff /** * Gets the lowercased name of the world. This method is required, since the permissables * lowercase all permissions when recalculating. @@ -158,6 +242,21 @@ public interface MultiverseWorld { */ String getPermissibleName(); + /** + * Gets the permission required to enter this world. + * + * @return The permission required to be exempt from charges to/from this world. + */ + Permission getAccessPermission(); + + /** + * Gets the permission required to be exempt when entering. + * + * @return The permission required to be exempt when entering. + */ + Permission getExemptPermission(); + // end of permission stuff + /** * Gets the alias of this world. *

@@ -174,6 +273,13 @@ public interface MultiverseWorld { */ void setAlias(String alias); + /** + * Gets the color that this world's name/alias will display as. + * + * @return The color of this world. + */ + ChatColor getColor(); + /** * Sets the color that this world's name/alias will display as. * @@ -183,18 +289,29 @@ public interface MultiverseWorld { boolean setColor(String color); /** - * Gets the color that this world's name/alias will display as. + * Gets the style that this world's name/alias will display as. * - * @return The color of this world. + * @return The style of this world. {@code null} for "normal" style. */ - ChatColor getColor(); + ChatColor getStyle(); + + /** + * Sets the style that this world's name/alias will display as. + * + * @param style A valid style name. + * @return True if the style was set, false if not. + */ + boolean setStyle(String style); /** * Tells you if someone entered a valid color. * * @param color A string that may translate to a color. * @return True if it is a color, false if not. + * + * @deprecated This has been moved: {@link com.onarandombox.MultiverseCore.enums.EnglishChatColor#isValidAliasColor(String)} */ + @Deprecated boolean isValidAliasColor(String color); /** @@ -204,6 +321,7 @@ public interface MultiverseWorld { */ String getColoredWorldString(); + // animals&monster stuff /** * Gets whether or not animals are allowed to spawn in this world. * @@ -211,6 +329,22 @@ public interface MultiverseWorld { */ boolean canAnimalsSpawn(); + /** + * Sets whether or not animals can spawn. + * If there are values in {@link #getAnimalList()} and this is false, + * those animals become the exceptions, and will spawn + * + * @param allowAnimalSpawn True to allow spawning of monsters, false to prevent. + */ + void setAllowAnimalSpawn(boolean allowAnimalSpawn); + + /** + * Returns a list of animals. This list always negates the {@link #canAnimalsSpawn()} result. + * + * @return A list of animals that will spawn if {@link #canAnimalsSpawn()} is false. + */ + List getAnimalList(); + /** * Gets whether or not monsters are allowed to spawn in this world. * @@ -219,7 +353,31 @@ public interface MultiverseWorld { boolean canMonstersSpawn(); /** - * Turn pvp on or off. This setting is used to set the world's PVP mode, and thus relies on fakePVP + * Sets whether or not monsters can spawn. + * If there are values in {@link #getMonsterList()} and this is false, + * those monsters become the exceptions, and will spawn + * + * @param allowMonsterSpawn True to allow spawning of monsters, false to prevent. + */ + void setAllowMonsterSpawn(boolean allowMonsterSpawn); + + /** + * Returns a list of monsters. This list always negates the {@link #canMonstersSpawn()} result. + * + * @return A list of monsters that will spawn if {@link #canMonstersSpawn()} is false. + */ + List getMonsterList(); + // end of animal&monster stuff + + /** + * Gets whether or not PVP is enabled in this world in some form (fake or not). + * + * @return True if players can take damage from other players. + */ + boolean isPVPEnabled(); + + /** + * Turn pvp on or off. This setting is used to set the world's PVP mode. * * @param pvpMode True to enable PVP damage, false to disable it. */ @@ -234,13 +392,6 @@ public interface MultiverseWorld { @Deprecated boolean getFakePVP(); - /** - * Gets whether or not PVP is enabled in this world in some form (fake or not). - * - * @return True if players can take damage from other players. - */ - boolean isPVPEnabled(); - /** * Gets whether or not this world will display in chat, mvw and mvl regardless if a user has the * access permissions to go to this world. @@ -257,6 +408,13 @@ public interface MultiverseWorld { */ void setHidden(boolean hidden); + /** + * Gets whether weather is enabled in this world. + * + * @return True if weather events will occur, false if not. + */ + boolean isWeatherEnabled(); + /** * Sets whether or not there will be weather events in a given world. * If set to false, Multiverse will disable the weather in the world immediately. @@ -266,11 +424,11 @@ public interface MultiverseWorld { void setEnableWeather(boolean enableWeather); /** - * Gets whether weather is enabled in this world. + * Gets whether or not CraftBukkit is keeping the chunks for this world in memory. * - * @return True if weather events will occur, false if not. + * @return True if CraftBukkit is keeping spawn chunks in memory. */ - boolean isWeatherEnabled(); + boolean isKeepingSpawnInMemory(); /** * If true, tells Craftbukkit to keep a worlds spawn chunks loaded in memory (default: true) @@ -282,29 +440,11 @@ public interface MultiverseWorld { void setKeepSpawnInMemory(boolean keepSpawnInMemory); /** - * Gets whether or not CraftBukkit is keeping the chunks for this world in memory. + * Gets the spawn location of this world. * - * @return True if CraftBukkit is keeping spawn chunks in memory. + * @return The spawn location of this world. */ - boolean isKeepingSpawnInMemory(); - - /** - * Sets the difficulty of this world and returns true if success. - * Valid string values are either an integer of difficulty(0-3) or - * the name that resides in the Bukkit enum, ex. PEACEFUL - * - * @param difficulty The difficulty to set the world to as a string. - * @return True if success, false if the provided string - * could not be translated to a difficulty. - */ - boolean setDifficulty(String difficulty); - - /** - * Gets the difficulty of this world. - * - * @return The difficulty of this world. - */ - Difficulty getDifficulty(); + Location getSpawnLocation(); /** * Sets the spawn location for a world. @@ -314,11 +454,11 @@ public interface MultiverseWorld { void setSpawnLocation(Location spawnLocation); /** - * Gets the spawn location of this world. + * Gets whether or not the hunger level of players will go down in a world. * - * @return The spawn location of this world. + * @return True if it will go down, false if it will remain steady. */ - Location getSpawnLocation(); + boolean getHunger(); /** * Sets whether or not the hunger level of players will go down in a world. @@ -328,22 +468,6 @@ public interface MultiverseWorld { */ void setHunger(boolean hungerEnabled); - /** - * Gets whether or not the hunger level of players will go down in a world. - * - * @return True if it will go down, false if it will remain steady. - */ - boolean getHunger(); - - /** - * Sets the game mode of this world. - * - * @param gameMode A valid game mode string (either - * an int ex. 0 or a string ex. creative). - * @return True if the game mode was successfully changed, false if not. - */ - boolean setGameMode(String gameMode); - /** * Gets the GameMode of this world. * @@ -352,18 +476,31 @@ public interface MultiverseWorld { GameMode getGameMode(); /** - * Gets the permission required to enter this world. + * Sets the game mode of this world. * - * @return The permission required to be exempt from charges to/from this world. + * @param gameMode A valid game mode string (either + * an int ex. 0 or a string ex. creative). + * @return True if the game mode was successfully changed, false if not. + * @deprecated Use {@link #setGameMode(GameMode)} instead. If you have to + * pass a string, use {@link #setPropertyValue(String, String)}. */ - Permission getAccessPermission(); + @Deprecated + boolean setGameMode(String gameMode); /** - * Gets the permission required to be exempt when entering. + * Sets the game mode of this world. * - * @return The permission required to be exempt when entering. + * @param gameMode The new {@link GameMode}. + * @return True if the game mode was successfully changed, false if not. */ - Permission getExemptPermission(); + boolean setGameMode(GameMode gameMode); + + /** + * Gets the amount of currency it requires to enter this world. + * + * @return The amount it costs to enter this world. + */ + double getPrice(); /** * Sets the price for entry to this world. @@ -375,11 +512,11 @@ public interface MultiverseWorld { void setPrice(double price); /** - * Gets the amount of currency it requires to enter this world. + * Gets the Type of currency that will be used when users enter this world. * - * @return The amount it costs to enter this world. + * @return The Type of currency that will be used when users enter this world. */ - double getPrice(); + int getCurrency(); /** * Sets the type of item that will be required given the price is not 0. @@ -390,11 +527,11 @@ public interface MultiverseWorld { void setCurrency(int item); /** - * Gets the Type of currency that will be used when users enter this world. + * Gets the world players will respawn in if they die in this one. * - * @return The Type of currency that will be used when users enter this world. + * @return A world that exists on the server. */ - int getCurrency(); + World getRespawnToWorld(); /** * Sets the world players will respawn in if they die in this one. @@ -406,11 +543,12 @@ public interface MultiverseWorld { boolean setRespawnToWorld(String respawnWorld); /** - * Gets the world players will respawn in if they die in this one. + * Gets the scaling value of this world.Really only has an effect if you use + * Multiverse-NetherPortals. * - * @return A world that exists on the server. + * @return This world's non-negative, non-zero scale. */ - World getRespawnToWorld(); + double getScaling(); /** * Sets the scale of this world. Really only has an effect if you use @@ -422,60 +560,11 @@ public interface MultiverseWorld { boolean setScaling(double scaling); /** - * Gets the scaling value of this world.Really only has an effect if you use - * Multiverse-NetherPortals. + * Gets whether or not a world will auto-heal players if the difficulty is on peaceful. * - * @return This world's non-negative, non-zero scale. + * @return True if the world should heal (default), false if not. */ - double getScaling(); - - /** - * Gets a list of all the worlds that players CANNOT travel to from this world, - * regardless of their access permissions. - * - * @return A List of world names. - */ - List getWorldBlacklist(); - - /** - * Returns a list of animals. This list always negates the {@link #canAnimalsSpawn()} result. - * - * @return A list of animals that will spawn if {@link #canAnimalsSpawn()} is false. - */ - List getAnimalList(); - - /** - * Sets whether or not animals can spawn. - * If there are values in {@link #getAnimalList()} and this is false, - * those animals become the exceptions, and will spawn - * - * @param allowAnimalSpawn True to allow spawning of monsters, false to prevent. - */ - void setAllowAnimalSpawn(boolean allowAnimalSpawn); - - /** - * Returns a list of monsters. This list always negates the {@link #canMonstersSpawn()} ()} result. - * - * @return A list of monsters that will spawn if {@link #canMonstersSpawn()} is false. - */ - List getMonsterList(); - - /** - * Sets whether or not monsters can spawn. - * If there are values in {@link #getMonsterList()} and this is false, - * those monsters become the exceptions, and will spawn - * - * @param allowMonsterSpawn True to allow spawning of monsters, false to prevent. - */ - void setAllowMonsterSpawn(boolean allowMonsterSpawn); - - /** - * Clears a list property (sets it to []). - * - * @param property The property to clear. - * @return True if success, false if fail. - */ - boolean clearList(String property); + boolean getAutoHeal(); /** * Sets whether or not a world will auto-heal players if the difficulty is on peaceful. @@ -485,11 +574,11 @@ public interface MultiverseWorld { void setAutoHeal(boolean heal); /** - * Gets whether or not a world will auto-heal players if the difficulty is on peaceful. + * Gets whether or not Multiverse should auto-adjust the spawn for this world. * - * @return True if the world should heal (default), false if not. + * @return True if Multiverse should adjust the spawn, false if not. */ - boolean getAutoHeal(); + boolean getAdjustSpawn(); /** * Sets whether or not Multiverse should auto-adjust the spawn for this world. @@ -499,11 +588,11 @@ public interface MultiverseWorld { void setAdjustSpawn(boolean adjust); /** - * Gets whether or not Multiverse should auto-adjust the spawn for this world. + * Gets whether or not Multiverse should auto-load this world. * - * @return True if Multiverse should adjust the spawn, false if not. + * @return True if Multiverse should auto-load this world. */ - boolean getAdjustSpawn(); + boolean getAutoLoad(); /** * Sets whether or not Multiverse should auto-load this world. @@ -515,11 +604,12 @@ public interface MultiverseWorld { void setAutoLoad(boolean autoLoad); /** - * Gets whether or not Multiverse should auto-load this world. + * Gets whether or not a player who dies in this world will respawn in their + * bed or follow the normal respawn pattern. * - * @return True if Multiverse should auto-load this world. + * @return True if players dying in this world should respawn at their bed. */ - boolean getAutoLoad(); + boolean getBedRespawn(); /** * Sets whether or not a player who dies in this world will respawn in their @@ -532,19 +622,10 @@ public interface MultiverseWorld { void setBedRespawn(boolean autoLoad); /** - * Gets whether or not a player who dies in this world will respawn in their - * bed or follow the normal respawn pattern. - * - * @return True if players dying in this world should respawn at their bed. + * Same as {@link #getTime()}, but returns a string. + * @return The time as a short string: 12:34pm */ - boolean getBedRespawn(); - - /** - * Gets all the names of all properties that can be SET. - * - * @return All property names, with alternating colors. - */ - String getAllPropertyNames(); + String getTime(); /** * Sets the current time in a world. @@ -559,22 +640,6 @@ public interface MultiverseWorld { */ boolean setTime(String timeAsString); - /** - * Same as {@link #getTime()}, but returns a string. - * @return The time as a short string: 12:34pm - */ - String getTime(); - - /** - * Gets the type of this world. As of 1.2 this will be: - * FLAT, NORMAL or VERSION_1_1 - *

- * This is *not* the generator. - * - * @return The Type of this world. - */ - WorldType getWorldType(); - /** * Sets The types of portals that are allowed in this world. * @@ -588,4 +653,20 @@ public interface MultiverseWorld { * @return The type of portals that are allowed. */ AllowedPortalType getAllowedPortals(); + + // properties that are not "getter+setter" style + /** + * Gets a list of all the worlds that players CANNOT travel to from this world, + * regardless of their access permissions. + * + * @return A List of world names. + */ + List getWorldBlacklist(); + + /** + * Gets all the names of all properties that can be SET. + * + * @return All property names, with alternating colors. + */ + String getAllPropertyNames(); } diff --git a/src/main/java/com/onarandombox/MultiverseCore/api/WorldPurger.java b/src/main/java/com/onarandombox/MultiverseCore/api/WorldPurger.java index 6be96bba..a52b73f3 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/api/WorldPurger.java +++ b/src/main/java/com/onarandombox/MultiverseCore/api/WorldPurger.java @@ -3,14 +3,14 @@ package com.onarandombox.MultiverseCore.api; import java.util.List; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Entity; /** * Used to remove animals from worlds that don't belong there. */ public interface WorldPurger { - /** - * Synchronizes the given world with it's settings. + * Synchronizes the given worlds with their settings. * * @param worlds A list of {@link MultiverseWorld} */ @@ -46,4 +46,23 @@ public interface WorldPurger { void purgeWorld(MultiverseWorld mvworld, List thingsToKill, boolean negateAnimals, boolean negateMonsters, CommandSender sender); + /** + * Determines whether the specified creature should be killed. + * + * @param e The creature. + * @param thingsToKill A {@link List} of animals/monsters to be killed. + * @param negateAnimals Whether the monsters in the list should be negated. + * @param negateMonsters Whether the animals in the list should be negated. + * @return {@code true} if the creature should be killed, otherwise {@code false}. + */ + boolean shouldWeKillThisCreature(Entity e, List thingsToKill, boolean negateAnimals, boolean negateMonsters); + + /** + * Determines whether the specified creature should be killed and automatically reads the params from a world object. + * + * @param w The world. + * @param e The creature. + * @return {@code true} if the creature should be killed, otherwise {@code false}. + */ + boolean shouldWeKillThisCreature(MultiverseWorld w, Entity e); } diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/AnchorCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/AnchorCommand.java index 731e6f95..55d0b2cf 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/AnchorCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/AnchorCommand.java @@ -11,6 +11,7 @@ import com.onarandombox.MultiverseCore.MultiverseCore; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionDefault; import java.util.ArrayList; @@ -34,7 +35,11 @@ public class AnchorCommand extends PaginatedCoreCommand { this.addCommandExample("/mv anchor " + ChatColor.GREEN + "otherthing"); this.addCommandExample("/mv anchor " + ChatColor.GREEN + "awesomething " + ChatColor.RED + "-d"); this.addCommandExample("/mv anchors "); - this.setPermission("multiverse.core.anchor", "Allows management of Anchor Destinations.", PermissionDefault.OP); + this.setPermission("multiverse.core.anchor.list", "Allows a player to list all anchors.", PermissionDefault.OP); + this.addAdditonalPermission(new Permission("multiverse.core.anchor.create", + "Allows a player to create anchors.", PermissionDefault.OP)); + this.addAdditonalPermission(new Permission("multiverse.core.anchor.delete", + "Allows a player to delete anchors.", PermissionDefault.OP)); this.setItemsPerPage(8); // SUPPRESS CHECKSTYLE: MagicNumberCheck } @@ -49,6 +54,11 @@ public class AnchorCommand extends PaginatedCoreCommand { } private void showList(CommandSender sender, List args) { + if (!this.plugin.getMVPerms().hasPermission(sender, "multiverse.core.anchor.list", true)) { + sender.sendMessage(ChatColor.RED + "You don't have the permission to list anchors!"); + return; + } + sender.sendMessage(ChatColor.LIGHT_PURPLE + "====[ Multiverse Anchor List ]===="); Player p = null; if (sender instanceof Player) { @@ -105,10 +115,14 @@ public class AnchorCommand extends PaginatedCoreCommand { return; } if (args.size() == 2 && args.get(1).equalsIgnoreCase("-d")) { - if (this.plugin.getAnchorManager().deleteAnchor(args.get(0))) { - sender.sendMessage("Anchor '" + args.get(0) + "' was successfully " + ChatColor.RED + "deleted!"); + if (!this.plugin.getMVPerms().hasPermission(sender, "multiverse.core.anchor.delete", true)) { + sender.sendMessage(ChatColor.RED + "You don't have the permission to delete anchors!"); } else { - sender.sendMessage("Anchor '" + args.get(0) + "' was " + ChatColor.RED + " NOT " + ChatColor.WHITE + "deleted!"); + if (this.plugin.getAnchorManager().deleteAnchor(args.get(0))) { + sender.sendMessage("Anchor '" + args.get(0) + "' was successfully " + ChatColor.RED + "deleted!"); + } else { + sender.sendMessage("Anchor '" + args.get(0) + "' was " + ChatColor.RED + " NOT " + ChatColor.WHITE + "deleted!"); + } } return; } @@ -118,13 +132,16 @@ public class AnchorCommand extends PaginatedCoreCommand { return; } - Player player = (Player) sender; - if (this.plugin.getAnchorManager().saveAnchorLocation(args.get(0), player.getLocation())) { - sender.sendMessage("Anchor '" + args.get(0) + "' was successfully " + ChatColor.GREEN + "created!"); + if (!this.plugin.getMVPerms().hasPermission(sender, "multiverse.core.anchor.create", true)) { + sender.sendMessage(ChatColor.RED + "You don't have the permission to create anchors!"); } else { - sender.sendMessage("Anchor '" + args.get(0) + "' was " + ChatColor.RED + " NOT " + ChatColor.WHITE + "created!"); + Player player = (Player) sender; + if (this.plugin.getAnchorManager().saveAnchorLocation(args.get(0), player.getLocation())) { + sender.sendMessage("Anchor '" + args.get(0) + "' was successfully " + ChatColor.GREEN + "created!"); + } else { + sender.sendMessage("Anchor '" + args.get(0) + "' was " + ChatColor.RED + " NOT " + ChatColor.WHITE + "created!"); + } } - } @Override diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/CloneCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/CloneCommand.java new file mode 100644 index 00000000..9dce1d69 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/CloneCommand.java @@ -0,0 +1,60 @@ +/****************************************************************************** + * Multiverse 2 Copyright (c) the Multiverse Team 2011. * + * Multiverse 2 is licensed under the BSD License. * + * For more information please check the README.md file included * + * with this project. * + ******************************************************************************/ + +package com.onarandombox.MultiverseCore.commands; + +import com.onarandombox.MultiverseCore.MultiverseCore; +import com.onarandombox.MultiverseCore.api.MVWorldManager; +import com.pneumaticraft.commandhandler.CommandHandler; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.permissions.PermissionDefault; + +import java.util.ArrayList; +import java.util.List; + +/** + * Creates a clone of a world. + */ +public class CloneCommand extends MultiverseCommand { + private MVWorldManager worldManager; + + public CloneCommand(MultiverseCore plugin) { + super(plugin); + this.setName("Clone World"); + this.setCommandUsage("/mv clone" + ChatColor.GREEN + " {TARGET} {NAME}" + ChatColor.GOLD + " -g [GENERATOR[:ID]]"); + this.setArgRange(2, 4); // SUPPRESS CHECKSTYLE: MagicNumberCheck + this.addKey("mvclone"); + this.addKey("mvcl"); + this.addKey("mv cl"); + this.addKey("mv clone"); + this.addCommandExample("/mv clone " + ChatColor.GOLD + "world" + ChatColor.GREEN + " world_backup"); + this.addCommandExample("/mv clone " + ChatColor.GOLD + "skyblock_pristine" + ChatColor.GREEN + " skyblock"); + this.addCommandExample("To clone a world that uses a generator:"); + this.addCommandExample("/mv clone " + ChatColor.GOLD + "CleanRoom" + + ChatColor.GREEN + " CleanRoomCopy" + ChatColor.DARK_AQUA + " -g CleanRoomGenerator"); + this.setPermission("multiverse.core.clone", "Clones a world.", PermissionDefault.OP); + this.worldManager = this.plugin.getMVWorldManager(); + } + + @Override + public void runCommand(CommandSender sender, List args) { + Class[] paramTypes = {String.class, String.class, String.class}; + List objectArgs = new ArrayList(); + objectArgs.add(args.get(0)); + objectArgs.add(args.get(1)); + objectArgs.add(CommandHandler.getFlag("-g", args)); + if (!this.worldManager.isMVWorld(args.get(0))) { + // If no world was found, we can't clone. + sender.sendMessage("Sorry, Multiverse doesn't know about world " + args.get(0) + ", so we can't clone it!"); + sender.sendMessage("Check the " + ChatColor.GREEN + "/mv list" + ChatColor.WHITE + " command to verify it is listed."); + return; + } + this.plugin.getCommandHandler().queueCommand(sender, "mvclone", "cloneWorld", objectArgs, + paramTypes, ChatColor.GREEN + "World Cloned!", ChatColor.RED + "World could NOT be cloned!"); + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/ConfigCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/ConfigCommand.java index 6290183a..55424a94 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/ConfigCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/ConfigCommand.java @@ -51,7 +51,7 @@ public class ConfigCommand extends MultiverseCommand { sender.sendMessage(message); return; } - if (!this.plugin.getMVConfig().setProperty(args.get(0).toLowerCase(), args.get(1))) { + if (!this.plugin.getMVConfig().setConfigProperty(args.get(0).toLowerCase(), args.get(1))) { sender.sendMessage(String.format("%sSetting '%s' to '%s' failed!", ChatColor.RED, args.get(0).toLowerCase(), args.get(1))); return; } diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/CreateCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/CreateCommand.java index d820626b..f432a01f 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/CreateCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/CreateCommand.java @@ -18,6 +18,8 @@ import org.bukkit.command.CommandSender; import org.bukkit.permissions.PermissionDefault; import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -65,7 +67,12 @@ public class CreateCommand extends MultiverseCommand { } } - if (worldFile.exists() || this.worldManager.isMVWorld(worldName)) { + if (this.worldManager.isMVWorld(worldName)) { + sender.sendMessage(ChatColor.RED + "Multiverse cannot create " + ChatColor.GOLD +ChatColor.UNDERLINE + "another" + ChatColor.RESET + ChatColor.RED + " world named " + worldName); + return; + } + + if (worldFile.exists()) { sender.sendMessage(ChatColor.RED + "A Folder/World already exists with this name!"); sender.sendMessage(ChatColor.RED + "If you are confident it is a world you can import with /mvimport"); return; @@ -88,7 +95,19 @@ public class CreateCommand extends MultiverseCommand { EnvironmentCommand.showWorldTypes(sender); return; } - + // Determine if the generator is valid. #918 + if (generator != null) { + List genarray = new ArrayList(Arrays.asList(generator.split(":"))); + if (genarray.size() < 2) { + // If there was only one arg specified, pad with another empty one. + genarray.add(""); + } + if (this.worldManager.getChunkGenerator(genarray.get(0), genarray.get(1), "test") == null) { + // We have an invalid generator. + sender.sendMessage("Invalid generator! '" + generator + "'. " + ChatColor.RED + "Aborting world creation."); + return; + } + } Command.broadcastCommandMessage(sender, "Starting creation of world '" + worldName + "'..."); if (this.worldManager.addWorld(worldName, environment, seed, type, allowStructures, generator, useSpawnAdjust)) { diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/DebugCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/DebugCommand.java index 53fc01b5..75a14fed 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/DebugCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/DebugCommand.java @@ -48,8 +48,8 @@ public class DebugCommand extends MultiverseCommand { sender.sendMessage(ChatColor.RED + "Error" + ChatColor.WHITE + " setting debug level. Please use a number 0-3 " + ChatColor.AQUA + "(3 being many many messages!)"); } - } + plugin.saveMVConfigs(); } this.displayDebugMode(sender); } diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/EnvironmentCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/EnvironmentCommand.java index 49367cfc..eec0242e 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/EnvironmentCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/EnvironmentCommand.java @@ -53,8 +53,8 @@ public class EnvironmentCommand extends MultiverseCommand { */ public static void showWorldTypes(CommandSender sender) { sender.sendMessage(ChatColor.YELLOW + "Valid World Types are:"); - sender.sendMessage(String.format("%sNORMAL%,s %sFLAT %sor %sVERSION_1_1", - ChatColor.GREEN, ChatColor.WHITE, ChatColor.AQUA, ChatColor.WHITE, ChatColor.GOLD)); + sender.sendMessage(String.format("%sNORMAL%s, %sFLAT, %sLARGEBIOMES %sor %sVERSION_1_1", + ChatColor.GREEN, ChatColor.WHITE, ChatColor.AQUA, ChatColor.RED, ChatColor.WHITE, ChatColor.GOLD)); } @Override @@ -75,6 +75,9 @@ public class EnvironmentCommand extends MultiverseCommand { type = "NORMAL"; if (type.equalsIgnoreCase("flat")) type = "FLAT"; + if (type.equalsIgnoreCase("largebiomes")) { + type = "LARGE_BIOMES"; + } try { // Now that we've converted a potentially unfriendly value // to a friendly one, get it from the ENUM! diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/InfoCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/InfoCommand.java index f9b5380d..67463f0a 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/InfoCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/InfoCommand.java @@ -124,8 +124,13 @@ public class InfoCommand extends MultiverseCommand { message.add(new FancyMessage("Spawn Location: ", plugin.getLocationManipulation().strCoords(spawn), colors)); message.add(new FancyMessage("World Scale: ", world.getScaling() + "", colors)); if (world.getPrice() > 0) { - message.add(new FancyMessage("Price to enter this world: ", - this.plugin.getBank().getFormattedAmount(p, world.getPrice(), world.getCurrency()), colors)); + final String formattedAmount; + if (world.getCurrency() <= 0 && plugin.getVaultEconomy() != null) { + formattedAmount = plugin.getVaultEconomy().format(world.getPrice()); + } else { + formattedAmount = this.plugin.getBank().getFormattedAmount(p, world.getPrice(), world.getCurrency()); + } + message.add(new FancyMessage("Price to enter this world: ", formattedAmount, colors)); } else { message.add(new FancyMessage("Price to enter this world: ", ChatColor.GREEN + "FREE!", colors)); } diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/ModifyAddCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/ModifyAddCommand.java index abd3e135..e7526118 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/ModifyAddCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/ModifyAddCommand.java @@ -81,9 +81,13 @@ public class ModifyAddCommand extends MultiverseCommand { return; } + // TODO fix this if (world.addToVariable(property, value)) { sender.sendMessage(ChatColor.GREEN + "Success! " + ChatColor.AQUA + value + ChatColor.WHITE + " was " + ChatColor.GREEN + "added to " + ChatColor.GREEN + property); + if (!plugin.saveWorldConfig()) { + sender.sendMessage(ChatColor.RED + "There was an issue saving worlds.yml! Your changes will only be temporary!"); + } } else { sender.sendMessage(value + " could not be added to " + property); } diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/ModifyClearCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/ModifyClearCommand.java index 78075432..6f153834 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/ModifyClearCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/ModifyClearCommand.java @@ -75,10 +75,14 @@ public class ModifyClearCommand extends MultiverseCommand { sender.sendMessage("Please visit our Github Wiki for more information: http://goo.gl/cgB2B"); return; } + // TODO fix this if (world.clearList(property)) { sender.sendMessage(property + " was cleared. It contains 0 values now."); sender.sendMessage(ChatColor.GREEN + "Success! " + ChatColor.AQUA + property + ChatColor.WHITE + " was " + ChatColor.GREEN + "CLEARED" + ChatColor.WHITE + ". It contains " + ChatColor.LIGHT_PURPLE + "0" + ChatColor.WHITE + " values now."); + if (!plugin.saveWorldConfig()) { + sender.sendMessage(ChatColor.RED + "There was an issue saving worlds.yml! Your changes will only be temporary!"); + } } else { sender.sendMessage(ChatColor.RED + "Error: " + ChatColor.GOLD + property + ChatColor.WHITE + " was " + ChatColor.GOLD + "NOT" + ChatColor.WHITE + " cleared."); diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/ModifyRemoveCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/ModifyRemoveCommand.java index 57b4a262..c60d733f 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/ModifyRemoveCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/ModifyRemoveCommand.java @@ -81,9 +81,13 @@ public class ModifyRemoveCommand extends MultiverseCommand { sender.sendMessage("Please visit our Github Wiki for more information: http://goo.gl/4W8cY"); return; } + // TODO fix this if (world.removeFromVariable(property, value)) { sender.sendMessage(ChatColor.GREEN + "Success! " + ChatColor.AQUA + value + ChatColor.WHITE + " was " + ChatColor.RED + "removed from " + ChatColor.GREEN + property); + if (!plugin.saveWorldConfig()) { + sender.sendMessage(ChatColor.RED + "There was an issue saving worlds.yml! Your changes will only be temporary!"); + } } else { sender.sendMessage(ChatColor.RED + "There was an error removing " + ChatColor.GRAY + value + ChatColor.WHITE + " from " + ChatColor.GOLD + property); diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/ModifySetCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/ModifySetCommand.java index 7c753ce4..54bf8a11 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/ModifySetCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/ModifySetCommand.java @@ -102,22 +102,24 @@ public class ModifySetCommand extends MultiverseCommand { return; } - if ((property.equalsIgnoreCase("aliascolor") || property.equalsIgnoreCase("color")) && !world.isValidAliasColor(value)) { + if ((property.equalsIgnoreCase("aliascolor") || property.equalsIgnoreCase("color")) && !EnglishChatColor.isValidAliasColor(value)) { sender.sendMessage(value + " is not a valid color. Please pick one of the following:"); sender.sendMessage(EnglishChatColor.getAllColors()); return; } try { - if (world.setProperty(property, value, sender)) { + if (world.setPropertyValue(property, value)) { sender.sendMessage(ChatColor.GREEN + "Success!" + ChatColor.WHITE + " Property " + ChatColor.AQUA + property + ChatColor.WHITE + " was set to " + ChatColor.GREEN + value); + if (!plugin.saveWorldConfig()) { + sender.sendMessage(ChatColor.RED + "There was an issue saving worlds.yml! Your changes will only be temporary!"); + } } else { - sender.sendMessage(world.getProperty(property, Object.class).getHelp()); + sender.sendMessage(ChatColor.RED + world.getPropertyHelp(property)); } } catch (PropertyDoesNotExistException e) { sender.sendMessage(ChatColor.RED + "Sorry, You can't set: '" + ChatColor.GRAY + property + ChatColor.RED + "'"); - // TODO: Display the list - sender.sendMessage(ChatColor.GOLD + "For a full list of thingys, see our wiki."); + sender.sendMessage("Valid world-properties: " + world.getAllPropertyNames()); } } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/ScriptCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/ScriptCommand.java new file mode 100644 index 00000000..2896a8e7 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/ScriptCommand.java @@ -0,0 +1,54 @@ +/****************************************************************************** + * Multiverse 2 Copyright (c) the Multiverse Team 2011. * + * Multiverse 2 is licensed under the BSD License. * + * For more information please check the README.md file included * + * with this project. * + ******************************************************************************/ + +package com.onarandombox.MultiverseCore.commands; + +import com.onarandombox.MultiverseCore.MultiverseCore; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.permissions.PermissionDefault; + +import java.io.File; +import java.util.List; + +/** + * States who is in what world. + */ +public class ScriptCommand extends MultiverseCommand { + + public ScriptCommand(MultiverseCore plugin) { + super(plugin); + this.setName("Runs a script."); + this.setCommandUsage("/mv script" + ChatColor.GOLD + " {script} [target]"); + this.setArgRange(1, 2); + this.addKey("mv script"); + this.addKey("mvscript"); + this.addCommandExample(String.format("/mv script %sscript.txt", ChatColor.GOLD)); + this.addCommandExample(String.format("/mv script %stest.txt %ssomeplayer", ChatColor.GOLD, ChatColor.GREEN)); + this.setPermission("multiverse.core.script", "Runs a script.", PermissionDefault.OP); + } + + @Override + public void runCommand(CommandSender sender, List args) { + File file = new File(plugin.getScriptAPI().getScriptFolder(), args.get(0)); + if (!file.exists()) { + sender.sendMessage("That script file does not exist in the Multiverse-Core scripts directory!"); + return; + } + Player player = null; + if (sender instanceof Player) { + player = (Player) sender; + } + String target = null; + if (args.size() == 2) { + target = args.get(1); + } + plugin.getScriptAPI().executeScript(file, target, player); + sender.sendMessage(String.format("Script '%s%s%s' finished!", ChatColor.GOLD, file.getName(), ChatColor.WHITE)); + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/SpoutCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/SpoutCommand.java index b993d5b1..3683d937 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/SpoutCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/SpoutCommand.java @@ -4,7 +4,7 @@ * For more information please check the README.md file included * * with this project. * ******************************************************************************/ - +/* package com.onarandombox.MultiverseCore.commands; import com.onarandombox.MultiverseCore.MultiverseCore; @@ -21,7 +21,7 @@ import java.util.List; /** * Edit a world with spout. - */ + * / public class SpoutCommand extends MultiverseCommand { public SpoutCommand(MultiverseCore plugin) { @@ -51,7 +51,7 @@ public class SpoutCommand extends MultiverseCommand { } PopupScreen pop = new GenericPopup(); GenericButton button = new GenericButton("Fish"); - // TODO maybe use constants for these + // TO-DO maybe use constants for these // BEGIN CHECKSTYLE-SUPPRESSION: MagicNumberCheck button.setX(50); button.setY(50); @@ -63,3 +63,4 @@ public class SpoutCommand extends MultiverseCommand { p.getMainScreen().attachPopupScreen(pop); } } +*/ diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/VersionCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/VersionCommand.java index d84bbce4..9d967d34 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/VersionCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/VersionCommand.java @@ -15,7 +15,6 @@ import com.onarandombox.MultiverseCore.utils.webpaste.PasteService; import com.onarandombox.MultiverseCore.utils.webpaste.PasteServiceFactory; import com.onarandombox.MultiverseCore.utils.webpaste.PasteServiceType; import com.onarandombox.MultiverseCore.utils.webpaste.URLShortener; - import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -52,9 +51,15 @@ public class VersionCommand extends MultiverseCommand { StringBuilder buffer = new StringBuilder(); buffer.append("[Multiverse-Core] Multiverse-Core Version: ").append(this.plugin.getDescription().getVersion()).append('\n'); buffer.append("[Multiverse-Core] Bukkit Version: ").append(this.plugin.getServer().getVersion()).append('\n'); - buffer.append("[Multiverse-Core] Loaded Worlds: ").append(this.plugin.getMVWorldManager().getMVWorlds().size()).append('\n'); + buffer.append("[Multiverse-Core] Loaded Worlds: ").append(this.plugin.getMVWorldManager().getMVWorlds()).append('\n'); buffer.append("[Multiverse-Core] Multiverse Plugins Loaded: ").append(this.plugin.getPluginCount()).append('\n'); - buffer.append("[Multiverse-Core] Economy being used: ").append(this.plugin.getBank().getEconUsed()).append('\n'); + final boolean usingVault = this.plugin.getVaultEconomy() != null; + buffer.append("[Multiverse-Core] Using Vault: ").append(usingVault).append('\n'); + if (usingVault) { + buffer.append("[Multiverse-Core] Economy being used: ").append(this.plugin.getVaultEconomy().getName()).append('\n'); + } else { + buffer.append("[Multiverse-Core] Economy being used: ").append(this.plugin.getBank().getEconUsed()).append('\n'); + } buffer.append("[Multiverse-Core] Permissions Plugin: ").append(this.plugin.getMVPerms().getType()).append('\n'); buffer.append("[Multiverse-Core] Dumping Config Values: (version ") .append(this.plugin.getMVConfig().getVersion()).append(")").append('\n'); diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/WhoCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/WhoCommand.java index 93a960ba..a1884f2b 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/WhoCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/WhoCommand.java @@ -15,6 +15,8 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.permissions.PermissionDefault; +import java.util.Collection; +import java.util.HashSet; import java.util.List; /** @@ -50,6 +52,14 @@ public class WhoCommand extends MultiverseCommand { showAll = false; } + final Player[] onlinePlayers = plugin.getServer().getOnlinePlayers(); + final Collection visiblePlayers = new HashSet(onlinePlayers.length); + for (final Player player : onlinePlayers) { + if (p == null || p.canSee(player)) { + visiblePlayers.add(player); + } + } + if (args.size() == 1) { if (args.get(0).equalsIgnoreCase("--all") || args.get(0).equalsIgnoreCase("-a")) { showAll = true; @@ -68,18 +78,19 @@ public class WhoCommand extends MultiverseCommand { sender.sendMessage(String.format("%s--- Players in %s%s ---", ChatColor.AQUA, world.getColoredWorldString(), ChatColor.AQUA)); - sender.sendMessage(buildPlayerString(world)); + sender.sendMessage(this.buildPlayerString(world, p, visiblePlayers)); return; } } // multiworld mode - sender.sendMessage(ChatColor.AQUA + "--- Worlds and their players ---"); + sender.sendMessage(ChatColor.AQUA + "--- Worlds and their players --- " + + visiblePlayers.size() + "/" + plugin.getServer().getMaxPlayers()); boolean shownOne = false; for (MultiverseWorld world : this.worldManager.getMVWorlds()) { if (this.plugin.getMVPerms().canEnterWorld(p, world)) { // only show world if the player can access it if (showAll || !world.getCBWorld().getPlayers().isEmpty()) { // either show all or show if the world is not empty - sender.sendMessage(String.format("%s%s - %s", world.getColoredWorldString(), ChatColor.WHITE, buildPlayerString(world))); + sender.sendMessage(String.format("%s%s - %s", world.getColoredWorldString(), ChatColor.WHITE, buildPlayerString(world, p, visiblePlayers))); shownOne = true; } } @@ -90,17 +101,18 @@ public class WhoCommand extends MultiverseCommand { return; } - private static String buildPlayerString(MultiverseWorld world) { + private static String buildPlayerString(MultiverseWorld world, Player viewer, final Collection visiblePlayers) { + // Retrieve the players in this world List players = world.getCBWorld().getPlayers(); - if (players.size() == 0) { - return "No players found."; - } else { - StringBuilder playerBuilder = new StringBuilder(); - for (Player player : players) { + StringBuilder playerBuilder = new StringBuilder(); + for (Player player : players) { + // If the viewer is the console or the viewier is allowed to see the player, show them. + // Make sure we're also ONLY showing online players. + // Since we already checked visible players, we'll just make sure who we're about to show is in that. + if (visiblePlayers.contains(player)) playerBuilder.append(player.getDisplayName()).append(", "); - } - String bString = playerBuilder.toString(); - return bString.substring(0, bString.length() - 2); } + String bString = playerBuilder.toString(); + return (bString.length() == 0) ? "No players found." : bString.substring(0, bString.length() - 2); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/ActiveStringConfigProperty.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/ActiveStringConfigProperty.java deleted file mode 100644 index 078ba1b5..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/ActiveStringConfigProperty.java +++ /dev/null @@ -1,115 +0,0 @@ -/****************************************************************************** - * Multiverse 2 Copyright (c) the Multiverse Team 2012. * - * Multiverse 2 is licensed under the BSD License. * - * For more information please check the README.md file included * - * with this project. * - ******************************************************************************/ - -package com.onarandombox.MultiverseCore.configuration; - -/** - * A {@link String} config-property that will NOT be saved to the config. - */ -public class ActiveStringConfigProperty implements MVActiveConfigProperty { - private String name; - private String value; - private String method; - private String help; - - public ActiveStringConfigProperty(String name, String defaultValue, String help) { - this.name = name; - this.help = help; - this.value = defaultValue; - this.parseValue(defaultValue); - } - - public ActiveStringConfigProperty(String name, String defaultValue, String help, String method) { - this(name, defaultValue, help); - this.method = method; - } - - /** - * {@inheritDoc} - */ - @Override - public String getName() { - return this.name; - } - - /** - * {@inheritDoc} - */ - @Override - public String getValue() { - return this.value; - } - - /** - * {@inheritDoc} - */ - @Override - public String getMethod() { - return this.method; - } - - /** - * {@inheritDoc} - */ - @Override - public void setMethod(String methodName) { - this.method = methodName; - } - - /** - * {@inheritDoc} - */ - @Override - public Class getPropertyClass() { - return String.class; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean parseValue(String value) { - if (value == null) { - return false; - } - this.setValue(value); - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public String getConfigNode() { - return ""; - } - - /** - * {@inheritDoc} - */ - @Override - public String getHelp() { - return this.help; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean setValue(String value) { - if (value == null) { - return false; - } - this.value = value; - return true; - } - - @Override - public String toString() { - return value; - } -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/BooleanConfigProperty.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/BooleanConfigProperty.java deleted file mode 100644 index 375a7872..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/BooleanConfigProperty.java +++ /dev/null @@ -1,135 +0,0 @@ -/****************************************************************************** - * Multiverse 2 Copyright (c) the Multiverse Team 2011. * - * Multiverse 2 is licensed under the BSD License. * - * For more information please check the README.md file included * - * with this project. * - ******************************************************************************/ - -package com.onarandombox.MultiverseCore.configuration; - -import org.bukkit.configuration.ConfigurationSection; - -/** - * A {@link Boolean} config-property. - */ -public class BooleanConfigProperty implements MVActiveConfigProperty { - private String name; - private Boolean value; - private String configNode; - private ConfigurationSection section; - private String help; - private String method; - - public BooleanConfigProperty(ConfigurationSection section, String name, Boolean defaultValue, String help) { - this(section, name, defaultValue, name, help); - } - - public BooleanConfigProperty(ConfigurationSection section, String name, Boolean defaultValue, String configNode, String help) { - this.name = name; - this.configNode = configNode; - this.section = section; - this.help = help; - this.value = defaultValue; - this.setValue(this.section.getBoolean(this.configNode, defaultValue)); - } - - public BooleanConfigProperty(ConfigurationSection section, String name, Boolean defaultValue, String configNode, String help, String method) { - this(section, name, defaultValue, configNode, help); - this.method = method; - } - - /** - * {@inheritDoc} - */ - @Override - public String getName() { - return this.name; - } - - /** - * {@inheritDoc} - */ - @Override - public Boolean getValue() { - return this.value; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean setValue(Boolean value) { - if (value == null) { - return false; - } - this.value = value; - this.section.set(configNode, this.value); - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean parseValue(String value) { - if (value == null) { - return false; - } - if (value.toLowerCase().equals("true") || value.toLowerCase().equals("false")) { - this.setValue(Boolean.parseBoolean(value)); - return true; - } - return false; - } - - /** - * {@inheritDoc} - */ - @Override - public String getConfigNode() { - return this.configNode; - } - - /** - * {@inheritDoc} - */ - @Override - public String getHelp() { - return this.help; - } - - @Override - public String toString() { - return value.toString(); - } - - /** - * Gets the method that will be executed. - * - * @return The name of the method in MVWorld to be called. - */ - @Override - public String getMethod() { - return this.method; - } - - /** - * Sets the method that will be executed. - * - * @param methodName The name of the method in MVWorld to be called. - */ - @Override - public void setMethod(String methodName) { - this.method = methodName; - } - - /** - * Returns the class of the object we're looking at. - * - * @return the class of the object we're looking at. - */ - @Override - public Class getPropertyClass() { - return Boolean.class; - } -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/ColorConfigProperty.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/ColorConfigProperty.java deleted file mode 100644 index 1149b815..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/ColorConfigProperty.java +++ /dev/null @@ -1,98 +0,0 @@ -/****************************************************************************** - * Multiverse 2 Copyright (c) the Multiverse Team 2011. * - * Multiverse 2 is licensed under the BSD License. * - * For more information please check the README.md file included * - * with this project. * - ******************************************************************************/ - -package com.onarandombox.MultiverseCore.configuration; - -import com.onarandombox.MultiverseCore.enums.EnglishChatColor; -import org.bukkit.configuration.ConfigurationSection; - -/** - * A {@link EnglishChatColor} config-property. - */ -public class ColorConfigProperty implements MVConfigProperty { - private String name; - private EnglishChatColor value; - private String configNode; - private ConfigurationSection section; - private String help; - - public ColorConfigProperty(ConfigurationSection section, String name, EnglishChatColor defaultValue, String help) { - this(section, name, defaultValue, name, help); - } - - public ColorConfigProperty(ConfigurationSection section, String name, EnglishChatColor defaultValue, String configNode, String help) { - this.name = name; - this.configNode = configNode; - this.section = section; - this.help = help; - this.value = defaultValue; - this.parseValue(this.section.getString(this.configNode, defaultValue.toString())); - } - - /** - * {@inheritDoc} - */ - @Override - public String getName() { - return this.name; - } - - /** - * {@inheritDoc} - */ - @Override - public EnglishChatColor getValue() { - return this.value; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean setValue(EnglishChatColor value) { - if (value == null) { - return false; - } - this.value = value; - this.section.set(configNode, this.value.getText()); - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean parseValue(String value) { - EnglishChatColor color = EnglishChatColor.fromString(value); - if (color == null) { - return false; - } - this.setValue(color); - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public String getConfigNode() { - return this.configNode; - } - - /** - * {@inheritDoc} - */ - @Override - public String getHelp() { - return this.help; - } - - @Override - public String toString() { - return value.toString(); - } -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/ConfigPropertyFactory.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/ConfigPropertyFactory.java deleted file mode 100644 index cb409484..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/ConfigPropertyFactory.java +++ /dev/null @@ -1,306 +0,0 @@ -/****************************************************************************** - * Multiverse 2 Copyright (c) the Multiverse Team 2012. * - * Multiverse 2 is licensed under the BSD License. * - * For more information please check the README.md file included * - * with this project. * - ******************************************************************************/ - -package com.onarandombox.MultiverseCore.configuration; - -import com.onarandombox.MultiverseCore.enums.AllowedPortalType; -import com.onarandombox.MultiverseCore.enums.EnglishChatColor; -import org.bukkit.Difficulty; -import org.bukkit.GameMode; -import org.bukkit.Location; -import org.bukkit.configuration.ConfigurationSection; - -/** A factory to create config properties for a given world. */ -public class ConfigPropertyFactory { - private ConfigurationSection section; - - public ConfigPropertyFactory(ConfigurationSection section) { - this.section = section; - } - - // Booleans - /** - * Constructs a new ConfigProperty. - * - * @param name The name of this ConfigProperty. - * @param defaultValue The default-value. - * @param help The text that's displayed when a user failed to set the property. - * @return The ConfigProperty. - */ - public BooleanConfigProperty getNewProperty(String name, boolean defaultValue, String help) { - return new BooleanConfigProperty(this.section, name, defaultValue, help); - } - - /** - * Constructs a new ConfigProperty. - * - * @param name The name of this ConfigProperty. - * @param defaultValue The default-value. - * @param node The name of the configuration-node this ConfigProperty will be stored as. - * @param help The text that's displayed when a user failed to set the property. - * @return The ConfigProperty. - */ - public BooleanConfigProperty getNewProperty(String name, boolean defaultValue, String node, String help) { - return new BooleanConfigProperty(this.section, name, defaultValue, node, help); - } - - /** - * Constructs a new ActiveBooleanConfigProperty - * - * This property will execute 'method' after it has been successfully set. - * - * @param name The name of this ConifgProperty - * @param defaultValue The default value. - * @param help What string is shown for help. - * @param node The name of the configuration-node this ConfigProperty will be stored as. - * @param method The method that should be executed. - * @return The ActiveStringConfigProperty - */ - public BooleanConfigProperty getNewProperty(String name, boolean defaultValue, String help, String node, String method) { - return new BooleanConfigProperty(this.section, name, defaultValue, help, node, method); - } - - // Integers - /** - * Constructs a new ConfigProperty. - * - * @param name The name of this ConfigProperty. - * @param defaultValue The default-value. - * @param help The text that's displayed when a user failed to set the property. - * @return The ConfigProperty. - */ - public IntegerConfigProperty getNewProperty(String name, int defaultValue, String help) { - return new IntegerConfigProperty(this.section, name, defaultValue, help); - } - - /** - * Constructs a new ConfigProperty. - * - * @param name The name of this ConfigProperty. - * @param defaultValue The default-value. - * @param node The name of the configuration-node this ConfigProperty will be stored as. - * @param help The text that's displayed when a user failed to set the property. - * @return The ConfigProperty. - */ - public IntegerConfigProperty getNewProperty(String name, int defaultValue, String node, String help) { - return new IntegerConfigProperty(this.section, name, defaultValue, node, help); - } - - // Doubles - /** - * Constructs a new ConfigProperty. - * - * @param name The name of this ConfigProperty. - * @param defaultValue The default-value. - * @param help The text that's displayed when a user failed to set the property. - * @return The ConfigProperty. - */ - public DoubleConfigProperty getNewProperty(String name, double defaultValue, String help) { - return new DoubleConfigProperty(this.section, name, defaultValue, help); - } - - /** - * Constructs a new ConfigProperty. - * - * @param name The name of this ConfigProperty. - * @param defaultValue The default-value. - * @param node The name of the configuration-node this ConfigProperty will be stored as. - * @param help The text that's displayed when a user failed to set the property. - * @return The ConfigProperty. - */ - public DoubleConfigProperty getNewProperty(String name, double defaultValue, String node, String help) { - return new DoubleConfigProperty(this.section, name, defaultValue, node, help); - } - - /** - * Constructs a new ConfigProperty. - * - * @param name The name of this ConfigProperty. - * @param defaultValue The default-value. - * @param node The name of the configuration-node this ConfigProperty will be stored as. - * @param help The text that's displayed when a user failed to set the property. - * @param method The name of the method that's used to set this property. - * @return The ConfigProperty. - */ - public DoubleConfigProperty getNewProperty(String name, double defaultValue, String node, String help, String method) { - return new DoubleConfigProperty(this.section, name, defaultValue, node, help, method); - } - - // Strings - /** - * Constructs a new ConfigProperty. - * - * @param name The name of this ConfigProperty. - * @param defaultValue The default-value. - * @param help The text that's displayed when a user failed to set the property. - * @return The ConfigProperty. - */ - public StringConfigProperty getNewProperty(String name, String defaultValue, String help) { - return new StringConfigProperty(this.section, name, defaultValue, help); - } - - /** - * Constructs a new ConfigProperty. - * - * @param name The name of this ConfigProperty. - * @param defaultValue The default-value. - * @param node The name of the configuration-node this ConfigProperty will be stored as. - * @param help The text that's displayed when a user failed to set the property. - * @return The ConfigProperty. - */ - public StringConfigProperty getNewProperty(String name, String defaultValue, String node, String help) { - return new StringConfigProperty(this.section, name, defaultValue, node, help); - } - - // Colors - /** - * Constructs a new ConfigProperty. - * - * @param name The name of this ConfigProperty. - * @param defaultValue The default-value. - * @param help The text that's displayed when a user failed to set the property. - * @return The ConfigProperty. - */ - public ColorConfigProperty getNewProperty(String name, EnglishChatColor defaultValue, String help) { - return new ColorConfigProperty(this.section, name, defaultValue, help); - } - - /** - * Constructs a new ConfigProperty. - * - * @param name The name of this ConfigProperty. - * @param defaultValue The default-value. - * @param node The name of the configuration-node this ConfigProperty will be stored as. - * @param help The text that's displayed when a user failed to set the property. - * @return The ConfigProperty. - */ - public ColorConfigProperty getNewProperty(String name, EnglishChatColor defaultValue, String node, String help) { - return new ColorConfigProperty(this.section, name, defaultValue, node, help); - } - - // Difficulty - /** - * Constructs a new ConfigProperty. - * - * @param name The name of this ConfigProperty. - * @param defaultValue The default-value. - * @param help The text that's displayed when a user failed to set the property. - * @return The ConfigProperty. - */ - public DifficultyConfigProperty getNewProperty(String name, Difficulty defaultValue, String help) { - return new DifficultyConfigProperty(this.section, name, defaultValue, help); - } - - /** - * Constructs a new ConfigProperty. - * - * @param name The name of this ConfigProperty. - * @param defaultValue The default-value. - * @param node The name of the configuration-node this ConfigProperty will be stored as. - * @param help The text that's displayed when a user failed to set the property. - * @return The ConfigProperty. - */ - public DifficultyConfigProperty getNewProperty(String name, Difficulty defaultValue, String node, String help) { - return new DifficultyConfigProperty(this.section, name, defaultValue, node, help); - } - - // GameMode - /** - * Constructs a new ConfigProperty. - * - * @param name The name of this ConfigProperty. - * @param defaultValue The default-value. - * @param help The text that's displayed when a user failed to set the property. - * @return The ConfigProperty. - */ - public GameModeConfigProperty getNewProperty(String name, GameMode defaultValue, String help) { - return new GameModeConfigProperty(this.section, name, defaultValue, help); - } - - /** - * Constructs a new ConfigProperty. - * - * @param name The name of this ConfigProperty. - * @param defaultValue The default-value. - * @param node The name of the configuration-node this ConfigProperty will be stored as. - * @param help The text that's displayed when a user failed to set the property. - * @return The ConfigProperty. - */ - public GameModeConfigProperty getNewProperty(String name, GameMode defaultValue, String node, String help) { - return new GameModeConfigProperty(this.section, name, defaultValue, node, help); - } - - // Location - /** - * Constructs a new LocationConfigProperty. - * - * @param name The name of this ConfigProperty. - * @param defaultValue The default-value. - * @param help The text that's displayed when a user failed to set the property. - * @return The ConfigProperty. - */ - public LocationConfigProperty getNewProperty(String name, Location defaultValue, String help) { - return new LocationConfigProperty(this.section, name, defaultValue, help); - } - - /** - * Constructs a new ConfigProperty. - * - * @param name The name of this ConfigProperty. - * @param defaultValue The default-value. - * @param node The name of the configuration-node this ConfigProperty will be stored as. - * @param help The text that's displayed when a user failed to set the property. - * @return The ConfigProperty. - */ - public LocationConfigProperty getNewProperty(String name, Location defaultValue, String node, String help) { - return new LocationConfigProperty(this.section, name, defaultValue, node, help); - } - - /** - * Constructs a new ConfigProperty. - * - * @param name The name of this ConfigProperty. - * @param defaultValue The default-value. - * @param node The name of the configuration-node this ConfigProperty will be stored as. - * @param help The text that's displayed when a user failed to set the property. - * @param method The name of the method that's used to set this property. - * @return The ConfigProperty. - */ - public LocationConfigProperty getNewProperty(String name, Location defaultValue, String node, String help, String method) { - return new LocationConfigProperty(this.section, name, defaultValue, node, help, method); - } - - // GameMode - /** - * Constructs a new ConfigProperty. - * - * @param name The name of this ConfigProperty. - * @param defaultValue The default-value. - * @param help The text that's displayed when a user failed to set the property. - * @return The ConfigProperty. - */ - public PortalTypeConfigProperty getNewProperty(String name, AllowedPortalType defaultValue, String help) { - return new PortalTypeConfigProperty(this.section, name, defaultValue, help); - } - - /** - * Constructs a new ActiveStringConfigProperty - * - * This property will execute 'method' after it has been successfully set. - * This string will NOT be saved to the config file. - * - * @param name The name of this ConifgProperty - * @param defaultValue The default value. - * @param help What string is shown for help. - * @param method The method that should be executed. - * @param saveToConfig Should the variable save to the config? - * @return The ActiveStringConfigProperty - */ - public ActiveStringConfigProperty getNewProperty(String name, String defaultValue, String help, String method, boolean saveToConfig) { - return new ActiveStringConfigProperty(name, defaultValue, help, method); - } -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/DifficultyConfigProperty.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/DifficultyConfigProperty.java deleted file mode 100644 index 42b692c6..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/DifficultyConfigProperty.java +++ /dev/null @@ -1,129 +0,0 @@ -/****************************************************************************** - * Multiverse 2 Copyright (c) the Multiverse Team 2011. * - * Multiverse 2 is licensed under the BSD License. * - * For more information please check the README.md file included * - * with this project. * - ******************************************************************************/ - -package com.onarandombox.MultiverseCore.configuration; - -import org.bukkit.Difficulty; -import org.bukkit.configuration.ConfigurationSection; - -/** - * A {@link Difficulty} config-property. - */ -public class DifficultyConfigProperty implements MVActiveConfigProperty { - private String name; - private Difficulty value; - private String configNode; - private ConfigurationSection section; - private String help; - - public DifficultyConfigProperty(ConfigurationSection section, String name, Difficulty defaultValue, String help) { - this(section, name, defaultValue, name, help); - } - - public DifficultyConfigProperty(ConfigurationSection section, String name, Difficulty defaultValue, String configNode, String help) { - this.name = name; - this.configNode = configNode; - this.section = section; - this.help = help; - this.value = defaultValue; - this.parseValue(this.section.getString(this.configNode, defaultValue.toString())); - } - - /** - * {@inheritDoc} - */ - @Override - public String getName() { - return this.name; - } - - /** - * {@inheritDoc} - */ - @Override - public Difficulty getValue() { - return this.value; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean setValue(Difficulty value) { - if (value == null) { - return false; - } - this.value = value; - this.section.set(configNode, this.value.toString()); - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean parseValue(String value) { - try { - return this.setValue(Difficulty.getByValue(Integer.parseInt(value))); - } catch (NumberFormatException nfe) { - try { - return this.setValue(Difficulty.valueOf(value.toUpperCase())); - } catch (Exception e) { - return false; - } - } - } - - /** - * {@inheritDoc} - */ - @Override - public String getConfigNode() { - return this.configNode; - } - - /** - * {@inheritDoc} - */ - @Override - public String getHelp() { - return this.help; - } - - @Override - public String toString() { - return value.toString(); - } - - /** - * Gets the method that will be executed. - * - * @return The name of the method in MVWorld to be called. - */ - @Override - public String getMethod() { - return "setActualDifficulty"; - } - - /** - * Sets the method that will be executed. - * - * @param methodName The name of the method in MVWorld to be called. - */ - @Override - public void setMethod(String methodName) { - // Unused here. This will only ever be setDifficulty. - } - - /** - * {@inheritDoc} - */ - @Override - public Class getPropertyClass() { - return Difficulty.class; - } -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/DoubleConfigProperty.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/DoubleConfigProperty.java deleted file mode 100644 index bd6af823..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/DoubleConfigProperty.java +++ /dev/null @@ -1,133 +0,0 @@ -/****************************************************************************** - * Multiverse 2 Copyright (c) the Multiverse Team 2011. * - * Multiverse 2 is licensed under the BSD License. * - * For more information please check the README.md file included * - * with this project. * - ******************************************************************************/ - -package com.onarandombox.MultiverseCore.configuration; - -import org.bukkit.configuration.ConfigurationSection; - -/** - * A {@link Double} config-property. - */ -public class DoubleConfigProperty implements MVActiveConfigProperty { - private String name; - private Double value; - private String configNode; - private ConfigurationSection section; - private String help; - private String method; - - public DoubleConfigProperty(ConfigurationSection section, String name, Double defaultValue, String help) { - this(section, name, defaultValue, name, help); - } - - public DoubleConfigProperty(ConfigurationSection section, String name, Double defaultValue, String configNode, String help) { - this.name = name; - this.configNode = configNode; - this.section = section; - this.help = help; - this.value = defaultValue; - this.setValue(this.section.getDouble(this.configNode, defaultValue)); - } - - public DoubleConfigProperty(ConfigurationSection section, String name, Double defaultValue, String configNode, String help, String method) { - this(section, name, defaultValue, configNode, help); - this.method = method; - } - - /** - * {@inheritDoc} - */ - @Override - public String getName() { - return this.name; - } - - /** - * {@inheritDoc} - */ - @Override - public Double getValue() { - return this.value; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean setValue(Double value) { - if (value == null) { - return false; - } - this.value = value; - this.section.set(configNode, this.value); - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean parseValue(String value) { - try { - this.setValue(Double.parseDouble(value)); - return true; - } catch (NumberFormatException e) { - return false; - } - } - - /** - * {@inheritDoc} - */ - @Override - public String getConfigNode() { - return this.configNode; - } - - /** - * {@inheritDoc} - */ - @Override - public String getHelp() { - return this.help; - } - - @Override - public String toString() { - return value.toString(); - } - - /** - * Gets the method that will be executed. - * - * @return The name of the method in MVWorld to be called. - */ - @Override - public String getMethod() { - return this.method; - } - - /** - * Sets the method that will be executed. - * - * @param methodName The name of the method in MVWorld to be called. - */ - @Override - public void setMethod(String methodName) { - this.method = methodName; - } - - /** - * Returns the class of the object we're looking at. - * - * @return the class of the object we're looking at. - */ - @Override - public Class getPropertyClass() { - return Double.class; - } -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/EntryFee.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/EntryFee.java new file mode 100644 index 00000000..e754e682 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/EntryFee.java @@ -0,0 +1,66 @@ +package com.onarandombox.MultiverseCore.configuration; + +import java.util.Map; + +import me.main__.util.SerializationConfig.Property; +import me.main__.util.SerializationConfig.SerializationConfig; + +import org.bukkit.configuration.serialization.SerializableAs; + +/** + * Entryfee-settings. + */ +@SerializableAs("MVEntryFee") +public class EntryFee extends SerializationConfig { + @Property + private double amount; + @Property + private int currency; + + public EntryFee() { + super(); + } + + public EntryFee(Map values) { + super(values); + } + + /** + * {@inheritDoc} + */ + @Override + protected void setDefaults() { + amount = 0D; + currency = -1; + } + + /** + * @return the amount + */ + public double getAmount() { + return amount; + } + + /** + * @return the currency + */ + public int getCurrency() { + return currency; + } + + /** + * Sets the amount. + * @param amount The new value. + */ + public void setAmount(double amount) { + this.amount = amount; + } + + /** + * Sets the currency. + * @param currency The new value. + */ + public void setCurrency(int currency) { + this.currency = currency; + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/GameModeConfigProperty.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/GameModeConfigProperty.java deleted file mode 100644 index 2812982c..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/GameModeConfigProperty.java +++ /dev/null @@ -1,129 +0,0 @@ -/****************************************************************************** - * Multiverse 2 Copyright (c) the Multiverse Team 2011. * - * Multiverse 2 is licensed under the BSD License. * - * For more information please check the README.md file included * - * with this project. * - ******************************************************************************/ - -package com.onarandombox.MultiverseCore.configuration; - -import org.bukkit.GameMode; -import org.bukkit.configuration.ConfigurationSection; - -/** - * A {@link GameMode} config-property. - */ -public class GameModeConfigProperty implements MVActiveConfigProperty { - private String name; - private GameMode value; - private String configNode; - private ConfigurationSection section; - private String help; - - public GameModeConfigProperty(ConfigurationSection section, String name, GameMode defaultValue, String help) { - this(section, name, defaultValue, name, help); - } - - public GameModeConfigProperty(ConfigurationSection section, String name, GameMode defaultValue, String configNode, String help) { - this.name = name; - this.configNode = configNode; - this.section = section; - this.help = help; - this.value = defaultValue; - this.parseValue(this.section.getString(this.configNode, defaultValue.toString())); - } - - /** - * {@inheritDoc} - */ - @Override - public String getName() { - return this.name; - } - - /** - * {@inheritDoc} - */ - @Override - public GameMode getValue() { - return this.value; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean setValue(GameMode value) { - if (value == null) { - return false; - } - this.value = value; - this.section.set(configNode, this.value.toString()); - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean parseValue(String value) { - try { - return this.setValue(GameMode.getByValue(Integer.parseInt(value))); - } catch (NumberFormatException nfe) { - try { - return this.setValue(GameMode.valueOf(value.toUpperCase())); - } catch (Exception e) { - return false; - } - } - } - - /** - * {@inheritDoc} - */ - @Override - public String getConfigNode() { - return this.configNode; - } - - /** - * {@inheritDoc} - */ - @Override - public String getHelp() { - return this.help; - } - - @Override - public String toString() { - return value.toString(); - } - - /** - * Gets the method that will be executed. - * - * @return The name of the method in MVWorld to be called. - */ - @Override - public String getMethod() { - return "setActualGameMode"; - } - - /** - * Sets the method that will be executed. - * - * @param methodName The name of the method in MVWorld to be called. - */ - @Override - public void setMethod(String methodName) { - // Not required. Gamemode will only ever be one. - } - - /** - * {@inheritDoc} - */ - @Override - public Class getPropertyClass() { - return GameMode.class; - } -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/IntegerConfigProperty.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/IntegerConfigProperty.java deleted file mode 100644 index 27961a24..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/IntegerConfigProperty.java +++ /dev/null @@ -1,97 +0,0 @@ -/****************************************************************************** - * Multiverse 2 Copyright (c) the Multiverse Team 2011. * - * Multiverse 2 is licensed under the BSD License. * - * For more information please check the README.md file included * - * with this project. * - ******************************************************************************/ - -package com.onarandombox.MultiverseCore.configuration; - -import org.bukkit.configuration.ConfigurationSection; - -/** - * A {@link Integer} config-property. - */ -public class IntegerConfigProperty implements MVConfigProperty { - private String name; - private Integer value; - private String configNode; - private ConfigurationSection section; - private String help; - - public IntegerConfigProperty(ConfigurationSection section, String name, Integer defaultValue, String help) { - this(section, name, defaultValue, name, help); - } - - public IntegerConfigProperty(ConfigurationSection section, String name, Integer defaultValue, String configNode, String help) { - this.name = name; - this.configNode = configNode; - this.section = section; - this.help = help; - this.value = defaultValue; - this.setValue(this.section.getInt(this.configNode, defaultValue)); - } - - /** - * {@inheritDoc} - */ - @Override - public String getName() { - return this.name; - } - - /** - * {@inheritDoc} - */ - @Override - public Integer getValue() { - return this.value; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean setValue(Integer value) { - if (value == null) { - return false; - } - this.value = value; - this.section.set(configNode, this.value); - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean parseValue(String value) { - try { - this.setValue(Integer.parseInt(value)); - return true; - } catch (NumberFormatException e) { - return false; - } - } - - /** - * {@inheritDoc} - */ - @Override - public String getConfigNode() { - return this.configNode; - } - - /** - * {@inheritDoc} - */ - @Override - public String getHelp() { - return this.help; - } - - @Override - public String toString() { - return value.toString(); - } -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/LocationConfigProperty.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/LocationConfigProperty.java deleted file mode 100644 index 9a7096f7..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/LocationConfigProperty.java +++ /dev/null @@ -1,154 +0,0 @@ -/****************************************************************************** - * Multiverse 2 Copyright (c) the Multiverse Team 2011. * - * Multiverse 2 is licensed under the BSD License. * - * For more information please check the README.md file included * - * with this project. * - ******************************************************************************/ - -package com.onarandombox.MultiverseCore.configuration; - -import com.onarandombox.MultiverseCore.utils.LocationManipulation; -import org.bukkit.Location; -import org.bukkit.configuration.ConfigurationSection; - -/** - * A {@link Location} config-property. - */ -public class LocationConfigProperty implements MVActiveConfigProperty { - private String name; - private Location value; - private String configNode; - private ConfigurationSection section; - private String help; - private String method; - - public LocationConfigProperty(ConfigurationSection section, String name, Location defaultValue, String help) { - this(section, name, defaultValue, name, help); - } - - public LocationConfigProperty(ConfigurationSection section, String name, Location defaultValue, String configNode, String help) { - this.name = name; - this.configNode = configNode; - this.section = section; - this.help = help; - this.value = defaultValue; - this.setValue(this.getLocationFromConfig(defaultValue)); - } - - public LocationConfigProperty(ConfigurationSection section, String name, Location defaultValue, String configNode, String help, String method) { - this(section, name, defaultValue, configNode, help); - this.method = method; - } - - /** - * {@inheritDoc} - */ - @Override - public String getName() { - return this.name; - } - - /** - * {@inheritDoc} - */ - @Override - public Location getValue() { - return this.value; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean parseValue(String value) { - // TODO: oh my god, what should we do here? - Location parsed = LocationManipulation.stringToLocation(value); - return this.setValue(parsed); - } - - /** - * {@inheritDoc} - */ - @Override - public String getConfigNode() { - return this.configNode; - } - - /** - * {@inheritDoc} - */ - @Override - public String getHelp() { - return this.help; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean setValue(Location value) { - if (value == null) { - return false; - } - this.value = value; - this.section.set(configNode + ".x", this.value.getX()); - this.section.set(configNode + ".y", this.value.getY()); - this.section.set(configNode + ".z", this.value.getZ()); - this.section.set(configNode + ".pitch", this.value.getPitch()); - this.section.set(configNode + ".yaw", this.value.getYaw()); - this.section.set(configNode + ".world", this.value.getWorld().getName()); - - return true; - } - - private Location getLocationFromConfig(Location defaultValue) { - double x = this.section.getDouble(this.configNode + ".x", defaultValue.getX()); - double y = this.section.getDouble(this.configNode + ".y", defaultValue.getY()); - double z = this.section.getDouble(this.configNode + ".z", defaultValue.getZ()); - double pitch = this.section.getDouble(this.configNode + ".pitch", defaultValue.getPitch()); - double yaw = this.section.getDouble(this.configNode + ".yaw", defaultValue.getYaw()); - String w = this.section.getString(this.configNode + ".world", defaultValue.getWorld().getName()); - Location found = LocationManipulation.stringToLocation(w + ":" + x + "," + y + "," + z + ":" + yaw + ":" + pitch); - // TODO: oh my god, what should we do here? - if (found != null) { - return found; - } - return defaultValue; - } - - @Override - public String toString() { - // TODO: oh my god, what should we do here? - return LocationManipulation.strCoordsRaw(this.value); - } - - /** - * Gets the method that will be executed. - * - * @return The name of the method in MVWorld to be called. - */ - @Override - public String getMethod() { - return this.method; - } - - /** - * Sets the method that will be executed. - * - * @param methodName The name of the method in MVWorld to be called. - */ - @Override - public void setMethod(String methodName) { - this.method = methodName; - } - - /** - * Returns the class of the object we're looking at. - * - * @return the class of the object we're looking at. - */ - @Override - public Class getPropertyClass() { - return Location.class; - } -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/MVActiveConfigProperty.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/MVActiveConfigProperty.java index 08d071ed..403d0026 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/MVActiveConfigProperty.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/MVActiveConfigProperty.java @@ -10,8 +10,10 @@ package com.onarandombox.MultiverseCore.configuration; /** * An "active" {@link MVConfigProperty} that uses the specified method to be "actually" set. * @param The type of the config-property. + * @deprecated This is deprecated. * @see MVConfigProperty */ +@Deprecated public interface MVActiveConfigProperty extends MVConfigProperty { /** * Gets the method that will be executed. diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/MVConfigProperty.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/MVConfigProperty.java index ccb5924d..537a46b5 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/MVConfigProperty.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/MVConfigProperty.java @@ -11,7 +11,9 @@ package com.onarandombox.MultiverseCore.configuration; * A generic config-property. * * @param The type of the config-property. + * @deprecated This is deprecated. */ +@Deprecated public interface MVConfigProperty { /** * Gets the name of this property. diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/PortalTypeConfigProperty.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/PortalTypeConfigProperty.java deleted file mode 100644 index 685a8101..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/PortalTypeConfigProperty.java +++ /dev/null @@ -1,97 +0,0 @@ -/****************************************************************************** - * Multiverse 2 Copyright (c) the Multiverse Team 2012. * - * Multiverse 2 is licensed under the BSD License. * - * For more information please check the README.md file included * - * with this project. * - ******************************************************************************/ - -package com.onarandombox.MultiverseCore.configuration; - -import com.onarandombox.MultiverseCore.enums.AllowedPortalType; -import org.bukkit.configuration.ConfigurationSection; - -/** - * A {@link AllowedPortalType} config-property. - */ -public class PortalTypeConfigProperty implements MVConfigProperty { - private String name; - private AllowedPortalType value; - private String configNode; - private ConfigurationSection section; - private String help; - - public PortalTypeConfigProperty(ConfigurationSection section, String name, AllowedPortalType defaultValue, String help) { - this(section, name, defaultValue, name, help); - } - - public PortalTypeConfigProperty(ConfigurationSection section, String name, AllowedPortalType defaultValue, String configNode, String help) { - this.name = name; - this.configNode = configNode; - this.section = section; - this.help = help; - this.value = defaultValue; - this.parseValue(this.section.getString(this.configNode, defaultValue.toString())); - } - - /** - * {@inheritDoc} - */ - @Override - public String getName() { - return this.name; - } - - /** - * {@inheritDoc} - */ - @Override - public AllowedPortalType getValue() { - return this.value; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean setValue(AllowedPortalType value) { - if (value == null) { - return false; - } - this.value = value; - this.section.set(configNode, this.value.toString()); - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean parseValue(String value) { - try { - return this.setValue(AllowedPortalType.valueOf(value.toUpperCase())); - } catch (Exception e) { - return false; - } - } - - /** - * {@inheritDoc} - */ - @Override - public String getConfigNode() { - return this.configNode; - } - - /** - * {@inheritDoc} - */ - @Override - public String getHelp() { - return this.help; - } - - @Override - public String toString() { - return value.toString(); - } -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/SpawnLocation.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/SpawnLocation.java new file mode 100644 index 00000000..a09391c1 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/SpawnLocation.java @@ -0,0 +1,98 @@ +package com.onarandombox.MultiverseCore.configuration; + +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.configuration.serialization.ConfigurationSerializable; +import org.bukkit.configuration.serialization.SerializableAs; + +/** + * Just like a regular {@link Location}, however {@code world} is usually {@code null} + * or just a weak reference and it implements {@link ConfigurationSerializable}. + */ +@SerializableAs("MVSpawnLocation") +public class SpawnLocation extends Location implements ConfigurationSerializable { + private Reference worldRef; + + public SpawnLocation(double x, double y, double z) { + super(null, x, y, z); + } + + public SpawnLocation(double x, double y, double z, float yaw, float pitch) { + super(null, x, y, z, yaw, pitch); + } + + public SpawnLocation(Location loc) { + this(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch()); + } + + /** + * {@inheritDoc} + */ + @Override + public World getWorld() { + return (this.worldRef != null) ? this.worldRef.get() : null; + } + + /** + * {@inheritDoc} + */ + @Override + public void setWorld(World world) { + this.worldRef = new WeakReference(world); + } + + /** + * {@inheritDoc} + */ + @Override + public Chunk getChunk() { + if ((this.worldRef != null) && (this.worldRef.get() != null)) + return this.worldRef.get().getChunkAt(this); + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public Block getBlock() { + if ((this.worldRef != null) && (this.worldRef.get() != null)) + return this.worldRef.get().getBlockAt(this); + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public Map serialize() { + Map serialized = new HashMap(5); // SUPPRESS CHECKSTYLE: MagicNumberCheck + serialized.put("x", this.getX()); + serialized.put("y", this.getY()); + serialized.put("z", this.getZ()); + serialized.put("pitch", this.getPitch()); + serialized.put("yaw", this.getYaw()); + return serialized; + } + + /** + * Let Bukkit be able to deserialize this. + * @param args The map. + * @return The deserialized object. + */ + public static SpawnLocation deserialize(Map args) { + double x = ((Number) args.get("x")).doubleValue(); + double y = ((Number) args.get("y")).doubleValue(); + double z = ((Number) args.get("z")).doubleValue(); + float pitch = ((Number) args.get("pitch")).floatValue(); + float yaw = ((Number) args.get("yaw")).floatValue(); + return new SpawnLocation(x, y, z, yaw, pitch); + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/SpawnSettings.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/SpawnSettings.java new file mode 100644 index 00000000..04f2cb71 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/SpawnSettings.java @@ -0,0 +1,50 @@ +package com.onarandombox.MultiverseCore.configuration; + +import java.util.Map; + +import me.main__.util.SerializationConfig.Property; +import me.main__.util.SerializationConfig.SerializationConfig; + +import org.bukkit.configuration.serialization.SerializableAs; + +/** + * Spawning-Settings. + */ +@SerializableAs("MVSpawnSettings") +public class SpawnSettings extends SerializationConfig { + @Property + private SubSpawnSettings animals; + @Property + private SubSpawnSettings monsters; + + public SpawnSettings() { + super(); + } + + public SpawnSettings(Map values) { + super(values); + } + + /** + * {@inheritDoc} + */ + @Override + public void setDefaults() { + animals = new SubSpawnSettings(); + monsters = new SubSpawnSettings(); + } + + /** + * @return the animal-settings + */ + public SubSpawnSettings getAnimalSettings() { + return animals; + } + + /** + * @return the monster-settings + */ + public SubSpawnSettings getMonsterSettings() { + return monsters; + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/StringConfigProperty.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/StringConfigProperty.java deleted file mode 100644 index 948034ce..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/StringConfigProperty.java +++ /dev/null @@ -1,96 +0,0 @@ -/****************************************************************************** - * Multiverse 2 Copyright (c) the Multiverse Team 2011. * - * Multiverse 2 is licensed under the BSD License. * - * For more information please check the README.md file included * - * with this project. * - ******************************************************************************/ - -package com.onarandombox.MultiverseCore.configuration; - -import org.bukkit.configuration.ConfigurationSection; - -/** - * A {@link String} config-property. - */ -public class StringConfigProperty implements MVConfigProperty { - private String name; - private String value; - private String configNode; - private ConfigurationSection section; - private String help; - - public StringConfigProperty(ConfigurationSection section, String name, String defaultValue, String help) { - this(section, name, defaultValue, defaultValue, help); - } - - public StringConfigProperty(ConfigurationSection section, String name, String defaultValue, String configNode, String help) { - this.name = name; - this.configNode = configNode; - this.section = section; - this.help = help; - this.value = defaultValue; - this.parseValue(this.section.getString(this.configNode, defaultValue)); - } - - /** - * {@inheritDoc} - */ - @Override - public String getName() { - return this.name; - } - - /** - * {@inheritDoc} - */ - @Override - public String getValue() { - return this.value; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean parseValue(String value) { - if (value == null) { - return false; - } - this.setValue(value); - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public String getConfigNode() { - return this.configNode; - } - - /** - * {@inheritDoc} - */ - @Override - public String getHelp() { - return this.help; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean setValue(String value) { - if (value == null) { - return false; - } - this.value = value; - this.section.set(configNode, this.value); - return true; - } - - @Override - public String toString() { - return value; - } -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/SubSpawnSettings.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/SubSpawnSettings.java new file mode 100644 index 00000000..d66bd133 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/SubSpawnSettings.java @@ -0,0 +1,59 @@ +package com.onarandombox.MultiverseCore.configuration; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import me.main__.util.SerializationConfig.Property; +import me.main__.util.SerializationConfig.SerializationConfig; + +import org.bukkit.configuration.serialization.SerializableAs; + +/** + * SpawnSubSettings. + */ +@SerializableAs("MVSpawnSubSettings") +public class SubSpawnSettings extends SerializationConfig { + @Property + private boolean spawn; + @Property + private List exceptions; + + public SubSpawnSettings() { + super(); + } + + public SubSpawnSettings(Map values) { + super(values); + } + + /** + * {@inheritDoc} + */ + @Override + public void setDefaults() { + spawn = true; + exceptions = new ArrayList(); + } + + /** + * @return spawn + */ + public boolean doSpawn() { + return spawn; + } + + /** + * @param spawn The new value. + */ + public void setSpawn(boolean spawn) { + this.spawn = spawn; + } + + /** + * @return the exceptions + */ + public List getExceptions() { + return exceptions; + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/WorldPropertyValidator.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/WorldPropertyValidator.java new file mode 100644 index 00000000..b051eabd --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/WorldPropertyValidator.java @@ -0,0 +1,27 @@ +package com.onarandombox.MultiverseCore.configuration; + +import org.bukkit.Bukkit; + +import com.onarandombox.MultiverseCore.MVWorld; +import com.onarandombox.MultiverseCore.event.MVWorldPropertyChangeEvent; + +import me.main__.util.SerializationConfig.ChangeDeniedException; +import me.main__.util.SerializationConfig.ObjectUsingValidator; + +/** + * Validates world-property-changes. + * @param The type of the property that should be validated. + */ +public class WorldPropertyValidator extends ObjectUsingValidator { + /** + * {@inheritDoc} + */ + @Override + public T validateChange(String property, T newValue, T oldValue, MVWorld object) throws ChangeDeniedException { + MVWorldPropertyChangeEvent event = new MVWorldPropertyChangeEvent(object, null, property, newValue); + Bukkit.getPluginManager().callEvent(event); + if (event.isCancelled()) + throw new ChangeDeniedException(); + return event.getTheNewValue(); + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/destination/BedDestination.java b/src/main/java/com/onarandombox/MultiverseCore/destination/BedDestination.java index 42bc8c56..5b73d0a9 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/destination/BedDestination.java +++ b/src/main/java/com/onarandombox/MultiverseCore/destination/BedDestination.java @@ -7,7 +7,9 @@ package com.onarandombox.MultiverseCore.destination; +import com.onarandombox.MultiverseCore.MultiverseCore; import com.onarandombox.MultiverseCore.api.MVDestination; +import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; @@ -21,6 +23,7 @@ public class BedDestination implements MVDestination { private boolean isValid; private Location knownBedLoc; + private MultiverseCore plugin; /** * {@inheritDoc} @@ -46,7 +49,10 @@ public class BedDestination implements MVDestination { @Override public Location getLocation(Entity entity) { if (entity instanceof Player) { - this.knownBedLoc = ((Player) entity).getBedSpawnLocation(); + this.knownBedLoc = this.plugin.getBlockSafety().getSafeBedSpawn(((Player) entity).getBedSpawnLocation()); + if (this.knownBedLoc == null) { + ((Player) entity).sendMessage("Your bed was " + ChatColor.RED + "invalid or blocked" + ChatColor.RESET + ". Sorry."); + } return this.knownBedLoc; } return null; @@ -65,7 +71,7 @@ public class BedDestination implements MVDestination { */ @Override public void setDestination(JavaPlugin plugin, String destination) { - // Not needed. + this.plugin = (MultiverseCore) plugin; } /** diff --git a/src/main/java/com/onarandombox/MultiverseCore/enums/EnglishChatColor.java b/src/main/java/com/onarandombox/MultiverseCore/enums/EnglishChatColor.java index 4f3d015a..87121a55 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/enums/EnglishChatColor.java +++ b/src/main/java/com/onarandombox/MultiverseCore/enums/EnglishChatColor.java @@ -11,49 +11,33 @@ import org.bukkit.ChatColor; /** * A regular {@link ChatColor} represented by an english string. + * @see ChatColor */ public enum EnglishChatColor { - /* - * I know. this is quite ugly. - */ - /** AQUA. */ - AQUA("AQUA", ChatColor.AQUA), - /** BLACK. */ - BLACK("BLACK", ChatColor.BLACK), - /** BLUE. */ - BLUE("BLUE", ChatColor.BLUE), - /** DARKAQUA. */ - DARKAQUA("DARKAQUA", ChatColor.DARK_AQUA), - /** DARKBLUE. */ - DARKBLUE("DARKBLUE", ChatColor.DARK_BLUE), - /** DARKGRAY. */ - DARKGRAY("DARKGRAY", ChatColor.DARK_GRAY), - /** DARKGREEN. */ - DARKGREEN("DARKGREEN", ChatColor.DARK_GREEN), - /** DARKPURPLE. */ - DARKPURPLE("DARKPURPLE", ChatColor.DARK_PURPLE), - /** DARKRED. */ - DARKRED("DARKRED", ChatColor.DARK_RED), - /** GOLD. */ - GOLD("GOLD", ChatColor.GOLD), - /** GRAY. */ - GRAY("GRAY", ChatColor.GRAY), - /** GREEN. */ - GREEN("GREEN", ChatColor.GREEN), - /** LIGHTPURPLE. */ - LIGHTPURPLE("LIGHTPURPLE", ChatColor.LIGHT_PURPLE), - /** RED. */ - RED("RED", ChatColor.RED), - /** YELLOW. */ - YELLOW("YELLOW", ChatColor.YELLOW), - /** WHITE. */ - WHITE("WHITE", ChatColor.WHITE); - private ChatColor color; - private String text; + // BEGIN CHECKSTYLE-SUPPRESSION: JavadocVariable + AQUA(ChatColor.AQUA), + BLACK(ChatColor.BLACK), + BLUE(ChatColor.BLUE), + DARKAQUA(ChatColor.DARK_AQUA), + DARKBLUE(ChatColor.DARK_BLUE), + DARKGRAY(ChatColor.DARK_GRAY), + DARKGREEN(ChatColor.DARK_GREEN), + DARKPURPLE(ChatColor.DARK_PURPLE), + DARKRED(ChatColor.DARK_RED), + GOLD(ChatColor.GOLD), + GRAY(ChatColor.GRAY), + GREEN(ChatColor.GREEN), + LIGHTPURPLE(ChatColor.LIGHT_PURPLE), + RED(ChatColor.RED), + YELLOW(ChatColor.YELLOW), + WHITE(ChatColor.WHITE); + // END CHECKSTYLE-SUPPRESSION: JavadocVariable - EnglishChatColor(String name, ChatColor color) { + private final ChatColor color; + //private final String text; + + EnglishChatColor(ChatColor color) { this.color = color; - this.text = name; } /** @@ -61,7 +45,7 @@ public enum EnglishChatColor { * @return The text. */ public String getText() { - return this.text; + return this.name(); } /** @@ -92,11 +76,20 @@ public enum EnglishChatColor { public static EnglishChatColor fromString(String text) { if (text != null) { for (EnglishChatColor c : EnglishChatColor.values()) { - if (text.equalsIgnoreCase(c.text)) { + if (text.equalsIgnoreCase(c.name())) { return c; } } } return null; } + + /** + * Looks if the given-color name is a valid color. + * @param aliasColor A color-name. + * @return True if the name is a valid color, false if it isn't. + */ + public static boolean isValidAliasColor(String aliasColor) { + return (EnglishChatColor.fromString(aliasColor) != null); + } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/enums/EnglishChatStyle.java b/src/main/java/com/onarandombox/MultiverseCore/enums/EnglishChatStyle.java new file mode 100644 index 00000000..e1bdf1ca --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/enums/EnglishChatStyle.java @@ -0,0 +1,49 @@ +package com.onarandombox.MultiverseCore.enums; + +import org.bukkit.ChatColor; + +/** + * A regular {@link ChatColor} represented by an english string. + * @see ChatColor + */ +public enum EnglishChatStyle { + // BEGIN CHECKSTYLE-SUPPRESSION: JavadocVariable + /** No style. */ + NORMAL(null), + MAGIC(ChatColor.MAGIC), + BOLD(ChatColor.BOLD), + STRIKETHROUGH(ChatColor.STRIKETHROUGH), + UNDERLINE(ChatColor.UNDERLINE), + ITALIC(ChatColor.ITALIC); + // END CHECKSTYLE-SUPPRESSION: JavadocVariable + + private final ChatColor color; + + EnglishChatStyle(ChatColor color) { + this.color = color; + } + + /** + * Gets the color. + * @return The color as {@link ChatColor}. + */ + public ChatColor getColor() { + return color; + } + + /** + * Constructs an {@link EnglishChatStyle} from a {@link String}. + * @param text The {@link String}. + * @return The {@link EnglishChatStyle}. + */ + public static EnglishChatStyle fromString(String text) { + if (text != null) { + for (EnglishChatStyle c : EnglishChatStyle.values()) { + if (text.equalsIgnoreCase(c.name())) { + return c; + } + } + } + return null; + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/event/MVPlayerTouchedPortalEvent.java b/src/main/java/com/onarandombox/MultiverseCore/event/MVPlayerTouchedPortalEvent.java index a4772cb0..56ec89e3 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/event/MVPlayerTouchedPortalEvent.java +++ b/src/main/java/com/onarandombox/MultiverseCore/event/MVPlayerTouchedPortalEvent.java @@ -20,6 +20,7 @@ public class MVPlayerTouchedPortalEvent extends Event implements Cancellable { private Player p; private Location l; private boolean isCancelled; + private boolean canUse = true; public MVPlayerTouchedPortalEvent(Player p, Location l) { this.p = p; @@ -60,6 +61,26 @@ public class MVPlayerTouchedPortalEvent extends Event implements Cancellable { return this.p; } + /** + * Gets whether or not the player in this event can use this portal. + * + * @return True if the player can use this portal. + */ + public boolean canUseThisPortal() { + return this.canUse; + } + + /** + * Sets whether or not the player in this event can use this portal. + *

+ * Setting this to false will cause the player to bounce back! + * + * @param canUse Whether or not the user can go through this portal. + */ + public void setCanUseThisPortal(boolean canUse) { + this.canUse = canUse; + } + @Override public boolean isCancelled() { return this.isCancelled; diff --git a/src/main/java/com/onarandombox/MultiverseCore/event/MVWorldPropertyChangeEvent.java b/src/main/java/com/onarandombox/MultiverseCore/event/MVWorldPropertyChangeEvent.java index 1cdd6404..d85e104a 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/event/MVWorldPropertyChangeEvent.java +++ b/src/main/java/com/onarandombox/MultiverseCore/event/MVWorldPropertyChangeEvent.java @@ -19,16 +19,18 @@ import org.bukkit.event.HandlerList; * If it is cancelled, no change will happen. *

* If you want to get the values of the world before the change, query the world. - * If you want to get the value being changed, use getProperty() + * To get the name of the property that was changed, use {@link #getPropertyName()}. + * To get the new value, use {@link #getTheNewValue()}. To change it, use {@link #setTheNewValue(Object)}. + * @param The type of the property that was set. */ -public class MVWorldPropertyChangeEvent extends Event implements Cancellable { +public class MVWorldPropertyChangeEvent extends Event implements Cancellable { private MultiverseWorld world; private CommandSender changer; private boolean isCancelled = false; - private String value; private String name; + private T value; - public MVWorldPropertyChangeEvent(MultiverseWorld world, CommandSender changer, String name, String value) { + public MVWorldPropertyChangeEvent(MultiverseWorld world, CommandSender changer, String name, T value) { this.world = world; this.changer = changer; this.name = name; @@ -64,16 +66,38 @@ public class MVWorldPropertyChangeEvent extends Event implements Cancellable { /** * Gets the new value. * @return The new value. + * @deprecated Use {@link #getTheNewValue()} instead. */ + @Deprecated public String getNewValue() { + return this.value.toString(); + } + + /** + * Gets the new value. + * @return The new value. + */ + public T getTheNewValue() { return this.value; } /** * Sets the new value. + *

+ * This method is only a stub, it'll always throw an {@link UnsupportedOperationException}! * @param value The new new value. + * @deprecated Use {@link #setTheNewValue(Object)} instead. */ + @Deprecated public void setNewValue(String value) { + throw new UnsupportedOperationException(); + } + + /** + * Sets the new value. + * @param value The new value. + */ + public void setTheNewValue(T value) { this.value = value; } @@ -88,6 +112,8 @@ public class MVWorldPropertyChangeEvent extends Event implements Cancellable { /** * Gets the person (or console) who was responsible for the change. + *

+ * This may be null! * * @return The person (or console) who was responsible for the change. */ diff --git a/src/main/java/com/onarandombox/MultiverseCore/exceptions/PropertyDoesNotExistException.java b/src/main/java/com/onarandombox/MultiverseCore/exceptions/PropertyDoesNotExistException.java index fc367342..95a24169 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/exceptions/PropertyDoesNotExistException.java +++ b/src/main/java/com/onarandombox/MultiverseCore/exceptions/PropertyDoesNotExistException.java @@ -14,4 +14,8 @@ public class PropertyDoesNotExistException extends Exception { public PropertyDoesNotExistException(String name) { super(name); } + + public PropertyDoesNotExistException(String name, Throwable cause) { + super(name, cause); + } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/listeners/AsyncChatEvent.java b/src/main/java/com/onarandombox/MultiverseCore/listeners/AsyncChatEvent.java new file mode 100644 index 00000000..38d48bef --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/listeners/AsyncChatEvent.java @@ -0,0 +1,35 @@ +package com.onarandombox.MultiverseCore.listeners; + +import org.bukkit.entity.Player; +import org.bukkit.event.player.AsyncPlayerChatEvent; + +/** + * A wrapper for the {@link AsyncPlayerChatEvent}. + */ +public class AsyncChatEvent implements ChatEvent { + private final AsyncPlayerChatEvent event; + + public AsyncChatEvent(AsyncPlayerChatEvent event) { + this.event = event; + } + + @Override + public boolean isCancelled() { + return event.isCancelled(); + } + + @Override + public String getFormat() { + return event.getFormat(); + } + + @Override + public void setFormat(String s) { + event.setFormat(s); + } + + @Override + public Player getPlayer() { + return event.getPlayer(); + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/listeners/ChatEvent.java b/src/main/java/com/onarandombox/MultiverseCore/listeners/ChatEvent.java new file mode 100644 index 00000000..16cafb81 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/listeners/ChatEvent.java @@ -0,0 +1,29 @@ +package com.onarandombox.MultiverseCore.listeners; + +import org.bukkit.entity.Player; + +/** + * A wrapper for the two chat-events in Bukkit. + */ +public interface ChatEvent { + /** + * @return Whether this event is cancelled. + */ + boolean isCancelled(); + + /** + * @return The format. + */ + String getFormat(); + + /** + * Sets the format. + * @param s The new format. + */ + void setFormat(String s); + + /** + * @return The player. + */ + Player getPlayer(); +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/listeners/MVAsyncPlayerChatListener.java b/src/main/java/com/onarandombox/MultiverseCore/listeners/MVAsyncPlayerChatListener.java new file mode 100644 index 00000000..eae4df20 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/listeners/MVAsyncPlayerChatListener.java @@ -0,0 +1,34 @@ +/****************************************************************************** + * Multiverse 2 Copyright (c) the Multiverse Team 2011. * + * Multiverse 2 is licensed under the BSD License. * + * For more information please check the README.md file included * + * with this project. * + ******************************************************************************/ + +package com.onarandombox.MultiverseCore.listeners; + +import java.util.logging.Level; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.AsyncPlayerChatEvent; + +import com.onarandombox.MultiverseCore.MultiverseCore; + +/** + * Multiverse's {@link org.bukkit.event.Listener} for players. + */ +public class MVAsyncPlayerChatListener extends MVChatListener { + public MVAsyncPlayerChatListener(MultiverseCore plugin, MVPlayerListener playerListener) { + super(plugin, playerListener); + plugin.log(Level.FINE, "Created AsyncPlayerChatEvent listener."); + } + + /** + * This method is called when a player wants to chat. + * @param event The Event that was fired. + */ + @EventHandler + public void playerChat(AsyncPlayerChatEvent event) { + this.playerChat(new AsyncChatEvent(event)); + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/listeners/MVChatListener.java b/src/main/java/com/onarandombox/MultiverseCore/listeners/MVChatListener.java new file mode 100644 index 00000000..9fcd8c70 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/listeners/MVChatListener.java @@ -0,0 +1,52 @@ +package com.onarandombox.MultiverseCore.listeners; + +import com.onarandombox.MultiverseCore.MultiverseCore; +import com.onarandombox.MultiverseCore.api.MVWorldManager; +import com.onarandombox.MultiverseCore.api.MultiverseWorld; +import org.bukkit.event.Listener; + +/** + * Multiverse's {@link org.bukkit.event.Listener} for players. + */ +public abstract class MVChatListener implements Listener { + private final MultiverseCore plugin; + private final MVWorldManager worldManager; + private final MVPlayerListener playerListener; + + public MVChatListener(MultiverseCore plugin, MVPlayerListener playerListener) { + this.plugin = plugin; + this.worldManager = plugin.getMVWorldManager(); + this.playerListener = playerListener; + } + + /** + * This handles a {@link ChatEvent}. + * @param event The {@link ChatEvent}. + */ + public void playerChat(ChatEvent event) { + if (event.isCancelled()) { + return; + } + // Check whether the Server is set to prefix the chat with the World name. + // If not we do nothing, if so we need to check if the World has an Alias. + if (plugin.getMVConfig().getPrefixChat()) { + String world = playerListener.getPlayerWorld().get(event.getPlayer().getName()); + if (world == null) { + world = event.getPlayer().getWorld().getName(); + playerListener.getPlayerWorld().put(event.getPlayer().getName(), world); + } + String prefix = ""; + // If we're not a MV world, don't do anything + if (!this.worldManager.isMVWorld(world)) { + return; + } + MultiverseWorld mvworld = this.worldManager.getMVWorld(world); + if (mvworld.isHidden()) { + return; + } + prefix = mvworld.getColoredWorldString(); + String format = event.getFormat(); + event.setFormat("[" + prefix + "]" + format); + } + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/listeners/MVEntityListener.java b/src/main/java/com/onarandombox/MultiverseCore/listeners/MVEntityListener.java index e4f060d9..4aa34ccd 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/listeners/MVEntityListener.java +++ b/src/main/java/com/onarandombox/MultiverseCore/listeners/MVEntityListener.java @@ -11,13 +11,8 @@ import com.onarandombox.MultiverseCore.MultiverseCore; import com.onarandombox.MultiverseCore.api.MVWorldManager; import com.onarandombox.MultiverseCore.api.MultiverseWorld; import org.bukkit.World; -import org.bukkit.entity.Animals; import org.bukkit.entity.EntityType; -import org.bukkit.entity.Ghast; -import org.bukkit.entity.Monster; import org.bukkit.entity.Player; -import org.bukkit.entity.Slime; -import org.bukkit.entity.Squid; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.CreatureSpawnEvent; @@ -26,14 +21,12 @@ import org.bukkit.event.entity.EntityRegainHealthEvent; import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; import org.bukkit.event.entity.FoodLevelChangeEvent; -import java.util.List; import java.util.logging.Level; /** * Multiverse's Entity {@link Listener}. */ public class MVEntityListener implements Listener { - private MultiverseCore plugin; private MVWorldManager worldManager; @@ -87,7 +80,8 @@ public class MVEntityListener implements Listener { public void creatureSpawn(CreatureSpawnEvent event) { // Check to see if the Creature is spawned by a plugin, we don't want to prevent this behaviour. // TODO: Allow the egg thing to be a config param. Doubt this will be per world; seems silly. - if (event.getSpawnReason() == SpawnReason.CUSTOM || event.getSpawnReason() == SpawnReason.SPAWNER_EGG) { + if (event.getSpawnReason() == SpawnReason.CUSTOM || event.getSpawnReason() == SpawnReason.SPAWNER_EGG + || event.getSpawnReason() == SpawnReason.BREEDING) { return; } @@ -100,53 +94,16 @@ public class MVEntityListener implements Listener { return; EntityType type = event.getEntityType(); - MultiverseWorld mvworld = this.worldManager.getMVWorld(world.getName()); - /** * Handle people with non-standard animals: ie a patched craftbukkit. */ - if (type == null) { + if (type == null || type.getName() == null) { this.plugin.log(Level.FINER, "Found a null typed creature."); return; } - /** - * Animal Handling - */ - if (event.getEntity() instanceof Animals || event.getEntity() instanceof Squid) { - event.setCancelled(shouldWeKillThisCreature(mvworld.getAnimalList(), mvworld.canAnimalsSpawn(), type.getName().toUpperCase())); - } - /** - * Monster Handling - */ - if (event.getEntity() instanceof Monster || event.getEntity() instanceof Ghast || event.getEntity() instanceof Slime) { - event.setCancelled(shouldWeKillThisCreature(mvworld.getMonsterList(), mvworld.canMonstersSpawn(), type.getName().toUpperCase())); - } - } - - private static boolean shouldWeKillThisCreature(List creatureList, boolean allowCreatureSpawning, String creature) { - if (creatureList.isEmpty() && allowCreatureSpawning) { - // 1. There are no exceptions and animals are allowed. Save it. - return false; - } else if (creatureList.isEmpty()) { - // 2. There are no exceptions and animals are NOT allowed. Kill it. - return true; - } else if (creatureList.contains(creature.toUpperCase()) && allowCreatureSpawning) { - // 3. There ARE exceptions and animals ARE allowed. Kill it. - return true; - } else if (!creatureList.contains(creature.toUpperCase()) && allowCreatureSpawning) { - // 4. There ARE exceptions and animals ARE NOT allowed. SAVE it. - return false; - } else if (creatureList.contains(creature.toUpperCase()) && !allowCreatureSpawning) { - // 5. No animals are allowed to be spawned, BUT this one can stay... - return false; - } else if (!creatureList.contains(creature.toUpperCase()) && !allowCreatureSpawning) { - // 6. Animals are NOT allowed to spawn, and this creature is not in the save list... KILL IT - return true; - } else { - // This code should NEVER execute. I just left the verbose conditions in right now. - throw new UnsupportedOperationException(); - } + MultiverseWorld mvworld = this.worldManager.getMVWorld(world.getName()); + event.setCancelled(this.plugin.getMVWorldManager().getTheWorldPurger().shouldWeKillThisCreature(mvworld, event.getEntity())); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/listeners/MVPlayerChatListener.java b/src/main/java/com/onarandombox/MultiverseCore/listeners/MVPlayerChatListener.java new file mode 100644 index 00000000..fc110522 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/listeners/MVPlayerChatListener.java @@ -0,0 +1,35 @@ +/****************************************************************************** + * Multiverse 2 Copyright (c) the Multiverse Team 2011. * + * Multiverse 2 is licensed under the BSD License. * + * For more information please check the README.md file included * + * with this project. * + ******************************************************************************/ + +package com.onarandombox.MultiverseCore.listeners; + +import java.util.logging.Level; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerChatEvent; + +import com.onarandombox.MultiverseCore.MultiverseCore; + +/** + * Multiverse's {@link org.bukkit.event.Listener} for players. + */ +@SuppressWarnings("deprecation") // this exists only for downwards compatibility +public class MVPlayerChatListener extends MVChatListener { + public MVPlayerChatListener(MultiverseCore plugin, MVPlayerListener playerListener) { + super(plugin, playerListener); + plugin.log(Level.FINE, "Registered PlayerChatEvent listener."); + } + + /** + * This method is called when a player wants to chat. + * @param event The Event that was fired. + */ + @EventHandler + public void playerChat(PlayerChatEvent event) { + this.playerChat(new NormalChatEvent(event)); + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/listeners/MVPlayerListener.java b/src/main/java/com/onarandombox/MultiverseCore/listeners/MVPlayerListener.java index e83fe783..632b5b36 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/listeners/MVPlayerListener.java +++ b/src/main/java/com/onarandombox/MultiverseCore/listeners/MVPlayerListener.java @@ -7,6 +7,7 @@ package com.onarandombox.MultiverseCore.listeners; +import com.dumptruckman.minecraft.util.Logging; import com.onarandombox.MultiverseCore.MultiverseCore; import com.onarandombox.MultiverseCore.api.MVWorldManager; import com.onarandombox.MultiverseCore.api.MultiverseWorld; @@ -21,55 +22,37 @@ 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.PlayerChatEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerPortalEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerRespawnEvent; import org.bukkit.event.player.PlayerTeleportEvent; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; /** * Multiverse's {@link Listener} for players. */ public class MVPlayerListener implements Listener { - private MultiverseCore plugin; - private MVWorldManager worldManager; - private PermissionTools pt; + private final MultiverseCore plugin; + private final MVWorldManager worldManager; + private final PermissionTools pt; + private final Map playerWorld = new ConcurrentHashMap(); public MVPlayerListener(MultiverseCore plugin) { this.plugin = plugin; worldManager = plugin.getMVWorldManager(); pt = new PermissionTools(plugin); } + /** - * This method is called when a player wants to chat. - * @param event The Event that was fired. + * @return the playerWorld-map */ - @EventHandler - public void playerChat(PlayerChatEvent event) { - if (event.isCancelled()) { - return; - } - // Check whether the Server is set to prefix the chat with the World name. - // If not we do nothing, if so we need to check if the World has an Alias. - if (plugin.getMVConfig().getPrefixChat()) { - String world = event.getPlayer().getWorld().getName(); - String prefix = ""; - // If we're not a MV world, don't do anything - if (!this.worldManager.isMVWorld(world)) { - return; - } - MultiverseWorld mvworld = this.worldManager.getMVWorld(world); - if (mvworld.isHidden()) { - return; - } - prefix = mvworld.getColoredWorldString(); - String format = event.getFormat(); - event.setFormat("[" + prefix + "]" + format); - } + public Map getPlayerWorld() { + return playerWorld; } /** @@ -128,8 +111,8 @@ public class MVPlayerListener implements Listener { if (!p.hasPlayedBefore()) { this.plugin.log(Level.FINER, "Player joined for the FIRST time!"); if (plugin.getMVConfig().getFirstSpawnOverride()) { - this.plugin.log(Level.FINE, String.format("Moving NEW player to(firstspawnoverride): %s", - worldManager.getFirstSpawnWorld().getSpawnLocation())); + this.plugin.log(Level.FINE, "Moving NEW player to(firstspawnoverride): " + + worldManager.getFirstSpawnWorld().getSpawnLocation()); this.sendPlayerToDefaultWorld(p); } return; @@ -143,6 +126,7 @@ public class MVPlayerListener implements Listener { } // Handle the Players GameMode setting for the new world. this.handleGameMode(event.getPlayer(), event.getPlayer().getWorld()); + playerWorld.put(p.getName(), p.getWorld().getName()); } /** @@ -153,6 +137,7 @@ public class MVPlayerListener implements Listener { public void playerChangedWorld(PlayerChangedWorldEvent event) { // Permissions now determine whether or not to handle a gamemode. this.handleGameMode(event.getPlayer(), event.getPlayer().getWorld()); + playerWorld.put(event.getPlayer().getName(), event.getPlayer().getWorld().getName()); } /** @@ -170,9 +155,8 @@ public class MVPlayerListener implements Listener { */ @EventHandler(priority = EventPriority.HIGHEST) public void playerTeleport(PlayerTeleportEvent event) { - this.plugin.log(Level.FINER, String.format( - "Got teleport event for player '%s' with cause '%s'", - event.getPlayer().getName(), event.getCause())); + this.plugin.log(Level.FINER, "Got teleport event for player '" + + event.getPlayer().getName() + "' with cause '" + event.getCause() + "'"); if (event.isCancelled()) { return; } @@ -187,14 +171,15 @@ public class MVPlayerListener implements Listener { teleporter = this.plugin.getServer().getPlayer(teleporterName); } } - this.plugin.log(Level.FINER, String.format("Inferred sender '%s' from name '%s', fetched from name '%s'", - teleporter, teleporterName, teleportee.getName())); + this.plugin.log(Level.FINER, "Inferred sender '" + teleporter + "' from name '" + + teleporterName + "', fetched from name '" + teleportee.getName() + "'"); MultiverseWorld fromWorld = this.worldManager.getMVWorld(event.getFrom().getWorld().getName()); MultiverseWorld toWorld = this.worldManager.getMVWorld(event.getTo().getWorld().getName()); + if (fromWorld == null || toWorld == null) + return; if (event.getFrom().getWorld().equals(event.getTo().getWorld())) { // The player is Teleporting to the same world. - this.plugin.log(Level.FINER, String.format("Player '%s' is teleporting to the same world.", - teleportee.getName())); + this.plugin.log(Level.FINER, "Player '" + teleportee.getName() + "' is teleporting to the same world."); this.stateSuccess(teleportee.getName(), toWorld.getAlias()); return; } @@ -202,33 +187,31 @@ public class MVPlayerListener implements Listener { // Charge the teleporter event.setCancelled(!pt.playerHasMoneyToEnter(fromWorld, toWorld, teleporter, teleportee, true)); if (event.isCancelled() && teleporter != null) { - this.plugin.log(Level.FINE, String.format( - "Player '%s' was DENIED ACCESS to '%s' because '%s' don't have the FUNDS required to enter it.", - teleportee.getName(), toWorld.getAlias(), teleporter.getName())); - + this.plugin.log(Level.FINE, "Player '" + teleportee.getName() + + "' was DENIED ACCESS to '" + toWorld.getAlias() + + "' because '" + teleporter.getName() + + "' don't have the FUNDS required to enter it."); return; } if (plugin.getMVConfig().getEnforceAccess()) { event.setCancelled(!pt.playerCanGoFromTo(fromWorld, toWorld, teleporter, teleportee)); if (event.isCancelled() && teleporter != null) { - this.plugin.log(Level.FINE, String.format( - "Player '%s' was DENIED ACCESS to '%s' because '%s' don't have: multiverse.access.%s", - teleportee.getName(), toWorld.getAlias(), teleporter.getName(), - event.getTo().getWorld().getName())); + this.plugin.log(Level.FINE, "Player '" + teleportee.getName() + + "' was DENIED ACCESS to '" + toWorld.getAlias() + + "' because '" + teleporter.getName() + + "' don't have: multiverse.access." + event.getTo().getWorld().getName()); } else { this.stateSuccess(teleportee.getName(), toWorld.getAlias()); } } else { - this.plugin.log(Level.FINE, String.format( - "Player '%s' was allowed to go to '%s' because enforceaccess is off.", - teleportee.getName(), toWorld.getAlias())); + this.plugin.log(Level.FINE, "Player '" + teleportee.getName() + + "' was allowed to go to '" + toWorld.getAlias() + "' because enforceaccess is off."); } } private void stateSuccess(String playerName, String worldName) { - this.plugin.log(Level.FINE, String.format( - "MV-Core is allowing Player '%s' to go to '%s'.", - playerName, worldName)); + this.plugin.log(Level.FINE, "MV-Core is allowing Player '" + playerName + + "' to go to '" + worldName + "'."); } /** @@ -238,7 +221,6 @@ public class MVPlayerListener implements Listener { */ @EventHandler(priority = EventPriority.LOWEST) public void playerPortalCheck(PlayerPortalEvent event) { - this.plugin.log(Level.FINE, "CALLING CORE-ADJUST!!!"); if (event.isCancelled() || event.getFrom() == null) { return; } @@ -280,19 +262,22 @@ public class MVPlayerListener implements Listener { } event.setCancelled(!pt.playerHasMoneyToEnter(fromWorld, toWorld, event.getPlayer(), event.getPlayer(), true)); if (event.isCancelled()) { - this.plugin.log(Level.FINE, String.format("Player '%s' was DENIED ACCESS to '%s' because they don't have the FUNDS required to enter.", - event.getPlayer().getName(), event.getTo().getWorld().getName())); + this.plugin.log(Level.FINE, "Player '" + event.getPlayer().getName() + + "' was DENIED ACCESS to '" + event.getTo().getWorld().getName() + + "' because they don't have the FUNDS required to enter."); return; } if (plugin.getMVConfig().getEnforceAccess()) { event.setCancelled(!pt.playerCanGoFromTo(fromWorld, toWorld, event.getPlayer(), event.getPlayer())); if (event.isCancelled()) { - this.plugin.log(Level.FINE, String.format("Player '%s' was DENIED ACCESS to '%s' because they don't have: multiverse.access.%s", - event.getPlayer().getName(), event.getTo().getWorld().getName(), event.getTo().getWorld().getName())); + this.plugin.log(Level.FINE, "Player '" + event.getPlayer().getName() + + "' was DENIED ACCESS to '" + event.getTo().getWorld().getName() + + "' because they don't have: multiverse.access." + event.getTo().getWorld().getName()); } } else { - this.plugin.log(Level.FINE, String.format("Player '%s' was allowed to go to '%s' because enforceaccess is off.", - event.getPlayer().getName(), event.getTo().getWorld().getName())); + this.plugin.log(Level.FINE, "Player '" + event.getPlayer().getName() + + "' was allowed to go to '" + event.getTo().getWorld().getName() + + "' because enforceaccess is off."); } } @@ -300,6 +285,7 @@ public class MVPlayerListener implements Listener { // Remove the player 1 tick after the login. I'm sure there's GOT to be a better way to do this... this.plugin.getServer().getScheduler().scheduleSyncDelayedTask(this.plugin, new Runnable() { + @Override public void run() { player.teleport(plugin.getMVWorldManager().getFirstSpawnWorld().getSpawnLocation()); } @@ -312,6 +298,9 @@ public class MVPlayerListener implements Listener { MultiverseWorld mvWorld = this.worldManager.getMVWorld(world.getName()); if (mvWorld != null) { this.handleGameMode(player, mvWorld); + } else { + this.plugin.log(Level.FINER, "Not handling gamemode for world '" + world.getName() + + "' not managed by Multiverse."); } } @@ -326,24 +315,21 @@ public class MVPlayerListener implements Listener { if (!this.pt.playerCanIgnoreGameModeRestriction(world, player)) { this.plugin.getServer().getScheduler().scheduleSyncDelayedTask(this.plugin, new Runnable() { + @Override public void run() { // Check that the player is in the new world and they haven't been teleported elsewhere or the event cancelled. if (player.getWorld() == world.getCBWorld()) { - MultiverseCore.staticLog(Level.FINE, String.format( - "Handling gamemode for player: %s, Changing to %s", - player.getName(), world.getGameMode().toString())); - MultiverseCore.staticLog(Level.FINEST, "From World: " + player.getWorld()); - MultiverseCore.staticLog(Level.FINEST, "To World: " + world); + Logging.fine("Handling gamemode for player: %s, Changing to %s", player.getName(), world.getGameMode().toString()); + Logging.finest("From World: %s", player.getWorld()); + Logging.finest("To World: %s", world); player.setGameMode(world.getGameMode()); } else { - MultiverseCore.staticLog(Level.FINE, - String.format("The gamemode was NOT changed for player '%s' because he is now in world '%s' instead of world '%s'", - player.getName(), player.getWorld().getName(), world.getName())); + Logging.fine("The gamemode was NOT changed for player '%s' because he is now in world '%s' instead of world '%s'", player.getName(), player.getWorld().getName(), world.getName()); } } }, 1L); } else { - this.plugin.log(Level.FINE, String.format("Player: %s is IMMUNE to gamemode changes!", player.getName())); + this.plugin.log(Level.FINE, "Player: " + player.getName() + " is IMMUNE to gamemode changes!"); } } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/listeners/MVPluginListener.java b/src/main/java/com/onarandombox/MultiverseCore/listeners/MVPluginListener.java index 4f6986f8..296fa156 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/listeners/MVPluginListener.java +++ b/src/main/java/com/onarandombox/MultiverseCore/listeners/MVPluginListener.java @@ -16,7 +16,6 @@ import org.bukkit.event.server.PluginDisableEvent; import org.bukkit.event.server.PluginEnableEvent; import java.util.Arrays; -import java.util.logging.Level; /** * Multiverse's Plugin {@link Listener}. @@ -35,11 +34,16 @@ public class MVPluginListener implements Listener { */ @EventHandler(priority = EventPriority.MONITOR) public void pluginEnable(PluginEnableEvent event) { + if (plugin.getVaultEconomy() != null) { + // Don't hook 2 economy plugins. + return; + } // Let AllPay handle all econ plugin loadings, only go for econ plugins we support if (Arrays.asList(AllPay.getValidEconPlugins()).contains(event.getPlugin().getDescription().getName())) { this.plugin.setBank(this.plugin.getBanker().loadEconPlugin()); } + /* if (event.getPlugin().getDescription().getName().equals("Spout")) { this.plugin.setSpout(); this.plugin.log(Level.INFO, "Spout integration enabled."); @@ -49,6 +53,7 @@ public class MVPluginListener implements Listener { this.plugin.setDynmap(); this.plugin.log(Level.INFO, "Dynmap integration enabled."); } + */ } /** diff --git a/src/main/java/com/onarandombox/MultiverseCore/listeners/NormalChatEvent.java b/src/main/java/com/onarandombox/MultiverseCore/listeners/NormalChatEvent.java new file mode 100644 index 00000000..a712c627 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/listeners/NormalChatEvent.java @@ -0,0 +1,37 @@ +package com.onarandombox.MultiverseCore.listeners; + +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerChatEvent; + +/** + * A wrapper for the {@link PlayerChatEvent}. + * @deprecated This is deprecated like the {@link PlayerChatEvent}. + */ +@Deprecated +public class NormalChatEvent implements ChatEvent { + private final PlayerChatEvent event; + + public NormalChatEvent(PlayerChatEvent event) { + this.event = event; + } + + @Override + public boolean isCancelled() { + return event.isCancelled(); + } + + @Override + public String getFormat() { + return event.getFormat(); + } + + @Override + public void setFormat(String s) { + event.setFormat(s); + } + + @Override + public Player getPlayer() { + return event.getPlayer(); + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/AnchorManager.java b/src/main/java/com/onarandombox/MultiverseCore/utils/AnchorManager.java index c06c7da8..ddbfc304 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/AnchorManager.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/AnchorManager.java @@ -7,6 +7,7 @@ package com.onarandombox.MultiverseCore.utils; +import com.dumptruckman.minecraft.util.Logging; import com.onarandombox.MultiverseCore.MultiverseCore; import org.bukkit.Location; import org.bukkit.configuration.ConfigurationSection; @@ -16,7 +17,6 @@ import org.bukkit.entity.Player; import java.io.File; import java.io.IOException; - import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -50,10 +50,10 @@ public class AnchorManager { //world:x,y,z:pitch:yaw Location anchorLocation = plugin.getLocationManipulation().stringToLocation(anchorsSection.getString(key, "")); if (anchorLocation != null) { - MultiverseCore.staticLog(Level.INFO, "Loading anchor: '" + key + "'..."); + Logging.info("Loading anchor: '%s'...", key); this.anchors.put(key, anchorLocation); } else { - MultiverseCore.staticLog(Level.WARNING, "The location for anchor '" + key + "' is INVALID."); + Logging.warning("The location for anchor '%s' is INVALID.", key); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/BlockSafety.java b/src/main/java/com/onarandombox/MultiverseCore/utils/BlockSafety.java index f5aca91e..d746951d 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/BlockSafety.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/BlockSafety.java @@ -7,15 +7,13 @@ package com.onarandombox.MultiverseCore.utils; -import com.onarandombox.MultiverseCore.MultiverseCore; +import com.dumptruckman.minecraft.util.Logging; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.entity.Minecart; import org.bukkit.entity.Vehicle; -import java.util.logging.Level; - /** * Used to determine block/location-related facts. * @@ -75,28 +73,28 @@ public class BlockSafety { if (this.isSolidBlock(world.getBlockAt(actual).getType()) || this.isSolidBlock(upOne.getBlock().getType())) { - MultiverseCore.staticLog(Level.FINER, "Error Here (Actual)? (" - + actual.getBlock().getType() + ")[" + this.isSolidBlock(actual.getBlock().getType()) + "]"); - MultiverseCore.staticLog(Level.FINER, "Error Here (upOne)? (" - + upOne.getBlock().getType() + ")[" + this.isSolidBlock(upOne.getBlock().getType()) + "]"); + Logging.finer("Error Here (Actual)? (%s)[%s]", actual.getBlock().getType(), + this.isSolidBlock(actual.getBlock().getType())); + Logging.finer("Error Here (upOne)? (%s)[%s]", upOne.getBlock().getType(), + this.isSolidBlock(upOne.getBlock().getType())); return false; } if (downOne.getBlock().getType() == Material.LAVA || downOne.getBlock().getType() == Material.STATIONARY_LAVA) { - MultiverseCore.staticLog(Level.FINER, "Error Here (downOne)? (" - + downOne.getBlock().getType() + ")[" + this.isSolidBlock(downOne.getBlock().getType()) + "]"); + Logging.finer("Error Here (downOne)? (%s)[%s]", downOne.getBlock().getType(), + this.isSolidBlock(downOne.getBlock().getType())); return false; } if (downOne.getBlock().getType() == Material.FIRE) { - MultiverseCore.staticLog(Level.FINER, "There's fire below! (" - + actual.getBlock().getType() + ")[" + this.isSolidBlock(actual.getBlock().getType()) + "]"); + Logging.finer("There's fire below! (%s)[%s]", actual.getBlock().getType(), + this.isSolidBlock(actual.getBlock().getType())); return false; } if (isBlockAboveAir(actual)) { - MultiverseCore.staticLog(Level.FINER, "Is block above air [" + isBlockAboveAir(actual) + "]"); - MultiverseCore.staticLog(Level.FINER, "Has 2 blocks of water below [" + this.hasTwoBlocksofWaterBelow(actual) + "]"); + Logging.finer("Is block above air [%s]", isBlockAboveAir(actual)); + Logging.finer("Has 2 blocks of water below [%s]", this.hasTwoBlocksofWaterBelow(actual)); return this.hasTwoBlocksofWaterBelow(actual); } return true; diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/DebugLog.java b/src/main/java/com/onarandombox/MultiverseCore/utils/DebugLog.java index 8cb9a53c..7f52111e 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/DebugLog.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/DebugLog.java @@ -7,10 +7,14 @@ package com.onarandombox.MultiverseCore.utils; +import com.onarandombox.MultiverseCore.MultiverseCoreConfiguration; + import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.List; import java.util.logging.FileHandler; import java.util.logging.Formatter; import java.util.logging.Handler; @@ -21,10 +25,10 @@ import java.util.logging.Logger; /** * The Multiverse debug-logger. */ -public class DebugLog { - +public class DebugLog extends Logger { private FileHandler fh; - private Logger log; + private Logger standardLog = null; + private String prefix = "[MVCore-Debug] "; /** * Creates a new debug logger. @@ -33,16 +37,16 @@ public class DebugLog { * @param file The file to log to. */ public DebugLog(String logger, String file) { - this.log = Logger.getLogger(logger); - + super(logger, null); try { this.fh = new FileHandler(file, true); - this.log.setUseParentHandlers(false); - for (Handler handler : this.log.getHandlers()) { - this.log.removeHandler(handler); + this.setUseParentHandlers(false); + List toRemove = Arrays.asList(this.getHandlers()); + for (Handler handler : toRemove) { + this.removeHandler(handler); } - this.log.addHandler(this.fh); - this.log.setLevel(Level.ALL); + this.addHandler(this.fh); + this.setLevel(Level.ALL); this.fh.setFormatter(new LogFormatter()); } catch (SecurityException e) { e.printStackTrace(); @@ -51,14 +55,39 @@ public class DebugLog { } } + /** + * Sets the log-tag. + * @param tag The new tag. + */ + public void setTag(String tag) { + this.prefix = tag + " "; + } + + /** + * Specifies the logger to use to send debug messages to as the debug logger itself only sends messages to a file. + * + * @param logger Logger to send debug messages to. + */ + public void setStandardLogger(Logger logger) { + this.standardLog = logger; + } + /** * Log a message at a certain level. * * @param level The log-{@link Level}. * @param msg the message. */ - public void log(Level level, String msg) { - this.log.log(level, msg); + @Override + public void log(final Level level, final String msg) { + if (MultiverseCoreConfiguration.isSet() && MultiverseCoreConfiguration.getInstance().getGlobalDebug() > 0) { + // only redirect to standardLog if it's lower than INFO so we don't log that twice! + if ((level.intValue() < Level.INFO.intValue()) && (standardLog != null)) { + standardLog.log(Level.INFO, prefix + msg); + } + + super.log(level, prefix + msg); + } } /** diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/FileUtils.java b/src/main/java/com/onarandombox/MultiverseCore/utils/FileUtils.java index 9d40b11d..161ff38e 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/FileUtils.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/FileUtils.java @@ -8,6 +8,13 @@ package com.onarandombox.MultiverseCore.utils; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.logging.Logger; /** * File-utilities. @@ -25,19 +32,70 @@ public class FileUtils { */ public static boolean deleteFolder(File file) { if (file.exists()) { + boolean ret = true; // If the file exists, and it has more than one file in it. if (file.isDirectory()) { for (File f : file.listFiles()) { - if (!FileUtils.deleteFolder(f)) { - return false; - } + ret = ret && deleteFolder(f); } } - file.delete(); - return !file.exists(); + return ret && file.delete(); } else { return false; } } + private static final int COPY_BLOCK_SIZE = 1024; + + /** + * Helper method to copy the world-folder. + * @param source Source-File + * @param target Target-File + * @param log A logger that logs the operation + * + * @return if it had success + */ + public static boolean copyFolder(File source, File target, Logger log) { + InputStream in = null; + OutputStream out = null; + try { + if (source.isDirectory()) { + + if (!target.exists()) + target.mkdir(); + + String[] children = source.list(); + // for (int i=0; i 0) { + out.write(buf, 0, len); + } + } + return true; + } catch (FileNotFoundException e) { + log.warning("Exception while copying file: " + e.getMessage()); + } catch (IOException e) { + log.warning("Exception while copying file: " + e.getMessage()); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException ignore) { } + } + if (out != null) { + try { + out.close(); + } catch (IOException ignore) { } + } + } + return false; + } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/MVPermissions.java b/src/main/java/com/onarandombox/MultiverseCore/utils/MVPermissions.java index d70e4055..d71de160 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/MVPermissions.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/MVPermissions.java @@ -76,6 +76,10 @@ public class MVPermissions implements PermissionsInterface { * @return Whether the {@link CommandSender} can travel to the specified {@link Location}. */ public boolean canTravelFromLocation(CommandSender sender, Location location) { + // Now The Bed destination can return null now. + if (location == null) { + return false; + } if (!(sender instanceof Player)) { return true; } @@ -256,10 +260,15 @@ public class MVPermissions implements PermissionsInterface { Player player = (Player) sender; boolean hasPermission = sender.hasPermission(node); + if (!sender.isPermissionSet(node)) { + this.plugin.log(Level.FINER, String.format("The node [%s%s%s] was %sNOT%s set for [%s%s%s].", + ChatColor.RED, node, ChatColor.WHITE, ChatColor.RED, ChatColor.WHITE, ChatColor.AQUA, + player.getDisplayName(), ChatColor.WHITE)); + } if (hasPermission) { - this.plugin.log(Level.FINEST, "Checking to see if player [" + player.getName() + "] has permission [" + node + "]... YES"); + this.plugin.log(Level.FINER, "Checking to see if player [" + player.getName() + "] has permission [" + node + "]... YES"); } else { - this.plugin.log(Level.FINEST, "Checking to see if player [" + player.getName() + "] has permission [" + node + "]... NO"); + this.plugin.log(Level.FINER, "Checking to see if player [" + player.getName() + "] has permission [" + node + "]... NO"); } return hasPermission; } diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/PermissionTools.java b/src/main/java/com/onarandombox/MultiverseCore/utils/PermissionTools.java index 1e404265..2851fc25 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/PermissionTools.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/PermissionTools.java @@ -7,7 +7,6 @@ package com.onarandombox.MultiverseCore.utils; -import java.util.logging.Level; import com.fernferret.allpay.GenericBank; import com.onarandombox.MultiverseCore.MultiverseCore; import com.onarandombox.MultiverseCore.api.MultiverseWorld; @@ -16,6 +15,8 @@ import org.bukkit.command.ConsoleCommandSender; import org.bukkit.entity.Player; import org.bukkit.permissions.Permission; +import java.util.logging.Level; + /** * Utility-class for permissions. */ @@ -134,21 +135,48 @@ public class PermissionTools { // Only check payments if it's a different world: if (!toWorld.equals(fromWorld)) { + // Don't bother checking economy stuff if it doesn't even cost to enter. + if (toWorld.getPrice() == 0D) { + return true; + } // If the player does not have to pay, return now. if (this.plugin.getMVPerms().hasPermission(teleporter, toWorld.getExemptPermission().getName(), true)) { return true; } - GenericBank bank = plugin.getBank(); - String errString = "You need " + bank.getFormattedAmount(teleporterPlayer, toWorld.getPrice(), toWorld.getCurrency()) - + " to send " + teleportee + " to " + toWorld.getColoredWorldString(); - if (teleportee.equals(teleporter)) { - errString = "You need " + bank.getFormattedAmount(teleporterPlayer, toWorld.getPrice(), toWorld.getCurrency()) - + " to enter " + toWorld.getColoredWorldString(); + final boolean usingVault; + final String formattedAmount; + if (toWorld.getCurrency() <= 0 && plugin.getVaultEconomy() != null) { + usingVault = true; + formattedAmount = plugin.getVaultEconomy().format(toWorld.getPrice()); + } else { + usingVault = false; + formattedAmount = this.plugin.getBank().getFormattedAmount(teleporterPlayer, toWorld.getPrice(), toWorld.getCurrency()); } - if (!bank.hasEnough(teleporterPlayer, toWorld.getPrice(), toWorld.getCurrency(), errString)) { - return false; - } else if (pay) { - bank.give(teleporterPlayer, toWorld.getPrice(), toWorld.getCurrency()); + String errString = "You need " + formattedAmount + " to send " + teleportee + " to " + toWorld.getColoredWorldString(); + if (teleportee.equals(teleporter)) { + errString = "You need " + formattedAmount + " to enter " + toWorld.getColoredWorldString(); + } + if (usingVault) { + if (!plugin.getVaultEconomy().has(teleporterPlayer.getName(), toWorld.getPrice())) { + return false; + } else if (pay) { + if (toWorld.getPrice() < 0D) { + plugin.getVaultEconomy().depositPlayer(teleporterPlayer.getName(), toWorld.getPrice() * -1D); + } else { + plugin.getVaultEconomy().withdrawPlayer(teleporterPlayer.getName(), toWorld.getPrice()); + } + } + } else { + GenericBank bank = plugin.getBank(); + if (!bank.hasEnough(teleporterPlayer, toWorld.getPrice(), toWorld.getCurrency(), errString)) { + return false; + } else if (pay) { + if (toWorld.getPrice() < 0D) { + bank.give(teleporterPlayer, toWorld.getPrice() * -1D, toWorld.getCurrency()); + } else { + bank.take(teleporterPlayer, toWorld.getPrice(), toWorld.getCurrency()); + } + } } } return true; diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/SimpleBlockSafety.java b/src/main/java/com/onarandombox/MultiverseCore/utils/SimpleBlockSafety.java index 5b21aecf..fd667d68 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/SimpleBlockSafety.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/SimpleBlockSafety.java @@ -7,23 +7,30 @@ package com.onarandombox.MultiverseCore.utils; -import com.onarandombox.MultiverseCore.MultiverseCore; +import com.dumptruckman.minecraft.util.Logging; import com.onarandombox.MultiverseCore.api.BlockSafety; import com.onarandombox.MultiverseCore.api.Core; - import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; +import org.bukkit.block.BlockFace; import org.bukkit.entity.Minecart; import org.bukkit.entity.Vehicle; +import org.bukkit.material.Bed; -import java.util.logging.Level; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; /** * The default-implementation of {@link BlockSafety}. */ public class SimpleBlockSafety implements BlockSafety { private final Core plugin; + private final static Set AROUND_BLOCK = new HashSet(){{ add(BlockFace.NORTH); add(BlockFace.NORTH_EAST); + add(BlockFace.EAST); add(BlockFace.SOUTH_EAST); + add(BlockFace.SOUTH); add(BlockFace.SOUTH_WEST); + add(BlockFace.WEST); add(BlockFace.NORTH_WEST); }}; public SimpleBlockSafety(Core plugin) { this.plugin = plugin; @@ -67,33 +74,88 @@ public class SimpleBlockSafety implements BlockSafety { if (isSolidBlock(world.getBlockAt(actual).getType()) || isSolidBlock(upOne.getBlock().getType())) { - MultiverseCore.staticLog(Level.FINER, "Error Here (Actual)? (" - + actual.getBlock().getType() + ")[" + isSolidBlock(actual.getBlock().getType()) + "]"); - MultiverseCore.staticLog(Level.FINER, "Error Here (upOne)? (" - + upOne.getBlock().getType() + ")[" + isSolidBlock(upOne.getBlock().getType()) + "]"); + Logging.finer("Error Here (Actual)? (%s)[%s]", actual.getBlock().getType(), + isSolidBlock(actual.getBlock().getType())); + Logging.finer("Error Here (upOne)? (%s)[%s]", upOne.getBlock().getType(), + isSolidBlock(upOne.getBlock().getType())); return false; } if (downOne.getBlock().getType() == Material.LAVA || downOne.getBlock().getType() == Material.STATIONARY_LAVA) { - MultiverseCore.staticLog(Level.FINER, "Error Here (downOne)? (" - + downOne.getBlock().getType() + ")[" + isSolidBlock(downOne.getBlock().getType()) + "]"); + Logging.finer("Error Here (downOne)? (%s)[%s]", downOne.getBlock().getType(), isSolidBlock(downOne.getBlock().getType())); return false; } if (downOne.getBlock().getType() == Material.FIRE) { - MultiverseCore.staticLog(Level.FINER, "There's fire below! (" - + actual.getBlock().getType() + ")[" + isSolidBlock(actual.getBlock().getType()) + "]"); + Logging.finer("There's fire below! (%s)[%s]", actual.getBlock().getType(), isSolidBlock(actual.getBlock().getType())); return false; } if (isBlockAboveAir(actual)) { - MultiverseCore.staticLog(Level.FINER, "Is block above air [" + isBlockAboveAir(actual) + "]"); - MultiverseCore.staticLog(Level.FINER, "Has 2 blocks of water below [" + this.hasTwoBlocksofWaterBelow(actual) + "]"); + Logging.finer("Is block above air [%s]", isBlockAboveAir(actual)); + Logging.finer("Has 2 blocks of water below [%s]", this.hasTwoBlocksofWaterBelow(actual)); return this.hasTwoBlocksofWaterBelow(actual); } return true; } + /** + * {@inheritDoc} + */ + @Override + public Location getSafeBedSpawn(Location l) { + // The passed location, may be null (if the bed is invalid) + if (l == null) { + return null; + } + final Location trySpawn = this.getSafeSpawnAroundABlock(l); + if (trySpawn != null) { + return trySpawn; + } + Location otherBlock = this.findOtherBedPiece(l); + if (otherBlock == null) { + return null; + } + // Now we have 2 locations, check around each, if the type is bed, skip it. + return this.getSafeSpawnAroundABlock(otherBlock); + } + + /** + * Find a safe spawn around a location. (N,S,E,W,NE,NW,SE,SW) + * @param l Location to check around + * @return A safe location, or none if it wasn't found. + */ + private Location getSafeSpawnAroundABlock(Location l) { + Iterator checkblock = AROUND_BLOCK.iterator(); + while(checkblock.hasNext()) { + final BlockFace face = checkblock.next(); + if (this.playerCanSpawnHereSafely(l.getBlock().getRelative(face).getLocation())) { + // Don't forget to center the player. + return l.getBlock().getRelative(face).getLocation().add(.5, 0, .5); + } + } + return null; + } + + /** + * Find the other bed block. + * @param checkLoc The location to check for the other piece at + * @return The location of the other bed piece, or null if it was a jacked up bed. + */ + private Location findOtherBedPiece(Location checkLoc) { + if (checkLoc.getBlock().getType() != Material.BED_BLOCK) { + return null; + } + // Construct a bed object at this location + final Bed b = new Bed(Material.BED_BLOCK, checkLoc.getBlock().getData()); + if (b.isHeadOfBed()) { + return checkLoc.getBlock().getRelative(b.getFacing().getOppositeFace()).getLocation(); + } + // We shouldn't ever be looking at the foot, but here's the code for it. + return checkLoc.getBlock().getRelative(b.getFacing()).getLocation(); + } + + /** * {@inheritDoc} */ diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/SimpleWorldPurger.java b/src/main/java/com/onarandombox/MultiverseCore/utils/SimpleWorldPurger.java index 4cf4e4c5..df86abd4 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/SimpleWorldPurger.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/SimpleWorldPurger.java @@ -62,6 +62,16 @@ public class SimpleWorldPurger implements WorldPurger { purgeWorld(world, allMobs, !world.canAnimalsSpawn(), !world.canMonstersSpawn()); } + /** + * {@inheritDoc} + */ + @Override + public boolean shouldWeKillThisCreature(MultiverseWorld world, Entity e) { + ArrayList allMobs = new ArrayList(world.getAnimalList()); + allMobs.addAll(world.getMonsterList()); + return this.shouldWeKillThisCreature(e, allMobs, !world.canAnimalsSpawn(), !world.canMonstersSpawn()); + } + /** * {@inheritDoc} */ @@ -80,49 +90,9 @@ public class SimpleWorldPurger implements WorldPurger { boolean specifiedAnimals = thingsToKill.contains("ANIMALS") || specifiedAll; boolean specifiedMonsters = thingsToKill.contains("MONSTERS") || specifiedAll; for (Entity e : world.getEntities()) { - boolean negate = false; - boolean specified = false; - if (e instanceof Squid || e instanceof Animals) { - // it's an animal - if (specifiedAnimals && !negateAnimals) { - this.plugin.log(Level.FINEST, "Removing an entity because I was told to remove all animals: " + e); - e.remove(); - entitiesKilled++; - continue; - } - if (specifiedAnimals) - specified = true; - negate = negateAnimals; - } else if (e instanceof Monster || e instanceof Ghast || e instanceof Slime) { - // it's a monster - if (specifiedMonsters && !negateMonsters) { - this.plugin.log(Level.FINEST, "Removing an entity because I was told to remove all monsters: " + e); - e.remove(); - entitiesKilled++; - continue; - } - if (specifiedMonsters) - specified = true; - negate = negateMonsters; - } - for (String s : thingsToKill) { - EntityType type = EntityType.fromName(s); - if (type != null && type.equals(e.getType())) { - specified = true; - if (!negate) { - this.plugin.log(Level.FINEST, "Removing an entity because it WAS specified and we are NOT negating: " + e); - e.remove(); - entitiesKilled++; - continue; - } - break; - } - } - if (!specified && negate) { - this.plugin.log(Level.FINEST, "Removing an entity because it was NOT specified and we ARE negating: " + e); + if (killDecision(e, thingsToKill, negateAnimals, negateMonsters, specifiedAnimals, specifiedMonsters)) { e.remove(); entitiesKilled++; - continue; } } if (sender != null) { @@ -130,6 +100,59 @@ public class SimpleWorldPurger implements WorldPurger { } } + private boolean killDecision(Entity e, List thingsToKill, boolean negateAnimals, + boolean negateMonsters, boolean specifiedAnimals, boolean specifiedMonsters) { + boolean negate = false; + boolean specified = false; + if (e instanceof Squid || e instanceof Animals) { + // it's an animal + if (specifiedAnimals && !negateAnimals) { + this.plugin.log(Level.FINEST, "Removing an entity because I was told to remove all animals: " + e); + return true; + } + if (specifiedAnimals) + specified = true; + negate = negateAnimals; + } else if (e instanceof Monster || e instanceof Ghast || e instanceof Slime) { + // it's a monster + if (specifiedMonsters && !negateMonsters) { + this.plugin.log(Level.FINEST, "Removing an entity because I was told to remove all monsters: " + e); + return true; + } + if (specifiedMonsters) + specified = true; + negate = negateMonsters; + } + for (String s : thingsToKill) { + EntityType type = EntityType.fromName(s); + if (type != null && type.equals(e.getType())) { + specified = true; + if (!negate) { + this.plugin.log(Level.FINEST, "Removing an entity because it WAS specified and we are NOT negating: " + e); + return true; + } + break; + } + } + if (!specified && negate) { + this.plugin.log(Level.FINEST, "Removing an entity because it was NOT specified and we ARE negating: " + e); + return true; + } + + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean shouldWeKillThisCreature(Entity e, List thingsToKill, boolean negateAnimals, boolean negateMonsters) { + boolean specifiedAll = thingsToKill.contains("ALL"); + boolean specifiedAnimals = thingsToKill.contains("ANIMALS") || specifiedAll; + boolean specifiedMonsters = thingsToKill.contains("MONSTERS") || specifiedAll; + return this.killDecision(e, thingsToKill, negateAnimals, negateMonsters, specifiedAnimals, specifiedMonsters); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/SpoutInterface.java b/src/main/java/com/onarandombox/MultiverseCore/utils/SpoutInterface.java index 2d0e817d..19221508 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/SpoutInterface.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/SpoutInterface.java @@ -4,14 +4,14 @@ * For more information please check the README.md file included * * with this project. * ******************************************************************************/ - +/* package com.onarandombox.MultiverseCore.utils; import org.getspout.spoutapi.SpoutManager; /** * A helper-class holding the {@link SpoutManager}. - */ + * / public class SpoutInterface { private SpoutManager spoutManager; @@ -22,8 +22,9 @@ public class SpoutInterface { /** * Gets the {@link SpoutManager}. * @return The {@link SpoutManager}. - */ + * / public SpoutManager getManager() { return this.spoutManager; } } +*/ diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/UpdateChecker.java b/src/main/java/com/onarandombox/MultiverseCore/utils/UpdateChecker.java index 683515b2..9c1555fc 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/UpdateChecker.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/UpdateChecker.java @@ -8,6 +8,7 @@ package com.onarandombox.MultiverseCore.utils; import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; @@ -54,6 +55,7 @@ public class UpdateChecker { } public void checkUpdate() { + BufferedReader rd = null; try { URL url = new URL("http://bukkit.onarandombox.com/multiverse/version.php?n=" + URLEncoder.encode(this.name, "UTF-8") + "&v=" + this.cversion); URLConnection conn = url.openConnection(); @@ -65,7 +67,7 @@ public class UpdateChecker { return; } - BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); + rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line; String version = null; @@ -76,7 +78,6 @@ public class UpdateChecker { } if (version == null) { - rd.close(); return; } @@ -92,6 +93,12 @@ public class UpdateChecker { rd.close(); } catch (Exception e) { // No need to alert the user of any error here... it's not important. + } finally { + if (rd != null) { + try { + rd.close(); + } catch (IOException ignore) { } + } } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/WorldManager.java b/src/main/java/com/onarandombox/MultiverseCore/utils/WorldManager.java index 388a694d..7d2ce8ec 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/WorldManager.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/WorldManager.java @@ -13,12 +13,14 @@ import com.onarandombox.MultiverseCore.api.MVWorldManager; import com.onarandombox.MultiverseCore.api.MultiverseWorld; import com.onarandombox.MultiverseCore.api.SafeTTeleporter; import com.onarandombox.MultiverseCore.api.WorldPurger; -import com.onarandombox.MultiverseCore.commands.EnvironmentCommand; import com.onarandombox.MultiverseCore.event.MVWorldDeleteEvent; +import com.onarandombox.MultiverseCore.exceptions.PropertyDoesNotExistException; +import org.bukkit.Location; import org.bukkit.World; import org.bukkit.World.Environment; import org.bukkit.WorldCreator; import org.bukkit.WorldType; +import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; @@ -35,25 +37,29 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.Set; +import java.util.Stack; +import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; +import java.util.logging.Logger; /** * Public facing API to add/remove Multiverse worlds. */ public class WorldManager implements MVWorldManager { - private MultiverseCore plugin; - private WorldPurger worldPurger; - private Map worlds; - private List unloadedWorlds; + private final MultiverseCore plugin; + private final WorldPurger worldPurger; + private final Map worlds; + private Map worldsFromTheConfig; private FileConfiguration configWorlds = null; private Map defaultGens; private String firstSpawn; public WorldManager(MultiverseCore core) { this.plugin = core; - this.worlds = new HashMap(); - this.unloadedWorlds = new ArrayList(); + this.worldsFromTheConfig = new HashMap(); + this.worlds = new ConcurrentHashMap(); this.worldPurger = new SimpleWorldPurger(plugin); } @@ -69,7 +75,7 @@ public class WorldManager implements MVWorldManager { return s.equalsIgnoreCase("bukkit.yml"); } }); - if (files.length == 1) { + if (files != null && files.length == 1) { FileConfiguration bukkitConfig = YamlConfiguration.loadConfiguration(files[0]); if (bukkitConfig.isConfigurationSection("worlds")) { Set keys = bukkitConfig.getConfigurationSection("worlds").getKeys(false); @@ -77,9 +83,92 @@ public class WorldManager implements MVWorldManager { defaultGens.put(key, bukkitConfig.getString("worlds." + key + ".generator", "")); } } + } else { + this.plugin.log(Level.WARNING, "Could not read 'bukkit.yml'. Any Default worldgenerators will not be loaded!"); } } + /** + * {@inheritDoc} + */ + @Override + public boolean cloneWorld(String oldName, String newName, String generator) { + // Make sure we don't already know about the new world. + if (this.isMVWorld(newName)) { + return false; + } + // Make sure the old world is actually a world! + if (this.getUnloadedWorlds().contains(oldName) || !this.isMVWorld(oldName)) { + return false; + } + + final File oldWorldFile = new File(this.plugin.getServer().getWorldContainer(), oldName); + final File newWorldFile = new File(this.plugin.getServer().getWorldContainer(), newName); + + // Make sure the new world doesn't exist outside of multiverse. + if (newWorldFile.exists()) { + return false; + } + + unloadWorld(oldName); + + removePlayersFromWorld(oldName); + + StringBuilder builder = new StringBuilder(); + builder.append("Copying data for world '").append(oldName).append("'..."); + this.plugin.log(Level.INFO, builder.toString()); + try { + Thread t = new Thread(new Runnable() { + @Override + public void run() { + FileUtils.copyFolder(oldWorldFile, newWorldFile, Logger.getLogger("Minecraft")); + } + }); + t.start(); + try { + t.join(); + } catch (InterruptedException e) { + // do nothing + } + File uidFile = new File(newWorldFile, "uid.dat"); + uidFile.delete(); + } catch (NullPointerException e) { + e.printStackTrace(); + return false; + } + this.plugin.log(Level.INFO, "Kind of copied stuff"); + + WorldCreator worldCreator = new WorldCreator(newName); + this.plugin.log(Level.INFO, "Started to copy settings"); + worldCreator.copy(this.getMVWorld(oldName).getCBWorld()); + this.plugin.log(Level.INFO, "Copied lots of settings"); + + boolean useSpawnAdjust = this.getMVWorld(oldName).getAdjustSpawn(); + this.plugin.log(Level.INFO, "Copied more settings"); + + Environment environment = worldCreator.environment(); + this.plugin.log(Level.INFO, "Copied most settings"); + if (newWorldFile.exists()) { + this.plugin.log(Level.INFO, "Succeeded at copying stuff"); + if (this.addWorld(newName, environment, null, null, null, generator, useSpawnAdjust)) { + // getMVWorld() doesn't actually return an MVWorld + this.plugin.log(Level.INFO, "Succeeded at importing stuff"); + MVWorld newWorld = (MVWorld) this.getMVWorld(newName); + MVWorld oldWorld = (MVWorld) this.getMVWorld(oldName); + newWorld.copyValues(oldWorld); + try { + // don't keep the alias the same -- that would be useless + newWorld.setPropertyValue("alias", newName); + } catch (PropertyDoesNotExistException e) { + // this should never happen + throw new RuntimeException(e); + } + return true; + } + } + return false; + } + /** * {@inheritDoc} */ @@ -118,7 +207,10 @@ public class WorldManager implements MVWorldManager { c.generateStructures(generateStructures); } - World world; + // Important: doLoad() needs the MVWorld-object in worldsFromTheConfig + if (!worldsFromTheConfig.containsKey(name)) + worldsFromTheConfig.put(name, new MVWorld(useSpawnAdjust)); + StringBuilder builder = new StringBuilder(); builder.append("Loading World & Settings - '").append(name).append("'"); builder.append(" - Env: ").append(env); @@ -131,27 +223,15 @@ public class WorldManager implements MVWorldManager { } this.plugin.log(Level.INFO, builder.toString()); - try { - world = c.createWorld(); - } catch (Exception e) { - this.plugin.log(Level.SEVERE, "The world '" + name + "' could NOT be loaded because it contains errors!"); - this.plugin.log(Level.SEVERE, "Try using Chukster to repair your world! '" + name + "'"); - this.plugin.log(Level.SEVERE, "http://forums.bukkit.org/threads/admin-chunkster.8186/"); - return false; - } - - if (world == null) { + if (!doLoad(c, true)) { this.plugin.log(Level.SEVERE, "Failed to Create/Load the world '" + name + "'"); return false; } - MultiverseWorld mvworld = new MVWorld(world, this.configWorlds, this.plugin, - this.plugin.getServer().getWorld(name).getSeed(), generator, useSpawnAdjust); - this.worldPurger.purgeWorld(mvworld); - this.worlds.put(name, mvworld); - if (this.unloadedWorlds.contains(name)) { - this.unloadedWorlds.remove(name); - } + // set generator (special case because we can't read it from org.bukkit.World) + this.worlds.get(name).setGenerator(generator); + + this.saveWorldsConfig(); return true; } @@ -180,15 +260,11 @@ public class WorldManager implements MVWorldManager { if (!unloadWorld(name)) { return false; } - if (this.configWorlds.get("worlds." + name) != null) { + if (this.worldsFromTheConfig.containsKey(name)) { + this.worldsFromTheConfig.remove(name); this.plugin.log(Level.INFO, "World '" + name + "' was removed from config.yml"); - this.configWorlds.set("worlds." + name, null); this.saveWorldsConfig(); - // Remove it from the list of unloaded worlds. - if (this.unloadedWorlds.contains(name)) { - this.unloadedWorlds.remove(name); - } return true; } else { this.plugin.log(Level.INFO, "World '" + name + "' was already removed from config.yml"); @@ -236,15 +312,19 @@ public class WorldManager implements MVWorldManager { if (this.unloadWorldFromBukkit(name, true)) { this.worlds.remove(name); this.plugin.log(Level.INFO, "World '" + name + "' was unloaded from memory."); - this.unloadedWorlds.add(name); + + this.worldsFromTheConfig.get(name).tearDown(); + 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 unload it using multiverse, use:"); - this.plugin.log(Level.WARNING, "/mv import " + name + " " + this.plugin.getServer().getWorld(name).getEnvironment().toString()); + 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 if (this.worldsFromTheConfig.containsKey(name)) { + return true; // it's already unloaded } else { this.plugin.log(Level.INFO, "Multiverse does not know about " + name + " and it's not loaded by Bukkit."); } @@ -258,36 +338,69 @@ public class WorldManager implements MVWorldManager { public boolean loadWorld(String name) { // Check if the World is already loaded if (this.worlds.containsKey(name)) { - // Ensure it's not unloaded, since it IS loaded. - if (this.unloadedWorlds.contains(name)) { - this.unloadedWorlds.remove(name); - } return true; } - // Grab all the Worlds from the Config. - Set worldKeys = this.configWorlds.getConfigurationSection("worlds").getKeys(false); - - // Check that the list is not null and that the config contains the world - if ((worldKeys != null) && (worldKeys.contains(name))) { - // Grab the initial values from the config file. - String environment = this.configWorlds.getString("worlds." + name + ".environment", "NORMAL"); // Grab the Environment as a String. - String type = this.configWorlds.getString("worlds." + name + ".type", "NORMAL"); - String seedString = this.configWorlds.getString("worlds." + name + ".seed", ""); - String generatorString = this.configWorlds.getString("worlds." + name + ".generator"); - boolean generateStructures = this.configWorlds.getBoolean("worlds." + name + ".generatestructures", true); - - this.addWorld(name, EnvironmentCommand.getEnvFromString(environment), seedString, - EnvironmentCommand.getWorldTypeFromString(type), generateStructures, generatorString); - if (this.unloadedWorlds.contains(name)) { - this.unloadedWorlds.remove(name); - } - return true; + // Check that the world is in the config + if (worldsFromTheConfig.containsKey(name)) { + return doLoad(name); } else { return false; } } + private void brokenWorld(String name) { + this.plugin.log(Level.SEVERE, "The world '" + name + "' could NOT be loaded because it contains errors!"); + this.plugin.log(Level.SEVERE, "Try using Chukster to repair your world! '" + name + "'"); + this.plugin.log(Level.SEVERE, "http://forums.bukkit.org/threads/admin-chunkster.8186/"); + } + + private boolean doLoad(String name) { + return doLoad(name, false); + } + + private boolean doLoad(String name, boolean ignoreExists) { + if (!worldsFromTheConfig.containsKey(name)) + throw new IllegalArgumentException("That world doesn't exist!"); + + MVWorld world = worldsFromTheConfig.get(name); + WorldCreator creator = WorldCreator.name(name); + + creator.environment(world.getEnvironment()).seed(world.getSeed()); + if ((world.getGenerator() != null) && (!world.getGenerator().equals("null"))) + creator.generator(world.getGenerator()); + + return doLoad(creator, ignoreExists); + } + + private boolean doLoad(WorldCreator creator, boolean ignoreExists) { + String worldName = creator.name(); + if (!worldsFromTheConfig.containsKey(worldName)) + throw new IllegalArgumentException("That world doesn't exist!"); + if (worlds.containsKey(worldName)) + throw new IllegalArgumentException("That world is already loaded!"); + + if (!ignoreExists && !new File(this.plugin.getServer().getWorldContainer(), worldName).exists()) { + this.plugin.log(Level.WARNING, "WorldManager: Can't load this world because the folder was deleted/moved: " + worldName); + this.plugin.log(Level.WARNING, "Use '/mv remove' to remove it from the config!"); + return false; + } + + MVWorld mvworld = worldsFromTheConfig.get(worldName); + World cbworld; + try { + cbworld = creator.createWorld(); + } catch (Exception e) { + e.printStackTrace(); + brokenWorld(worldName); + return false; + } + mvworld.init(cbworld, plugin); + this.worldPurger.purgeWorld(mvworld); + this.worlds.put(worldName, mvworld); + return true; + } + /** * {@inheritDoc} */ @@ -389,8 +502,12 @@ public class WorldManager implements MVWorldManager { */ @Override public MultiverseWorld getMVWorld(String name) { - if (this.worlds.containsKey(name)) { - return this.worlds.get(name); + if (name == null) { + return null; + } + MultiverseWorld world = this.worlds.get(name); + if (world != null) { + return world; } return this.getMVWorldByAlias(name); } @@ -425,7 +542,7 @@ public class WorldManager implements MVWorldManager { * {@inheritDoc} */ @Override - public boolean isMVWorld(String name) { + public boolean isMVWorld(final String name) { return (this.worlds.containsKey(name) || isMVWorldAlias(name)); } @@ -443,7 +560,7 @@ public class WorldManager implements MVWorldManager { * @param alias The alias of the world to check. * @return True if the world exists, false if not. */ - private boolean isMVWorldAlias(String alias) { + private boolean isMVWorldAlias(final String alias) { for (MultiverseWorld w : this.worlds.values()) { if (w.getAlias().equalsIgnoreCase(alias)) { return true; @@ -459,30 +576,22 @@ public class WorldManager implements MVWorldManager { public void loadDefaultWorlds() { this.ensureConfigIsPrepared(); List myWorlds = this.plugin.getServer().getWorlds(); - Set worldStrings = this.configWorlds.getConfigurationSection("worlds").getKeys(false); for (World w : myWorlds) { String name = w.getName(); - if (!worldStrings.contains(name)) { + if (!worldsFromTheConfig.containsKey(name)) { + String generator = null; if (this.defaultGens.containsKey(name)) { - this.addWorld(name, w.getEnvironment(), w.getSeed() + "", w.getWorldType(), - w.canGenerateStructures(), this.defaultGens.get(name)); - } else { - this.addWorld(name, w.getEnvironment(), w.getSeed() + "", w.getWorldType(), - w.canGenerateStructures(), null); + generator = this.defaultGens.get(name); } - + this.addWorld(name, w.getEnvironment(), String.valueOf(w.getSeed()), w.getWorldType(), w.canGenerateStructures(), generator); } } } private void ensureConfigIsPrepared() { + this.configWorlds.options().pathSeparator(SEPARATOR); if (this.configWorlds.getConfigurationSection("worlds") == null) { this.configWorlds.createSection("worlds"); - try { - this.configWorlds.save(new File(this.plugin.getDataFolder(), "worlds.yml")); - } catch (IOException e) { - this.plugin.log(Level.SEVERE, "Failed to save worlds.yml. Please check your file permissions."); - } } } @@ -495,13 +604,10 @@ public class WorldManager implements MVWorldManager { int count = 0; this.ensureConfigIsPrepared(); this.ensureSecondNamespaceIsPrepared(); - // Grab all the Worlds from the Config. - Set worldKeys = this.configWorlds.getConfigurationSection("worlds").getKeys(false); // Force the worlds to be loaded, ie don't just load new worlds. if (forceLoad) { // Remove all world permissions. - Permission allAccess = this.plugin.getServer().getPluginManager().getPermission("multiverse.access.*"); Permission allExempt = this.plugin.getServer().getPluginManager().getPermission("multiverse.exempt.*"); for (MultiverseWorld w : this.worlds.values()) { @@ -523,45 +629,20 @@ public class WorldManager implements MVWorldManager { this.worlds.clear(); } - // Check that the list is not null. - if (worldKeys != null) { - for (String worldKey : worldKeys) { - // Check if the World is already loaded within the Plugin. - if (this.worlds.containsKey(worldKey)) { - continue; - } - - // If autoload was set to false, don't load this one. - if (!this.configWorlds.getBoolean("worlds." + worldKey + ".autoload", true)) { - if (!this.unloadedWorlds.contains(worldKey)) { - this.unloadedWorlds.add(worldKey); - } - continue; - } - // Grab the initial values from the config file. - String environment = this.configWorlds.getString("worlds." + worldKey + ".environment", "NORMAL"); - String type = this.configWorlds.getString("worlds." + worldKey + ".type", "NORMAL"); - String seedString = this.configWorlds.getString("worlds." + worldKey + ".seed", null); - boolean generateStructures = this.configWorlds.getBoolean("worlds." + worldKey + ".generatestructures", true); - if (seedString == null) { - seedString = this.configWorlds.getLong("worlds." + worldKey + ".seed") + ""; - } - - String generatorString = this.configWorlds.getString("worlds." + worldKey + ".generator"); - if (environment.equalsIgnoreCase("skylands")) { - this.plugin.log(Level.WARNING, "Found SKYLANDS world. Not importing automatically, as it won't work atm :("); - continue; - } - addWorld(worldKey, EnvironmentCommand.getEnvFromString(environment), seedString, - EnvironmentCommand.getWorldTypeFromString(type), generateStructures, generatorString); - - // Increment the world count - count++; + for (Map.Entry entry : worldsFromTheConfig.entrySet()) { + if (worlds.containsKey(entry.getKey())) { + continue; } + if (!entry.getValue().getAutoLoad()) + continue; + + if (doLoad(entry.getKey())) + count++; } // Simple Output to the Console to show how many Worlds were loaded. this.plugin.log(Level.INFO, count + " - World(s) loaded."); + this.saveWorldsConfig(); } private void ensureSecondNamespaceIsPrepared() { @@ -590,15 +671,59 @@ public class WorldManager implements MVWorldManager { return worldPurger; } + private static final char SEPARATOR = '\uF8FF'; + /** - * Load the config from a file. - * - * @param file The file to load. - * @return A loaded configuration. + * {@inheritDoc} */ @Override public FileConfiguration loadWorldConfig(File file) { this.configWorlds = YamlConfiguration.loadConfiguration(file); + this.ensureConfigIsPrepared(); + try { + this.configWorlds.save(new File(this.plugin.getDataFolder(), "worlds.yml")); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // load world-objects + Stack worldKeys = new Stack(); + worldKeys.addAll(this.configWorlds.getConfigurationSection("worlds").getKeys(false)); + Map newWorldsFromTheConfig = new HashMap(); + while (!worldKeys.isEmpty()) { + String key = worldKeys.pop(); + String path = "worlds" + SEPARATOR + key; + Object obj = this.configWorlds.get(path); + if ((obj != null) && (obj instanceof MVWorld)) { + String worldName = key.replaceAll(String.valueOf(SEPARATOR), "."); + MVWorld mvWorld = null; + if (this.worldsFromTheConfig.containsKey(worldName)) { + // Object-Recycling :D + // TODO Why is is checking worldsFromTheConfig and then getting from worlds? So confused... (DTM) + mvWorld = (MVWorld) this.worlds.get(worldName); + if (mvWorld != null) { + mvWorld.copyValues((MVWorld) obj); + } + } + if (mvWorld == null) { + // we have to use a new one + World cbworld = this.plugin.getServer().getWorld(worldName); + mvWorld = (MVWorld) obj; + if (cbworld != null) { + mvWorld.init(cbworld, this.plugin); + } + } + newWorldsFromTheConfig.put(worldName, mvWorld); + } else if (this.configWorlds.isConfigurationSection(path)) { + ConfigurationSection section = this.configWorlds.getConfigurationSection(path); + Set subkeys = section.getKeys(false); + for (String subkey : subkeys) { + worldKeys.push(key + SEPARATOR + subkey); + } + } + } + this.worldsFromTheConfig = newWorldsFromTheConfig; + this.worlds.keySet().retainAll(this.worldsFromTheConfig.keySet()); return this.configWorlds; } @@ -608,6 +733,11 @@ public class WorldManager implements MVWorldManager { @Override public boolean saveWorldsConfig() { try { + this.configWorlds.options().pathSeparator(SEPARATOR); + this.configWorlds.set("worlds", null); + for (Map.Entry entry : worldsFromTheConfig.entrySet()) { + this.configWorlds.set("worlds" + SEPARATOR + entry.getKey(), entry.getValue()); + } this.configWorlds.save(new File(this.plugin.getDataFolder(), "worlds.yml")); return true; } catch (IOException e) { @@ -629,7 +759,49 @@ public class WorldManager implements MVWorldManager { */ @Override public List getUnloadedWorlds() { - return this.unloadedWorlds; + List allNames = new ArrayList(this.worldsFromTheConfig.keySet()); + allNames.removeAll(worlds.keySet()); + return allNames; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean regenWorld(String name, boolean useNewSeed, boolean randomSeed, String seed) { + MultiverseWorld world = this.getMVWorld(name); + if (world == null) + return false; + + List ps = world.getCBWorld().getPlayers(); + + if (useNewSeed) { + long theSeed; + + if (randomSeed) { + theSeed = new Random().nextLong(); + } else { + try { + theSeed = Long.parseLong(seed); + } catch (NumberFormatException e) { + theSeed = seed.hashCode(); + } + } + + world.setSeed(theSeed); + } + + if (this.deleteWorld(name, false)) { + this.doLoad(name, true); + SafeTTeleporter teleporter = this.plugin.getSafeTTeleporter(); + Location newSpawn = world.getSpawnLocation(); + // Send all players that were in the old world, BACK to it! + for (Player p : ps) { + teleporter.safelyTeleport(null, p, newSpawn, true); + } + return true; + } + return false; } /** diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/HttpAPIClient.java b/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/HttpAPIClient.java index 07bc0fb5..55d69c5c 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/HttpAPIClient.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/HttpAPIClient.java @@ -26,16 +26,25 @@ public abstract class HttpAPIClient { * @throws IOException When the I/O-operation failed. */ protected final String exec(Object... args) throws IOException { + URLConnection conn = new URL(String.format(this.urlFormat, args)).openConnection(); conn.connect(); - BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); - while (!reader.ready()); // wait until reader is ready, may not be necessary, SUPPRESS CHECKSTYLE: EmptyStatement - StringBuilder ret = new StringBuilder(); - while (reader.ready()) { - ret.append(reader.readLine()).append('\n'); + BufferedReader reader = null; + try { + reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); + while (!reader.ready()); // wait until reader is ready, may not be necessary, SUPPRESS CHECKSTYLE: EmptyStatement + + while (reader.ready()) { + ret.append(reader.readLine()).append('\n'); + } + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException ignore) { } + } } - reader.close(); return ret.toString(); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PastebinPasteService.java b/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PastebinPasteService.java index 84e3acd5..8dce6b99 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PastebinPasteService.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PastebinPasteService.java @@ -1,6 +1,7 @@ package com.onarandombox.MultiverseCore.utils.webpaste; import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; @@ -54,24 +55,35 @@ public class PastebinPasteService implements PasteService { */ @Override public String postData(String encodedData, URL url) throws PasteFailedException { + OutputStreamWriter wr = null; + BufferedReader rd = null; try { URLConnection conn = url.openConnection(); conn.setDoOutput(true); - OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream()); + wr = new OutputStreamWriter(conn.getOutputStream()); wr.write(encodedData); wr.flush(); - BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); + rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line; String pastebinUrl = ""; while ((line = rd.readLine()) != null) { pastebinUrl = line; } - wr.close(); - rd.close(); return pastebinUrl; } catch (Exception e) { throw new PasteFailedException(e); + } finally { + if (wr != null) { + try { + wr.close(); + } catch (IOException ignore) { } + } + if (rd != null) { + try { + rd.close(); + } catch (IOException ignore) { } + } } } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PastiePasteService.java b/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PastiePasteService.java index d912edc6..3cb0f169 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PastiePasteService.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PastiePasteService.java @@ -1,6 +1,7 @@ package com.onarandombox.MultiverseCore.utils.webpaste; import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; @@ -55,14 +56,16 @@ public class PastiePasteService implements PasteService { */ @Override public String postData(String encodedData, URL url) throws PasteFailedException { + OutputStreamWriter wr = null; + BufferedReader rd = null; try { URLConnection conn = url.openConnection(); conn.setDoOutput(true); - OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream()); + wr = new OutputStreamWriter(conn.getOutputStream()); wr.write(encodedData); wr.flush(); - BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); + rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line; String pastieUrl = ""; Pattern pastiePattern = this.getURLMatchingPattern(); @@ -73,11 +76,20 @@ public class PastiePasteService implements PasteService { pastieUrl = this.formatURL(pastieID); } } - wr.close(); - rd.close(); return pastieUrl; } catch (Exception e) { throw new PasteFailedException(e); + } finally { + if (wr != null) { + try { + wr.close(); + } catch (IOException ignore) { } + } + if (rd != null) { + try { + rd.close(); + } catch (IOException ignore) { } + } } } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index ca3427b9..79ac2a9e 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -202,3 +202,12 @@ commands: description: Regenerates a world Multiverse already knows about. usage: | / {WORLD} + mvscript: + description: Runs a script from the Multiverse scripts directory. + usage: | + / {script} [target] + mvclone: + description: World clone command + usage: | + / + / creative grieftastic -- Creates a world called 'grieftastic' exactly identical to the world 'creative'. diff --git a/src/test/java/com/onarandombox/MultiverseCore/test/TestDebugMode.java b/src/test/java/com/onarandombox/MultiverseCore/test/TestDebugMode.java index b0438e1c..10f82651 100644 --- a/src/test/java/com/onarandombox/MultiverseCore/test/TestDebugMode.java +++ b/src/test/java/com/onarandombox/MultiverseCore/test/TestDebugMode.java @@ -23,7 +23,6 @@ import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginDescriptionFile; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; diff --git a/src/test/java/com/onarandombox/MultiverseCore/test/TestEntitySpawnRules.java b/src/test/java/com/onarandombox/MultiverseCore/test/TestEntitySpawnRules.java new file mode 100644 index 00000000..de2745c7 --- /dev/null +++ b/src/test/java/com/onarandombox/MultiverseCore/test/TestEntitySpawnRules.java @@ -0,0 +1,158 @@ +package com.onarandombox.MultiverseCore.test; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Sheep; +import org.bukkit.entity.Zombie; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; +import org.bukkit.plugin.PluginDescriptionFile; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.onarandombox.MultiverseCore.MultiverseCore; +import com.onarandombox.MultiverseCore.api.MVWorldManager; +import com.onarandombox.MultiverseCore.api.MultiverseWorld; +import com.onarandombox.MultiverseCore.listeners.MVEntityListener; +import com.onarandombox.MultiverseCore.test.utils.TestInstanceCreator; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ MultiverseCore.class, PluginDescriptionFile.class }) +public class TestEntitySpawnRules { + TestInstanceCreator creator; + MultiverseCore core; + MVEntityListener listener; + + MultiverseWorld mvWorld; + World cbworld; + + Sheep sheep; + Zombie zombie; + + CreatureSpawnEvent sheepEvent; + CreatureSpawnEvent zombieEvent; + + @Before + public void setUp() throws Exception { + creator = new TestInstanceCreator(); + assertTrue(creator.setUp()); + core = creator.getCore(); + listener = core.getEntityListener(); + + mvWorld = mock(MultiverseWorld.class); + cbworld = mock(World.class); + when(mvWorld.getCBWorld()).thenReturn(cbworld); + + MVWorldManager worldman = mock(MVWorldManager.class); + when(worldman.isMVWorld(anyString())).thenReturn(true); + when(worldman.getMVWorld(anyString())).thenReturn(mvWorld); + Field worldmanfield = MVEntityListener.class.getDeclaredField("worldManager"); + worldmanfield.setAccessible(true); + worldmanfield.set(listener, worldman); + + core.getMVConfig().setGlobalDebug(3); + } + + @After + public void tearDown() throws Exception { + creator.tearDown(); + } + + private static CreatureSpawnEvent mockSpawnEvent(LivingEntity e, SpawnReason reason) { + CreatureSpawnEvent event = mock(CreatureSpawnEvent.class); + when(event.getEntity()).thenReturn(e); + EntityType type = e.getType(); + when(event.getEntityType()).thenReturn(type); + when(event.getSpawnReason()).thenReturn(reason); + return event; + } + + private void spawnAll(SpawnReason reason) { + sheepEvent = mockSpawnEvent(sheep, reason); + zombieEvent = mockSpawnEvent(zombie, reason); + listener.creatureSpawn(sheepEvent); + listener.creatureSpawn(zombieEvent); + } + + private void spawnAllNatural() { + spawnAll(SpawnReason.NATURAL); + } + + private void adjustSettings(boolean animalSpawn, boolean monsterSpawn, + List animalExceptions, List monsterExceptions) { + when(this.mvWorld.canAnimalsSpawn()).thenReturn(animalSpawn); + when(this.mvWorld.canMonstersSpawn()).thenReturn(monsterSpawn); + when(this.mvWorld.getAnimalList()).thenReturn(animalExceptions); + when(this.mvWorld.getMonsterList()).thenReturn(monsterExceptions); + } + + @Test + public void test() { + // test 1: no spawning at all allowed + adjustSettings(false, false, Collections.EMPTY_LIST, Collections.EMPTY_LIST); + createAnimals(); + spawnAllNatural(); + verify(sheepEvent).setCancelled(true); + verify(zombieEvent).setCancelled(true); + + // test 2: only monsters + adjustSettings(false, true, Collections.EMPTY_LIST, Collections.EMPTY_LIST); + createAnimals(); + spawnAllNatural(); + verify(sheepEvent).setCancelled(true); + verify(zombieEvent).setCancelled(false); + + // test 3: all spawning allowed + adjustSettings(true, true, Collections.EMPTY_LIST, Collections.EMPTY_LIST); + createAnimals(); + spawnAllNatural(); + verify(sheepEvent).setCancelled(false); + verify(zombieEvent).setCancelled(false); + + // test 4: no spawning with zombie exception + adjustSettings(false, false, Collections.EMPTY_LIST, Arrays.asList("ZOMBIE")); + createAnimals(); + spawnAllNatural(); + verify(sheepEvent).setCancelled(true); + verify(zombieEvent).setCancelled(false); + + // test 5: all spawning with sheep exception + adjustSettings(true, true, Arrays.asList("SHEEP"), Collections.EMPTY_LIST); + createAnimals(); + spawnAllNatural(); + verify(sheepEvent).setCancelled(true); + verify(zombieEvent).setCancelled(false); + + // test 6: eggs + adjustSettings(false, false, Collections.EMPTY_LIST, Collections.EMPTY_LIST); + createAnimals(); + spawnAll(SpawnReason.SPAWNER_EGG); + verify(sheepEvent, never()).setCancelled(anyBoolean()); + verify(zombieEvent, never()).setCancelled(anyBoolean()); + } + + private void createAnimals() { + sheep = mock(Sheep.class); + when(sheep.getType()).thenReturn(EntityType.SHEEP); + when(sheep.getWorld()).thenReturn(this.cbworld); + zombie = mock(Zombie.class); + when(zombie.getType()).thenReturn(EntityType.ZOMBIE); + when(zombie.getWorld()).thenReturn(this.cbworld); + + when(cbworld.getEntities()).thenReturn(Arrays.asList((Entity) sheep, (Entity) zombie)); + } +} diff --git a/src/test/java/com/onarandombox/MultiverseCore/test/TestModifyCommand.java b/src/test/java/com/onarandombox/MultiverseCore/test/TestModifyCommand.java new file mode 100644 index 00000000..6eff3363 --- /dev/null +++ b/src/test/java/com/onarandombox/MultiverseCore/test/TestModifyCommand.java @@ -0,0 +1,61 @@ +package com.onarandombox.MultiverseCore.test; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import org.bukkit.Server; +import org.bukkit.World.Environment; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.PluginDescriptionFile; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.onarandombox.MultiverseCore.MultiverseCore; +import com.onarandombox.MultiverseCore.api.MultiverseWorld; +import com.onarandombox.MultiverseCore.test.utils.TestInstanceCreator; + + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ MultiverseCore.class, PluginDescriptionFile.class }) +public class TestModifyCommand { + TestInstanceCreator creator; + Server mockServer; + MultiverseCore core; + CommandSender mockCommandSender; + + @Before + public void setUp() throws Exception { + creator = new TestInstanceCreator(); + assertTrue(creator.setUp()); + mockServer = creator.getServer(); + mockCommandSender = creator.getCommandSender(); + core = creator.getCore(); + + // create world + assertTrue(core.getMVWorldManager().addWorld("world", Environment.NORMAL, null, null, null, null)); + } + + @After + public void tearDown() throws Exception { + creator.tearDown(); + } + + @Test + public void testSetHidden() { + Command cmd = mock(Command.class); + when(cmd.getName()).thenReturn("mv"); + + MultiverseWorld world = core.getMVWorldManager().getMVWorld("world"); + assertNotNull(world); + + assertFalse(world.isHidden()); // ensure it's not hidden now + assertTrue(core.onCommand(mockCommandSender, cmd, "", // run the command + new String[] { "modify", "set", "hidden", "true", "world" })); + assertTrue(world.isHidden()); // test if it worked + } +} diff --git a/src/test/java/com/onarandombox/MultiverseCore/test/TestWorldCreation.java b/src/test/java/com/onarandombox/MultiverseCore/test/TestWorldCreation.java deleted file mode 100644 index eb2e46c1..00000000 --- a/src/test/java/com/onarandombox/MultiverseCore/test/TestWorldCreation.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.onarandombox.MultiverseCore.test; - -import com.onarandombox.MultiverseCore.MultiverseCore; -import com.onarandombox.MultiverseCore.test.utils.TestInstanceCreator; -import com.onarandombox.MultiverseCore.utils.WorldManager; -import org.bukkit.ChatColor; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.configuration.Configuration; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.plugin.PluginDescriptionFile; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.internal.verification.VerificationModeFactory; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import java.lang.reflect.Field; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; - -@RunWith(PowerMockRunner.class) -@PrepareForTest({ MultiverseCore.class, PluginDescriptionFile.class }) -public class TestWorldCreation { - - private TestInstanceCreator creator; - private MultiverseCore core; - private CommandSender mockCommandSender; - - @Before - public void setUp() throws Exception { - this.creator = new TestInstanceCreator(); - assertTrue(this.creator.setUp()); - this.core = this.creator.getCore(); - this.mockCommandSender = this.creator.getCommandSender(); - } - - @After - public void tearDown() throws Exception { - creator.tearDown(); - } - - @Test - public void test() { - // Initialize a fake command - Command mockCommand = mock(Command.class); - when(mockCommand.getName()).thenReturn("mv"); - - // Try to create a world that exists - String[] normalArgs = new String[] { "create", "world", "normal" }; - core.onCommand(mockCommandSender, mockCommand, "", normalArgs); - verify(mockCommandSender).sendMessage(ChatColor.RED + "A Folder/World already exists with this name!"); - verify(mockCommandSender).sendMessage(ChatColor.RED + "If you are confident it is a world you can import with /mvimport"); - - // Try to create a world that is new - String[] newArgs = new String[] { "create", "world2", "normal" }; - core.onCommand(mockCommandSender, mockCommand, "", newArgs); - verify(mockCommandSender).sendMessage("Starting creation of world 'world2'..."); - - String[] dottedWorld = new String[] { "create", "fish.world", "normal" }; - core.onCommand(mockCommandSender, mockCommand, "", dottedWorld); - verify(mockCommandSender).sendMessage("Starting creation of world 'fish.world'..."); - verify(mockCommandSender, VerificationModeFactory.times(2)).sendMessage("Complete!"); - - // Grab the Config - Field worldConfigField = null; - ConfigurationSection worldsSection = null; - try { - worldConfigField = WorldManager.class.getDeclaredField("configWorlds"); - worldConfigField.setAccessible(true); - Configuration rootConfig = (Configuration) worldConfigField.get(this.core.getMVWorldManager()); - worldsSection = rootConfig.getConfigurationSection("worlds"); - } catch (NoSuchFieldException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - - // Verify that the world was added to the configs - // TODO: Expand this. - assertNotNull(worldsSection); - assertEquals(2, worldsSection.getKeys(false).size()); - assertTrue(worldsSection.getKeys(false).contains("world2")); - // TODO: Uncomment once this is fixed!!! - //assertTrue(worldsSection.getKeys(false).contains("'fish.world'")); - - // Worlds with .s are a special case, verify that they work. - } -} diff --git a/src/test/java/com/onarandombox/MultiverseCore/test/TestWorldProperties.java b/src/test/java/com/onarandombox/MultiverseCore/test/TestWorldProperties.java index 5dc074a6..0db2d5f1 100644 --- a/src/test/java/com/onarandombox/MultiverseCore/test/TestWorldProperties.java +++ b/src/test/java/com/onarandombox/MultiverseCore/test/TestWorldProperties.java @@ -7,25 +7,29 @@ package com.onarandombox.MultiverseCore.test; -import static org.junit.Assert.*; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.*; - +import com.onarandombox.MultiverseCore.MVWorld; +import com.onarandombox.MultiverseCore.MultiverseCore; +import com.onarandombox.MultiverseCore.api.MVWorldManager; +import com.onarandombox.MultiverseCore.api.MultiverseWorld; +import com.onarandombox.MultiverseCore.configuration.SpawnLocation; +import com.onarandombox.MultiverseCore.listeners.MVAsyncPlayerChatListener; +import com.onarandombox.MultiverseCore.test.utils.TestInstanceCreator; +import com.onarandombox.MultiverseCore.utils.WorldManager; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Difficulty; import org.bukkit.GameMode; import org.bukkit.Location; -import org.bukkit.World; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import org.bukkit.event.entity.EntityRegainHealthEvent; import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; import org.bukkit.event.entity.FoodLevelChangeEvent; -import org.bukkit.event.player.PlayerChatEvent; +import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerRespawnEvent; import org.bukkit.event.weather.ThunderChangeEvent; @@ -42,15 +46,16 @@ import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; -import com.onarandombox.MultiverseCore.MultiverseCore; -import com.onarandombox.MultiverseCore.api.MVWorldManager; -import com.onarandombox.MultiverseCore.api.MultiverseWorld; -import com.onarandombox.MultiverseCore.test.utils.TestInstanceCreator; -import com.onarandombox.MultiverseCore.utils.WorldManager; +import java.io.File; + +import static org.junit.Assert.*; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; @RunWith(PowerMockRunner.class) @PrepareForTest({ PluginManager.class, MultiverseCore.class, Permission.class, Bukkit.class, - WeatherChangeEvent.class, ThunderChangeEvent.class, PlayerChatEvent.class, + WeatherChangeEvent.class, ThunderChangeEvent.class, AsyncPlayerChatEvent.class, PlayerJoinEvent.class, PlayerRespawnEvent.class, EntityRegainHealthEvent.class, FoodLevelChangeEvent.class, WorldManager.class, PluginDescriptionFile.class }) public class TestWorldProperties { @@ -64,7 +69,7 @@ public class TestWorldProperties { private ThunderChangeEvent thunderChangeOffEvent; private ThunderChangeEvent thunderChangeOnEvent; private Player mockPlayer; - private PlayerChatEvent playerChatEvent; + private AsyncPlayerChatEvent playerChatEvent; private Player mockNewPlayer; private PlayerJoinEvent playerNewJoinEvent; private PlayerJoinEvent playerJoinEvent; @@ -89,7 +94,7 @@ public class TestWorldProperties { } @Test - public void test() { + public void test() throws Exception { // Initialize a fake command Command mockCommand = mock(Command.class); when(mockCommand.getName()).thenReturn("mv"); @@ -127,12 +132,9 @@ public class TestWorldProperties { assertEquals(mvWorld.getName(), mvWorld.getAlias()); assertEquals(ChatColor.WHITE, mvWorld.getColor()); assertTrue(mvWorld.isPVPEnabled()); - assertEquals((Object) 1D, (Object) mvWorld.getScaling()); // we're casting this to objects to use - // assertEquals(Object,Object) instead of assertEquals(double,double) + assertEquals(1D, mvWorld.getScaling(), 0); assertNull(mvWorld.getRespawnToWorld()); assertTrue(mvWorld.isWeatherEnabled()); - World cbWorld = mvWorld.getCBWorld(); - when(cbWorld.getDifficulty()).thenReturn(Difficulty.NORMAL); assertEquals(Difficulty.NORMAL, mvWorld.getDifficulty()); assertTrue(mvWorld.canAnimalsSpawn()); assertTrue(mvWorld.canMonstersSpawn()); @@ -145,7 +147,7 @@ public class TestWorldProperties { assertTrue(mvWorld.isKeepingSpawnInMemory()); assertTrue(mvWorld.getBedRespawn()); assertTrue(mvWorld.getAutoLoad()); - assertEquals(new Location(mvWorld.getCBWorld(), 0, 64, 0), mvWorld.getSpawnLocation()); + assertEquals(new SpawnLocation(0, 64, 0), mvWorld.getSpawnLocation()); /* ****************************************** * * Call some events and verify behavior @@ -166,10 +168,10 @@ public class TestWorldProperties { // call player chat event core.getMVConfig().setPrefixChat(true); - core.getPlayerListener().playerChat(playerChatEvent); + ((MVAsyncPlayerChatListener) core.getChatListener()).playerChat(playerChatEvent); verify(playerChatEvent).setFormat("[" + mvWorld.getColoredWorldString() + "]" + "format"); core.getMVConfig().setPrefixChat(false); - core.getPlayerListener().playerChat(playerChatEvent); + ((MVAsyncPlayerChatListener) core.getChatListener()).playerChat(playerChatEvent); verify(playerChatEvent, times(1)).setFormat(anyString()); // only ONE TIME (not the 2nd time!) // call player join events @@ -199,24 +201,21 @@ public class TestWorldProperties { mvWorld.setAlias("alias"); assertEquals("alias", mvWorld.getAlias()); assertTrue(mvWorld.setColor("BLACK")); - ChatColor oldColor = mvWorld.getColor(); assertFalse(mvWorld.setColor("INVALID COLOR")); - assertEquals(oldColor, mvWorld.getColor()); - assertEquals(oldColor.toString() + "alias" + ChatColor.WHITE.toString(), mvWorld.getColoredWorldString()); + assertEquals(ChatColor.BLACK, mvWorld.getColor()); + assertEquals(ChatColor.BLACK.toString() + "alias" + ChatColor.WHITE.toString(), mvWorld.getColoredWorldString()); mvWorld.setPVPMode(false); assertEquals(false, mvWorld.isPVPEnabled()); assertTrue(mvWorld.setScaling(2D)); - assertEquals((Object) 2D, (Object) mvWorld.getScaling()); + assertEquals(2D, mvWorld.getScaling(), 0); assertFalse(mvWorld.setRespawnToWorld("INVALID WORLD")); assertTrue(mvWorld.setRespawnToWorld("world_nether")); assertSame(worldManager.getMVWorld("world_nether").getCBWorld(), mvWorld.getRespawnToWorld()); mvWorld.setEnableWeather(false); assertEquals(false, mvWorld.isWeatherEnabled()); - assertTrue(mvWorld.setDifficulty("PEACEFUL")); - Difficulty oldDifficulty = mvWorld.getDifficulty(); - assertFalse(mvWorld.setDifficulty("INVALID DIFFICULTY")); - assertEquals(oldDifficulty, mvWorld.getDifficulty()); + assertTrue(mvWorld.setDifficulty(Difficulty.PEACEFUL)); + assertEquals(Difficulty.PEACEFUL, mvWorld.getDifficulty()); mvWorld.setAllowAnimalSpawn(false); assertEquals(false, mvWorld.canAnimalsSpawn()); mvWorld.setAllowMonsterSpawn(false); @@ -224,17 +223,15 @@ public class TestWorldProperties { mvWorld.setCurrency(1); assertEquals(1, mvWorld.getCurrency()); mvWorld.setPrice(1D); - assertEquals((Object) 1D, (Object) mvWorld.getPrice()); + assertEquals(1D, mvWorld.getPrice(), 0); mvWorld.setHunger(false); assertEquals(false, mvWorld.getHunger()); mvWorld.setAutoHeal(false); assertEquals(false, mvWorld.getAutoHeal()); mvWorld.setAdjustSpawn(false); assertEquals(false, mvWorld.getAdjustSpawn()); - assertTrue(mvWorld.setGameMode("CREATIVE")); - GameMode oldGamemode = mvWorld.getGameMode(); - assertFalse(mvWorld.setGameMode("INVALID GAMEMODE")); - assertEquals(oldGamemode, mvWorld.getGameMode()); + assertTrue(mvWorld.setGameMode(GameMode.CREATIVE)); + assertEquals(GameMode.CREATIVE, mvWorld.getGameMode()); mvWorld.setKeepSpawnInMemory(false); assertEquals(false, mvWorld.isKeepingSpawnInMemory()); mvWorld.setBedRespawn(false); @@ -242,7 +239,8 @@ public class TestWorldProperties { mvWorld.setAutoLoad(false); assertEquals(false, mvWorld.getAutoLoad()); mvWorld.setSpawnLocation(new Location(mvWorld.getCBWorld(), 1, 1, 1)); - assertEquals(new Location(mvWorld.getCBWorld(), 1, 1, 1), mvWorld.getSpawnLocation()); + assertEquals(new SpawnLocation(1, 1, 1), mvWorld.getSpawnLocation()); + /* ****************************************** * * Call some events and verify behavior @@ -264,22 +262,23 @@ public class TestWorldProperties { // call player chat event core.getMVConfig().setPrefixChat(true); - core.getPlayerListener().playerChat(playerChatEvent); + ((MVAsyncPlayerChatListener) core.getChatListener()).playerChat(playerChatEvent); // never because it's hidden! verify(playerChatEvent, never()).setFormat( "[" + mvWorld.getColoredWorldString() + "]" + "format"); mvWorld.setHidden(false); - core.getPlayerListener().playerChat(playerChatEvent); + ((MVAsyncPlayerChatListener) core.getChatListener()).playerChat(playerChatEvent); verify(playerChatEvent).setFormat("[" + mvWorld.getColoredWorldString() + "]" + "format"); core.getMVConfig().setPrefixChat(false); - core.getPlayerListener().playerChat(playerChatEvent); + ((MVAsyncPlayerChatListener) core.getChatListener()).playerChat(playerChatEvent); verify(playerChatEvent, times(1)).setFormat(anyString()); // only ONE TIME (not the 2nd time!) + mvWorld.setHidden(true); // reset hidden-state // call player join events core.getPlayerListener().playerJoin(playerJoinEvent); verify(mockPlayer, never()).teleport(any(Location.class)); core.getPlayerListener().playerJoin(playerNewJoinEvent); - verify(mockNewPlayer).teleport(new Location(mvWorld.getCBWorld(), 1, 1, 1)); + verify(mockNewPlayer).teleport(new SpawnLocation(1, 1, 1)); // call player respawn events core.getPlayerListener().playerRespawn(playerRespawnBed); @@ -292,6 +291,44 @@ public class TestWorldProperties { core.getEntityListener().entityRegainHealth(entityRegainHealthEvent); // autoheal is off so something should happen verify(entityRegainHealthEvent).setCancelled(true); + + + /* ****************************************** * + * Test saving/loading + * ****************************************** */ + assertTrue(core.saveMVConfigs()); + // change a value here + FileConfiguration config = YamlConfiguration.loadConfiguration(new File(core.getDataFolder(), "worlds.yml")); + MVWorld worldObj = (MVWorld) config.get("worlds.world"); + assertTrue(worldObj.setColor("GREEN")); + config.set("worlds.world", worldObj); + config.save(new File(core.getDataFolder(), "worlds.yml")); + // load + core.loadConfigs(); + + mvWorld = worldManager.getMVWorld("world"); + assertEquals(true, mvWorld.isHidden()); + assertEquals("alias", mvWorld.getAlias()); + assertEquals(ChatColor.GREEN, mvWorld.getColor()); + assertEquals(ChatColor.GREEN.toString() + "alias" + ChatColor.WHITE.toString(), mvWorld.getColoredWorldString()); + assertEquals(false, mvWorld.isPVPEnabled()); + assertEquals(2D, mvWorld.getScaling(), 0); + assertSame(worldManager.getMVWorld("world_nether").getCBWorld(), + mvWorld.getRespawnToWorld()); + assertEquals(false, mvWorld.isWeatherEnabled()); + assertEquals(Difficulty.PEACEFUL, mvWorld.getDifficulty()); + assertEquals(false, mvWorld.canAnimalsSpawn()); + assertEquals(false, mvWorld.canMonstersSpawn()); + assertEquals(1, mvWorld.getCurrency()); + assertEquals(1D, mvWorld.getPrice(), 0); + assertEquals(false, mvWorld.getHunger()); + assertEquals(false, mvWorld.getAutoHeal()); + assertEquals(false, mvWorld.getAdjustSpawn()); + assertEquals(GameMode.CREATIVE, mvWorld.getGameMode()); + assertEquals(false, mvWorld.isKeepingSpawnInMemory()); + assertEquals(false, mvWorld.getBedRespawn()); + assertEquals(false, mvWorld.getAutoLoad()); + assertEquals(new SpawnLocation(1, 1, 1), mvWorld.getSpawnLocation()); } public void createEvents(MultiverseWorld mvWorld) { @@ -308,7 +345,8 @@ public class TestWorldProperties { when(mockPlayer.getWorld()).thenReturn(mvWorld.getCBWorld()); when(mockPlayer.hasPlayedBefore()).thenReturn(true); when(mockPlayer.hasPermission("multiverse.access.world")).thenReturn(true); - playerChatEvent = PowerMockito.mock(PlayerChatEvent.class); + when(mockPlayer.getName()).thenReturn("MultiverseMan"); + playerChatEvent = PowerMockito.mock(AsyncPlayerChatEvent.class); when(playerChatEvent.getPlayer()).thenReturn(mockPlayer); when(playerChatEvent.getFormat()).thenReturn("format"); // player join diff --git a/src/test/java/com/onarandombox/MultiverseCore/test/TestWorldStuff.java b/src/test/java/com/onarandombox/MultiverseCore/test/TestWorldStuff.java index fc63b0e6..e8baa2d8 100644 --- a/src/test/java/com/onarandombox/MultiverseCore/test/TestWorldStuff.java +++ b/src/test/java/com/onarandombox/MultiverseCore/test/TestWorldStuff.java @@ -168,6 +168,35 @@ public class TestWorldStuff { verify(mockServer).createWorld(Matchers.argThat(matcher)); } + @Test + public void testWorldCreateInvalidGenerator() { + // Pull a core instance from the server. + Plugin plugin = mockServer.getPluginManager().getPlugin("Multiverse-Core"); + + // Make sure Core is not null + assertNotNull(plugin); + + // Make sure Core is enabled + assertTrue(plugin.isEnabled()); + + // Initialize a fake command + Command mockCommand = mock(Command.class); + when(mockCommand.getName()).thenReturn("mv"); + + // Ensure that there are no worlds imported. This is a fresh setup. + assertEquals(0, creator.getCore().getMVWorldManager().getMVWorlds().size()); + + // Create the world + String[] normalArgs = new String[]{ "create", "newworld", "normal", "-g", "BogusGen"}; + plugin.onCommand(mockCommandSender, mockCommand, "", normalArgs); + + // This command should halt, not creating any worlds + assertEquals(0, creator.getCore().getMVWorldManager().getMVWorlds().size()); + + // Verify + verify(mockCommandSender).sendMessage("Invalid generator! 'BogusGen'. " + ChatColor.RED + "Aborting world creation."); + } + @Test public void testNullWorld() { // Pull a core instance from the server. @@ -235,13 +264,13 @@ public class TestWorldStuff { // Now fail one. plugin.onCommand(mockCommandSender, mockCommand, "", new String[]{ "modify", "set", "mode", "fish", "world" }); try { - verify(mockCommandSender).sendMessage(mainWorld.getProperty("mode", Object.class).getHelp()); + verify(mockCommandSender).sendMessage(ChatColor.RED + mainWorld.getPropertyHelp("mode")); } catch (PropertyDoesNotExistException e) { fail("Mode property did not exist."); } plugin.onCommand(mockCommandSender, mockCommand, "", new String[]{ "modify", "set", "blah", "fish", "world" }); - verify(mockCommandSender).sendMessage(ChatColor.RED + "Sorry, You can't set: '"+ChatColor.GRAY+ "blah" + ChatColor.RED + "'"); + verify(mockCommandSender).sendMessage(ChatColor.RED + "Sorry, You can't set: '" + ChatColor.GRAY + "blah" + ChatColor.RED + "'"); } private void createInitialWorlds(Plugin plugin, Command command) { diff --git a/src/test/java/com/onarandombox/MultiverseCore/test/utils/MockWorldFactory.java b/src/test/java/com/onarandombox/MultiverseCore/test/utils/MockWorldFactory.java index c0f22b03..72daf003 100644 --- a/src/test/java/com/onarandombox/MultiverseCore/test/utils/MockWorldFactory.java +++ b/src/test/java/com/onarandombox/MultiverseCore/test/utils/MockWorldFactory.java @@ -14,7 +14,9 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.WeakHashMap; +import org.bukkit.Difficulty; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; @@ -28,20 +30,74 @@ public class MockWorldFactory { private static final Map createdWorlds = new HashMap(); + private static final Map pvpStates = new WeakHashMap(); + private static final Map keepSpawnInMemoryStates = new WeakHashMap(); + private static final Map difficultyStates = new WeakHashMap(); + private MockWorldFactory() { } private static void registerWorld(World world) { createdWorlds.put(world.getName(), world); + new File(TestInstanceCreator.worldsDirectory, world.getName()).mkdir(); } private static World basics(String world, World.Environment env, WorldType type) { World mockWorld = mock(World.class); when(mockWorld.getName()).thenReturn(world); + when(mockWorld.getPVP()).thenAnswer(new Answer() { + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + World w = (World) invocation.getMock(); + if (!pvpStates.containsKey(w)) + pvpStates.put(w, true); // default value + return pvpStates.get(w); + } + }); + doAnswer(new Answer() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + pvpStates.put((World) invocation.getMock(), (Boolean) invocation.getArguments()[0]); + return null; + } + }).when(mockWorld).setPVP(anyBoolean()); + when(mockWorld.getKeepSpawnInMemory()).thenAnswer(new Answer() { + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + World w = (World) invocation.getMock(); + if (!keepSpawnInMemoryStates.containsKey(w)) + keepSpawnInMemoryStates.put(w, true); // default value + return keepSpawnInMemoryStates.get(w); + } + }); + doAnswer(new Answer() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + keepSpawnInMemoryStates.put((World) invocation.getMock(), (Boolean) invocation.getArguments()[0]); + return null; + } + }).when(mockWorld).setKeepSpawnInMemory(anyBoolean()); + when(mockWorld.getDifficulty()).thenAnswer(new Answer() { + @Override + public Difficulty answer(InvocationOnMock invocation) throws Throwable { + World w = (World) invocation.getMock(); + if (!difficultyStates.containsKey(w)) + difficultyStates.put(w, Difficulty.NORMAL); // default value + return difficultyStates.get(w); + } + }); + doAnswer(new Answer() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + difficultyStates.put((World) invocation.getMock(), (Difficulty) invocation.getArguments()[0]); + return null; + } + }).when(mockWorld).setDifficulty(any(Difficulty.class)); when(mockWorld.getEnvironment()).thenReturn(env); when(mockWorld.getWorldType()).thenReturn(type); when(mockWorld.getSpawnLocation()).thenReturn(new Location(mockWorld, 0, 64, 0)); when(mockWorld.getWorldFolder()).thenAnswer(new Answer() { + @Override public File answer(InvocationOnMock invocation) throws Throwable { if (!(invocation.getMock() instanceof World)) return null; @@ -51,6 +107,7 @@ public class MockWorldFactory { } }); when(mockWorld.getBlockAt(any(Location.class))).thenAnswer(new Answer() { + @Override public Block answer(InvocationOnMock invocation) throws Throwable { Location loc; try { @@ -85,6 +142,7 @@ public class MockWorldFactory { when(mockWorld.getWorldType()).thenReturn(type); when(mockWorld.getSpawnLocation()).thenReturn(new Location(mockWorld, 0, 64, 0)); when(mockWorld.getWorldFolder()).thenAnswer(new Answer() { + @Override public File answer(InvocationOnMock invocation) throws Throwable { if (!(invocation.getMock() instanceof World)) return null; @@ -94,6 +152,7 @@ public class MockWorldFactory { } }); when(mockWorld.getBlockAt(any(Location.class))).thenAnswer(new Answer() { + @Override public Block answer(InvocationOnMock invocation) throws Throwable { Location loc; try { @@ -155,6 +214,8 @@ public class MockWorldFactory { } public static void clearWorlds() { + for (String name : createdWorlds.keySet()) + new File(TestInstanceCreator.worldsDirectory, name).delete(); createdWorlds.clear(); } } diff --git a/src/test/java/com/onarandombox/MultiverseCore/test/utils/TestInstanceCreator.java b/src/test/java/com/onarandombox/MultiverseCore/test/utils/TestInstanceCreator.java index 1f93233c..3b3a6b7b 100644 --- a/src/test/java/com/onarandombox/MultiverseCore/test/utils/TestInstanceCreator.java +++ b/src/test/java/com/onarandombox/MultiverseCore/test/utils/TestInstanceCreator.java @@ -7,18 +7,15 @@ package com.onarandombox.MultiverseCore.test.utils; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.*; - -import java.io.File; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - +import buscript.Buscript; +import com.onarandombox.MultiverseCore.MultiverseCore; +import com.onarandombox.MultiverseCore.api.MultiverseWorld; +import com.onarandombox.MultiverseCore.listeners.MVEntityListener; +import com.onarandombox.MultiverseCore.listeners.MVPlayerListener; +import com.onarandombox.MultiverseCore.listeners.MVWeatherListener; +import com.onarandombox.MultiverseCore.utils.FileUtils; +import com.onarandombox.MultiverseCore.utils.WorldManager; import junit.framework.Assert; - import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Server; @@ -37,13 +34,15 @@ import org.mockito.stubbing.Answer; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.MockGateway; -import com.onarandombox.MultiverseCore.MultiverseCore; -import com.onarandombox.MultiverseCore.api.MultiverseWorld; -import com.onarandombox.MultiverseCore.listeners.MVEntityListener; -import com.onarandombox.MultiverseCore.listeners.MVPlayerListener; -import com.onarandombox.MultiverseCore.listeners.MVWeatherListener; -import com.onarandombox.MultiverseCore.utils.FileUtils; -import com.onarandombox.MultiverseCore.utils.WorldManager; +import java.io.File; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; public class TestInstanceCreator { private MultiverseCore core; @@ -62,6 +61,12 @@ public class TestInstanceCreator { MockGateway.MOCK_STANDARD_METHODS = false; core = PowerMockito.spy(new MultiverseCore()); + PowerMockito.doAnswer(new Answer() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + return null; // don't run metrics in tests + } + }).when(core, "setupMetrics"); // Let's let all MV files go to bin/test doReturn(pluginDirectory).when(core).getDataFolder(); @@ -82,6 +87,8 @@ public class TestInstanceCreator { when(mockPluginManager.getPlugins()).thenReturn(plugins); when(mockPluginManager.getPlugin("Multiverse-Core")).thenReturn(core); when(mockPluginManager.getPermission(anyString())).thenReturn(null); + // Tell Buscript Vault is not available. + when(mockPluginManager.getPermission("Vault")).thenReturn(null); // Make some fake folders to fool the fake MV into thinking these worlds exist File worldNormalFile = new File(core.getServerFolder(), "world"); @@ -103,6 +110,7 @@ public class TestInstanceCreator { // Give the server some worlds when(mockServer.getWorld(anyString())).thenAnswer(new Answer() { + @Override public World answer(InvocationOnMock invocation) throws Throwable { String arg; try { @@ -115,6 +123,7 @@ public class TestInstanceCreator { }); when(mockServer.getWorlds()).thenAnswer(new Answer>() { + @Override public List answer(InvocationOnMock invocation) throws Throwable { return MockWorldFactory.getWorlds(); } @@ -124,6 +133,7 @@ public class TestInstanceCreator { when(mockServer.createWorld(Matchers.isA(WorldCreator.class))).thenAnswer( new Answer() { + @Override public World answer(InvocationOnMock invocation) throws Throwable { WorldCreator arg; try { @@ -146,6 +156,7 @@ public class TestInstanceCreator { BukkitScheduler mockScheduler = mock(BukkitScheduler.class); when(mockScheduler.scheduleSyncDelayedTask(any(Plugin.class), any(Runnable.class), anyLong())). thenAnswer(new Answer() { + @Override public Integer answer(InvocationOnMock invocation) throws Throwable { Runnable arg; try { @@ -158,6 +169,7 @@ public class TestInstanceCreator { }}); when(mockScheduler.scheduleSyncDelayedTask(any(Plugin.class), any(Runnable.class))). thenAnswer(new Answer() { + @Override public Integer answer(InvocationOnMock invocation) throws Throwable { Runnable arg; try { @@ -175,6 +187,13 @@ public class TestInstanceCreator { serverfield.setAccessible(true); serverfield.set(core, mockServer); + // Set buscript + Buscript buscript = PowerMockito.spy(new Buscript(core)); + Field buscriptfield = MultiverseCore.class.getDeclaredField("buscript"); + buscriptfield.setAccessible(true); + buscriptfield.set(core, buscript); + when(buscript.getPlugin()).thenReturn(core); + // Set worldManager WorldManager wm = PowerMockito.spy(new WorldManager(core)); Field worldmanagerfield = MultiverseCore.class.getDeclaredField("worldManager"); @@ -204,6 +223,7 @@ public class TestInstanceCreator { commandSenderLogger.setParent(Util.logger); commandSender = mock(CommandSender.class); doAnswer(new Answer() { + @Override public Void answer(InvocationOnMock invocation) throws Throwable { commandSenderLogger.info(ChatColor.stripColor((String) invocation.getArguments()[0])); return null; @@ -252,6 +272,8 @@ public class TestInstanceCreator { return false; } + core.onDisable(); + FileUtils.deleteFolder(serverDirectory); MockWorldFactory.clearWorlds();