.
This commit is contained in:
parent
13ced30434
commit
a9b7f47494
35 changed files with 1024 additions and 123 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="run dev server" type="ShConfigurationType">
|
<configuration default="false" name="run dev server" type="ShConfigurationType">
|
||||||
<option name="SCRIPT_TEXT" value="bazel run //dev-server:dev" />
|
<option name="SCRIPT_TEXT" value="bazel run //build:dev" />
|
||||||
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||||
<option name="SCRIPT_PATH" value="" />
|
<option name="SCRIPT_PATH" value="" />
|
||||||
<option name="SCRIPT_OPTIONS" value="" />
|
<option name="SCRIPT_OPTIONS" value="" />
|
||||||
|
|
|
||||||
|
|
@ -27,12 +27,14 @@ maven.install(
|
||||||
"org.postgresql:postgresql:42.7.12",
|
"org.postgresql:postgresql:42.7.12",
|
||||||
"org.mongodb:bson:5.8.0",
|
"org.mongodb:bson:5.8.0",
|
||||||
"io.nats:jnats:2.25.2",
|
"io.nats:jnats:2.25.2",
|
||||||
"de.kentoj.scrow:kencommandapi-core:0.36-SNAPSHOT",
|
"de.kentoj.scrow:kencommandapi-core:0.39-SNAPSHOT",
|
||||||
"de.kentoj.scrow:kencommandapi-bukkit:0.36-SNAPSHOT",
|
"de.kentoj.scrow:kencommandapi-bukkit:0.39-SNAPSHOT",
|
||||||
"de.kentoj.scrow:kencommandapi-velocity:0.36-SNAPSHOT",
|
"de.kentoj.scrow:kencommandapi-velocity:0.39-SNAPSHOT",
|
||||||
"io.papermc.paper:paper-api:[26.2.build,)",
|
"io.papermc.paper:paper-api:[26.2.build,)",
|
||||||
"net.luckperms:api:5.5",
|
"net.luckperms:api:5.5",
|
||||||
|
"com.google.code.gson:gson:2.14.0",
|
||||||
],
|
],
|
||||||
|
fetch_sources = True,
|
||||||
repositories = [
|
repositories = [
|
||||||
"https://repo.papermc.io/repository/maven-public/",
|
"https://repo.papermc.io/repository/maven-public/",
|
||||||
"https://git.lab0x13.site/api/packages/scrow/maven",
|
"https://git.lab0x13.site/api/packages/scrow/maven",
|
||||||
|
|
|
||||||
0
buildserver/BUILD
Normal file
0
buildserver/BUILD
Normal file
26
buildserver/configurator/BUILD
Normal file
26
buildserver/configurator/BUILD
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
load("@rules_jvm_external//:defs.bzl", "artifact")
|
||||||
|
load("@rules_java//java:java_binary.bzl", "java_binary")
|
||||||
|
|
||||||
|
java_binary(
|
||||||
|
name = "_plugin",
|
||||||
|
srcs = glob(["main/java/**/*.java"]),
|
||||||
|
create_executable = False,
|
||||||
|
resources = glob(["main/resources/**"]),
|
||||||
|
resource_strip_prefix = "buildserver/configurator/main/resources",
|
||||||
|
deps = [
|
||||||
|
"//core/bukkit:api",
|
||||||
|
artifact("com.google.code.gson:gson"),
|
||||||
|
artifact("io.papermc.paper:paper-api"),
|
||||||
|
],
|
||||||
|
add_exports = [
|
||||||
|
artifact("com.google.code.gson:gson"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
genrule(
|
||||||
|
name = "plugin",
|
||||||
|
srcs = [":_plugin_deploy.jar"],
|
||||||
|
outs = ["plugin.jar"],
|
||||||
|
cmd = "cp $< $@",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
40
buildserver/configurator/README.md
Normal file
40
buildserver/configurator/README.md
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
# configurator
|
||||||
|
|
||||||
|
helper for generating json configs interactively.
|
||||||
|
Plugins that hook into this plugin can register configuration nodes like "lobby.spawnpoint" with type Location.
|
||||||
|
server operators can then go ingame and do `/cfg key lobby.spawnpoint` to set a spawn location and then
|
||||||
|
`/cfg export` ig
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
- lists
|
||||||
|
- exporting
|
||||||
|
- proper namespaces
|
||||||
|
- split into api and impl
|
||||||
|
- more types(region pickers especially; also itemstacks)
|
||||||
|
- type variants like location without yaw/pitch
|
||||||
|
|
||||||
|
## design
|
||||||
|
|
||||||
|
in json we have primitives(like "hi", 1, false"), structures(like {"foo":"bar}) and lists(like []).
|
||||||
|
everything consists of primitives eventually so we can go from
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"arenas": [
|
||||||
|
{
|
||||||
|
"name": "skyfall",
|
||||||
|
"minPlayers": 3,
|
||||||
|
"maxPlayers": 8
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
to
|
||||||
|
```text
|
||||||
|
arenas.0.name = Primitive("skyfall")
|
||||||
|
arenas.0.minPlayers = Primitive(3)
|
||||||
|
arenas.0.maxPlayers = Primitive(8)
|
||||||
|
```
|
||||||
|
|
||||||
|
We can define a complex type as "type has a string field called name" and it will just use
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
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.ConfigRootNode;
|
||||||
|
import site.lab0x13.scrow.configurator.node.ConfigValueNode;
|
||||||
|
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 ConfigValueNode<>(LocationConfigType.INSTANCE));
|
||||||
|
ScrowAPI.playerCommands().register(new ConfigCommand(nodeRegistry).rootLiteral());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
package site.lab0x13.scrow.configurator.action;
|
||||||
|
|
||||||
|
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
|
||||||
|
import de.kentoj.kencommandapi.api.invocation.CommandContext;
|
||||||
|
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface ConfigOptionAction<T> {
|
||||||
|
|
||||||
|
/* FIXME not too clean */
|
||||||
|
List<ConfigOptionAction<?>> GLOBAL_ACTIONS = List.of(new GlobalShowAction<>());
|
||||||
|
|
||||||
|
String name();
|
||||||
|
|
||||||
|
List<CommandArgumentSpec<Player, ?>> arguments();
|
||||||
|
|
||||||
|
boolean requiresValue();
|
||||||
|
|
||||||
|
void execute(
|
||||||
|
ScrowMessageStyle style,
|
||||||
|
T node,
|
||||||
|
CommandContext<Player> ctx
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
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.scrowlib.convention.ScrowMessageStyle;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.event.ClickEvent;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import site.lab0x13.scrow.configurator.node.ConfigNode;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public final class GlobalShowAction<S extends ConfigNode<S>> implements ConfigOptionAction<S> {
|
||||||
|
|
||||||
|
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return "show";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CommandArgumentSpec<Player, ?>> arguments() {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean requiresValue() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(ScrowMessageStyle style, S node, CommandContext<Player> ctx) {
|
||||||
|
var jsonElement = node.type().serialize(node.value());
|
||||||
|
var prettyJson = GSON.toJson(jsonElement, JsonElement.class);
|
||||||
|
var component = Component.text(prettyJson + " [click to copy]")
|
||||||
|
.clickEvent(ClickEvent.copyToClipboard(prettyJson));
|
||||||
|
ctx.sender().sendMessage(style.ok(component));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package site.lab0x13.scrow.configurator.action;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
public interface ValuePicker<T> {
|
||||||
|
|
||||||
|
CompletableFuture<T> pick(Player player);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package site.lab0x13.scrow.configurator.command;
|
||||||
|
|
||||||
|
import de.kentoj.kencommandapi.api.literal.Literal;
|
||||||
|
import de.kentoj.kencommandapi.api.literal.RootLiteral;
|
||||||
|
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
|
||||||
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import site.lab0x13.scrow.configurator.node.ConfigRootNode;
|
||||||
|
import site.lab0x13.scrow.configurator.noderegistry.ConfigNodeWalker;
|
||||||
|
|
||||||
|
public final class ConfigCommand {
|
||||||
|
private final RootLiteral<Player> rootLiteral;
|
||||||
|
|
||||||
|
public ConfigCommand(ConfigRootNode nodeRegistry) {
|
||||||
|
var style = new ScrowMessageStyle("config", TextColor.color(0x28B088));
|
||||||
|
rootLiteral = Literal.<Player>builder("config", "cfg")
|
||||||
|
.withPermission("command.config")
|
||||||
|
.withLiteral(new KeyLiteral(style, new ConfigNodeWalker(nodeRegistry)).literal())
|
||||||
|
.asRootLiteral(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RootLiteral<Player> rootLiteral() {
|
||||||
|
return rootLiteral;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
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.ConfigListNode;
|
||||||
|
import site.lab0x13.scrow.configurator.node.ConfigNode;
|
||||||
|
import site.lab0x13.scrow.configurator.node.ConfigRootNode;
|
||||||
|
import site.lab0x13.scrow.configurator.node.SubFielded;
|
||||||
|
import site.lab0x13.scrow.configurator.noderegistry.ConfigNodeWalker;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
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_FIELDS, SUCCESS -> Collections.emptyList();
|
||||||
|
case NO_SUCH_FIELD, INDEX_OUT_OF_RANGE, INDEX_EXPECTED -> {
|
||||||
|
if (res.node() instanceof ConfigListNode<?> list)
|
||||||
|
return IntStream.range(0, list.size()).mapToObj(Integer::toString).toList();
|
||||||
|
if (res.node() instanceof SubFielded subFielded)
|
||||||
|
return subFielded.fields().keySet().stream()
|
||||||
|
.map(it -> res.parentKey() + "." + it)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
package site.lab0x13.scrow.configurator.command;
|
||||||
|
|
||||||
|
import com.leakyabstractions.result.core.Results;
|
||||||
|
import de.kentoj.kencommandapi.api.literal.Literal;
|
||||||
|
import de.kentoj.kencommandapi.api.literal.LiteralBuilder;
|
||||||
|
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import site.lab0x13.scrow.configurator.action.ConfigOptionAction;
|
||||||
|
import site.lab0x13.scrow.configurator.node.ConfigNode;
|
||||||
|
import site.lab0x13.scrow.configurator.node.ConfigValueNode;
|
||||||
|
import site.lab0x13.scrow.configurator.noderegistry.ConfigNodeWalker;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class KeyLiteral {
|
||||||
|
|
||||||
|
private final ScrowMessageStyle style;
|
||||||
|
private final Literal<Player> literal;
|
||||||
|
|
||||||
|
KeyLiteral(ScrowMessageStyle style, ConfigNodeWalker nodeWalker) {
|
||||||
|
this.style = style;
|
||||||
|
|
||||||
|
var builder = Literal.<Player>builder("key");
|
||||||
|
nodeWalker.getAllNodes().forEach((key, node) ->
|
||||||
|
addNodeLiteral(builder, key, node));
|
||||||
|
literal = builder.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()));
|
||||||
|
addNodeActionLiteral(nodeLiteralBuilder, (ConfigNode<Object>) node, ConfigOptionAction.GLOBAL_ACTIONS);
|
||||||
|
builder.withLiteral(nodeLiteralBuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addNodeActionLiteral(LiteralBuilder<Player> builder, ConfigNode<Object> node, List<ConfigOptionAction<?>> 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);
|
||||||
|
actionLiteralBuilder.withSyncExecutor(ctx -> {
|
||||||
|
if (action.requiresValue() && node.value() == null) {
|
||||||
|
ctx.sender().sendMessage(style.err("No value set."));
|
||||||
|
return Results.success(new Object());
|
||||||
|
}
|
||||||
|
action.execute(style, node, ctx);
|
||||||
|
return Results.success(new Object());
|
||||||
|
});
|
||||||
|
builder.withLiteral(actionLiteralBuilder.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Literal<Player> literal() {
|
||||||
|
return literal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
package site.lab0x13.scrow.configurator.node;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import site.lab0x13.scrow.configurator.type.ConfigType;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public final class ConfigListNode<T>
|
||||||
|
extends ArrayList<ConfigNode<T>>
|
||||||
|
implements ConfigNode<List<ConfigNode<T>>>, List<ConfigNode<T>> {
|
||||||
|
|
||||||
|
private final ConfigType<ConfigNode<T>> elementType;
|
||||||
|
|
||||||
|
public ConfigListNode(ConfigType<ConfigNode<T>> elementType) {
|
||||||
|
this.elementType = elementType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigType<ConfigNode<T>> elementType() {
|
||||||
|
return this.elementType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigType<List<ConfigNode<T>>> type() {
|
||||||
|
return new ConfigType<>() {
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(List<ConfigNode<T>> value) {
|
||||||
|
var list = new JsonArray();
|
||||||
|
forEach(n -> list.add(n.type().serialize(n.value())));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ConfigNode<T>> deserialize(JsonElement json) {
|
||||||
|
var res = new ArrayList<ConfigNode<T>>();
|
||||||
|
var list = json.getAsJsonArray();
|
||||||
|
list.forEach(e -> res.add(elementType.deserialize(e)));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ConfigNode<T>> value() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void value(List<ConfigNode<T>> value) {
|
||||||
|
this.clear();
|
||||||
|
this.addAll(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package site.lab0x13.scrow.configurator.node;
|
||||||
|
|
||||||
|
import site.lab0x13.scrow.configurator.type.ConfigType;
|
||||||
|
|
||||||
|
public sealed interface ConfigNode<T> permits ConfigValueNode, ConfigListNode, ConfigRootNode {
|
||||||
|
ConfigType<T> type();
|
||||||
|
|
||||||
|
T value();
|
||||||
|
|
||||||
|
void value(T value);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package site.lab0x13.scrow.configurator.node;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import site.lab0x13.scrow.configurator.type.ConfigMapType;
|
||||||
|
import site.lab0x13.scrow.configurator.type.ConfigType;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public final class ConfigRootNode implements ConfigNode<Map<String, ConfigNode<?>>>, SubFielded {
|
||||||
|
|
||||||
|
private final ConfigMapType<ConfigNode<?>> type = new ConfigMapType<>(new HashMap<>());
|
||||||
|
private Map<String, ConfigNode<?>> value = new HashMap<>();
|
||||||
|
|
||||||
|
public void register(String name, ConfigNode<?> node) {
|
||||||
|
value.put(name, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigType<Map<String, ConfigNode<?>>> type() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, ConfigNode<?>> value() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void value(Map<String, ConfigNode<?>> value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, ConfigNode<?>> fields() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ConfigNode<?> getField(String name) {
|
||||||
|
return value.get(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package site.lab0x13.scrow.configurator.node;
|
||||||
|
|
||||||
|
import site.lab0x13.scrow.configurator.type.ConfigType;
|
||||||
|
|
||||||
|
public final class ConfigValueNode<T> implements ConfigNode<T> {
|
||||||
|
private final ConfigType<T> type;
|
||||||
|
private final T defaultValue;
|
||||||
|
private T value;
|
||||||
|
|
||||||
|
public ConfigValueNode(ConfigType<T> type, T defaultValue) {
|
||||||
|
this.type = type;
|
||||||
|
this.defaultValue = defaultValue;
|
||||||
|
this.value = defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigValueNode(ConfigType<T> type) {
|
||||||
|
this(type, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
this.value = defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T defaultValue() {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T value() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void value(T value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean required() {
|
||||||
|
return defaultValue == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigType<T> type() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package site.lab0x13.scrow.configurator.node;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface SubFielded {
|
||||||
|
Map<String, ConfigNode<?>> fields();
|
||||||
|
|
||||||
|
@Nullable ConfigNode<?> getField(String name);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
package site.lab0x13.scrow.configurator.noderegistry;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import site.lab0x13.scrow.configurator.node.ConfigListNode;
|
||||||
|
import site.lab0x13.scrow.configurator.node.ConfigNode;
|
||||||
|
import site.lab0x13.scrow.configurator.node.ConfigRootNode;
|
||||||
|
import site.lab0x13.scrow.configurator.node.SubFielded;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public final class ConfigNodeWalker {
|
||||||
|
|
||||||
|
private final ConfigRootNode rootNode;
|
||||||
|
|
||||||
|
public ConfigNodeWalker(ConfigRootNode rootNode) {
|
||||||
|
this.rootNode = rootNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, ConfigNode<?>> getAllNodes() {
|
||||||
|
var result = new HashMap<String, ConfigNode<?>>();
|
||||||
|
processNode("", result, rootNode);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processNode(String key, Map<String, ConfigNode<?>> result, ConfigNode<?> node) {
|
||||||
|
result.put(key, node);
|
||||||
|
if (node instanceof ConfigListNode<?> list) {
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
var element = list.get(i);
|
||||||
|
processNode(key + "." + i, result, element);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* FIXME not clean at all */
|
||||||
|
SubFielded sf = null;
|
||||||
|
if (node instanceof SubFielded n)
|
||||||
|
sf = n;
|
||||||
|
else if (node.type() instanceof SubFielded n)
|
||||||
|
sf = n;
|
||||||
|
if (sf != null)
|
||||||
|
sf.fields().forEach((name, v) ->
|
||||||
|
processNode(key + "." + name, result, v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public WalkResult walk(String key) {
|
||||||
|
return walk(Arrays.stream(key.split("\\.")).iterator());
|
||||||
|
}
|
||||||
|
|
||||||
|
public WalkResult walk(Iterator<String> iter) {
|
||||||
|
var cursor = new Cursor(iter);
|
||||||
|
ConfigNode<?> cur = rootNode;
|
||||||
|
String token;
|
||||||
|
|
||||||
|
while ((token = cursor.nextToken()) != null) {
|
||||||
|
if (token.isEmpty()) continue;
|
||||||
|
if (cur instanceof ConfigListNode<?> list) {
|
||||||
|
int index;
|
||||||
|
try {
|
||||||
|
index = Integer.parseInt(token);
|
||||||
|
} catch (NumberFormatException _) {
|
||||||
|
return new WalkResult(WalkResult.Type.INDEX_EXPECTED, cursor.key(), cur);
|
||||||
|
}
|
||||||
|
if (index < 0 || index >= list.size())
|
||||||
|
return new WalkResult(WalkResult.Type.INDEX_OUT_OF_RANGE, cursor.key(), cur);
|
||||||
|
cur = list.get(index);
|
||||||
|
} else if (cur.type() instanceof SubFielded subFielded) {
|
||||||
|
cur = subFielded.getField(token);
|
||||||
|
if (cur == null)
|
||||||
|
return new WalkResult(WalkResult.Type.NO_SUCH_FIELD, cursor.key(), cur);
|
||||||
|
} else {
|
||||||
|
return new WalkResult(WalkResult.Type.NO_FIELDS, cursor.key(), cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new WalkResult(WalkResult.Type.SUCCESS, cursor.key(), cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Cursor {
|
||||||
|
private String key = "";
|
||||||
|
|
||||||
|
private final Iterator<String> iter;
|
||||||
|
|
||||||
|
private Cursor(Iterator<String> iter) {
|
||||||
|
this.iter = iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String nextToken() {
|
||||||
|
if (!iter.hasNext()) return null;
|
||||||
|
var token = iter.next();
|
||||||
|
key += "." + token;
|
||||||
|
key = key.replaceFirst("\\.", "");
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String key() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package site.lab0x13.scrow.configurator.noderegistry;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import site.lab0x13.scrow.configurator.node.ConfigNode;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public record WalkResult(
|
||||||
|
Type type,
|
||||||
|
String key,
|
||||||
|
@Nullable ConfigNode<?> node
|
||||||
|
) {
|
||||||
|
public String parentKey() {
|
||||||
|
var dotInd = key.lastIndexOf('.');
|
||||||
|
return dotInd < 0 ? "" : key.substring(0, dotInd - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String error() {
|
||||||
|
return type().message.apply(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
INDEX_EXPECTED(r -> "Numeric index expected at " + r.key() + "."),
|
||||||
|
INDEX_OUT_OF_RANGE(_ -> "Index out of range."),
|
||||||
|
NO_FIELDS(r -> r.key() + " has no fields."),
|
||||||
|
NO_SUCH_FIELD(r -> "Invalid key " + r.key()),
|
||||||
|
SUCCESS(_ -> null);
|
||||||
|
|
||||||
|
private final Function<WalkResult, String> message;
|
||||||
|
|
||||||
|
Type(Function<WalkResult, String> message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
package site.lab0x13.scrow.configurator.type;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import site.lab0x13.scrow.configurator.node.SubFielded;
|
||||||
|
import site.lab0x13.scrow.configurator.node.ConfigNode;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public abstract class ConfigComplexType<T> implements ConfigType<T>, SubFielded {
|
||||||
|
|
||||||
|
private final Map<String, ConfigNode<?>> entries = new HashMap<>();
|
||||||
|
|
||||||
|
protected abstract T deserialize(JsonObject obj);
|
||||||
|
|
||||||
|
protected void addEntry(String name, ConfigNode<?> node) {
|
||||||
|
entries.put(name, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected <S> S readNode(JsonObject object, String name) {
|
||||||
|
var node = (ConfigNode<Object>) entries.get(name);
|
||||||
|
return (S) node.type().deserialize(object.get(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T deserialize(JsonElement json) {
|
||||||
|
return deserialize(json.getAsJsonObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(T value) {
|
||||||
|
var obj = new JsonObject();
|
||||||
|
entries.forEach((name, node) -> writeNode(obj, name, node));
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <S> void writeNode(JsonObject object, String name, ConfigNode<S> node) {
|
||||||
|
var value = node.type().serialize(node.value());
|
||||||
|
object.add(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, ConfigNode<?>> fields() {
|
||||||
|
return new HashMap<>(entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable ConfigNode<?> getField(String name) {
|
||||||
|
return entries.get(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
package site.lab0x13.scrow.configurator.type;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import site.lab0x13.scrow.configurator.node.ConfigNode;
|
||||||
|
import site.lab0x13.scrow.configurator.node.SubFielded;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ConfigMapType<T> implements ConfigType<Map<String, T>>, SubFielded {
|
||||||
|
|
||||||
|
private final Map<String, ConfigType<?>> types;
|
||||||
|
|
||||||
|
public ConfigMapType(Map<String, ConfigType<?>> types) {
|
||||||
|
this.types = types;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public Map<String, T> deserialize(JsonElement json) {
|
||||||
|
var result = new HashMap<String, T>();
|
||||||
|
var obj = json.getAsJsonObject();
|
||||||
|
types.forEach((k, v) -> {
|
||||||
|
var type = (ConfigType<Object>) v;
|
||||||
|
var value = (T) type.deserialize(obj.get(k));
|
||||||
|
result.put(k, value);
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(Map<String, T> value) {
|
||||||
|
var res = new JsonObject();
|
||||||
|
types.forEach((k, v) -> {
|
||||||
|
var type = (ConfigType<T>) v;
|
||||||
|
var serialized = type.serialize(value.get(k));
|
||||||
|
res.add(k, serialized);
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, ConfigNode<?>> fields() {
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ConfigNode<?> getField(String name) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
package site.lab0x13.scrow.configurator.type;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class ConfigPrimitiveType<T> implements ConfigType<T> {
|
||||||
|
|
||||||
|
public static final ConfigPrimitiveType<Double> DOUBLE =
|
||||||
|
new ConfigPrimitiveType<>(JsonPrimitive::new, JsonPrimitive::getAsDouble);
|
||||||
|
public static final ConfigPrimitiveType<Integer> INT =
|
||||||
|
new ConfigPrimitiveType<>(JsonPrimitive::new, JsonPrimitive::getAsInt);
|
||||||
|
public static final ConfigPrimitiveType<Float> FLOAT =
|
||||||
|
new ConfigPrimitiveType<>(JsonPrimitive::new, JsonPrimitive::getAsFloat);
|
||||||
|
public static final ConfigPrimitiveType<Long> LONG =
|
||||||
|
new ConfigPrimitiveType<>(JsonPrimitive::new, JsonPrimitive::getAsLong);
|
||||||
|
public static final ConfigPrimitiveType<BigInteger> BIG_INT =
|
||||||
|
new ConfigPrimitiveType<>(JsonPrimitive::new, JsonPrimitive::getAsBigInteger);
|
||||||
|
public static final ConfigPrimitiveType<Boolean> BOOL =
|
||||||
|
new ConfigPrimitiveType<>(JsonPrimitive::new, JsonPrimitive::getAsBoolean);
|
||||||
|
public static final ConfigPrimitiveType<String> STRING =
|
||||||
|
new ConfigPrimitiveType<>(JsonPrimitive::new, JsonPrimitive::getAsString);
|
||||||
|
public static final ConfigPrimitiveType<Byte> BYTE =
|
||||||
|
new ConfigPrimitiveType<>(JsonPrimitive::new, JsonPrimitive::getAsByte);
|
||||||
|
|
||||||
|
private final Function<T, JsonPrimitive> serializer;
|
||||||
|
private final Function<JsonPrimitive, T> deserializer;
|
||||||
|
|
||||||
|
private ConfigPrimitiveType(Function<T, JsonPrimitive> serializer, Function<JsonPrimitive, T> deserializer) {
|
||||||
|
this.serializer = serializer;
|
||||||
|
this.deserializer = deserializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(T value) {
|
||||||
|
return serializer.apply(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T deserialize(JsonElement json) {
|
||||||
|
return deserializer.apply(json.getAsJsonPrimitive());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package site.lab0x13.scrow.configurator.type;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import site.lab0x13.scrow.configurator.action.ConfigOptionAction;
|
||||||
|
import site.lab0x13.scrow.configurator.node.ConfigNode;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface ConfigType<T> {
|
||||||
|
|
||||||
|
default List<ConfigOptionAction<?>> actions() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonElement serialize(T value);
|
||||||
|
|
||||||
|
T deserialize(JsonElement json);
|
||||||
|
|
||||||
|
default String toJson(T value) {
|
||||||
|
return serialize(value).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
default T fromJson(String json) {
|
||||||
|
return deserialize(JsonParser.parseString(json));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
package site.lab0x13.scrow.configurator.type.location;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import site.lab0x13.scrow.configurator.action.ConfigOptionAction;
|
||||||
|
import site.lab0x13.scrow.configurator.node.ConfigNode;
|
||||||
|
import site.lab0x13.scrow.configurator.node.ConfigValueNode;
|
||||||
|
import site.lab0x13.scrow.configurator.type.ConfigComplexType;
|
||||||
|
import site.lab0x13.scrow.configurator.type.ConfigPrimitiveType;
|
||||||
|
import site.lab0x13.scrow.configurator.type.world.WorldConfigType;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class LocationConfigType extends ConfigComplexType<Location> {
|
||||||
|
|
||||||
|
public static final LocationConfigType INSTANCE = new LocationConfigType();
|
||||||
|
|
||||||
|
private LocationConfigType() {
|
||||||
|
addEntry("world", new ConfigValueNode<>(WorldConfigType.INSTANCE));
|
||||||
|
addEntry("x", new ConfigValueNode<>(ConfigPrimitiveType.DOUBLE));
|
||||||
|
addEntry("y", new ConfigValueNode<>(ConfigPrimitiveType.DOUBLE));
|
||||||
|
addEntry("z", new ConfigValueNode<>(ConfigPrimitiveType.DOUBLE));
|
||||||
|
addEntry("yaw", new ConfigValueNode<>(ConfigPrimitiveType.FLOAT));
|
||||||
|
addEntry("pitch", new ConfigValueNode<>(ConfigPrimitiveType.FLOAT));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ConfigOptionAction<?>> actions() {
|
||||||
|
return List.of(
|
||||||
|
new LocationTeleportAction(),
|
||||||
|
new LocationPickCurrentAction()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Location deserialize(JsonObject obj) {
|
||||||
|
return new Location(
|
||||||
|
readNode(obj, "world"),
|
||||||
|
readNode(obj, "x"),
|
||||||
|
readNode(obj, "y"),
|
||||||
|
readNode(obj, "z"),
|
||||||
|
readNode(obj, "yaw"),
|
||||||
|
readNode(obj, "pitch")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package site.lab0x13.scrow.configurator.type.location;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import site.lab0x13.scrow.configurator.node.ConfigNode;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
class LocationPickCurrentAction extends PickAction<Location, ConfigNode<Location>> {
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return "pick-current";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean requiresValue() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CompletableFuture<Location> pick(Player player) {
|
||||||
|
return CompletableFuture.completedFuture(player.getLocation());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package site.lab0x13.scrow.configurator.type.location;
|
||||||
|
|
||||||
|
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
|
||||||
|
import de.kentoj.kencommandapi.api.invocation.CommandContext;
|
||||||
|
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import site.lab0x13.scrow.configurator.action.ConfigOptionAction;
|
||||||
|
import site.lab0x13.scrow.configurator.node.ConfigValueNode;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class LocationTeleportAction implements ConfigOptionAction<ConfigValueNode<Location>> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return "teleport";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CommandArgumentSpec<Player, ?>> arguments() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean requiresValue() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(ScrowMessageStyle style, ConfigValueNode<Location> node, CommandContext<Player> ctx) {
|
||||||
|
ctx.sender().teleport(node.value());
|
||||||
|
ctx.sender().sendMessage(style.ok("You've been teleported."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
package site.lab0x13.scrow.configurator.type.location;
|
||||||
|
|
||||||
|
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
|
||||||
|
import de.kentoj.kencommandapi.api.invocation.CommandContext;
|
||||||
|
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import site.lab0x13.scrow.configurator.action.ConfigOptionAction;
|
||||||
|
import site.lab0x13.scrow.configurator.node.ConfigNode;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
public abstract class PickAction<S, T extends ConfigNode<S>> implements ConfigOptionAction<T> {
|
||||||
|
|
||||||
|
protected abstract CompletableFuture<S> pick(Player player);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return "pick";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CommandArgumentSpec<Player, ?>> arguments() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(ScrowMessageStyle style, T node, CommandContext<Player> ctx) {
|
||||||
|
pick(ctx.sender())
|
||||||
|
.orTimeout(10, TimeUnit.MINUTES)
|
||||||
|
.whenComplete((picked, ex) -> {
|
||||||
|
if (ex instanceof TimeoutException) {
|
||||||
|
ctx.sender().sendMessage(style.err("Timed out picking value."));
|
||||||
|
}
|
||||||
|
|
||||||
|
node.value(picked);
|
||||||
|
ctx.sender().playSound(ctx.sender().getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 0.5f, 0f);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
package site.lab0x13.scrow.configurator.type.world;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
import com.leakyabstractions.result.api.Result;
|
||||||
|
import com.leakyabstractions.result.core.Results;
|
||||||
|
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
|
||||||
|
import de.kentoj.kencommandapi.api.invocation.CommandContext;
|
||||||
|
import de.kentoj.kencommandapi.type.WorldArgumentType;
|
||||||
|
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import site.lab0x13.scrow.configurator.action.ConfigOptionAction;
|
||||||
|
import site.lab0x13.scrow.configurator.node.ConfigValueNode;
|
||||||
|
import site.lab0x13.scrow.configurator.type.ConfigType;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class WorldConfigType implements ConfigType<World> {
|
||||||
|
|
||||||
|
public static ConfigType<World> INSTANCE = new WorldConfigType();
|
||||||
|
|
||||||
|
private WorldConfigType() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(World value) {
|
||||||
|
return new JsonPrimitive(value.getUID().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public World deserialize(JsonElement json) {
|
||||||
|
return Bukkit.getWorld(UUID.fromString(json.getAsString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ConfigOptionAction<?>> actions() {
|
||||||
|
return List.of(new SetAction());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SetAction implements ConfigOptionAction<ConfigValueNode<World>> {
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return "set";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CommandArgumentSpec<Player, ?>> arguments() {
|
||||||
|
return List.of(
|
||||||
|
CommandArgumentSpec.builder("world", new WorldArgumentType<Player>()).build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean requiresValue() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(ScrowMessageStyle style, ConfigValueNode<World> node, CommandContext<Player> ctx) {
|
||||||
|
World world = ctx.getArg("world");
|
||||||
|
node.value(world);
|
||||||
|
ctx.sender().sendMessage(style.ok("Set world to " + world.getName() + "("+ world.getUID() + ")"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
buildserver/configurator/main/resources/plugin.yml
Normal file
6
buildserver/configurator/main/resources/plugin.yml
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
name: "Configurator"
|
||||||
|
version: "0"
|
||||||
|
depend: [ "CoreBukkit" ]
|
||||||
|
main: "site.lab0x13.scrow.configurator.ConfiguratorPlugin"
|
||||||
|
api-version: "26.2"
|
||||||
|
author: "Kento2"
|
||||||
|
|
@ -16,21 +16,24 @@ java_library(
|
||||||
artifact("de.kentoj.scrow:kencommandapi-bukkit"),
|
artifact("de.kentoj.scrow:kencommandapi-bukkit"),
|
||||||
artifact("org.mongodb:bson"),
|
artifact("org.mongodb:bson"),
|
||||||
],
|
],
|
||||||
|
neverlink = True,
|
||||||
)
|
)
|
||||||
|
|
||||||
java_binary(
|
java_binary(
|
||||||
name = "_plugin",
|
name = "_plugin",
|
||||||
srcs = glob(["plugin/main/java/**/*.java"]),
|
srcs = glob(["plugin/main/java/**/*.java", "api/main/java/**/*.java"]),
|
||||||
create_executable = False,
|
create_executable = False,
|
||||||
resources = glob(["plugin/main/resources/**"]),
|
resources = glob(["plugin/main/resources/**"]),
|
||||||
resource_strip_prefix = "core/bukkit/plugin/main/resources",
|
resource_strip_prefix = "core/bukkit/plugin/main/resources",
|
||||||
deps = [
|
deps = [
|
||||||
":api",
|
"//core/common",
|
||||||
|
artifact("de.kentoj.scrow:kencommandapi-bukkit"),
|
||||||
artifact("net.luckperms:api"),
|
artifact("net.luckperms:api"),
|
||||||
artifact("io.papermc.paper:paper-api"),
|
artifact("io.papermc.paper:paper-api"),
|
||||||
artifact("io.nats:jnats"),
|
artifact("io.nats:jnats"),
|
||||||
artifact("net.kyori:adventure-key:5.2.0"),
|
artifact("net.kyori:adventure-key:5.2.0"),
|
||||||
artifact("org.postgresql:postgresql"),
|
artifact("org.postgresql:postgresql"),
|
||||||
|
artifact("org.mongodb:bson"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package de.kentoj.scrow.bukkit;
|
package de.kentoj.scrow.bukkit;
|
||||||
|
|
||||||
import de.kentoj.scrow.bukkit.style.ChatStyleListener;
|
|
||||||
import de.kentoj.scrow.bukkit.command.economy.CoinsCommand;
|
import de.kentoj.scrow.bukkit.command.economy.CoinsCommand;
|
||||||
import de.kentoj.scrow.bukkit.command.friends.FriendCommand;
|
import de.kentoj.scrow.bukkit.command.friends.FriendCommand;
|
||||||
import de.kentoj.scrow.bukkit.command.instance.InstanceCache;
|
import de.kentoj.scrow.bukkit.command.instance.InstanceCache;
|
||||||
|
|
@ -9,22 +8,22 @@ import de.kentoj.scrow.bukkit.command.instance.LobbyCommand;
|
||||||
import de.kentoj.scrow.bukkit.command.instance.PlayCommand;
|
import de.kentoj.scrow.bukkit.command.instance.PlayCommand;
|
||||||
import de.kentoj.scrow.bukkit.internal.player.prefix.CachedPrefixProvider;
|
import de.kentoj.scrow.bukkit.internal.player.prefix.CachedPrefixProvider;
|
||||||
import de.kentoj.scrow.bukkit.internal.player.prefix.LuckPermsPrefixSetter;
|
import de.kentoj.scrow.bukkit.internal.player.prefix.LuckPermsPrefixSetter;
|
||||||
|
import de.kentoj.scrow.bukkit.style.ChatStyleListener;
|
||||||
import de.kentoj.scrow.bukkit.style.TabStyleListener;
|
import de.kentoj.scrow.bukkit.style.TabStyleListener;
|
||||||
import net.luckperms.api.LuckPermsProvider;
|
import net.luckperms.api.LuckPermsProvider;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.slf4j.Logger;
|
||||||
import java.io.IOException;
|
import org.slf4j.LoggerFactory;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.channels.FileChannel;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.StandardOpenOption;
|
|
||||||
|
|
||||||
public final class CoreImplPlugin extends JavaPlugin {
|
public final class CoreImplPlugin extends JavaPlugin {
|
||||||
|
|
||||||
|
private final Logger log = LoggerFactory.getLogger(CoreImplPlugin.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
var cachedPrefixProvider = new CachedPrefixProvider();
|
var cachedPrefixProvider = new CachedPrefixProvider();
|
||||||
ScrowAPISurface.initScrowAPI(this, cachedPrefixProvider);
|
ScrowAPISurface.initScrowAPI(this, cachedPrefixProvider);
|
||||||
|
log.info("Initialized ScrowAPI");
|
||||||
|
|
||||||
ScrowAPI.playerCommands().register(new CoinsCommand().rootLiteral());
|
ScrowAPI.playerCommands().register(new CoinsCommand().rootLiteral());
|
||||||
ScrowAPI.playerCommands().register(new FriendCommand().rootLiteral());
|
ScrowAPI.playerCommands().register(new FriendCommand().rootLiteral());
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ public final class InstanceDestroyLiteral {
|
||||||
this.style = style;
|
this.style = style;
|
||||||
|
|
||||||
handleArg = CommandArgumentSpec.builder("handle", new StringArgumentType<CommandSender>())
|
handleArg = CommandArgumentSpec.builder("handle", new StringArgumentType<CommandSender>())
|
||||||
.withSuggestionProvider(_ ->
|
.withSuggestionProvider((_, _) ->
|
||||||
cache.getInstances().stream()
|
cache.getInstances().stream()
|
||||||
.map(ServerInstance::handle)
|
.map(ServerInstance::handle)
|
||||||
.toList())
|
.toList())
|
||||||
|
|
|
||||||
|
|
@ -16,16 +16,19 @@ java_library(
|
||||||
artifact("de.kentoj.scrow:kencommandapi-velocity"),
|
artifact("de.kentoj.scrow:kencommandapi-velocity"),
|
||||||
artifact("org.mongodb:bson"),
|
artifact("org.mongodb:bson"),
|
||||||
],
|
],
|
||||||
|
neverlink = True,
|
||||||
)
|
)
|
||||||
|
|
||||||
java_binary(
|
java_binary(
|
||||||
name = "plugin",
|
name = "plugin",
|
||||||
srcs = glob(["plugin/main/java/**/*.java"]),
|
srcs = glob(["plugin/main/java/**/*.java", "api/main/java/**/*.java"]),
|
||||||
create_executable = False,
|
create_executable = False,
|
||||||
deps = [
|
deps = [
|
||||||
":api",
|
"//core/common",
|
||||||
artifact("com.velocitypowered:velocity-api"),
|
artifact("com.velocitypowered:velocity-api"),
|
||||||
artifact("com.google.inject:guice"),
|
artifact("com.google.inject:guice"),
|
||||||
artifact("io.nats:jnats"),
|
artifact("io.nats:jnats"),
|
||||||
|
artifact("de.kentoj.scrow:kencommandapi-velocity"),
|
||||||
|
artifact("org.mongodb:bson"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
load(":minecraft.bzl", "dev_server", "fetch_file")
|
|
||||||
|
|
||||||
dev_server(
|
|
||||||
name = "dev",
|
|
||||||
server_jar = ":papermc",
|
|
||||||
plugins = [
|
|
||||||
":luckperms",
|
|
||||||
":viaversion",
|
|
||||||
":viabackwards",
|
|
||||||
],
|
|
||||||
local_plugins = [
|
|
||||||
"//core/bukkit:plugin",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
fetch_file(
|
|
||||||
name = "papermc",
|
|
||||||
filename = "paper.jar",
|
|
||||||
url = "https://fill-data.papermc.io/v1/objects/5953a1f1deaa3572be420c3a5b18406c4b752412a78be4acab7c8b467633caed/paper-26.2-100.jar",
|
|
||||||
)
|
|
||||||
fetch_file(
|
|
||||||
name = "luckperms",
|
|
||||||
filename = "LuckPerms.jar",
|
|
||||||
url = "https://download.luckperms.net/1652/bukkit/loader/LuckPerms-Bukkit-5.5.65.jar",
|
|
||||||
)
|
|
||||||
fetch_file(
|
|
||||||
name = "viaversion",
|
|
||||||
filename = "ViaVersion.jar",
|
|
||||||
url = "https://hangarcdn.papermc.io/plugins/ViaVersion/ViaVersion/versions/5.11.0/PAPER/ViaVersion-5.11.0.jar"
|
|
||||||
)
|
|
||||||
fetch_file(
|
|
||||||
name = "viabackwards",
|
|
||||||
filename = "ViaBackwards.jar",
|
|
||||||
url = "https://hangarcdn.papermc.io/plugins/ViaVersion/ViaBackwards/versions/5.11.0/PAPER/ViaBackwards-5.11.0.jar"
|
|
||||||
)
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
def _dev_server_impl(ctx):
|
|
||||||
script = ctx.actions.declare_file(ctx.label.name + "_runner")
|
|
||||||
content = """
|
|
||||||
#!/bin/sh
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
cp -f '%s' server.jar
|
|
||||||
printf eula=true > eula.txt
|
|
||||||
mkdir -p plugins
|
|
||||||
rm -f plugins/*.jar
|
|
||||||
for plugin in %s
|
|
||||||
do
|
|
||||||
cp -v \"$plugin\" plugins/
|
|
||||||
done
|
|
||||||
|
|
||||||
mkdir -p postgres-data
|
|
||||||
podman run \
|
|
||||||
--rm \
|
|
||||||
--name scrow-postgres-dev \
|
|
||||||
-p 5432:5432 \
|
|
||||||
-v ./postgres-data/:/data \
|
|
||||||
-e POSTGRES_USER=postgres \
|
|
||||||
-e POSTGRES_HOST_AUTH_METHOD=trust \
|
|
||||||
-d \
|
|
||||||
docker.io/postgres:alpine || true
|
|
||||||
echo "Starting paper server in $PWD"
|
|
||||||
exec env HOST_POSTGRES='jdbc:postgresql://127.0.0.1:5432/postgres' java -jar server.jar --nogui %s
|
|
||||||
""" % (
|
|
||||||
ctx.file.server_jar.short_path,
|
|
||||||
" ".join([p.short_path for p in ctx.files.plugins]),
|
|
||||||
" ".join(["--add-plugin %s" % p.short_path for p in ctx.files.local_plugins]),
|
|
||||||
)
|
|
||||||
ctx.actions.write(
|
|
||||||
output = script,
|
|
||||||
content = content,
|
|
||||||
is_executable = True,
|
|
||||||
)
|
|
||||||
return DefaultInfo(
|
|
||||||
executable = script,
|
|
||||||
runfiles = ctx.runfiles(files = [ctx.file.server_jar] + ctx.files.plugins + ctx.files.local_plugins)
|
|
||||||
)
|
|
||||||
|
|
||||||
dev_server = rule(
|
|
||||||
implementation = _dev_server_impl,
|
|
||||||
executable = True,
|
|
||||||
attrs = {
|
|
||||||
"server_jar": attr.label(allow_single_file = True, mandatory = True),
|
|
||||||
"plugins": attr.label_list(),
|
|
||||||
"local_plugins": attr.label_list(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
def _fetch_plugin_impl(ctx):
|
|
||||||
out_file = ctx.actions.declare_file(ctx.attr.filename)
|
|
||||||
ctx.actions.run_shell(
|
|
||||||
outputs = [out_file],
|
|
||||||
command = "curl -Lso \"$1\" \"$2\"",
|
|
||||||
arguments = [out_file.path, ctx.attr.url],
|
|
||||||
execution_requirements = {
|
|
||||||
"requires-network": "1",
|
|
||||||
},
|
|
||||||
progress_message = "Downloading plugin %s" % ctx.attr.filename,
|
|
||||||
)
|
|
||||||
return [DefaultInfo(files = depset([out_file]))]
|
|
||||||
|
|
||||||
fetch_file = rule(
|
|
||||||
implementation = _fetch_plugin_impl,
|
|
||||||
attrs = {
|
|
||||||
"url": attr.string(mandatory = True),
|
|
||||||
"filename": attr.string(mandatory = True),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue