This commit is contained in:
kento2 2026-08-29 03:06:29 +02:00
parent ce56c6e105
commit 35a0784e40
46 changed files with 597 additions and 673 deletions

View file

@ -13,12 +13,16 @@ public interface ConfigApi {
this.register(key, null);
}
<V> @Nullable ConfigNode<V> getNode(ConfigKey<V> key);
@Nullable ConfigNode<?> getNode(String id);
default <V> @Nullable ConfigNode<?> getNode(ConfigKey<V> key) {
return this.getNode(key.id());
}
default <V> @Nullable V get(ConfigKey<V> key) {
var n = getNode(key);
if (n == null) return null;
return n.value();
return (V) n.value();
}
Map<String, ConfigNode<?>> allNodes();

View file

@ -27,9 +27,8 @@ public class ConfigApiImpl implements ConfigApi {
identifier first, and then descend into the Sub-Nodes.
*/
@Override
public @Nullable <V> ConfigNode<V> getNode(ConfigKey<V> key) {
public @Nullable ConfigNode<?> getNode(String id) {
ConfigNode<Object> node;
var id = key.id();
var fields = new ArrayDeque<String>();
while (true) {
node = (ConfigNode<Object>) nodes.get(id);
@ -52,7 +51,7 @@ public class ConfigApiImpl implements ConfigApi {
if (node == null)
return null;
}
return (ConfigNode<V>) node;
return node;
}
@Override

View file

@ -3,14 +3,16 @@ package site.lab0x13.scrow.configurator;
import de.kentoj.scrow.bukkit.ScrowAPI;
import org.bukkit.plugin.java.JavaPlugin;
import site.lab0x13.scrow.configurator.command.ConfigCommand;
import site.lab0x13.scrow.configurator.node.ConfigNode;
import site.lab0x13.scrow.configurator.type.location.LocationConfigType;
public class ConfiguratorPlugin extends JavaPlugin {
@Override
public void onEnable() {
ConfigRootNode nodeRegistry = new ConfigRootNode();
nodeRegistry.register("spawnLocation", new Config<>(LocationConfigType.INSTANCE));
ScrowAPI.playerCommands().register(new ConfigCommand(nodeRegistry).rootLiteral());
ConfigApi api = new ConfigApiImpl();
var spawnLocation = new ConfigKey<>("spawnLocation", new LocationConfigType());
api.register(spawnLocation);
ScrowAPI.commands().register(new ConfigCommand(api).rootLiteral());
}
}

View file

@ -1,8 +1,7 @@
package site.lab0x13.scrow.configurator.action;
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import org.bukkit.entity.Player;
import de.kentoj.scrow.bukkit.command.ScrowBukkitCC;
import site.lab0x13.scrow.commands.model.argument.Argument;
import site.lab0x13.scrow.configurator.node.ConfigNode;
import java.util.List;
@ -13,9 +12,9 @@ import java.util.List;
public interface ConfigAction<N extends ConfigNode<?>> {
String name();
List<CommandArgumentSpec<Player, ?>> arguments();
List<Argument<ScrowBukkitCC, ?>> arguments();
boolean requiresValue();
void execute(N node, CommandContext<Player> ctx);
void execute(N node, ScrowBukkitCC ctx);
}

View file

@ -3,13 +3,11 @@ package site.lab0x13.scrow.configurator.action;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.scrow.bukkit.command.ScrowBukkitCC;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.entity.Player;
import site.lab0x13.scrow.commands.model.argument.Argument;
import site.lab0x13.scrow.configurator.node.ConfigNode;
import site.lab0x13.scrow.configurator.type.ConfigType;
import java.util.List;
@ -23,7 +21,7 @@ public final class GlobalShowAction implements ConfigAction<ConfigNode<Object>>
}
@Override
public List<CommandArgumentSpec<Player, ?>> arguments() {
public List<Argument<ScrowBukkitCC, ?>> arguments() {
return List.of();
}
@ -33,7 +31,7 @@ public final class GlobalShowAction implements ConfigAction<ConfigNode<Object>>
}
@Override
public void execute(ConfigNode<Object> node, CommandContext<Player> ctx) {
public void execute(ConfigNode<Object> node, ScrowBukkitCC ctx) {
var jsonElement = node.type().serialize(node.value());
var prettyJson = GSON.toJson(jsonElement, JsonElement.class);
var component = Component.text(prettyJson + " [click to copy]")

View file

@ -1,7 +1,7 @@
package site.lab0x13.scrow.configurator.action;
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import site.lab0x13.scrow.commands.model.argument.Argument;
import de.kentoj.scrow.bukkit.command.ScrowBukkitCC;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import site.lab0x13.scrow.configurator.node.ConfigNode;
@ -22,7 +22,7 @@ public abstract class PickAction<V, N extends ConfigNode<V>> implements ConfigAc
}
@Override
public List<CommandArgumentSpec<Player, ?>> arguments() {
public List<Argument<ScrowBukkitCC, ?>> arguments() {
return Collections.emptyList();
}
@ -32,15 +32,15 @@ public abstract class PickAction<V, N extends ConfigNode<V>> implements ConfigAc
}
@Override
public void execute(N node, CommandContext<Player> ctx) {
pick(ctx.sender())
public void execute(N node, ScrowBukkitCC ctx) {
pick(ctx.player())
.orTimeout(10, TimeUnit.MINUTES)
.whenComplete((picked, ex) -> {
if (ex instanceof TimeoutException) {
ctx.sender().sendMessage(ctx.style().err("Timed out picking value."));
ctx.player().sendMessage(ctx.style().err("Timed out picking value."));
return;
}
ctx.sender().playSound(ctx.sender().getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 0.5f, 0f);
ctx.player().playSound(ctx.player().getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 0.5f, 0f);
node.value(picked);
});
}

View file

@ -1,25 +1,24 @@
package site.lab0x13.scrow.configurator.command;
import de.kentoj.kencommandapi.api.literal.Literal;
import de.kentoj.kencommandapi.api.literal.RootLiteral;
import de.kentoj.scrow.bukkit.command.ScrowBukkitCC;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import net.kyori.adventure.text.format.TextColor;
import org.bukkit.entity.Player;
import site.lab0x13.scrow.commands.model.literal.Literal;
import site.lab0x13.scrow.commands.model.literal.RootLiteral;
import site.lab0x13.scrow.configurator.ConfigApi;
import site.lab0x13.scrow.configurator.noderegistry.ConfigNodeWalker;
public final class ConfigCommand {
private final RootLiteral<Player> rootLiteral;
private final RootLiteral<ScrowBukkitCC> rootLiteral;
public ConfigCommand(ConfigApi configApi) {
var style = new ScrowMessageStyle("config", TextColor.color(0x28B088));
rootLiteral = Literal.<Player>builder("config", "cfg")
rootLiteral = Literal.<ScrowBukkitCC>builder("config", "cfg")
.withPermission("command.config")
.withLiteral(new KeyLiteral(style, configApi).literal())
.withSubLiteral(new KeyLiteral(configApi).literal())
.asRootLiteral(style);
}
public RootLiteral<Player> rootLiteral() {
public RootLiteral<ScrowBukkitCC> rootLiteral() {
return rootLiteral;
}
}

View file

@ -1,48 +0,0 @@
package site.lab0x13.scrow.configurator.command;
import com.leakyabstractions.result.api.Result;
import com.leakyabstractions.result.core.Results;
import de.kentoj.kencommandapi.api.argument.ArgumentType;
import de.kentoj.kencommandapi.api.suggestion.SuggestionProvider;
import org.bukkit.entity.Player;
import site.lab0x13.scrow.configurator.node.ConfigNode;
import site.lab0x13.scrow.configurator.noderegistry.ConfigNodeWalker;
import java.util.Collections;
public class ConfigNodeArgumentType implements ArgumentType<Player, ConfigNode<?>> {
private final ConfigNodeWalker nodeWalker;
public ConfigNodeArgumentType(ConfigRootNode rootNode) {
nodeWalker = new ConfigNodeWalker(rootNode);
}
@Override
public Result<ConfigNode<?>, String> parseInputUnchecked(String input) throws IllegalArgumentException {
assert input != null;
var res = nodeWalker.walk(input);
if (res.error() != null)
Results.failure(res.error());
assert res.node() != null;
return Results.success(res.node());
}
@Override
public SuggestionProvider<Player> getDefaultSuggestionProvider() {
return (_, input) -> {
var res = nodeWalker.walk(input);
switch (res.type()) {
case NO_SUCH_FIELD, INDEX_OUT_OF_RANGE, INDEX_EXPECTED -> {
assert res.node() != null;
return res.node().getFieldNames().stream()
.map(it -> res.parentKey() + "." + it)
.toList();
}
default -> {
return Collections.emptyList();
}
}
};
}
}

View file

@ -1,73 +1,50 @@
package site.lab0x13.scrow.configurator.command;
import de.kentoj.kencommandapi.api.literal.Literal;
import de.kentoj.kencommandapi.api.literal.LiteralBuilder;
import de.kentoj.scrow.bukkit.command.ScrowBukkitCC;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.Nullable;
import site.lab0x13.scrow.commands.model.literal.Literal;
import site.lab0x13.scrow.configurator.ConfigApi;
import site.lab0x13.scrow.configurator.action.ConfigAction;
import site.lab0x13.scrow.configurator.node.ConfigNode;
import java.util.ArrayList;
import java.util.List;
class KeyLiteral {
private final ScrowMessageStyle style;
private final Literal<Player> literal;
private final Literal<ScrowBukkitCC> literal;
private final ConfigApi api;
KeyLiteral(ScrowMessageStyle style, ConfigApi api) {
/*
All registered nodes should be added as literals. SubNoded nodes should be added
recursively.
When foo is a list node(implements SubNoded):
/cfg key foo <- list node itself is registered, has actions like append, delete, etc.
/cfg key foo.0 <- operate on first element, has actions of foo.0's type
*/
this.style = style;
var builder = Literal.<Player>builder("key");
api.allNodes().forEach((key, node) ->
addNodeLiteral(builder, key, node));
this.literal = builder.build();
KeyLiteral(ConfigApi api) {
this.api = api;
literal = Literal.<ScrowBukkitCC>dynamic("key")
.withSubLiteralNames(() -> new ArrayList<>(api.allNodes().keySet()))
.withSubLiteralProvider(this::keyLiteral)
.build();
}
private void addNodeLiteral(LiteralBuilder<Player> builder, String key, ConfigNode<?> node) {
var nodeLiteralBuilder = Literal.<Player>builder(key);
addNodeActionLiteral(nodeLiteralBuilder, (ConfigNode<Object>) node, new ArrayList<>(node.type().actions()));
/*
FUCK ME WE NEED TO ADD LITERALS AT RUNTIME.
I just need /cfg key <node> <actions dependent on node>
except nodes are registered at runtime so we need to register literals at runtime.
or we make it an argument, but then we can't make action's work nicely(only hackishly at best);
or a dy
*/
for (String fieldName : node.type().getSubNodeNames(node.value())) {
var subNode = node.type().getSubNode(node.value(), fieldName);
if (subNode == null) continue;
addNodeActionLiteral();
}
builder.withLiteral(nodeLiteralBuilder.build());
}
private @Nullable Literal<ScrowBukkitCC> keyLiteral(String name) {
var node = api.getNode(name);
if (node == null)
return null;
private void addNodeActionLiteral(LiteralBuilder<Player> builder, ConfigNode<Object> node, List<ConfigAction<?>> actions) {
for (var _action : actions) {
var action = (ConfigOptionAction<ConfigNode<Object>>) _action;
var actionLiteralBuilder = Literal.<Player>builder(action.name());
for (var argument : action.arguments())
actionLiteralBuilder.withArgument(argument);
var literalBuilder = Literal.<ScrowBukkitCC>builder(name);
for (var action : node.type().actions()) {
var actionLiteralBuilder = Literal.<ScrowBukkitCC>builder(action.name());
action.arguments().forEach(actionLiteralBuilder::withArgument);
actionLiteralBuilder.withSyncExecutor(ctx -> {
if (action.requiresValue() && node.value() == null) {
ctx.sender().sendMessage(style.err("No value set."));
ctx.sender().sendMessage(ctx.style().err("No value set."));
return;
}
action.execute(node, ctx);
((ConfigAction<ConfigNode<?>>) action).execute(node, ctx);
});
builder.withLiteral(actionLiteralBuilder.build());
literalBuilder.withSubLiteral(actionLiteralBuilder.build());
}
return literalBuilder.build();
}
public Literal<Player> literal() {
public Literal<ScrowBukkitCC> literal() {
return literal;
}
}

View file

@ -1,56 +0,0 @@
package site.lab0x13.scrow.configurator.command;
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
import de.kentoj.kencommandapi.api.literal.Literal;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import site.lab0x13.scrow.configurator.node.ConfigNode;
import java.util.List;
public class KeyLiteralImpl implements Literal<Player> {
private final ConfigNode<?> node;
public KeyLiteralImpl(String key, ConfigNode<?> node) {
this.key = key;
this.node = node;
}
@Override
public @Nullable Literal<Player> getLiteral(@NotNull String name) {
node.
return null;
}
@Override
public @NotNull List<Literal<Player>> literals() {
gh
}
@Override
public @NotNull String[] names() {
return new String[]{key};
}
@Override
public @Nullable String description() {
return null;
}
@Override
public List<CommandArgumentSpec<Player, ?>> arguments() {
return List.of();
}
@Override
public @Nullable CommandExecutor<Player> executor() {
return null;
}
@Override
public @Nullable String permission() {
return "";
}
}

View file

@ -13,7 +13,7 @@ public class LocationConfigType extends ConfigComplexType<Location> {
public static final LocationConfigType INSTANCE = new LocationConfigType();
private LocationConfigType() {
public LocationConfigType() {
addField("world", WorldConfigType.INSTANCE, Location::getWorld);
addField("x", ConfigPrimitiveType.DOUBLE, Location::getX);
addField("y", ConfigPrimitiveType.DOUBLE, Location::getY);

View file

@ -1,7 +1,7 @@
package site.lab0x13.scrow.configurator.type.location;
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import site.lab0x13.scrow.commands.model.argument.Argument;
import de.kentoj.scrow.bukkit.command.ScrowBukkitCC;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import site.lab0x13.scrow.configurator.action.ConfigAction;
@ -18,7 +18,7 @@ class LocationTeleportAction implements ConfigAction<ConfigNode<Location>> {
}
@Override
public List<CommandArgumentSpec<Player, ?>> arguments() {
public List<Argument<ScrowBukkitCC, ?>> arguments() {
return Collections.emptyList();
}
@ -28,8 +28,9 @@ class LocationTeleportAction implements ConfigAction<ConfigNode<Location>> {
}
@Override
public void execute(ConfigNode<Location> node, CommandContext<Player> ctx) {
ctx.sender().teleport(node.value());
ctx.sender().sendMessage(ctx.style().ok("You've been teleported."));
public void execute(ConfigNode<Location> node, ScrowBukkitCC ctx) {
assert node.value() != null;
ctx.player().teleport(node.value());
ctx.player().sendMessage(ctx.style().ok("You've been teleported."));
}
}

View file

@ -1,10 +1,9 @@
package site.lab0x13.scrow.configurator.type.world;
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.type.WorldArgumentType;
import site.lab0x13.scrow.commands.bukkit.type.WorldArgumentType;
import site.lab0x13.scrow.commands.model.argument.Argument;
import de.kentoj.scrow.bukkit.command.ScrowBukkitCC;
import org.bukkit.World;
import org.bukkit.entity.Player;
import site.lab0x13.scrow.configurator.action.ConfigAction;
import site.lab0x13.scrow.configurator.node.ConfigNode;
@ -12,8 +11,8 @@ import java.util.List;
class SetWorldAction implements ConfigAction<ConfigNode<World>> {
private final CommandArgumentSpec<Player, World> arg =
CommandArgumentSpec.builder("world", new WorldArgumentType<Player>()).build();
private final Argument<ScrowBukkitCC, World> arg =
Argument.builder("world", new WorldArgumentType<ScrowBukkitCC>()).build();
@Override
public String name() {
@ -21,7 +20,7 @@ class SetWorldAction implements ConfigAction<ConfigNode<World>> {
}
@Override
public List<CommandArgumentSpec<Player, ?>> arguments() {
public List<Argument<ScrowBukkitCC, ?>> arguments() {
return List.of(arg);
}
@ -31,7 +30,7 @@ class SetWorldAction implements ConfigAction<ConfigNode<World>> {
}
@Override
public void execute(ConfigNode<World> node, CommandContext<Player> ctx) {
public void execute(ConfigNode<World> node, ScrowBukkitCC ctx) {
World world = ctx.getArg(arg);
node.value(world);
ctx.sender().sendMessage(ctx.style().ok("Set world to " + world.getName() + "(" + world.getUID() + ")"));