package com.nicewuerfel.blockown; import com.google.common.annotations.VisibleForTesting; import com.nicewuerfel.blockown.output.Output; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Animals; import org.bukkit.entity.Entity; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class Setting { /** * What kind of release this is. Update before releases. */ private static final ReleaseChannel RELEASE_TYPE = ReleaseChannel.STABLE; private static final class KEY { private static final String VERSION = "version"; private static final String DEBUG_MODE = "debug-mode"; private static final String ENABLED_WORLDS = "enabledWorlds"; private static final String DISABLED_WORLDS = "disabledWorlds"; private static final class DATABASE { private static final class MYSQL { private static final String ENABLE = "Database.MySQL.enable"; private static final String HOST = "Database.MySQL.host"; private static final String PORT = "Database.MySQL.port"; private static final String DATABASE = "Database.MySQL.database"; private static final String USER = "Database.MySQL.user"; private static final String PASSWORD = "Database.MySQL.password"; } private static final String ALLOW_ENTITIES = "Database.allowEntities"; private static final String ALLOW_ANIMALS = "Database.allowAnimals"; private static final String ALLOWED_MATERIALS = "Database.allowedMaterials"; private static final String DISALLOWED_MATERIALS = "Database.disallowedMaterials"; private static final String MAX_SELECTION = "Database.maxSelectionSize"; } private static final class PROTECTION { private static final String AUTO_PROTECT_OWNED_BLOCKS = "Protection.autoProtectOwnedBlocks"; private static final String AUTO_PROTECT_OWNED_ENTITIES = "Protection.autoProtectOwnedEntities"; private static final String AUTO_PROTECT_OWNED_ANIMALS = "Protection.autoProtectOwnedAnimals"; private static final String AUTO_PROTECT_MATERIALS = "Protection.autoProtectMaterials"; private static final String ALLOWED_MATERIALS = "Protection.allowedMaterials"; private static final String DISALLOWED_MATERIALS = "Protection.disallowedMaterials"; private static final String PROTECT_AGAINST_ENVIRONMENT = "Protection.protectAgainstEnvironment"; private static final String ALLOW_RIGHT_CLICKS_ON = "Protection.allowRightClicksOn"; private static final String DECAY = "Protection.decay"; private static final String ENABLE_MESSAGES = "Protection.enableMessages"; } } public PluginVersion VERSION; public boolean DEBUG_MODE; private Set<String> ENABLED_WORLDS; private Set<String> DISABLED_WORLDS; public final class DATABASE { public final class MYSQL { public boolean ENABLE; public String HOST; public int PORT; public String DATABASE; public String USER; public String PASSWORD; } public final MYSQL MYSQL = new MYSQL(); public boolean ALLOW_ENTITIES; public boolean ALLOW_ANIMALS; public Set<Material> ALLOWED_MATERIALS; public Set<Material> DISALLOWED_MATERIALS; public int MAX_SELECTION; } public final DATABASE DATABASE = new DATABASE(); public final class PROTECTION { public boolean AUTO_PROTECT_OWNED_BLOCKS; public boolean AUTO_PROTECT_OWNED_ENTITIES; public boolean AUTO_PROTECT_OWNED_ANIMALS; public Set<Material> AUTO_PROTECT_MATERIALS; public Set<Material> ALLOWED_MATERIALS; public Set<Material> DISALLOWED_MATERIALS; public boolean PROTECT_AGAINST_ENVIRONMENT; public Set<Material> ALLOW_RIGHT_CLICKS_ON; /** * Protection decay in hours */ public long DECAY; public boolean ENABLE_MESSAGES; } public final PROTECTION PROTECTION = new PROTECTION(); public void updateDeprecatedSettings() { for (Old old : Old.values()) { PluginVersion deprecatingVersion = new PluginVersion(old.getDeprecatingVersion(), ReleaseChannel.STABLE); if (deprecatingVersion.compareTo(VERSION) > 0) { Object o = getConfig().get(old.getOldKey()); if (o != null) { if (old.getNewKey() != null) { getConfig().set(old.getNewKey(), o); } getConfig().set(old.getOldKey(), null); } } } reload(); } @Deprecated private enum Old { PROTECTION_PROTECT_ONLY_LEFT_CLICKS("3.0.5", "Protection.onlyLeftClicks", null), PROTECTION_PROTECT_ALLOW_RIGHT_CLICKS("5.1", "Protection.allowRightClicks", null); private final String deprecatingVersion; private final String key; private final String newKey; Old(String deprecatingVersion, String key, String newKey) { this.deprecatingVersion = deprecatingVersion; this.key = key; this.newKey = newKey; } public String getDeprecatingVersion() { return deprecatingVersion; } @Nonnull public String getOldKey() { return key; } @Nullable public String getNewKey() { return newKey; } } private final File configFile; private final FileConfiguration config; private Output output; private Set<World> enabledWorlds; private final Set<User> ignoringUsers; private final Set<User> nonOwningUsers; private final Map<User, WaitType> waitingUsers; @Nullable public static Setting load(Output output, File configFile) { FileConfiguration config = YamlConfiguration.loadConfiguration(configFile); try { config.addDefaults(YamlConfiguration.loadConfiguration( new InputStreamReader(Setting.class.getResourceAsStream("/config.yml"), "UTF-8"))); } catch (UnsupportedEncodingException e) { output.printError("UTF-8 is not supported."); return null; } Setting result = new Setting(output, configFile, config); result.load(); return result; } /** * Only visible for testing * * @param output the Output * @param config the config * @return a Setting instance */ @VisibleForTesting public static Setting load(Output output, FileConfiguration config) { Setting result = new Setting(output, null, config); result.load(); return result; } private Setting(Output output, File configFile, FileConfiguration config) { this.output = output; this.configFile = configFile; this.config = config; ignoringUsers = new HashSet<>(128 * 2); nonOwningUsers = new HashSet<>(128 * 2); waitingUsers = new HashMap<>(128 * 2); } /** * Returns a set of worlds the plugin should be enabled in.<br> * The set contains either the elements of ENABLED_WORLDS without the elements of DISABLED_WORLDS * or all valid worlds without the element of DISABLED_WORLDS * * @param worldMap maps lower case world names to worlds * @return a Set<World> */ private Set<World> getEnabledWorlds(Map<String, World> worldMap) { Set<World> result; if (ENABLED_WORLDS.isEmpty()) { result = new HashSet<>(worldMap.values()); } else { result = new HashSet<>(ENABLED_WORLDS.size() * 2); for (String worldName : ENABLED_WORLDS) { World world; if ((world = worldMap.get(worldName)) != null) { result.add(world); } else { getOutput().printConsole("Could not find enabled world: " + worldName); } } } for (String worldName : DISABLED_WORLDS) { World world; if ((world = worldMap.get(worldName)) != null) { result.remove(world); } else { getOutput().printConsole("Could not find disabled world: " + worldName); } } return result; } /** * Determines whether it is allowed to own a material. * * @param material the Material * @return true, if it is allowed to own the material */ public boolean isOwnEnabled(Material material) { if (DATABASE.DISALLOWED_MATERIALS.contains(material)) { return false; } if (DATABASE.ALLOWED_MATERIALS.contains(material)) { return true; } if (material.isBlock()) { return DATABASE.ALLOWED_MATERIALS.isEmpty(); } Class<? extends Entity> materialClass = material.getEntityType().getEntityClass(); if (material.getEntityType().isAlive() && (materialClass == null || Animals.class.isAssignableFrom(materialClass))) { return DATABASE.ALLOW_ANIMALS; } if (!material.getEntityType().isAlive()) { return DATABASE.ALLOW_ENTITIES; } return false; } public boolean isProtectEnabled(Material material) { if (PROTECTION.DISALLOWED_MATERIALS.contains(material)) { return false; } else { return PROTECTION.ALLOWED_MATERIALS.isEmpty() || PROTECTION.ALLOWED_MATERIALS.contains(material); } } public boolean isEnabledIn(World world) { if (enabledWorlds == null) { throw new IllegalStateException("Enabled worlds have not been loaded yet"); } return enabledWorlds.contains(world); } private void load() { DEBUG_MODE = getConfig().getBoolean(KEY.DEBUG_MODE); ENABLED_WORLDS = createWorldNameSet(getConfig().getStringList(KEY.ENABLED_WORLDS)); DISABLED_WORLDS = createWorldNameSet(getConfig().getStringList(KEY.DISABLED_WORLDS)); VERSION = new PluginVersion(getConfig().getString(KEY.VERSION), RELEASE_TYPE); // PROTECTION PROTECTION.ALLOW_RIGHT_CLICKS_ON = createMaterialSet(getConfig().getStringList(KEY.PROTECTION.ALLOW_RIGHT_CLICKS_ON)); PROTECTION.ALLOWED_MATERIALS = createMaterialSet(getConfig().getStringList(KEY.PROTECTION.ALLOWED_MATERIALS)); PROTECTION.DISALLOWED_MATERIALS = createMaterialSet(getConfig().getStringList(KEY.PROTECTION.DISALLOWED_MATERIALS)); PROTECTION.AUTO_PROTECT_MATERIALS = createMaterialSet(getConfig().getStringList(KEY.PROTECTION.AUTO_PROTECT_MATERIALS)); PROTECTION.AUTO_PROTECT_OWNED_ANIMALS = getConfig().getBoolean(KEY.PROTECTION.AUTO_PROTECT_OWNED_ANIMALS); PROTECTION.AUTO_PROTECT_OWNED_BLOCKS = getConfig().getBoolean(KEY.PROTECTION.AUTO_PROTECT_OWNED_BLOCKS); PROTECTION.AUTO_PROTECT_OWNED_ENTITIES = getConfig().getBoolean(KEY.PROTECTION.AUTO_PROTECT_OWNED_ENTITIES); PROTECTION.PROTECT_AGAINST_ENVIRONMENT = getConfig().getBoolean(KEY.PROTECTION.PROTECT_AGAINST_ENVIRONMENT); PROTECTION.DECAY = getConfig().getLong(KEY.PROTECTION.DECAY); PROTECTION.ENABLE_MESSAGES = getConfig().getBoolean(KEY.PROTECTION.ENABLE_MESSAGES); // DATABASE DATABASE.ALLOW_ANIMALS = getConfig().getBoolean(KEY.DATABASE.ALLOW_ANIMALS); DATABASE.ALLOW_ENTITIES = getConfig().getBoolean(KEY.DATABASE.ALLOW_ENTITIES); DATABASE.ALLOWED_MATERIALS = createMaterialSet(getConfig().getStringList(KEY.DATABASE.ALLOWED_MATERIALS)); DATABASE.DISALLOWED_MATERIALS = createMaterialSet(getConfig().getStringList(KEY.DATABASE.DISALLOWED_MATERIALS)); DATABASE.MAX_SELECTION = getConfig().getInt(KEY.DATABASE.MAX_SELECTION); // MYSQL DATABASE.MYSQL.ENABLE = getConfig().getBoolean(KEY.DATABASE.MYSQL.ENABLE); DATABASE.MYSQL.HOST = getConfig().getString(KEY.DATABASE.MYSQL.HOST); DATABASE.MYSQL.PORT = getConfig().getInt(KEY.DATABASE.MYSQL.PORT); DATABASE.MYSQL.DATABASE = getConfig().getString(KEY.DATABASE.MYSQL.DATABASE); DATABASE.MYSQL.USER = getConfig().getString(KEY.DATABASE.MYSQL.USER); DATABASE.MYSQL.PASSWORD = getConfig().getString(KEY.DATABASE.MYSQL.PASSWORD); } private void reload() { List<World> validWorlds = Bukkit.getServer().getWorlds(); load(); loadEnabledWorlds(validWorlds); } private Set<String> createWorldNameSet(List<String> stringList) { Set<String> result = new HashSet<>(stringList.size() * 2); for (String worldName : stringList) { worldName = worldName.toLowerCase(); result.add(worldName); } return result; } private Set<Material> createMaterialSet(List<String> stringList) { Set<Material> result = new HashSet<>(stringList.size() * 3); for (String materialName : stringList) { Material material = Material.parseMaterial(materialName); result.add(material); } return result; } public void save() throws IOException { getConfig().set(KEY.VERSION, VERSION.getVersion() + "-" + VERSION.getReleaseChannel()); getConfig().set(KEY.DEBUG_MODE, DEBUG_MODE); getConfig().set(KEY.ENABLED_WORLDS, new ArrayList<>(ENABLED_WORLDS)); getConfig().set(KEY.DISABLED_WORLDS, new ArrayList<>(DISABLED_WORLDS)); // PROTECTION getConfig().set(KEY.PROTECTION.ALLOW_RIGHT_CLICKS_ON, getMaterialStringList(PROTECTION.ALLOW_RIGHT_CLICKS_ON)); getConfig().set(KEY.PROTECTION.PROTECT_AGAINST_ENVIRONMENT, PROTECTION.PROTECT_AGAINST_ENVIRONMENT); getConfig().set(KEY.PROTECTION.ALLOWED_MATERIALS, getMaterialStringList(PROTECTION.ALLOWED_MATERIALS)); getConfig().set(KEY.PROTECTION.DISALLOWED_MATERIALS, getMaterialStringList(PROTECTION.DISALLOWED_MATERIALS)); getConfig().set(KEY.PROTECTION.AUTO_PROTECT_MATERIALS, getMaterialStringList(PROTECTION.AUTO_PROTECT_MATERIALS)); getConfig().set(KEY.PROTECTION.AUTO_PROTECT_OWNED_BLOCKS, PROTECTION.AUTO_PROTECT_OWNED_BLOCKS); getConfig().set(KEY.PROTECTION.AUTO_PROTECT_OWNED_ENTITIES, PROTECTION.AUTO_PROTECT_OWNED_ENTITIES); getConfig().set(KEY.PROTECTION.AUTO_PROTECT_OWNED_ANIMALS, PROTECTION.AUTO_PROTECT_OWNED_ANIMALS); getConfig().set(KEY.PROTECTION.DECAY, PROTECTION.DECAY); getConfig().set(KEY.PROTECTION.ENABLE_MESSAGES, PROTECTION.ENABLE_MESSAGES); // DATABASE getConfig().set(KEY.DATABASE.MAX_SELECTION, DATABASE.MAX_SELECTION); getConfig().set(KEY.DATABASE.ALLOW_ENTITIES, DATABASE.ALLOW_ENTITIES); getConfig().set(KEY.DATABASE.ALLOW_ANIMALS, DATABASE.ALLOW_ANIMALS); getConfig().set(KEY.DATABASE.ALLOWED_MATERIALS, getMaterialStringList(DATABASE.ALLOWED_MATERIALS)); getConfig().set(KEY.DATABASE.DISALLOWED_MATERIALS, getMaterialStringList(DATABASE.DISALLOWED_MATERIALS)); // MYSQL getConfig().set(KEY.DATABASE.MYSQL.ENABLE, DATABASE.MYSQL.ENABLE); getConfig().set(KEY.DATABASE.MYSQL.HOST, DATABASE.MYSQL.HOST); getConfig().set(KEY.DATABASE.MYSQL.PORT, DATABASE.MYSQL.PORT); getConfig().set(KEY.DATABASE.MYSQL.DATABASE, DATABASE.MYSQL.DATABASE); getConfig().set(KEY.DATABASE.MYSQL.USER, DATABASE.MYSQL.USER); getConfig().set(KEY.DATABASE.MYSQL.PASSWORD, DATABASE.MYSQL.PASSWORD); getConfig().save(getConfigFile()); } /** * Creates a List<String> containing the values the materials in the given set return for * {@link Material#toString()} * * @param materialSet the Set<Material> * @return the list */ private List<String> getMaterialStringList(Set<Material> materialSet) { List<String> result = new ArrayList<>(materialSet.size()); for (Material material : materialSet) { result.add(material.toString()); } return result; } void setOutput(Output output) { this.output = output; } public Output getOutput() { return output; } private FileConfiguration getConfig() { return config; } private File getConfigFile() { return configFile; } void loadEnabledWorlds(List<World> validWorlds) { Map<String, World> worldMap = new HashMap<>(validWorlds.size() * 3); for (World world : validWorlds) { worldMap.put(world.getName().toLowerCase(), world); } this.enabledWorlds = getEnabledWorlds(worldMap); } public boolean isIgnoring(User user) { return ignoringUsers.contains(user); } /** * Set the ignore mode state of a user. * * @param user the User * @param enable the new ignore mode state */ public void setIgnoring(User user, boolean enable) { if (enable) { ignoringUsers.add(user); } else { ignoringUsers.remove(user); } } public boolean isOwning(User user) { return !nonOwningUsers.contains(user); } /** * Set the owning mode state of a user. * * @param user the User * @param enable the new owning mode state */ public void setOwning(User user, boolean enable) { if (enable) { nonOwningUsers.remove(user); } else { nonOwningUsers.add(user); } } public void addWaiting(User user, WaitType waitType) { waitingUsers.put(user, waitType); } public boolean isWaiting(User user, WaitType waitType) { return waitingUsers.get(user) == waitType; } public WaitType getWaiting(User user) { return waitingUsers.get(user); } public void removeWaiting(User user) { waitingUsers.remove(user); } }