Skip to content

Instantly share code, notes, and snippets.

@boy0001
Last active June 5, 2016 00:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save boy0001/5415dd0a4ffe02b80663494240893eea to your computer and use it in GitHub Desktop.
Save boy0001/5415dd0a4ffe02b80663494240893eea to your computer and use it in GitHub Desktop.
example config for plotsquared
package com.intellectualcrafters.plot.config;
import com.intellectualcrafters.configuration.MemorySection;
import com.intellectualcrafters.configuration.file.YamlConfiguration;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.util.StringMan;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Settings {
/*
START OF CONFIGURATION SECTION:
*/
@Comment("These first 4 aren't configurable") // This is a comment
@Final // Indicates that this value isn't configurable
public static final String ISSUES = "'https://github.com/IntellectualSites/PlotSquared/issues'";
@Final
public static final String WIKI = "'https://github.com/IntellectualSites/PlotSquared/wiki'";
@Final
public static final String VERSION = null; // These values are set from PS before loading
@Final
public static final String PLATFORM = null; // These values are set from PS before loading
@Comment("Send anonymous usage statistics")
public static boolean METRICS = true;
@Comment("Show additional information in console")
public static boolean DEBUG = true;
@Comment({"The big annoying text that appears when you enter a plot", "For a single plot: `/plot flag set titles false`", "FOr just you `/plot toggle titles`"})
public static boolean TITLES = true;
@Comment({"Enable or disable part of the plugin","Note: A cache will use some memory if enabled"})
public static final class ENABLED_COMPONENTS { // Group the following values into a new config section
@Comment("The database stores all the plots")
public static boolean DATABASE = true;
@Comment("Events are needed to track a lot of things")
public static boolean EVENTS = true;
@Comment("Commands are used to interact with the plugin")
public static boolean COMMANDS = true;
@Comment("The UUID cacher is used to resolve player names")
public static boolean UUID_CACHE = true;
@Comment("Notify players of updates")
public static boolean UPDATER = true;
@Comment("Optimizes permission checks")
public static boolean PERMISSION_CACHE = true;
@Comment("Optimizes block changing code")
public static boolean BLOCK_CACHE = true;
@Comment("Getting a rating won't need the database")
public static boolean RATING_CACHE = true;
@Comment("The converter will attempt to convert the PlotMe database")
public static boolean PLOTME_CONVERTER = true;
@Comment("Allow WorldEdit to be restricted to plots")
public static boolean WORLDEDIT_RESTRICTIONS = true;
@Comment("Expiry will clear old or simplistic plots")
public static boolean PLOT_EXPIRY = false;
@Comment("Processes chunks (trimming, or entity/tile limits) ")
public static boolean CHUNK_PROCESSOR = false;
@Comment("Kill mobs or vehicles on roads")
public static boolean KILL_ROAD_MOBS = false;
public static boolean KILL_ROAD_VEHICLES = false;
@Comment("Notify a player of any missed comments upon plot entry")
public static boolean COMMENT_NOTIFIER = false;
@Comment("Actively purge invalid database entries")
public static boolean DATABASE_PURGER = false;
@Comment("Delete plots when a player is banned")
public static boolean BAN_DELETER = false;
}
@Create // This value will be generated automatically
public static final ConfigBlock<AUTO_CLEAR> AUTO_CLEAR = null; // A ConfigBlock is a section that can have multiple instances e.g. multiple expiry tasks
@Comment("This is an auto clearing task called `task1`")
@BlockName("task1") // The name for the default block
public static final class AUTO_CLEAR extends ConfigBlock {
@Create // This value has to be generated since an instance isn't static
public CALIBRATION CALIBRATION = null;
@Comment("See: https://github.com/IntellectualSites/PlotSquared/wiki/Plot-analysis")
public static final class CALIBRATION {
public int VARIETY = 0;
public int VARIETY_SD = 0;
public int CHANGES = 0;
public int CHANGES_SD = 1;
public int FACES = 0;
public int FACES_SD = 0;
public int DATA_SD = 0;
public int AIR = 0;
public int AIR_SD = 0;
public int DATA = 0;
}
public int THRESHOLD = 1;
public boolean CONFIRMATION = true;
public int DAYS = 7;
public int CLEAR_INTERVAL_SECONDS = 120;
}
public static class CHUNK_PROCESSOR {
@Comment("Auto trim will not save chunks which aren't claimed")
public static boolean AUTO_TRIM = false;
@Comment("Max tile entities per chunk")
public static int MAX_TILES = 4096;
@Comment("Max entities per chunk")
public static int MAX_ENTITIES = 512;
@Comment("Disable block physics")
public static boolean DISABLE_PHYSICS = false;
}
public static class UUID {
@Comment("Force PlotSquared to use offline UUIDs (it usually detects the right mode)")
public static boolean OFFLINE = false;
@Comment("Force PlotSquared to use lowercase UUIDs")
public static boolean FORCE_LOWERCASE = false;
@Comment("Use a database to store UUID/name info")
public static boolean USE_SQLUUIDHANDLER = false;
}
@Comment("Configure the paths PlotSquared will use")
public static final class PATHS {
public static String SCHEMATICS = "'schematics'";
public static String BO3 = "'bo3'";
public static String SCRIPTS = "'scripts'";
public static String TEMPLATES = "'templates'";
public static String TRANSLATIONS = "'translations'";
}
public static class WEB {
@Comment("We are already hosting a web interface for you:")
public static String URL = "'http://empcraft.com/plots/'";
@Comment("The ip that will show up in the interface")
public static String SERVER_IP = "'your.ip.here'";
}
public static final class DONE {
@Comment("Require a done plot to download")
public static boolean REQUIRED_FOR_DOWNLOAD = false;
@Comment("Only done plots can be rated")
public static boolean REQUIRED_FOR_RATINGS = false;
@Comment("Restrict building when a plot is done")
public static boolean RESTRICT_BUILDING = false;
@Comment("The limit being how many plots a player can claim")
public static boolean COUNTS_TOWARDS_LIMIT = true;
}
public static final class CHAT {
@Comment("Sometimes console color doesn't work, you can disable it here")
public static boolean CONSOLE_COLOR = true;
@Comment("Should chat be interactive")
public static boolean INTERACTIVE = true;
}
@Comment("Relating to how many plots someone can claim ")
public static final class LIMIT {
@Comment("Should the limit be global (over multiple worlds)")
public static boolean GLOBAL = false;
@Comment("The range of permissions to check e.g. plots.plot.127")
public static int MAX_PLOTS = 127;
}
@Comment("Switching from PlotMe?")
public static final class PLOTME {
@Comment("Cache the uuids from the PlotMe database")
public static boolean CACHE_UUDS = false;
@Comment("Have `/plotme` as a command alias")
public static boolean ALIAS = false;
}
public static final class TELEPORT {
@Comment("Teleport to your plot on death")
public static boolean ON_DEATH = false;
@Comment("Teleport to your plot on login")
public static boolean ON_LOGIN = false;
@Comment("Add a teleportation delay to all commands")
public static int DELAY = 0;
}
public static final class REDSTONE {
@Comment("Disable redstone in unoccupied plots")
public static boolean DISABLE_UNOCCUPIED = false;
@Comment("Disable redstone when all owners/trusted/members are offline")
public static boolean DISABLE_OFFLINE = false;
}
public static final class CLAIM {
@Comment("The max plots claimed in a single `/plot auto <size>` command")
public static int MAX_AUTO_AREA = 4;
}
public static final class RATINGS {
public static List<String> CATEGORIES = new ArrayList<>();
}
/*
END OF CONFIGURATION SECTION:
*/
/**
* Indicates that a field should be instantiated / created
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
private @interface Create {}
/**
* Indicates that a field cannot be modified
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
private @interface Final {}
/**
* Creates a comment
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE})
private @interface Comment {
String[] value();
}
/**
* The names of any default blocks
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE})
private @interface BlockName {
String[] value();
}
/**
* Any field or class with is not part of the config
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE})
private @interface Ignore {}
@Ignore // This is not part of the config
public static class ConfigBlock<T> {
private HashMap<String, T> INSTANCES = new HashMap<>();
public T get(String key) {
return INSTANCES.get(key);
}
public void put(String key, T value) {
INSTANCES.put(key, value);
}
public Map<String, T> getRaw() {
return INSTANCES;
}
}
public static boolean load(File file) {
if (!file.exists()) {
return false;
}
YamlConfiguration yml = YamlConfiguration.loadConfiguration(file);
for (String key : yml.getKeys(true)) {
Object value = yml.get(key);
if (value instanceof MemorySection) {
continue;
}
set(key, value);
}
return true;
}
/**
* Set all values in the file (load first to avoid overwriting)
* @param file
* @throws IOException
*/
public static void save(File file) throws IOException {
if (!file.exists()) {
file.getParentFile().mkdirs();
file.createNewFile();
}
PrintWriter writer = new PrintWriter(file);
Class clazz = Settings.class;
Object instance = new Settings();
save(writer, clazz, instance, 0);
writer.close();
}
public static boolean convertLegacy(File file) {
if (!file.exists()) {
return false;
}
YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
// Protection
REDSTONE.DISABLE_OFFLINE = config.getBoolean("protection.redstone.disable-offline");
REDSTONE.DISABLE_UNOCCUPIED = config.getBoolean("protection.redstone.disable-unoccupied", REDSTONE.DISABLE_UNOCCUPIED);
// PlotMe
PLOTME.ALIAS = config.getBoolean("plotme-alias", PLOTME.ALIAS);
ENABLED_COMPONENTS.PLOTME_CONVERTER = config.getBoolean("plotme-convert.enabled", ENABLED_COMPONENTS.PLOTME_CONVERTER);
PLOTME.CACHE_UUDS = config.getBoolean("plotme-convert.cache-uuids", PLOTME.CACHE_UUDS);
// UUID
UUID.USE_SQLUUIDHANDLER = config.getBoolean("uuid.use_sqluuidhandler", UUID.USE_SQLUUIDHANDLER);
UUID.OFFLINE = config.getBoolean("UUID.offline", UUID.OFFLINE);
UUID.FORCE_LOWERCASE = config.getBoolean("UUID.force-lowercase", UUID.FORCE_LOWERCASE);
// Mob stuff
ENABLED_COMPONENTS.KILL_ROAD_MOBS = config.getBoolean("kill_road_mobs", ENABLED_COMPONENTS.KILL_ROAD_MOBS);
ENABLED_COMPONENTS.KILL_ROAD_VEHICLES = config.getBoolean("kill_road_vehicles", ENABLED_COMPONENTS.KILL_ROAD_VEHICLES);
// Clearing + Expiry
// FAST_CLEAR = config.getBoolean("clear.fastmode");
ENABLED_COMPONENTS.PLOT_EXPIRY = config.getBoolean("clear.auto.enabled", ENABLED_COMPONENTS.PLOT_EXPIRY);
if (ENABLED_COMPONENTS.PLOT_EXPIRY) {
ENABLED_COMPONENTS.BAN_DELETER = config.getBoolean("clear.on.ban");
AUTO_CLEAR.put("task1", new AUTO_CLEAR());
AUTO_CLEAR task = AUTO_CLEAR.get("task1");
task.CALIBRATION = new AUTO_CLEAR.CALIBRATION();
task.DAYS = config.getInt("clear.auto.days", task.DAYS);
task.THRESHOLD = config.getInt("clear.auto.threshold", task.THRESHOLD);
task.CLEAR_INTERVAL_SECONDS = config.getInt("clear.auto.clear-interval-seconds", task.CLEAR_INTERVAL_SECONDS);
task.CONFIRMATION = config.getBoolean("clear.auto.confirmation", task.CONFIRMATION);
task.CALIBRATION.CHANGES = config.getInt("clear.auto.calibration.changes", task.CALIBRATION.CHANGES);
task.CALIBRATION.FACES = config.getInt("clear.auto.calibration.faces", task.CALIBRATION.FACES);
task.CALIBRATION.DATA = config.getInt("clear.auto.calibration.data", task.CALIBRATION.DATA);
task.CALIBRATION.AIR = config.getInt("clear.auto.calibration.air", task.CALIBRATION.AIR);
task.CALIBRATION.VARIETY = config.getInt("clear.auto.calibration.variety", task.CALIBRATION.VARIETY);
task.CALIBRATION.CHANGES_SD = config.getInt("clear.auto.calibration.changes_sd", task.CALIBRATION.CHANGES_SD);
task.CALIBRATION.FACES_SD = config.getInt("clear.auto.calibration.faces_sd", task.CALIBRATION.FACES_SD);
task.CALIBRATION.DATA_SD = config.getInt("clear.auto.calibration.data_sd", task.CALIBRATION.DATA_SD);
task.CALIBRATION.AIR_SD = config.getInt("clear.auto.calibration.air_sd", task.CALIBRATION.AIR_SD);
task.CALIBRATION.VARIETY_SD = config.getInt("clear.auto.calibration.variety_sd", task.CALIBRATION.VARIETY_SD);
}
// Done
DONE.REQUIRED_FOR_RATINGS = config.getBoolean("approval.ratings.check-done", DONE.REQUIRED_FOR_RATINGS);
DONE.COUNTS_TOWARDS_LIMIT = config.getBoolean("approval.done.counts-towards-limit", DONE.COUNTS_TOWARDS_LIMIT);
DONE.RESTRICT_BUILDING = config.getBoolean("approval.done.restrict-building", DONE.RESTRICT_BUILDING);
DONE.REQUIRED_FOR_DOWNLOAD = config.getBoolean("approval.done.required-for-download", DONE.REQUIRED_FOR_DOWNLOAD);
// Schematics
PATHS.SCHEMATICS = config.getString("schematics.save_path", PATHS.SCHEMATICS);
PATHS.BO3 = config.getString("bo3.save_path", PATHS.BO3);
// Web
WEB.URL = config.getString("web.url", WEB.URL);
WEB.SERVER_IP = config.getString("web.server-ip", WEB.SERVER_IP);
// Caching
ENABLED_COMPONENTS.PERMISSION_CACHE = config.getBoolean("cache.permissions", ENABLED_COMPONENTS.PERMISSION_CACHE);
ENABLED_COMPONENTS.RATING_CACHE = config.getBoolean("cache.ratings", ENABLED_COMPONENTS.RATING_CACHE);
// Rating system
RATINGS.CATEGORIES = config.contains("ratings.categories") ? config.getStringList("ratings.categories") : RATINGS.CATEGORIES;
// Titles
TITLES = config.getBoolean("titles", TITLES);
// Teleportation
TELEPORT.DELAY = config.getInt("teleport.delay", TELEPORT.DELAY);
TELEPORT.ON_LOGIN = config.getBoolean("teleport.on_login", TELEPORT.ON_LOGIN);
TELEPORT.ON_DEATH = config.getBoolean("teleport.on_death", TELEPORT.ON_DEATH);
// WorldEdit
// WE_ALLOW_HELPER = config.getBoolean("worldedit.enable-for-helpers");
// Chunk processor
ENABLED_COMPONENTS.CHUNK_PROCESSOR = config.getBoolean("chunk-processor.enabled", ENABLED_COMPONENTS.CHUNK_PROCESSOR);
CHUNK_PROCESSOR.AUTO_TRIM = config.getBoolean("chunk-processor.auto-unload", CHUNK_PROCESSOR.AUTO_TRIM);
CHUNK_PROCESSOR.MAX_TILES = config.getInt("chunk-processor.max-blockstates", CHUNK_PROCESSOR.MAX_TILES);
CHUNK_PROCESSOR.MAX_ENTITIES = config.getInt("chunk-processor.max-entities", CHUNK_PROCESSOR.MAX_ENTITIES);
CHUNK_PROCESSOR.DISABLE_PHYSICS = config.getBoolean("chunk-processor.disable-physics", CHUNK_PROCESSOR.DISABLE_PHYSICS);
// Comments
ENABLED_COMPONENTS.COMMENT_NOTIFIER = config.getBoolean("comments.notifications.enabled", ENABLED_COMPONENTS.COMMENT_NOTIFIER);
// Plot limits
CLAIM.MAX_AUTO_AREA = config.getInt("claim.max-auto-area", CLAIM.MAX_AUTO_AREA);
LIMIT.MAX_PLOTS = config.getInt("max_plots", LIMIT.MAX_PLOTS);
LIMIT.GLOBAL = config.getBoolean("global_limit", LIMIT.GLOBAL);
// Misc
DEBUG = config.getBoolean("debug", DEBUG);
CHAT.CONSOLE_COLOR = config.getBoolean("console.color", CHAT.CONSOLE_COLOR);
CHAT.INTERACTIVE = config.getBoolean("chat.fancy", CHAT.INTERACTIVE);
METRICS = config.getBoolean("metrics");
ENABLED_COMPONENTS.UPDATER = config.getBoolean("update-notifications", ENABLED_COMPONENTS.UPDATER);
ENABLED_COMPONENTS.DATABASE_PURGER = config.getBoolean("auto-purge", ENABLED_COMPONENTS.DATABASE_PURGER);
return true;
}
private static String toYamlString(Object value) {
if (value instanceof List) {
Collection<?> listValue = (Collection<?>) value;
if (listValue.isEmpty()) {
return "[]";
}
return System.lineSeparator() + StringMan.join(listValue, "- " + System.lineSeparator());
}
return value != null ? value.toString() : "null";
}
private static void save(PrintWriter writer, Class clazz, Object instance, int indent) {
try {
String CTRF = System.lineSeparator();
String spacing = StringMan.repeat(" ", indent);
for (Field field : clazz.getFields()) {
if (field.getAnnotation(Ignore.class) != null) {
continue;
}
Comment comment = field.getAnnotation(Comment.class);
if (comment != null) {
for (String commentLine : comment.value()) {
writer.write(spacing + "# " + commentLine + CTRF);
}
}
Create create = field.getAnnotation(Create.class);
if (create != null) {
Object value = field.get(instance);
if (value == null && field.getType() != ConfigBlock.class) {
setAccessible(field);
Class<?>[] classes = clazz.getDeclaredClasses();
for (Class current : classes) {
if (StringMan.isEqual(current.getSimpleName(), field.getName())) {
field.set(instance, current.newInstance());
break;
}
}
}
continue;
} else {
writer.write(spacing + toNodeName(field.getName() + ": ") + toYamlString(field.get(instance)) + CTRF);
}
}
for (Class<?> current : clazz.getClasses()) {
if (current.isInterface() || current.getAnnotation(Ignore.class) != null) {
continue;
}
if (indent == 0) {
writer.write(CTRF);
}
Comment comment = current.getAnnotation(Comment.class);
if (comment != null) {
for (String commentLine : comment.value()) {
writer.write(spacing + "# " + commentLine + CTRF);
}
}
writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF);
BlockName blockNames = current.getAnnotation(BlockName.class);
if (blockNames != null) {
Field instanceField = clazz.getDeclaredField(toFieldName(current.getSimpleName()));
setAccessible(instanceField);
ConfigBlock value = (ConfigBlock) instanceField.get(instance);
if (value == null) {
value = new ConfigBlock();
instanceField.set(instance, value);
for (String blockName : blockNames.value()) {
value.put(blockName, current.newInstance());
}
}
// Save each instance
for (Map.Entry<String, Object> entry: ((Map<String, Object>) value.getRaw()).entrySet()) {
String key = entry.getKey();
writer.write(spacing + " " + toNodeName(key) + ":" + CTRF);
save(writer, current, entry.getValue(), indent + 4);
}
continue;
} else {
save(writer, current, current.newInstance(), indent + 2);
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}
/**
* Get the value for a node<br>
* Probably throws some error if you try to get a non existent key
* @param key
* @param <T>
* @return
*/
public static <T> T get(String key) {
String[] split = key.split("\\.");
Object instance = getInstance(split);
if (instance != null) {
Field field = getField(split, instance);
if (field != null) {
try {
return (T) field.get(instance);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
PS.debug("Failed to get config option: " + key);
return null;
}
/**
* Set the value of a specific node<br>
* Probably throws some error if you supply non existing keys or invalid values
* @param key config node
* @param value value
*
*/
public static void set(String key, Object value) {
String[] split = key.split("\\.");
Object instance = getInstance(split);
if (instance != null) {
Field field = getField(split, instance);
if (field != null) {
try {
if (field.getAnnotation(Final.class) != null) {
return;
}
field.set(instance, value);
return;
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
PS.debug("Failed to set config option: " + key + ": " + value);
}
/**
* Get the field for a specific config node
* @param split the node (split by period)
* @return
*/
private static Field getField(String[] split) {
Object instance = getInstance(split);
if (instance == null) {
return null;
}
return getField(split, instance);
}
/**
* Get the field for a specific config node and instance<br>
* Note: As expiry can have multiple blocks there will be multiple instances
* @param split the node (split by period)
* @param instance the instance
* @return
*/
private static Field getField(String[] split, Object instance) {
try {
Field field = instance.getClass().getField(toFieldName(split[split.length - 1]));
setAccessible(field);
return field;
} catch (Throwable e) {
e.printStackTrace();
return null;
}
}
/**
* Get the instance for a specific config node
* @param split the node (split by period)
* @return The instance or null
*/
private static Object getInstance(String[] split) {
try {
Class<?> clazz = MethodHandles.lookup().lookupClass();
Object instance = clazz.newInstance();
while (split.length > 0) {
switch (split.length) {
case 1:
return instance;
default:
Class found = null;
Class<?>[] classes = clazz.getDeclaredClasses();
for (Class current : classes) {
if (StringMan.isEqual(current.getSimpleName(), toFieldName(split[0]))) {
found = current;
break;
}
}
try {
Field instanceField = clazz.getDeclaredField(toFieldName(split[0]));
setAccessible(instanceField);
if (instanceField.getType() != ConfigBlock.class) {
Object value = instanceField.get(instance);
if (value == null) {
value = found.newInstance();
instanceField.set(instance, value);
}
clazz = found;
instance = value;
split = Arrays.copyOfRange(split, 1, split.length);
continue;
}
ConfigBlock value = (ConfigBlock) instanceField.get(instance);
if (value == null) {
value = new ConfigBlock();
instanceField.set(instance, value);
}
instance = value.get(split[1]);
if (instance == null) {
instance = found.newInstance();
value.put(split[1], instance);
}
clazz = found;
split = Arrays.copyOfRange(split, 2, split.length);
continue;
} catch (NoSuchFieldException ignore) {}
if (found != null) {
split = Arrays.copyOfRange(split, 1, split.length);
clazz = found;
instance = clazz.newInstance();
continue;
}
return null;
}
}
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
/**
* Translate a node to a java field name
* @param node
* @return
*/
private static String toFieldName(String node) {
return node.toUpperCase().replaceAll("-","_");
}
/**
* Translate a field to a config node
* @param field
* @return
*/
private static String toNodeName(String field) {
return field.toLowerCase().replace("_","-");
}
/**
* Set some field to be accesible
* @param field
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
private static void setAccessible(Field field) throws NoSuchFieldException, IllegalAccessException {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment