fix: extract new config option for deleting disk history on logout (#2772)

* fix: extract new config option for deleting disk history on logout
 - fixes #2663

* Copyto is nullable
This commit is contained in:
Jordan 2024-06-26 17:32:36 +02:00 committed by GitHub
parent 06bf7104cc
commit 75af797d4c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 69 additions and 20 deletions

View File

@ -6,6 +6,7 @@ import com.sk89q.util.StringUtil;
import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.internal.util.LogManagerCompat;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import javax.annotation.Nullable;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.PrintWriter; import java.io.PrintWriter;
@ -18,6 +19,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.util.AbstractMap;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -31,10 +33,15 @@ public class Config {
private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Logger LOGGER = LogManagerCompat.getLogger();
private final Map<String, Object> removedKeyVals = new HashMap<>(); private final Map<String, Object> removedKeyVals = new HashMap<>();
@Nullable
private Map<String, Map.Entry<String, Object>> copyTo = new HashMap<>();
private boolean performCopyTo = false;
private List<String> existingMigrateNodes = null; private List<String> existingMigrateNodes = null;
public Config() { public Config() {
save(new PrintWriter(new ByteArrayOutputStream(0)), getClass(), this, 0); // This is now definitely required as the save -> load -> save order means the @CopiedFrom annotated fields work
save(new PrintWriter(new ByteArrayOutputStream(0)), getClass(), this, 0, null);
performCopyTo = true;
} }
/** /**
@ -60,11 +67,12 @@ public class Config {
/** /**
* Set the value of a specific node. Probably throws some error if you supply non existing keys or invalid values. * Set the value of a specific node. Probably throws some error if you supply non existing keys or invalid values.
* This should only be called during loading of a config file
* *
* @param key config node * @param key config node
* @param value value * @param value value
*/ */
private void set(String key, Object value, Class<?> root) { private void setLoadedNode(String key, Object value, Class<?> root) {
String[] split = key.split("\\."); String[] split = key.split("\\.");
Object instance = getInstance(split, root); Object instance = getInstance(split, root);
if (instance != null) { if (instance != null) {
@ -74,8 +82,18 @@ public class Config {
if (field.getAnnotation(Final.class) != null) { if (field.getAnnotation(Final.class) != null) {
return; return;
} }
if (copyTo != null) {
copyTo.remove(key); // Remove if the config field is already written
final Object finalValue = value;
copyTo.replaceAll((copyToNode, entry) -> {
if (!key.equals(entry.getKey())) {
return entry;
}
return new AbstractMap.SimpleEntry<>(key, finalValue);
});
}
Migrate migrate = field.getAnnotation(Migrate.class); Migrate migrate = field.getAnnotation(Migrate.class);
if (existingMigrateNodes != null && migrate != null) { if (migrate != null) {
existingMigrateNodes.add(migrate.value()); existingMigrateNodes.add(migrate.value());
} }
if (field.getType() == String.class && !(value instanceof String)) { if (field.getType() == String.class && !(value instanceof String)) {
@ -90,8 +108,9 @@ public class Config {
} }
} }
removedKeyVals.put(key, value); removedKeyVals.put(key, value);
LOGGER.error( LOGGER.warn(
"Failed to set config option: {}: {} | {} | {}.yml. This is likely because it was removed.", "Failed to set config option: {}: {} | {} | {}.yml. This is likely because it was removed or was set with an " +
"invalid value.",
key, key,
value, value,
instance, instance,
@ -110,7 +129,7 @@ public class Config {
if (value instanceof MemorySection) { if (value instanceof MemorySection) {
continue; continue;
} }
set(key, value, getClass()); setLoadedNode(key, value, getClass());
} }
for (String node : existingMigrateNodes) { for (String node : existingMigrateNodes) {
removedKeyVals.remove(node); removedKeyVals.remove(node);
@ -133,7 +152,7 @@ public class Config {
} }
PrintWriter writer = new PrintWriter(file); PrintWriter writer = new PrintWriter(file);
Object instance = this; Object instance = this;
save(writer, getClass(), instance, 0); save(writer, getClass(), instance, 0, null);
writer.close(); writer.close();
} catch (Throwable e) { } catch (Throwable e) {
LOGGER.error("Failed to save config file: {}", file, e); LOGGER.error("Failed to save config file: {}", file, e);
@ -190,7 +209,7 @@ public class Config {
} }
/** /**
* Indicates that a field should be instantiated / created. * Indicates that a field should be migrated from a node that is deleted
* *
* @since 2.10.0 * @since 2.10.0
*/ */
@ -202,6 +221,19 @@ public class Config {
} }
/**
* Indicates that a field's default value should match another input if the config is otherwise already generated
*
* @since TODO
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface CopiedFrom {
String value();
}
@Ignore // This is not part of the config @Ignore // This is not part of the config
public static class ConfigBlock<T> { public static class ConfigBlock<T> {
@ -254,7 +286,7 @@ public class Config {
return value != null ? value.toString() : "null"; return value != null ? value.toString() : "null";
} }
private void save(PrintWriter writer, Class<?> clazz, final Object instance, int indent) { private void save(PrintWriter writer, Class<?> clazz, final Object instance, int indent, String parentNode) {
try { try {
String CTRF = System.lineSeparator(); String CTRF = System.lineSeparator();
String spacing = StringMan.repeat(" ", indent); String spacing = StringMan.repeat(" ", indent);
@ -274,7 +306,7 @@ public class Config {
} }
if (current == ConfigBlock.class) { if (current == ConfigBlock.class) {
current = (Class<?>) ((ParameterizedType) (field.getGenericType())).getActualTypeArguments()[0]; current = (Class<?>) ((ParameterizedType) (field.getGenericType())).getActualTypeArguments()[0];
handleConfigBlockSave(writer, instance, indent, field, spacing, CTRF, current); handleConfigBlockSave(writer, instance, indent, field, spacing, CTRF, current, parentNode);
continue; continue;
} else if (!removedKeyVals.isEmpty()) { } else if (!removedKeyVals.isEmpty()) {
Migrate migrate = field.getAnnotation(Migrate.class); Migrate migrate = field.getAnnotation(Migrate.class);
@ -283,6 +315,17 @@ public class Config {
field.set(instance, value); field.set(instance, value);
} }
} }
CopiedFrom copiedFrom;
if (copyTo != null && (copiedFrom = field.getAnnotation(CopiedFrom.class)) != null) {
String node = toNodeName(field.getName());
node = parentNode == null ? node : parentNode + "." + node;
Map.Entry<String, Object> entry = copyTo.remove(node);
if (entry == null) {
copyTo.put(node,new AbstractMap.SimpleEntry<>(copiedFrom.value(), null));
} else {
field.set(instance, entry.getValue());
}
}
Create create = field.getAnnotation(Create.class); Create create = field.getAnnotation(Create.class);
if (create != null) { if (create != null) {
Object value = field.get(instance); Object value = field.get(instance);
@ -296,11 +339,12 @@ public class Config {
writer.write(spacing + "# " + commentLine + CTRF); writer.write(spacing + "# " + commentLine + CTRF);
} }
} }
writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF); String node = toNodeName(current.getSimpleName());
writer.write(spacing + node + ":" + CTRF);
if (value == null) { if (value == null) {
field.set(instance, value = current.getDeclaredConstructor().newInstance()); field.set(instance, value = current.getDeclaredConstructor().newInstance());
} }
save(writer, current, value, indent + 2); save(writer, current, value, indent + 2, parentNode == null ? node : parentNode + "." + node);
} else { } else {
writer.write(spacing + toNodeName(field.getName() + ": ") + toYamlString( writer.write(spacing + toNodeName(field.getName() + ": ") + toYamlString(
field.get(instance), field.get(instance),
@ -311,6 +355,10 @@ public class Config {
} catch (Throwable e) { } catch (Throwable e) {
LOGGER.error("Failed to save config file", e); LOGGER.error("Failed to save config file", e);
} }
if (parentNode == null && performCopyTo) {
performCopyTo = false;
copyTo = null;
}
} }
private <T> void handleConfigBlockSave( private <T> void handleConfigBlockSave(
@ -320,7 +368,8 @@ public class Config {
Field field, Field field,
String spacing, String spacing,
String CTRF, String CTRF,
Class<T> current Class<T> current,
String parentNode
) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException { ) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
Comment comment = current.getAnnotation(Comment.class); Comment comment = current.getAnnotation(Comment.class);
if (comment != null) { if (comment != null) {
@ -330,6 +379,7 @@ public class Config {
} }
BlockName blockNames = current.getAnnotation(BlockName.class); BlockName blockNames = current.getAnnotation(BlockName.class);
if (blockNames != null) { if (blockNames != null) {
String node = toNodeName(current.getSimpleName());
writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF); writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF);
ConfigBlock<T> configBlock = (ConfigBlock<T>) field.get(instance); ConfigBlock<T> configBlock = (ConfigBlock<T>) field.get(instance);
if (configBlock == null || configBlock.getInstances().isEmpty()) { if (configBlock == null || configBlock.getInstances().isEmpty()) {
@ -343,7 +393,7 @@ public class Config {
for (Map.Entry<String, T> entry : configBlock.getRaw().entrySet()) { for (Map.Entry<String, T> entry : configBlock.getRaw().entrySet()) {
String key = entry.getKey(); String key = entry.getKey();
writer.write(spacing + " " + toNodeName(key) + ":" + CTRF); writer.write(spacing + " " + toNodeName(key) + ":" + CTRF);
save(writer, current, entry.getValue(), indent + 4); save(writer, current, entry.getValue(), indent + 4, parentNode == null ? node : parentNode + "." + node);
} }
} }
} }

View File

@ -518,6 +518,9 @@ public class Settings extends Config {
public int DELETE_AFTER_DAYS = 7; public int DELETE_AFTER_DAYS = 7;
@Comment("Delete history in memory on logout (does not effect disk)") @Comment("Delete history in memory on logout (does not effect disk)")
public boolean DELETE_ON_LOGOUT = true; public boolean DELETE_ON_LOGOUT = true;
@Comment("Delete history on disk on logout")
@CopiedFrom("history.delete-on-logout")
public boolean DELETE_DISK_ON_LOGOUT = false;
@Comment({ @Comment({
"If history should be enabled by default for plugins using WorldEdit:", "If history should be enabled by default for plugins using WorldEdit:",
" - It is faster to have disabled", " - It is faster to have disabled",

View File

@ -22,19 +22,15 @@ package com.sk89q.worldedit.entity;
import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.configuration.Caption;
import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.clipboard.DiskOptimizedClipboard;
import com.fastasyncworldedit.core.internal.exception.FaweClipboardVersionMismatchException; import com.fastasyncworldedit.core.internal.exception.FaweClipboardVersionMismatchException;
import com.fastasyncworldedit.core.regions.FaweMaskManager; import com.fastasyncworldedit.core.regions.FaweMaskManager;
import com.fastasyncworldedit.core.util.MainUtil; import com.fastasyncworldedit.core.util.MainUtil;
import com.sk89q.worldedit.EmptyClipboardException;
import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.internal.util.DeprecationUtil; import com.sk89q.worldedit.internal.util.DeprecationUtil;
@ -43,7 +39,6 @@ import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
@ -432,7 +427,8 @@ public interface Player extends Entity, Actor {
} else if (Settings.settings().CLIPBOARD.DELETE_ON_LOGOUT) { } else if (Settings.settings().CLIPBOARD.DELETE_ON_LOGOUT) {
session.setClipboard(null); session.setClipboard(null);
} }
if (Settings.settings().HISTORY.DELETE_ON_LOGOUT) { if (!Settings.settings().HISTORY.USE_DISK && Settings.settings().HISTORY.DELETE_ON_LOGOUT
|| Settings.settings().HISTORY.USE_DISK && Settings.settings().HISTORY.DELETE_DISK_ON_LOGOUT) {
session.clearHistory(); session.clearHistory();
} }
} }