Better defaults and completions for ListConfigNode

This commit is contained in:
Ben Woo 2023-09-14 19:07:39 +08:00
parent 362d871ab8
commit ee1bf8216e
No known key found for this signature in database
GPG Key ID: FB2A3645536E12C8
6 changed files with 119 additions and 48 deletions

View File

@ -5,6 +5,7 @@ import co.aikar.commands.annotation.CommandCompletion;
import co.aikar.commands.annotation.CommandPermission;
import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Flags;
import co.aikar.commands.annotation.Single;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.dumptruckman.minecraft.util.Logging;
@ -55,6 +56,7 @@ class ModifyCommand extends MultiverseCommand {
String propertyName,
@Optional
@Single
@Syntax("[value]")
@Description("")
String propertyValue) {

View File

@ -42,11 +42,11 @@ public class ConfigNode<T> extends ConfigHeaderNode implements ValueNode<T> {
protected final @Nullable String name;
protected final @NotNull Class<T> type;
protected final @Nullable Supplier<T> defaultValueSupplier;
protected final @Nullable NodeSuggester suggester;
protected final @Nullable NodeStringParser<T> stringParser;
protected final @Nullable NodeSerializer<T> serializer;
protected final @Nullable Function<T, Try<Void>> validator;
protected final @Nullable BiConsumer<T, T> onSetValue;
protected @Nullable NodeSuggester suggester;
protected @Nullable NodeStringParser<T> stringParser;
protected @Nullable NodeSerializer<T> serializer;
protected @Nullable Function<T, Try<Void>> validator;
protected @Nullable BiConsumer<T, T> onSetValue;
protected ConfigNode(
@NotNull String path,

View File

@ -1,13 +1,17 @@
package org.mvplugins.multiverse.core.configuration.node;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
import com.dumptruckman.minecraft.util.Logging;
import io.vavr.Value;
import io.vavr.control.Try;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -70,6 +74,91 @@ public class ListConfigNode<I> extends ConfigNode<List<I>> implements ListValueN
this.itemSerializer = itemSerializer;
this.itemValidator = itemValidator;
this.onSetItemValue = onSetItemValue;
if (this.itemSuggester != null && this.suggester == null) {
setDefaultSuggester();
}
if (this.itemStringParser != null && this.stringParser == null) {
Logging.fine("Setting default string parser for list node " + path);
setDefaultStringParser();
}
if (this.itemValidator != null && this.validator == null) {
setDefaultValidator();
}
if (this.itemSerializer != null && this.serializer == null) {
setDefaultSerialiser();
}
if (this.onSetItemValue != null && this.onSetValue == null) {
setDefaultOnSetValue();
}
}
private void setDefaultSuggester() {
this.suggester = input -> {
int lastIndexOf = input.lastIndexOf(',');
if (lastIndexOf == -1) {
return itemSuggester.suggest(input);
}
String lastInput = input.substring(lastIndexOf + 1);
String inputBeforeLast = input.substring(0, lastIndexOf + 1);
Set<String> inputs = Set.of(inputBeforeLast.split(","));
return itemSuggester.suggest(lastInput).stream()
.filter(item -> !inputs.contains(item))
.map(item -> inputBeforeLast + item)
.toList();
};
}
private void setDefaultStringParser() {
this.stringParser = (input, type) -> {
if (input == null) {
return Try.failure(new IllegalArgumentException("Input cannot be null"));
}
return Try.sequence(Arrays.stream(input.split(","))
.map(inputItem -> itemStringParser.parse(inputItem, itemType))
.toList()).map(Value::toJavaList);
};
}
private void setDefaultValidator() {
this.validator = value -> {
if (value != null) {
return Try.sequence(value.stream().map(itemValidator).toList()).map(v -> null);
}
return Try.success(null);
};
}
private void setDefaultSerialiser() {
this.serializer = new NodeSerializer<>() {
@Override
public List<I> deserialize(Object object, Class<List<I>> type) {
if (object instanceof List list) {
return list.stream().map(item -> itemSerializer.deserialize(item, itemType)).toList();
}
return new ArrayList<>();
}
@Override
public Object serialize(List<I> object, Class<List<I>> type) {
if (object != null) {
return object.stream().map(item -> itemSerializer.serialize(item, itemType)).toList();
}
return new ArrayList<>();
}
};
}
private void setDefaultOnSetValue() {
this.onSetValue = (oldValue, newValue) -> {
if (oldValue != null) {
oldValue.stream()
.filter(value -> !newValue.contains(value))
.forEach(item -> onSetItemValue.accept(item, null));
}
newValue.forEach(item -> onSetItemValue.accept(null, item));
};
}
/**
@ -80,6 +169,9 @@ public class ListConfigNode<I> extends ConfigNode<List<I>> implements ListValueN
return itemType;
}
/**
* {@inheritDoc}
*/
@Override
public @NotNull Collection<String> suggestItem(@Nullable String input) {
if (itemSuggester != null) {
@ -88,6 +180,9 @@ public class ListConfigNode<I> extends ConfigNode<List<I>> implements ListValueN
return Collections.emptyList();
}
/**
* {@inheritDoc}
*/
@Override
public @NotNull Try<I> parseItemFromString(@Nullable String input) {
if (itemStringParser != null) {
@ -176,21 +271,9 @@ public class ListConfigNode<I> extends ConfigNode<List<I>> implements ListValueN
*/
public @NotNull B itemValidator(@NotNull Function<I, Try<Void>> itemValidator) {
this.itemValidator = itemValidator;
if (validator == null) {
setDefaultValidator();
}
return self();
}
private void setDefaultValidator() {
this.validator = value -> {
if (value != null) {
return Try.sequence(value.stream().map(itemValidator).toList()).map(v -> null);
}
return Try.success(null);
};
}
/**
* Sets the onSetValue for the node.
*
@ -199,23 +282,9 @@ public class ListConfigNode<I> extends ConfigNode<List<I>> implements ListValueN
*/
public @NotNull B onSetItemValue(@Nullable BiConsumer<I, I> onSetItemValue) {
this.onSetItemValue = onSetItemValue;
if (onSetValue == null) {
setDefaultOnSetValue();
}
return self();
}
private void setDefaultOnSetValue() {
this.onSetValue = (oldValue, newValue) -> {
if (oldValue != null) {
oldValue.stream()
.filter(value -> !newValue.contains(value))
.forEach(item -> onSetItemValue.accept(item, null));
}
newValue.forEach(item -> onSetItemValue.accept(null, item));
};
}
/**
* {@inheritDoc}
*/

View File

@ -14,6 +14,7 @@ import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.mvplugins.multiverse.core.MultiverseCore;
import org.mvplugins.multiverse.core.configuration.handle.ConfigModifyType;
import org.mvplugins.multiverse.core.configuration.handle.ConfigurationSectionHandle;
import org.mvplugins.multiverse.core.configuration.migration.BooleanMigratorAction;
@ -24,7 +25,6 @@ import org.mvplugins.multiverse.core.configuration.migration.MoveMigratorAction;
import org.mvplugins.multiverse.core.configuration.migration.NullStringMigratorAction;
import org.mvplugins.multiverse.core.configuration.migration.VersionMigrator;
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
import org.mvplugins.multiverse.core.world.helpers.EnforcementHandler;
/**
* Represents a world configuration.
@ -38,9 +38,9 @@ public final class WorldConfig {
WorldConfig(
@NotNull String worldName,
@NotNull ConfigurationSection configSection,
@NotNull EnforcementHandler enforcementHandler) {
@NotNull MultiverseCore multiverseCore) {
this.worldName = worldName;
this.configNodes = new WorldConfigNodes(enforcementHandler);
this.configNodes = new WorldConfigNodes(multiverseCore);
this.configHandle = ConfigurationSectionHandle.builder(configSection)
.logger(Logging.getLogger())
.nodes(configNodes.getNodes())

View File

@ -1,8 +1,5 @@
package org.mvplugins.multiverse.core.world.config;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.Difficulty;
import org.bukkit.GameMode;
import org.bukkit.Location;
@ -10,12 +7,14 @@ import org.bukkit.Material;
import org.bukkit.World;
import org.jetbrains.annotations.NotNull;
import org.mvplugins.multiverse.core.MultiverseCore;
import org.mvplugins.multiverse.core.configuration.node.ConfigNode;
import org.mvplugins.multiverse.core.configuration.node.ListConfigNode;
import org.mvplugins.multiverse.core.configuration.node.Node;
import org.mvplugins.multiverse.core.configuration.node.NodeGroup;
import org.mvplugins.multiverse.core.world.config.AllowedPortalType;
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
import org.mvplugins.multiverse.core.world.MultiverseWorld;
import org.mvplugins.multiverse.core.world.WorldManager;
import org.mvplugins.multiverse.core.world.helpers.EnforcementHandler;
/**
@ -26,10 +25,12 @@ public class WorldConfigNodes {
private final NodeGroup nodes = new NodeGroup();
private EnforcementHandler enforcementHandler;
private WorldManager worldManager;
private LoadedMultiverseWorld world = null;
WorldConfigNodes(@NotNull EnforcementHandler enforcementHandler) {
this.enforcementHandler = enforcementHandler;
WorldConfigNodes(@NotNull MultiverseCore multiverseCore) {
this.enforcementHandler = multiverseCore.getService(EnforcementHandler.class);
this.worldManager = multiverseCore.getService(WorldManager.class);
}
LoadedMultiverseWorld getWorld() {
@ -245,6 +246,7 @@ public class WorldConfigNodes {
final ListConfigNode<String> WORLD_BLACKLIST = node(ListConfigNode
.listBuilder("world-blacklist", String.class)
.itemSuggester(input -> worldManager.getWorlds().stream().map(MultiverseWorld::getName).toList())
.build());
final ConfigNode<Double> VERSION = node(ConfigNode.builder("version", Double.class)

View File

@ -33,16 +33,14 @@ public final class WorldsConfigManager {
private final Map<String, WorldConfig> worldConfigMap;
private final File worldConfigFile;
private final MultiverseCore multiverseCore;
private YamlConfiguration worldsConfig;
private final EnforcementHandler enforcementHandler;
@Inject
WorldsConfigManager(@NotNull MultiverseCore core, @NotNull EnforcementHandler enforcementHandler) {
WorldsConfigManager(@NotNull MultiverseCore multiverseCore) {
worldConfigMap = new HashMap<>();
worldConfigFile = core.getDataFolder().toPath().resolve(CONFIG_FILENAME).toFile();
this.enforcementHandler = enforcementHandler;
worldConfigFile = multiverseCore.getDataFolder().toPath().resolve(CONFIG_FILENAME).toFile();
this.multiverseCore = multiverseCore;
}
/**
@ -128,7 +126,7 @@ public final class WorldsConfigManager {
WorldConfig newWorldConfig = new WorldConfig(
worldName,
getWorldConfigSection(worldName),
enforcementHandler);
multiverseCore);
worldConfigMap.put(worldName, newWorldConfig);
newWorldsAdded.add(newWorldConfig);
});
@ -183,7 +181,7 @@ public final class WorldsConfigManager {
if (worldConfigMap.containsKey(worldName)) {
throw new IllegalArgumentException("WorldConfig for world " + worldName + " already exists.");
}
WorldConfig worldConfig = new WorldConfig(worldName, getWorldConfigSection(worldName), enforcementHandler);
WorldConfig worldConfig = new WorldConfig(worldName, getWorldConfigSection(worldName), multiverseCore);
worldConfigMap.put(worldName, worldConfig);
return worldConfig;
}