mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-12-22 09:17:39 +00:00
feat: introduce migrating config nodes to new locations (#2642)
- Initial case of moving schematic limits from experimental to limits - Closes #2533
This commit is contained in:
parent
1b2e2fe12a
commit
debfabff08
@ -2,6 +2,7 @@ package com.fastasyncworldedit.core.configuration;
|
||||
|
||||
import com.fastasyncworldedit.core.configuration.file.YamlConfiguration;
|
||||
import com.fastasyncworldedit.core.util.StringMan;
|
||||
import com.sk89q.util.StringUtil;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@ -14,8 +15,10 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
@ -27,6 +30,9 @@ public class Config {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private final Map<String, Object> removedKeyVals = new HashMap<>();
|
||||
private List<String> existingMigrateNodes = null;
|
||||
|
||||
public Config() {
|
||||
save(new PrintWriter(new ByteArrayOutputStream(0)), getClass(), this, 0);
|
||||
}
|
||||
@ -43,7 +49,8 @@ public class Config {
|
||||
try {
|
||||
return (T) field.get(instance);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Failed to get config option: {}", key, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -67,6 +74,10 @@ public class Config {
|
||||
if (field.getAnnotation(Final.class) != null) {
|
||||
return;
|
||||
}
|
||||
Migrate migrate = field.getAnnotation(Migrate.class);
|
||||
if (existingMigrateNodes != null && migrate != null) {
|
||||
existingMigrateNodes.add(migrate.value());
|
||||
}
|
||||
if (field.getType() == String.class && !(value instanceof String)) {
|
||||
value = value + "";
|
||||
}
|
||||
@ -74,17 +85,22 @@ public class Config {
|
||||
field.set(instance, value);
|
||||
return;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Failed to set config option: {}", key);
|
||||
}
|
||||
}
|
||||
}
|
||||
LOGGER.error("Failed to set config option: {}: {} | {} | {}.yml", key, value, instance, root.getSimpleName());
|
||||
removedKeyVals.put(key, value);
|
||||
LOGGER.error(
|
||||
"Failed to set config option: {}: {} | {} | {}.yml. This is likely because it was removed.",
|
||||
key,
|
||||
value,
|
||||
instance,
|
||||
root.getSimpleName()
|
||||
);
|
||||
}
|
||||
|
||||
public boolean load(File file) {
|
||||
if (!file.exists()) {
|
||||
return false;
|
||||
}
|
||||
existingMigrateNodes = new ArrayList<>();
|
||||
YamlConfiguration yml = YamlConfiguration.loadConfiguration(file);
|
||||
for (String key : yml.getKeys(true)) {
|
||||
Object value = yml.get(key);
|
||||
@ -93,6 +109,10 @@ public class Config {
|
||||
}
|
||||
set(key, value, getClass());
|
||||
}
|
||||
for (String node : existingMigrateNodes) {
|
||||
removedKeyVals.remove(node);
|
||||
}
|
||||
existingMigrateNodes = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -113,7 +133,7 @@ public class Config {
|
||||
save(writer, getClass(), instance, 0);
|
||||
writer.close();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Failed to save config file: {}", file, e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,6 +186,19 @@ public class Config {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that a field should be instantiated / created.
|
||||
*
|
||||
* @since TODO
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD})
|
||||
public @interface Migrate {
|
||||
|
||||
String value();
|
||||
|
||||
}
|
||||
|
||||
@Ignore // This is not part of the config
|
||||
public static class ConfigBlock<T> {
|
||||
|
||||
@ -222,7 +255,6 @@ public class Config {
|
||||
try {
|
||||
String CTRF = System.lineSeparator();
|
||||
String spacing = StringMan.repeat(" ", indent);
|
||||
HashMap<Class<?>, Object> instances = new HashMap<>();
|
||||
for (Field field : clazz.getFields()) {
|
||||
if (field.getAnnotation(Ignore.class) != null) {
|
||||
continue;
|
||||
@ -239,31 +271,14 @@ public class Config {
|
||||
}
|
||||
if (current == ConfigBlock.class) {
|
||||
current = (Class<?>) ((ParameterizedType) (field.getGenericType())).getActualTypeArguments()[0];
|
||||
comment = current.getAnnotation(Comment.class);
|
||||
if (comment != null) {
|
||||
for (String commentLine : comment.value()) {
|
||||
writer.write(spacing + "# " + commentLine + CTRF);
|
||||
}
|
||||
}
|
||||
BlockName blockNames = current.getAnnotation(BlockName.class);
|
||||
if (blockNames != null) {
|
||||
writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF);
|
||||
ConfigBlock configBlock = (ConfigBlock) field.get(instance);
|
||||
if (configBlock == null || configBlock.getInstances().isEmpty()) {
|
||||
configBlock = new ConfigBlock();
|
||||
field.set(instance, configBlock);
|
||||
for (String blockName : blockNames.value()) {
|
||||
configBlock.put(blockName, current.getDeclaredConstructor().newInstance());
|
||||
}
|
||||
}
|
||||
// Save each instance
|
||||
for (Map.Entry<String, Object> entry : ((Map<String, Object>) configBlock.getRaw()).entrySet()) {
|
||||
String key = entry.getKey();
|
||||
writer.write(spacing + " " + toNodeName(key) + ":" + CTRF);
|
||||
save(writer, current, entry.getValue(), indent + 4);
|
||||
}
|
||||
}
|
||||
handleConfigBlockSave(writer, instance, indent, field, spacing, CTRF, current);
|
||||
continue;
|
||||
} else if (!removedKeyVals.isEmpty()) {
|
||||
Migrate migrate = field.getAnnotation(Migrate.class);
|
||||
Object value;
|
||||
if (migrate != null && (value = removedKeyVals.remove(migrate.value())) != null) {
|
||||
field.set(instance, value);
|
||||
}
|
||||
}
|
||||
Create create = field.getAnnotation(Create.class);
|
||||
if (create != null) {
|
||||
@ -281,7 +296,6 @@ public class Config {
|
||||
writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF);
|
||||
if (value == null) {
|
||||
field.set(instance, value = current.getDeclaredConstructor().newInstance());
|
||||
instances.put(current, value);
|
||||
}
|
||||
save(writer, current, value, indent + 2);
|
||||
} else {
|
||||
@ -292,7 +306,42 @@ public class Config {
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Failed to save config file", e);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void handleConfigBlockSave(
|
||||
PrintWriter writer,
|
||||
Object instance,
|
||||
int indent,
|
||||
Field field,
|
||||
String spacing,
|
||||
String CTRF,
|
||||
Class<T> current
|
||||
) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
|
||||
Comment comment = current.getAnnotation(Comment.class);
|
||||
if (comment != null) {
|
||||
for (String commentLine : comment.value()) {
|
||||
writer.write(spacing + "# " + commentLine + CTRF);
|
||||
}
|
||||
}
|
||||
BlockName blockNames = current.getAnnotation(BlockName.class);
|
||||
if (blockNames != null) {
|
||||
writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF);
|
||||
ConfigBlock<T> configBlock = (ConfigBlock<T>) field.get(instance);
|
||||
if (configBlock == null || configBlock.getInstances().isEmpty()) {
|
||||
configBlock = new ConfigBlock<>();
|
||||
field.set(instance, configBlock);
|
||||
for (String blockName : blockNames.value()) {
|
||||
configBlock.put(blockName, current.getDeclaredConstructor().newInstance());
|
||||
}
|
||||
}
|
||||
// Save each instance
|
||||
for (Map.Entry<String, T> entry : configBlock.getRaw().entrySet()) {
|
||||
String key = entry.getKey();
|
||||
writer.write(spacing + " " + toNodeName(key) + ":" + CTRF);
|
||||
save(writer, current, entry.getValue(), indent + 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -311,7 +360,7 @@ public class Config {
|
||||
return field;
|
||||
} catch (Throwable ignored) {
|
||||
LOGGER.warn(
|
||||
"Invalid config field: {} for {}",
|
||||
"Invalid config field: {} for {}. It is possible this is because it has been removed.",
|
||||
StringMan.join(split, "."),
|
||||
toNodeName(instance.getClass().getSimpleName())
|
||||
);
|
||||
@ -379,7 +428,7 @@ public class Config {
|
||||
return null;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Failed retrieving instance for config node: {}", StringUtil.joinString(split, "."), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -145,6 +145,14 @@ public class Settings extends Config {
|
||||
limit.MAX_HISTORY,
|
||||
newLimit.MAX_HISTORY_MB != -1 ? newLimit.MAX_HISTORY_MB : Integer.MAX_VALUE
|
||||
);
|
||||
limit.SCHEM_FILE_NUM_LIMIT = Math.max(
|
||||
limit.SCHEM_FILE_NUM_LIMIT,
|
||||
newLimit.SCHEM_FILE_NUM_LIMIT != -1 ? newLimit.SCHEM_FILE_NUM_LIMIT : Integer.MAX_VALUE
|
||||
);
|
||||
limit.SCHEM_FILE_SIZE_LIMIT = Math.max(
|
||||
limit.SCHEM_FILE_SIZE_LIMIT,
|
||||
newLimit.SCHEM_FILE_SIZE_LIMIT != -1 ? newLimit.SCHEM_FILE_SIZE_LIMIT : Integer.MAX_VALUE
|
||||
);
|
||||
limit.MAX_EXPRESSION_MS = Math.max(
|
||||
limit.MAX_EXPRESSION_MS,
|
||||
newLimit.MAX_EXPRESSION_MS != -1 ? newLimit.MAX_EXPRESSION_MS : Integer.MAX_VALUE
|
||||
@ -353,6 +361,18 @@ public class Settings extends Config {
|
||||
" - History on disk or memory will be deleted",
|
||||
})
|
||||
public int MAX_HISTORY_MB = -1;
|
||||
@Comment({
|
||||
"Sets a maximum limit (in kb) for the size of a player's schematics directory (per-player mode only)",
|
||||
"Set to -1 to disable"
|
||||
})
|
||||
@Migrate("experimental.per-player-file-size-limit")
|
||||
public int SCHEM_FILE_SIZE_LIMIT = -1;
|
||||
@Comment({
|
||||
"Sets a maximum limit for the amount of schematics in a player's schematics directory (per-player mode only)",
|
||||
"Set to -1 to disable"
|
||||
})
|
||||
@Migrate("experimental.per-player-file-num-limit")
|
||||
public int SCHEM_FILE_NUM_LIMIT = -1;
|
||||
@Comment("Maximum time in milliseconds //calc can execute")
|
||||
public int MAX_EXPRESSION_MS = 50;
|
||||
@Comment({
|
||||
@ -615,18 +635,6 @@ public class Settings extends Config {
|
||||
})
|
||||
public boolean ALLOW_TICK_FLUIDS = false;
|
||||
|
||||
@Comment({
|
||||
"Sets a maximum limit (in kb) for the size of a player's schematics directory (per-player mode only)",
|
||||
"Set to -1 to disable"
|
||||
})
|
||||
public int PER_PLAYER_FILE_SIZE_LIMIT = -1;
|
||||
|
||||
@Comment({
|
||||
"Sets a maximum limit for the amount of schematics in a player's schematics directory (per-player mode only)",
|
||||
"Set to -1 to disable"
|
||||
})
|
||||
public int PER_PLAYER_FILE_NUM_LIMIT = -1;
|
||||
|
||||
}
|
||||
|
||||
@Comment({"Web/HTTP connection related settings"})
|
||||
|
@ -15,6 +15,8 @@ public class FaweLimit {
|
||||
public int MAX_BLOCKSTATES = 0;
|
||||
public int MAX_ENTITIES = 0;
|
||||
public int MAX_HISTORY = 0;
|
||||
public int SCHEM_FILE_SIZE_LIMIT = 0;
|
||||
public int SCHEM_FILE_NUM_LIMIT = 0;
|
||||
public int MAX_EXPRESSION_MS = 0;
|
||||
public int INVENTORY_MODE = Integer.MAX_VALUE;
|
||||
public int SPEED_REDUCTION = Integer.MAX_VALUE;
|
||||
@ -111,6 +113,8 @@ public class FaweLimit {
|
||||
MAX.MAX_BLOCKSTATES = Integer.MAX_VALUE;
|
||||
MAX.MAX_ENTITIES = Integer.MAX_VALUE;
|
||||
MAX.MAX_HISTORY = Integer.MAX_VALUE;
|
||||
MAX.SCHEM_FILE_NUM_LIMIT = Integer.MAX_VALUE;
|
||||
MAX.SCHEM_FILE_SIZE_LIMIT = Integer.MAX_VALUE;
|
||||
MAX.MAX_EXPRESSION_MS = 50;
|
||||
MAX.FAST_PLACEMENT = true;
|
||||
MAX.CONFIRM_LARGE = true;
|
||||
@ -237,6 +241,8 @@ public class FaweLimit {
|
||||
&& MAX_BLOCKSTATES == Integer.MAX_VALUE
|
||||
&& MAX_ENTITIES == Integer.MAX_VALUE
|
||||
&& MAX_HISTORY == Integer.MAX_VALUE
|
||||
&& SCHEM_FILE_SIZE_LIMIT == Integer.MAX_VALUE
|
||||
&& SCHEM_FILE_NUM_LIMIT == Integer.MAX_VALUE
|
||||
&& INVENTORY_MODE == 0
|
||||
&& SPEED_REDUCTION == 0
|
||||
&& FAST_PLACEMENT
|
||||
@ -256,6 +262,8 @@ public class FaweLimit {
|
||||
MAX_FAILS = limit.MAX_FAILS;
|
||||
MAX_ITERATIONS = limit.MAX_ITERATIONS;
|
||||
MAX_HISTORY = limit.MAX_HISTORY;
|
||||
SCHEM_FILE_NUM_LIMIT = limit.SCHEM_FILE_NUM_LIMIT;
|
||||
SCHEM_FILE_SIZE_LIMIT = limit.SCHEM_FILE_SIZE_LIMIT;
|
||||
INVENTORY_MODE = limit.INVENTORY_MODE;
|
||||
SPEED_REDUCTION = limit.SPEED_REDUCTION;
|
||||
FAST_PLACEMENT = limit.FAST_PLACEMENT;
|
||||
@ -279,6 +287,8 @@ public class FaweLimit {
|
||||
limit.MAX_FAILS = MAX_FAILS;
|
||||
limit.MAX_ITERATIONS = MAX_ITERATIONS;
|
||||
limit.MAX_HISTORY = MAX_HISTORY;
|
||||
limit.SCHEM_FILE_SIZE_LIMIT = SCHEM_FILE_SIZE_LIMIT;
|
||||
limit.SCHEM_FILE_NUM_LIMIT = SCHEM_FILE_NUM_LIMIT;
|
||||
limit.FAST_PLACEMENT = FAST_PLACEMENT;
|
||||
limit.CONFIRM_LARGE = CONFIRM_LARGE;
|
||||
limit.RESTRICT_HISTORY_TO_REGIONS = RESTRICT_HISTORY_TO_REGIONS;
|
||||
|
@ -700,10 +700,10 @@ public class SchematicCommands {
|
||||
|
||||
String headerBytesElem = String.format("%.1fkb", totalBytes / 1000.0);
|
||||
|
||||
if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_SIZE_LIMIT > -1) {
|
||||
if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && actor.getLimit().SCHEM_FILE_SIZE_LIMIT > -1) {
|
||||
headerBytesElem += String.format(
|
||||
" / %dkb",
|
||||
Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_SIZE_LIMIT
|
||||
actor.getLimit().SCHEM_FILE_SIZE_LIMIT
|
||||
);
|
||||
}
|
||||
|
||||
@ -837,7 +837,7 @@ public class SchematicCommands {
|
||||
|
||||
//FAWE start
|
||||
boolean checkFilesize = Settings.settings().PATHS.PER_PLAYER_SCHEMATICS
|
||||
&& Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_SIZE_LIMIT > -1;
|
||||
&& actor.getLimit().SCHEM_FILE_SIZE_LIMIT > -1;
|
||||
|
||||
double directorysizeKb = 0;
|
||||
String curFilepath = file.getAbsolutePath();
|
||||
@ -867,7 +867,7 @@ public class SchematicCommands {
|
||||
}
|
||||
|
||||
|
||||
if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_NUM_LIMIT > -1) {
|
||||
if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && actor.getLimit().SCHEM_FILE_NUM_LIMIT > -1) {
|
||||
|
||||
if (numFiles == -1) {
|
||||
numFiles = 0;
|
||||
@ -880,7 +880,7 @@ public class SchematicCommands {
|
||||
}
|
||||
}
|
||||
}
|
||||
int limit = Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_NUM_LIMIT;
|
||||
int limit = actor.getLimit().SCHEM_FILE_NUM_LIMIT;
|
||||
|
||||
if (numFiles >= limit) {
|
||||
TextComponent noSlotsErr = TextComponent.of( //TODO - to be moved into captions/translatablecomponents
|
||||
@ -931,7 +931,7 @@ public class SchematicCommands {
|
||||
if (checkFilesize) {
|
||||
|
||||
double curKb = filesizeKb + directorysizeKb;
|
||||
int allocatedKb = Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_SIZE_LIMIT;
|
||||
int allocatedKb = actor.getLimit().SCHEM_FILE_SIZE_LIMIT;
|
||||
|
||||
if (overwrite) {
|
||||
curKb -= oldKbOverwritten;
|
||||
@ -966,11 +966,11 @@ public class SchematicCommands {
|
||||
actor.print(kbRemainingNotif);
|
||||
}
|
||||
|
||||
if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_NUM_LIMIT > -1) {
|
||||
if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && actor.getLimit().SCHEM_FILE_NUM_LIMIT > -1) {
|
||||
|
||||
TextComponent slotsRemainingNotif = TextComponent.of(
|
||||
//TODO - to be moved into captions/translatablecomponents
|
||||
"You have " + (Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_NUM_LIMIT - numFiles)
|
||||
"You have " + (actor.getLimit().SCHEM_FILE_NUM_LIMIT - numFiles)
|
||||
+ " schematic file slots left.",
|
||||
TextColor.GRAY
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user