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);
}
}