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

@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="run dev server" type="ShConfigurationType">
<option name="SCRIPT_TEXT" value="bazel run //build:dev" />
<option name="SCRIPT_TEXT" value="bazel run //rules:dev" />
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
<option name="SCRIPT_PATH" value="" />
<option name="SCRIPT_OPTIONS" value="" />

View file

@ -2,11 +2,13 @@ bazel_dep(name = "rules_java", version = "9.7.0")
bazel_dep(name = "rules_jvm_external", version = "7.1")
bazel_dep(name = "bazel_jar_jar", version = "0.1.15")
bazel_dep(name = "rules_shell", version = "0.8.0")
bazel_dep(name = "contrib_rules_jvm", version = "0.34.0")
bazel_dep(name = "apple_rules_lint", version = "0.4.0")
git_override(
module_name = "rules_jvm_external",
remote = "https://github.com/acecilia/rules_jvm_external.git",
branch = "3-snapshot_support",
commit = "f799b1bacc6b05776275b180bb245bc4a94e795f",
)
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
@ -21,34 +23,37 @@ maven.install(
"org.slf4j:slf4j-simple:2.0.18",
"net.kyori:adventure-api:5.2.0",
"net.kyori:adventure-text-minimessage:5.2.0",
# use `env REPIN=1 bazel run @maven//:pin` after updating
"com.velocitypowered:velocity-api:4.1.0-SNAPSHOT",
# use `env REPIN=1 bazel run @maven//:pin` after changing velocity-api version
"com.velocitypowered:velocity-api:4.0.0",
"org.jdbi:jdbi3-core:3.53.0",
"org.jdbi:jdbi3-postgres:3.53.0",
"org.postgresql:postgresql:42.7.12",
"org.mongodb:bson:5.8.0",
"io.nats:jnats:2.25.2",
"de.kentoj.scrow:kencommandapi-core:0.42-SNAPSHOT",
"de.kentoj.scrow:kencommandapi-bukkit:0.42-SNAPSHOT",
"de.kentoj.scrow:kencommandapi-velocity:0.42-SNAPSHOT",
"site.lab0x13.scrow:commands-common:1.2.0",
"site.lab0x13.scrow:commands-bukkit:1.2.0",
"site.lab0x13.scrow:commands-velocity:1.2.0",
"io.papermc.paper:paper-api:[26.2.build,)",
"net.luckperms:api:5.5",
"com.google.code.gson:gson:2.14.0",
],
fetch_sources = False,
# fetch_sources = True,
## fix com.github.bazelbuild.rules_jvm_external.resolver.remote.UriNotFoundException: Unable to download
## com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
#excluded_artifacts = ["com.google.guava:listenablefuture"],
repositories = [
"https://repo1.maven.org/maven2",
"https://repo.maven.apache.org/maven2",
"https://git.lab0x13.site/api/packages/scrow/maven",
"https://repo.papermc.io/repository/maven-public/",
],
known_contributing_modules = ["protobuf"],
fail_on_missing_checksum = False, # for kencommandapi
resolver = "gradle",
lock_file = "//:maven_install.json",
)
# luckperms is provided at runtime
maven.amend_artifact(coordinates = "net.luckperms:api", neverlink = "true")
use_repo(maven, "maven")
linter = use_extension("@apple_rules_lint//lint:extensions.bzl", "linter")
linter.configure(name = "java-spotbugs", config = "@contrib_rules_jvm//java:spotbugs-default-config")
use_repo(linter, "apple_linters")

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() + ")"));

View file

@ -9,11 +9,11 @@ java_library(
deps = [
"//core/common",
artifact("io.papermc.paper:paper-api"),
artifact("de.kentoj.scrow:kencommandapi-bukkit"),
artifact("site.lab0x13.scrow:commands-bukkit"),
],
exports = [
"//core/common",
artifact("de.kentoj.scrow:kencommandapi-bukkit"),
artifact("site.lab0x13.scrow:commands-bukkit"),
artifact("org.mongodb:bson"),
],
neverlink = True,
@ -27,7 +27,7 @@ java_binary(
resource_strip_prefix = "core/bukkit/plugin/main/resources",
deps = [
"//core/common",
artifact("de.kentoj.scrow:kencommandapi-bukkit"),
artifact("site.lab0x13.scrow:commands-bukkit"),
artifact("net.luckperms:api"),
artifact("io.papermc.paper:paper-api"),
artifact("io.nats:jnats"),

View file

@ -1,6 +1,6 @@
package de.kentoj.scrow.bukkit;
import de.kentoj.kencommandapi.CommandAPI;
import de.kentoj.scrow.bukkit.command.ScrowBukkitCC;
import de.kentoj.scrow.bukkit.minigame.MinigameManager;
import de.kentoj.scrow.bukkit.region.RegionManager;
import de.kentoj.scrowlib.economy.EconomyService;
@ -12,12 +12,11 @@ import de.kentoj.scrowlib.player.NetworkPlayer;
import de.kentoj.scrowlib.player.NetworkPlayerFactory;
import de.kentoj.scrowlib.player.PlayerPrefixProvider;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.jdbi.v3.core.Jdbi;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import site.lab0x13.scrow.commands.bukkit.ScrowCommands;
import java.util.UUID;
@ -38,8 +37,7 @@ public class ScrowAPI {
private static MessageBroker messageBroker;
private static InstanceManager instanceManager;
private static RegionManager regionManager;
private static CommandAPI<Player> playerCommands;
private static CommandAPI<CommandSender> commands;
private static ScrowCommands<ScrowBukkitCC> commands;
private static PlayerPrefixProvider playerPrefixProvider;
private static final MinigameManager minigameManager = new MinigameManager();
private static NetworkPlayerFactory playerFactory;
@ -103,13 +101,8 @@ public class ScrowAPI {
}
@ApiStatus.Internal
public static void setPlayerCommands(CommandAPI<Player> playerCommands) {
ScrowAPI.playerCommands = playerCommands;
}
@ApiStatus.Internal
public static void setCommands(CommandAPI<CommandSender> commands) {
ScrowAPI.commands = commands;
public static void setCommands(ScrowCommands<ScrowBukkitCC> commandsManager) {
ScrowAPI.commands = commandsManager;
}
public static @Nullable Jdbi jdbi() {
@ -143,17 +136,15 @@ public class ScrowAPI {
/**
* Regions are not a reliable enough to detect fast movements.
* The way regions work is that every few ticks, all regions are checked for players.
*
* @see org.bukkit.event.player.PlayerMoveEvent
*/
public static RegionManager regionManager() {
return regionManager;
}
public static CommandAPI<Player> playerCommands() {
return playerCommands;
}
public static CommandAPI<CommandSender> commands() {
@ApiStatus.Internal
public static ScrowCommands<ScrowBukkitCC> commands() {
return commands;
}

View file

@ -0,0 +1,18 @@
package de.kentoj.scrow.bukkit.command;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import org.bukkit.command.CommandSender;
import site.lab0x13.scrow.commands.bukkit.BukkitCommandContext;
public final class ScrowBukkitCC extends BukkitCommandContext<ScrowBukkitCC> {
private final ScrowMessageStyle style;
public ScrowBukkitCC(CommandSender sender, ScrowMessageStyle style) {
super(sender);
this.style = style;
}
public ScrowMessageStyle style() {
return style;
}
}

View file

@ -1,11 +1,11 @@
package de.kentoj.scrow.bukkit.minigame.phaseflow;
import de.kentoj.kencommandapi.api.platform.MessageStyle;
import de.kentoj.scrow.bukkit.minigame.Minigame;
import de.kentoj.scrow.bukkit.minigame.PlayerManager;
import de.kentoj.scrow.bukkit.minigame.phase.PhaseFlow;
import de.kentoj.scrow.bukkit.minigame.phase.event.PhaseListeners;
import de.kentoj.scrow.bukkit.minigame.phase.event.PhaseListenersImpl;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
public class PhaseContext<T extends Minigame> {
private final T game;
@ -29,7 +29,7 @@ public class PhaseContext<T extends Minigame> {
return game.playerManager();
}
public MessageStyle style() {
public ScrowMessageStyle style() {
return game.messageStyle();
}

View file

@ -21,8 +21,8 @@ public final class CoreImplPlugin extends JavaPlugin {
ScrowAPISurface.initScrowAPI(this, cachedPrefixProvider);
log.info("Initialized ScrowAPI");
ScrowAPI.playerCommands().register(new CoinsCommand().rootLiteral());
ScrowAPI.playerCommands().register(new FriendCommand().rootLiteral());
ScrowAPI.commands().register(new CoinsCommand().rootLiteral());
ScrowAPI.commands().register(new FriendCommand().rootLiteral());
var luckperms = LuckPermsProvider.get();
new LuckPermsPrefixSetter(luckperms, cachedPrefixProvider).init(this);

View file

@ -1,10 +1,11 @@
package de.kentoj.scrow.bukkit;
import de.kentoj.kencommandapi.CommandAPI;
import de.kentoj.scrow.bukkit.command.ScrowBukkitCC;
import de.kentoj.scrow.bukkit.internal.player.NetworkPlayerWatchdog;
import de.kentoj.scrow.bukkit.internal.region.RegionManagerImpl;
import de.kentoj.scrow.bukkit.internal.region.RegionPlayerTracker;
import de.kentoj.scrow.bukkit.internal.region.RegionTask;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import de.kentoj.scrowlib.economy.InMemoryEconomyService;
import de.kentoj.scrowlib.economy.PostgresEconomyService;
import de.kentoj.scrowlib.friends.friendship.InMemoryFriendshipService;
@ -18,12 +19,11 @@ import de.kentoj.scrowlib.player.NetworkPlayerImpl;
import de.kentoj.scrowlib.player.PlayerPrefixProvider;
import io.nats.client.Nats;
import io.nats.client.Options;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.jdbi.v3.core.Jdbi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import site.lab0x13.scrow.commands.bukkit.ScrowCommands;
import java.io.IOException;
import java.util.Properties;
@ -70,8 +70,7 @@ public class ScrowAPISurface {
ScrowAPI.setPlayerFactory(playerId -> new NetworkPlayerImpl(ScrowAPI.messageBroker(), playerId));
ScrowAPI.setRegionManager(new RegionManagerImpl());
ScrowAPI.setCommands(new CommandAPI<>(plugin, CommandSender.class));
ScrowAPI.setPlayerCommands(new CommandAPI<>(plugin, Player.class));
ScrowAPI.setCommands(new ScrowCommands<>(plugin, (literal, sender) -> new ScrowBukkitCC(sender, (ScrowMessageStyle) literal.style())));
ScrowAPI.setInstanceManager(new InstanceManagerImpl(ScrowAPI.messageBroker()));
ScrowAPI.setEconomyService(ScrowAPI.jdbi() != null ?
new PostgresEconomyService(ScrowAPI.jdbi()) : new InMemoryEconomyService());

View file

@ -1,31 +1,29 @@
package de.kentoj.scrow.bukkit.command.economy;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.api.literal.Literal;
import de.kentoj.kencommandapi.api.literal.RootLiteral;
import de.kentoj.kencommandapi.api.platform.MessageStyle;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.command.ScrowBukkitCC;
import de.kentoj.scrow.bukkit.scheduler.Tasks;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import org.bukkit.entity.Player;
import site.lab0x13.scrow.commands.model.literal.Literal;
import site.lab0x13.scrow.commands.model.literal.RootLiteral;
import java.util.concurrent.CompletableFuture;
public final class CoinsCommand {
private final RootLiteral<Player> rootLiteral;
private final RootLiteral<ScrowBukkitCC> rootLiteral;
public CoinsCommand() {
rootLiteral = Literal.<Player>builder("coins", "bal", "balance")
rootLiteral = Literal.<ScrowBukkitCC>builder("coins", "bal", "balance")
.withPermission("command.coins.get.self")
.withExecutor(this::execute)
.withLiteral(new CoinsSetLiteral().literal())
.withLiteral(new CoinsGetLiteral().literal())
.withSubLiteral(new CoinsSetLiteral().literal())
.withSubLiteral(new CoinsGetLiteral().literal())
.asRootLiteral(ScrowMessageStyle.GENERIC);
}
public CompletableFuture<?> execute(CommandContext<Player> ctx) {
var player = ctx.sender();
public CompletableFuture<?> execute(ScrowBukkitCC ctx) {
var player = ctx.player();
return Tasks.supplyAsync(() ->
ScrowAPI.economyService().getCoins(player.getUniqueId()))
.thenSync(amount ->
@ -33,7 +31,7 @@ public final class CoinsCommand {
.toFuture();
}
public RootLiteral<Player> rootLiteral() {
public RootLiteral<ScrowBukkitCC> rootLiteral() {
return rootLiteral;
}
}

View file

@ -1,34 +1,32 @@
package de.kentoj.scrow.bukkit.command.economy;
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.api.literal.Literal;
import de.kentoj.kencommandapi.api.platform.MessageStyle;
import de.kentoj.kencommandapi.type.OfflinePlayerArgumentType;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.command.ScrowBukkitCC;
import de.kentoj.scrow.bukkit.scheduler.Tasks;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import site.lab0x13.scrow.commands.bukkit.type.OfflinePlayerArgumentType;
import site.lab0x13.scrow.commands.model.argument.Argument;
import site.lab0x13.scrow.commands.model.literal.Literal;
import java.util.concurrent.CompletableFuture;
public final class CoinsGetLiteral {
private final Literal<Player> literal;
private final CommandArgumentSpec<Player, OfflinePlayer> playerArg;
private final Literal<ScrowBukkitCC> literal;
private final Argument<ScrowBukkitCC, OfflinePlayer> playerArg;
public CoinsGetLiteral() {
playerArg = CommandArgumentSpec.builder("player", new OfflinePlayerArgumentType<Player>())
.withDefaultValue(CommandContext::sender)
playerArg = Argument.builder("player", new OfflinePlayerArgumentType<ScrowBukkitCC>())
.withDefaultValue(ScrowBukkitCC::player)
.build();
literal = Literal.<Player>builder("get")
literal = Literal.<ScrowBukkitCC>builder("get")
.withPermission("command.coins.get.others")
.withArgument(playerArg)
.withExecutor(this::execute)
.build();
}
private CompletableFuture<?> execute(CommandContext<Player> ctx) {
private CompletableFuture<?> execute(ScrowBukkitCC ctx) {
var player = ctx.getArg(playerArg);
return Tasks.supplyAsync(() ->
ScrowAPI.economyService().getCoins(player.getUniqueId()))
@ -37,7 +35,7 @@ public final class CoinsGetLiteral {
.toFuture();
}
public Literal<Player> literal() {
public Literal<ScrowBukkitCC> literal() {
return literal;
}
}

View file

@ -1,11 +1,10 @@
package de.kentoj.scrow.bukkit.command.economy;
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
import de.kentoj.kencommandapi.api.argument.types.IntegerArgumentType;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.api.literal.Literal;
import de.kentoj.kencommandapi.api.platform.MessageStyle;
import de.kentoj.kencommandapi.type.OfflinePlayerArgumentType;
import de.kentoj.scrow.bukkit.command.ScrowBukkitCC;
import site.lab0x13.scrow.commands.model.argument.Argument;
import site.lab0x13.scrow.commands.model.argument.types.IntegerArgumentType;
import site.lab0x13.scrow.commands.model.literal.Literal;
import site.lab0x13.scrow.commands.bukkit.type.OfflinePlayerArgumentType;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.scheduler.Tasks;
import org.bukkit.OfflinePlayer;
@ -15,17 +14,17 @@ import java.util.concurrent.CompletableFuture;
public final class CoinsSetLiteral {
private final Literal<Player> literal;
private final CommandArgumentSpec<Player, OfflinePlayer> playerArg;
private final CommandArgumentSpec<Player, Integer> amountArg;
private final Literal<ScrowBukkitCC> literal;
private final Argument<ScrowBukkitCC, OfflinePlayer> playerArg;
private final Argument<ScrowBukkitCC, Integer> amountArg;
CoinsSetLiteral() {
playerArg = CommandArgumentSpec.builder("player", new OfflinePlayerArgumentType<Player>())
.withDefaultValue(CommandContext::sender)
playerArg = Argument.builder("player", new OfflinePlayerArgumentType<ScrowBukkitCC>())
.withDefaultValue(ScrowBukkitCC::player)
.build();
amountArg = CommandArgumentSpec.builder("amount", new IntegerArgumentType<Player>())
amountArg = Argument.builder("amount", new IntegerArgumentType<ScrowBukkitCC>())
.build();
literal = Literal.<Player>builder("set")
literal = Literal.<ScrowBukkitCC>builder("set")
.withPermission("command.coins.set")
.withArgument(playerArg)
.withArgument(amountArg)
@ -33,7 +32,7 @@ public final class CoinsSetLiteral {
.build();
}
private CompletableFuture<?> execute(CommandContext<Player> ctx) {
private CompletableFuture<?> execute(ScrowBukkitCC ctx) {
var player = ctx.getArg(playerArg);
var amount = ctx.getArg(amountArg);
return Tasks.runAsync(() ->
@ -43,7 +42,7 @@ public final class CoinsSetLiteral {
.toFuture();
}
public Literal<Player> literal() {
public Literal<ScrowBukkitCC> literal() {
return literal;
}
}

View file

@ -2,15 +2,13 @@ package de.kentoj.scrow.bukkit.command.friends;
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.api.literal.Literal;
import de.kentoj.kencommandapi.api.platform.MessageStyle;
import de.kentoj.kencommandapi.type.OfflinePlayerArgumentType;
import site.lab0x13.scrow.commands.model.argument.Argument;
import de.kentoj.scrow.bukkit.command.ScrowBukkitCC;
import site.lab0x13.scrow.commands.model.literal.Literal;
import site.lab0x13.scrow.commands.bukkit.type.OfflinePlayerArgumentType;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.scheduler.Task;
import de.kentoj.scrow.bukkit.scheduler.Tasks;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import de.kentoj.scrowlib.friends.FriendRequestService;
import de.kentoj.scrowlib.friends.FriendshipService;
import de.kentoj.scrowlib.friends.friendship.FriendshipImpl;
@ -18,6 +16,7 @@ import de.kentoj.scrowlib.friends.request.FriendRequestImpl;
import net.kyori.adventure.text.Component;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import site.lab0x13.scrow.commands.model.literal.MessageStyle;
import java.time.Instant;
import java.util.Objects;
@ -26,22 +25,22 @@ import java.util.concurrent.CompletableFuture;
public final class FriendAddLiteral {
private final Literal<Player> literal;
private final CommandArgumentSpec<Player, OfflinePlayer> playerArg;
private final Literal<ScrowBukkitCC> literal;
private final Argument<ScrowBukkitCC, OfflinePlayer> playerArg;
private final FriendRequestService requestService = ScrowAPI.friendRequestService();
private final FriendshipService friendsService = ScrowAPI.friendshipService();
FriendAddLiteral() {
playerArg = CommandArgumentSpec.builder("player", new OfflinePlayerArgumentType<Player>())
playerArg = Argument.builder("player", new OfflinePlayerArgumentType<ScrowBukkitCC>())
.build();
literal = Literal.<Player>builder("add")
literal = Literal.<ScrowBukkitCC>builder("add")
.withArgument(playerArg)
.withExecutor(this::execute)
.build();
}
private CompletableFuture<?> execute(CommandContext<Player> ctx) {
var self = ctx.sender();
private CompletableFuture<?> execute(ScrowBukkitCC ctx) {
var self = ctx.player();
var other = ctx.getArg(playerArg);
return Tasks.supplyAsync(() -> findAction(self, other)
.mapSuccess(action -> {
@ -53,6 +52,10 @@ public final class FriendAddLiteral {
}
private void sendRequest(MessageStyle style, Player self, OfflinePlayer other) {
if (other.equals(self)) {
self.sendMessage(style.ok("You can't send yourself a friend request."));
return;
}
Tasks.runAsync(() ->
requestService.saveFriendRequest(new FriendRequestImpl(self.getUniqueId(), other.getUniqueId())))
.runSync(() -> {
@ -110,7 +113,7 @@ public final class FriendAddLiteral {
.mapSync(Objects::nonNull);
}
public Literal<Player> literal() {
public Literal<ScrowBukkitCC> literal() {
return literal;
}

View file

@ -1,25 +1,25 @@
package de.kentoj.scrow.bukkit.command.friends;
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.Component;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.entity.Player;
import site.lab0x13.scrow.commands.model.literal.Literal;
import site.lab0x13.scrow.commands.model.literal.RootLiteral;
public final class FriendCommand {
private final RootLiteral<Player> rootLiteral;
private final RootLiteral<ScrowBukkitCC> rootLiteral;
public FriendCommand() {
rootLiteral = Literal.<Player>builder("f", "friend")
.withLiteral(new FriendListLiteral().literal())
.withLiteral(new FriendAddLiteral().literal())
.withLiteral(new FriendRemoveLiteral().literal())
.withLiteral(new FriendRequestDeclineLiteral().literal())
.withLiteral(new FriendRequestsLiteral().literal())
rootLiteral = Literal.<ScrowBukkitCC>builder("f", "friend")
.withSubLiteral(new FriendListLiteral().literal())
.withSubLiteral(new FriendAddLiteral().literal())
.withSubLiteral(new FriendRemoveLiteral().literal())
.withSubLiteral(new FriendRequestDeclineLiteral().literal())
.withSubLiteral(new FriendRequestsLiteral().literal())
.asRootLiteral(new ScrowMessageStyle("Friends", NamedTextColor.AQUA));
}
@ -38,7 +38,7 @@ public final class FriendCommand {
.color(NamedTextColor.RED));
}
public RootLiteral<Player> rootLiteral() {
public RootLiteral<ScrowBukkitCC> rootLiteral() {
return rootLiteral;
}
}

View file

@ -1,8 +1,7 @@
package de.kentoj.scrow.bukkit.command.friends;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.api.literal.Literal;
import de.kentoj.kencommandapi.api.platform.MessageStyle;
import de.kentoj.scrow.bukkit.command.ScrowBukkitCC;
import site.lab0x13.scrow.commands.model.literal.Literal;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.scheduler.Tasks;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
@ -11,7 +10,6 @@ import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@ -20,16 +18,16 @@ import static java.util.Objects.requireNonNull;
import static net.kyori.adventure.text.Component.text;
public final class FriendListLiteral {
private final Literal<Player> literal;
private final Literal<ScrowBukkitCC> literal;
FriendListLiteral() {
literal = Literal.<Player>builder("list")
literal = Literal.<ScrowBukkitCC>builder("list")
.withExecutor(this::displayFriendList)
.build();
}
private CompletableFuture<?> displayFriendList(CommandContext<Player> ctx) {
var sender = ctx.sender();
private CompletableFuture<?> displayFriendList(ScrowBukkitCC ctx) {
var sender = ctx.player();
return Tasks.supplyAsync(() ->
ScrowAPI.friendshipService().getFriendships(sender.getUniqueId()))
.thenSync(friendships -> {
@ -67,7 +65,7 @@ public final class FriendListLiteral {
return message;
}
public Literal<Player> literal() {
public Literal<ScrowBukkitCC> literal() {
return literal;
}
}

View file

@ -1,36 +1,33 @@
package de.kentoj.scrow.bukkit.command.friends;
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.api.literal.Literal;
import de.kentoj.kencommandapi.type.OfflinePlayerArgumentType;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.command.ScrowBukkitCC;
import de.kentoj.scrow.bukkit.scheduler.Tasks;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import site.lab0x13.scrow.commands.bukkit.type.OfflinePlayerArgumentType;
import site.lab0x13.scrow.commands.model.argument.Argument;
import site.lab0x13.scrow.commands.model.literal.Literal;
import java.util.concurrent.CompletableFuture;
public final class FriendRemoveLiteral {
private final Literal<Player> literal;
private final CommandArgumentSpec<Player, OfflinePlayer> playerArg;
private final Literal<ScrowBukkitCC> literal;
private final Argument<ScrowBukkitCC, OfflinePlayer> playerArg;
FriendRemoveLiteral() {
playerArg = CommandArgumentSpec.<Player, OfflinePlayer>builder("player", new OfflinePlayerArgumentType<>())
playerArg = Argument.<ScrowBukkitCC, OfflinePlayer>builder("player", new OfflinePlayerArgumentType<>())
.build();
literal = Literal.<Player>builder("remove")
literal = Literal.<ScrowBukkitCC>builder("remove")
.withArgument(playerArg)
.withExecutor(this::removeFriend)
.build();
}
private CompletableFuture<?> removeFriend(CommandContext<Player> ctx) {
private CompletableFuture<?> removeFriend(ScrowBukkitCC ctx) {
var friend = ctx.getArg(playerArg);
return Tasks.supplyAsync(() ->
ScrowAPI.friendshipService().deleteFriendship(friend.getUniqueId(), ctx.sender().getUniqueId()))
ScrowAPI.friendshipService().deleteFriendship(friend.getUniqueId(), ctx.player().getUniqueId()))
.thenSync(deleted -> {
if (!deleted) {
ctx.sender().sendMessage(ctx.style().err("You are not friends with " + friend.getName() + "."));
@ -40,7 +37,7 @@ public final class FriendRemoveLiteral {
}).toFuture();
}
public Literal<Player> literal() {
public Literal<ScrowBukkitCC> literal() {
return literal;
}
}

View file

@ -1,50 +1,46 @@
package de.kentoj.scrow.bukkit.command.friends;
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.api.literal.Literal;
import de.kentoj.kencommandapi.type.OfflinePlayerArgumentType;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.command.ScrowBukkitCC;
import de.kentoj.scrow.bukkit.scheduler.Tasks;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import de.kentoj.scrowlib.friends.FriendRequestService;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import site.lab0x13.scrow.commands.bukkit.type.OfflinePlayerArgumentType;
import site.lab0x13.scrow.commands.model.argument.Argument;
import site.lab0x13.scrow.commands.model.literal.Literal;
import java.util.concurrent.CompletableFuture;
public final class FriendRequestDeclineLiteral {
private final Literal<Player> literal;
private final CommandArgumentSpec<Player, OfflinePlayer> playerArg;
private final Literal<ScrowBukkitCC> literal;
private final Argument<ScrowBukkitCC, OfflinePlayer> playerArg;
private final FriendRequestService requestService = ScrowAPI.friendRequestService();
FriendRequestDeclineLiteral() {
playerArg = CommandArgumentSpec.builder("player", new OfflinePlayerArgumentType<Player>())
playerArg = Argument.builder("player", new OfflinePlayerArgumentType<ScrowBukkitCC>())
.build();
literal = Literal.<Player>builder("reject", "decline")
literal = Literal.<ScrowBukkitCC>builder("reject", "decline")
.withArgument(playerArg)
.withExecutor(this::declineFriendRequest)
.build();
}
private CompletableFuture<?> declineFriendRequest(CommandContext<Player> ctx) {
private CompletableFuture<?> declineFriendRequest(ScrowBukkitCC ctx) {
var other = ctx.getArg(playerArg);
return Tasks.supplyAsync(() ->
requestService.deleteFriendRequest(other.getUniqueId(), ctx.sender().getUniqueId()))
requestService.deleteFriendRequest(other.getUniqueId(), ctx.player().getUniqueId()))
.thenSync(deleted -> {
if (!deleted) {
ctx.sender().sendMessage(ctx.style().err("There's no incoming friend request from " + other.getName() + "."));
ctx.player().sendMessage(ctx.style().err("There's no incoming friend request from " + other.getName() + "."));
return;
}
ctx.sender().sendMessage(ctx.style().ok("Friend request declined."));
ScrowAPI.getPlayer(other).sendMessage(ctx.style().ok(ctx.sender().getName() + " has declined your friend request."));
ctx.player().sendMessage(ctx.style().ok("Friend request declined."));
ScrowAPI.getPlayer(other).sendMessage(ctx.style().ok(ctx.player().getName() + " has declined your friend request."));
}).toFuture();
}
public Literal<Player> literal() {
public Literal<ScrowBukkitCC> literal() {
return literal;
}
}

View file

@ -1,8 +1,7 @@
package de.kentoj.scrow.bukkit.command.friends;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.api.literal.Literal;
import de.kentoj.kencommandapi.api.platform.MessageStyle;
import de.kentoj.scrow.bukkit.command.ScrowBukkitCC;
import site.lab0x13.scrow.commands.model.literal.Literal;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.scheduler.Tasks;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
@ -11,7 +10,6 @@ import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@ -20,26 +18,26 @@ import static net.kyori.adventure.text.Component.text;
public final class FriendRequestsLiteral {
private final Literal<Player> literal;
private final Literal<ScrowBukkitCC> literal;
FriendRequestsLiteral() {
literal = Literal.<Player>builder("requests")
literal = Literal.<ScrowBukkitCC>builder("requests")
.withExecutor(this::displayFriendRequests)
.build();
}
private CompletableFuture<?> displayFriendRequests(CommandContext<Player> ctx) {
private CompletableFuture<?> displayFriendRequests(ScrowBukkitCC ctx) {
return Tasks.supplyAsync(() ->
ScrowAPI.friendRequestService().getFriendRequestsTo(ctx.sender().getUniqueId()))
ScrowAPI.friendRequestService().getFriendRequestsTo(ctx.player().getUniqueId()))
.thenSync(list -> {
if (list.isEmpty()) {
ctx.sender().sendMessage(ctx.style().err("You have no friend requests."));
ctx.player().sendMessage(ctx.style().err("You have no friend requests."));
return;
}
var requesters = list.stream()
.sorted(this::compareByAge)
.map(fr -> Bukkit.getOfflinePlayer(fr.from()).getName());
ctx.sender().sendMessage(formatList(ctx.style(), requesters.toList()));
ctx.player().sendMessage(formatList(ctx.style(), requesters.toList()));
}).toFuture();
}
@ -59,7 +57,7 @@ public final class FriendRequestsLiteral {
return message;
}
public Literal<Player> literal() {
public Literal<ScrowBukkitCC> literal() {
return literal;
}
}

View file

@ -7,7 +7,7 @@ shared_deps = [
artifact("org.jetbrains:annotations"),
artifact("com.google.guava:guava"),
artifact("org.slf4j.slf4j:api"),
artifact("de.kentoj.scrow:kencommandapi-core"),
artifact("site.lab0x13.scrow:commands-common"),
artifact("net.kyori:adventure-api"),
artifact("net.kyori:adventure-text-minimessage"),
artifact("org.jdbi:jdbi3-core"),

View file

@ -1,10 +1,10 @@
package de.kentoj.scrowlib.convention;
import de.kentoj.kencommandapi.api.platform.MessageStyle;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;
import site.lab0x13.scrow.commands.model.literal.MessageStyle;
public record ScrowMessageStyle(
Component prefix,

View file

@ -9,12 +9,14 @@ java_library(
visibility = ["//visibility:public"],
deps = [
"//core/common",
artifact("site.lab0x13.scrow:commands-common"),
artifact("com.velocitypowered:velocity-api"),
artifact("de.kentoj.scrow:kencommandapi-velocity"),
artifact("site.lab0x13.scrow:commands-velocity"),
],
exports = [
"//core/common",
artifact("de.kentoj.scrow:kencommandapi-velocity"),
artifact("site.lab0x13.scrow:commands-common"),
artifact("site.lab0x13.scrow:commands-velocity"),
artifact("org.mongodb:bson"),
],
neverlink = True,
@ -25,11 +27,13 @@ java_binary(
srcs = glob(["plugin/main/java/**/*.java", "api/main/java/**/*.java"]),
create_executable = False,
deps = [
":api",
"//core/common",
artifact("site.lab0x13.scrow:commands-common"),
artifact("com.velocitypowered:velocity-api"),
artifact("com.google.inject:guice"),
artifact("io.nats:jnats"),
artifact("de.kentoj.scrow:kencommandapi-velocity"),
artifact("site.lab0x13.scrow:commands-velocity"),
artifact("org.mongodb:bson"),
artifact("org.postgresql:postgresql"),
artifact("com.google.code.gson:gson"),

View file

@ -1,22 +1,21 @@
package de.kentoj.scrow.velocity;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.Player;
import de.kentoj.kencommandapi.CommandAPI;
import de.kentoj.scrow.velocity.commands.ScrowVelocityCC;
import de.kentoj.scrowlib.instancemanager.InstanceManager;
import de.kentoj.scrowlib.messaging.MessageBroker;
import de.kentoj.scrowlib.player.NetworkPlayer;
import de.kentoj.scrowlib.player.NetworkPlayerFactory;
import org.jdbi.v3.core.Jdbi;
import org.jetbrains.annotations.ApiStatus;
import site.lab0x13.scrow.commands.velocity.ScrowCommands;
import java.util.UUID;
public class ScrowAPI {
private static Jdbi jdbi;
private static CommandAPI<CommandSource> commands;
private static CommandAPI<Player> playerCommands;
private static ScrowCommands<ScrowVelocityCC> commands;
private static MessageBroker messageBroker;
private static InstanceManager instanceManager;
private static NetworkPlayerFactory playerFactory;
@ -30,32 +29,27 @@ public class ScrowAPI {
}
@ApiStatus.Internal
public static void initMessageBroker(MessageBroker messageBroker) {
public static void setMessageBroker(MessageBroker messageBroker) {
ScrowAPI.messageBroker = messageBroker;
}
@ApiStatus.Internal
public static void initInstanceManager(InstanceManager instanceManager) {
public static void setInstanceManager(InstanceManager instanceManager) {
ScrowAPI.instanceManager = instanceManager;
}
@ApiStatus.Internal
public static void initJdbi(Jdbi jdbi) {
public static void setJdbi(Jdbi jdbi) {
ScrowAPI.jdbi = jdbi;
}
@ApiStatus.Internal
public static void initPlayerFactory(NetworkPlayerFactory playerFactory) {
public static void setPlayerFactory(NetworkPlayerFactory playerFactory) {
ScrowAPI.playerFactory = playerFactory;
}
@ApiStatus.Internal
public static void initPlayerCommands(CommandAPI<Player> playerCommands) {
ScrowAPI.playerCommands = playerCommands;
}
@ApiStatus.Internal
public static void initCommands(CommandAPI<CommandSource> commands) {
public static void setCommands(ScrowCommands<ScrowVelocityCC> commands) {
ScrowAPI.commands = commands;
}
@ -63,14 +57,10 @@ public class ScrowAPI {
return jdbi;
}
public static CommandAPI<CommandSource> commands() {
public static ScrowCommands<ScrowVelocityCC> commands() {
return commands;
}
public static CommandAPI<Player> playerCommands() {
return playerCommands;
}
public static MessageBroker messageBroker() {
return messageBroker;
}

View file

@ -0,0 +1,19 @@
package de.kentoj.scrow.velocity.commands;
import com.velocitypowered.api.command.CommandSource;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import site.lab0x13.scrow.commands.velocity.VelocityCommandContext;
public class ScrowVelocityCC extends VelocityCommandContext<ScrowVelocityCC> {
private final ScrowMessageStyle style;
public ScrowVelocityCC(CommandSource sender, ScrowMessageStyle style) {
super(sender);
this.style = style;
}
public ScrowMessageStyle style() {
return style;
}
}

View file

@ -3,6 +3,7 @@ package de.kentoj.scrow.corevelocity;
import com.google.inject.Inject;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.proxy.ProxyServer;
import de.kentoj.scrow.corevelocity.misc.OnlineCommand;
@ -12,14 +13,12 @@ import de.kentoj.scrow.corevelocity.privmsg.MsgCommand;
import de.kentoj.scrow.corevelocity.privmsg.PrivMsgHandler;
import de.kentoj.scrow.corevelocity.privmsg.ReplyCommand;
import de.kentoj.scrow.corevelocity.serverregistration.ConsulV1ServerInstanceScanner;
import de.kentoj.scrow.corevelocity.serverregistration.RegistrationTask;
import de.kentoj.scrow.corevelocity.serverregistration.ServerInstanceScanner;
import de.kentoj.scrow.corevelocity.serverregistration.PlayerTryJoinLobbyListener;
import de.kentoj.scrow.velocity.ScrowAPI;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import de.kentoj.scrowlib.utils.EnvUtils;
import net.kyori.adventure.text.format.NamedTextColor;
import java.time.Duration;
import site.lab0x13.scrow.commands.model.literal.MessageStyle;
@Plugin(
id = "corevelocity",
@ -31,6 +30,7 @@ public final class CoreVelocityPlugin {
@Inject
private ProxyServer server;
private ConsulV1ServerInstanceScanner instanceScanner;
@Subscribe
private void onInit(ProxyInitializeEvent __) {
@ -39,15 +39,21 @@ public final class CoreVelocityPlugin {
var lastTargetCache = new LastTargetCache();
var style = new ScrowMessageStyle("MSG", NamedTextColor.LIGHT_PURPLE);
var privmsgHelper = new PrivMsgHandler(style);
ScrowAPI.playerCommands().register(new ReplyCommand(server, lastTargetCache, privmsgHelper, style).rootLiteral());
ScrowAPI.playerCommands().register(new MsgCommand(server, lastTargetCache, privmsgHelper, style).rootLiteral());
ScrowAPI.commands().register(new ReplyCommand(server, lastTargetCache, privmsgHelper, style).rootLiteral());
ScrowAPI.commands().register(new MsgCommand(server, lastTargetCache, privmsgHelper, style).rootLiteral());
ScrowAPI.commands().register(new OnlineCommand(server).rootLiteral());
var sendPlayerWatchdog = new SendPlayerWatchdog(server);
sendPlayerWatchdog.listen();
ServerInstanceScanner instanceScanner = new ConsulV1ServerInstanceScanner(EnvUtils.envOrThrow("HOST_CONSUL"));
server.getScheduler().buildTask(this, new RegistrationTask(server, instanceScanner))
.repeat(Duration.ofSeconds(3))
instanceScanner = new ConsulV1ServerInstanceScanner(server, EnvUtils.envOrThrow("HOST_CONSUL"));
server.getEventManager().register(this, new PlayerTryJoinLobbyListener(server));
server.getScheduler()
.buildTask(this, () -> instanceScanner.start())
.schedule();
}
@Subscribe
private void onShutdown(ProxyShutdownEvent __) {
instanceScanner.close();
}
}

View file

@ -1,10 +1,9 @@
package de.kentoj.scrow.corevelocity;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
import de.kentoj.kencommandapi.CommandAPI;
import de.kentoj.scrow.velocity.ScrowAPI;
import de.kentoj.scrow.velocity.commands.ScrowVelocityCC;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import de.kentoj.scrowlib.instancemanager.InstanceManagerImpl;
import de.kentoj.scrowlib.messaging.InMemoyMessageBroker;
import de.kentoj.scrowlib.messaging.NatsMessageBroker;
@ -14,6 +13,7 @@ import io.nats.client.Options;
import org.jdbi.v3.core.Jdbi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import site.lab0x13.scrow.commands.velocity.ScrowCommands;
import java.io.IOException;
import java.util.Properties;
@ -30,13 +30,13 @@ public class ScrowAPISurface {
.server(natsHost)
.pedantic()
.build();
ScrowAPI.initMessageBroker(new NatsMessageBroker(Nats.connect(options)));
ScrowAPI.setMessageBroker(new NatsMessageBroker(Nats.connect(options)));
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
} else {
log.error("HOST_NATS not set -> Using in-memory dummy message broker");
ScrowAPI.initMessageBroker(new InMemoyMessageBroker());
ScrowAPI.setMessageBroker(new InMemoyMessageBroker());
}
var hostPostgres = System.getenv().get("HOST_POSTGRES");
@ -45,7 +45,7 @@ public class ScrowAPISurface {
Class.forName("org.postgresql.Driver", true, ScrowAPISurface.class.getClassLoader());
var props = new Properties();
props.setProperty("user", "postgres");
ScrowAPI.initJdbi(Jdbi.create(hostPostgres, props));
ScrowAPI.setJdbi(Jdbi.create(hostPostgres, props));
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
@ -53,10 +53,9 @@ public class ScrowAPISurface {
log.error("HOST_POSTGRES not set -> Using in-memory database");
}
ScrowAPI.initInstanceManager(new InstanceManagerImpl(ScrowAPI.messageBroker()));
ScrowAPI.initCommands(new CommandAPI<>(server, CommandSource.class));
ScrowAPI.initPlayerCommands(new CommandAPI<>(server, Player.class));
ScrowAPI.initPlayerFactory(playerId -> new NetworkPlayerImpl(ScrowAPI.messageBroker(), playerId));
ScrowAPI.setInstanceManager(new InstanceManagerImpl(ScrowAPI.messageBroker()));
ScrowAPI.setCommands(new ScrowCommands<>(server, (literal, sender) -> new ScrowVelocityCC(sender, (ScrowMessageStyle) literal.style())));
ScrowAPI.setPlayerFactory(playerId -> new NetworkPlayerImpl(ScrowAPI.messageBroker(), playerId));
}
public static void destroyScrowAPI() {

View file

@ -1,38 +1,33 @@
package de.kentoj.scrow.corevelocity.misc;
import com.leakyabstractions.result.api.Result;
import com.leakyabstractions.result.core.Results;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.ProxyServer;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.api.invocation.SyncCommandExecutor;
import de.kentoj.kencommandapi.api.literal.Literal;
import de.kentoj.kencommandapi.api.literal.RootLiteral;
import de.kentoj.scrow.velocity.commands.ScrowVelocityCC;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import site.lab0x13.scrow.commands.model.literal.Literal;
import site.lab0x13.scrow.commands.model.literal.RootLiteral;
public final class OnlineCommand {
private final RootLiteral<CommandSource> rootLiteral;
private final RootLiteral<ScrowVelocityCC> rootLiteral;
private final ScrowMessageStyle style = ScrowMessageStyle.GENERIC;
private final ProxyServer server;
public OnlineCommand(ProxyServer server) {
this.server = server;
rootLiteral = Literal.<CommandSource>builder("online")
rootLiteral = Literal.<ScrowVelocityCC>builder("online")
.withSyncExecutor(this::executeSync)
.asRootLiteral(ScrowMessageStyle.GENERIC);
}
private Result<Object, String> executeSync(CommandContext<CommandSource> ctx) {
private void executeSync(ScrowVelocityCC ctx) {
int cnt = server.getPlayerCount();
var msg = cnt != 1
? "There are currently " + cnt + " players online."
: "There is currently 1 player online.";
ctx.sender().sendMessage(style.ok(msg));
return Results.success(new Object());
}
public RootLiteral<CommandSource> rootLiteral() {
public RootLiteral<ScrowVelocityCC> rootLiteral() {
return rootLiteral;
}
}

View file

@ -1,54 +1,53 @@
package de.kentoj.scrow.corevelocity.privmsg;
import com.leakyabstractions.result.api.Result;
import com.leakyabstractions.result.core.Results;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
import de.kentoj.kencommandapi.api.argument.types.StringArgumentType;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.api.literal.Literal;
import de.kentoj.kencommandapi.api.literal.RootLiteral;
import de.kentoj.kencommandapi.api.platform.MessageStyle;
import de.kentoj.kencommandapi.type.PlayerArgumentType;
import de.kentoj.scrow.velocity.commands.ScrowVelocityCC;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import site.lab0x13.scrow.commands.model.argument.Argument;
import site.lab0x13.scrow.commands.model.argument.types.StringArgumentType;
import site.lab0x13.scrow.commands.model.literal.Literal;
import site.lab0x13.scrow.commands.model.literal.RootLiteral;
import site.lab0x13.scrow.commands.velocity.type.PlayerArgumentType;
public class MsgCommand {
private final RootLiteral<Player> rootLiteral;
private final CommandArgumentSpec<Player, Player> targetArg;
private final CommandArgumentSpec<Player, String> msgArg;
private final RootLiteral<ScrowVelocityCC> rootLiteral;
private final Argument<ScrowVelocityCC, Player> targetArg;
private final Argument<ScrowVelocityCC, String> msgArg;
private final LastTargetCache cache;
private final PrivMsgHandler privMsgHandler;
public MsgCommand(ProxyServer server, LastTargetCache cache, PrivMsgHandler helper, MessageStyle style) {
public MsgCommand(ProxyServer server, LastTargetCache cache, PrivMsgHandler helper, ScrowMessageStyle style) {
this.cache = cache;
this.privMsgHandler = helper;
targetArg = CommandArgumentSpec.builder("target", new PlayerArgumentType<Player>(server)).build();
msgArg = CommandArgumentSpec.builder("msg", new StringArgumentType<Player>(true)).build();
targetArg = Argument.builder("target", new PlayerArgumentType<ScrowVelocityCC>(server)).build();
msgArg = Argument.builder("msg", new StringArgumentType<ScrowVelocityCC>(true)).build();
rootLiteral = Literal.<Player>builder("msg", "w", "privmsg")
rootLiteral = Literal.<ScrowVelocityCC>builder("msg", "w", "privmsg")
.withArgument(targetArg)
.withArgument(msgArg)
.withSyncExecutor(this::executeSync)
.asRootLiteral(style);
}
private Result<Object, String> executeSync(CommandContext<Player> ctx) {
var target = ctx.getArg(targetArg);
private void executeSync(ScrowVelocityCC ctx) {
var target = ctx.getarg(targetArg);
var msg = ctx.getArg(msgArg);
var isMessagingSelf = target.getUniqueId().equals(ctx.sender().getUniqueId());
if (isMessagingSelf) return Results.failure("You can't message yourself.");
cache.setLastTarget(ctx.sender().getUniqueId(), target.getUniqueId());
privMsgHandler.handle(ctx.sender(), target, msg);
return Results.success(new Object());
var isMessagingSelf = target.getUniqueId().equals(ctx.player().getUniqueId());
if (isMessagingSelf) {
ctx.player().sendMessage(ctx.style().err("You can't message yourself."));
return;
}
public RootLiteral<Player> rootLiteral() {
cache.setLastTarget(ctx.player().getUniqueId(), target.getUniqueId());
privMsgHandler.handle(ctx.player(), target, msg);
}
public RootLiteral<ScrowVelocityCC> rootLiteral() {
return rootLiteral;
}
}

View file

@ -1,53 +1,51 @@
package de.kentoj.scrow.corevelocity.privmsg;
import com.leakyabstractions.result.api.Result;
import com.leakyabstractions.result.core.Results;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
import de.kentoj.kencommandapi.api.argument.types.StringArgumentType;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.api.literal.Literal;
import de.kentoj.kencommandapi.api.literal.RootLiteral;
import de.kentoj.kencommandapi.api.platform.MessageStyle;
import de.kentoj.kencommandapi.type.PlayerArgumentType;
import de.kentoj.scrow.velocity.commands.ScrowVelocityCC;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import site.lab0x13.scrow.commands.model.argument.Argument;
import site.lab0x13.scrow.commands.model.argument.types.StringArgumentType;
import site.lab0x13.scrow.commands.model.literal.Literal;
import site.lab0x13.scrow.commands.model.literal.RootLiteral;
public class ReplyCommand {
private final RootLiteral<Player> rootLiteral;
private final CommandArgumentSpec<Player, String> msgArg;
private final RootLiteral<ScrowVelocityCC> rootLiteral;
private final Argument<ScrowVelocityCC, String> msgArg;
private final LastTargetCache cache;
private final ProxyServer server;
private final PrivMsgHandler privMsgHandler;
public ReplyCommand(ProxyServer server, LastTargetCache cache, PrivMsgHandler privMsgHandler, MessageStyle style) {
public ReplyCommand(ProxyServer server, LastTargetCache cache, PrivMsgHandler privMsgHandler, ScrowMessageStyle style) {
this.cache = cache;
this.server = server;
this.privMsgHandler = privMsgHandler;
msgArg = CommandArgumentSpec.builder("msg", new StringArgumentType<Player>(true)).build();
rootLiteral = Literal.<Player>builder("reply", "r")
msgArg = Argument.builder("msg", new StringArgumentType<ScrowVelocityCC>(true)).build();
rootLiteral = Literal.<ScrowVelocityCC>builder("reply", "r")
.withArgument(msgArg)
.withSyncExecutor(this::executeSync)
.asRootLiteral(style);
}
private Result<Object, String> executeSync(CommandContext<Player> ctx) {
var targetId = cache.getLastTarget(ctx.sender().getUniqueId());
if (targetId == null)
return Results.failure("You didn't messaged anyone recently. Use /msg first");
private void executeSync(ScrowVelocityCC ctx) {
var targetId = cache.getLastTarget(ctx.player().getUniqueId());
if (targetId == null) {
ctx.player().sendMessage(ctx.style().err("You didn't messaged anyone recently. Use /msg first"));
return;
}
var target = server.getPlayer(targetId).orElse(null);
var msg = ctx.getArg(msgArg);
if (target == null)
return Results.failure("The player you last messaged is no longer online.");
if (target == null) {
ctx.player().sendMessage(ctx.style().err("The player you last messaged is no longer online."));
return;
}
privMsgHandler.handle(ctx.sender(), target, msg);
return Results.success(new Object());
}
public RootLiteral<Player> rootLiteral() {
public RootLiteral<ScrowVelocityCC> rootLiteral() {
return rootLiteral;
}
}

View file

@ -1,50 +1,105 @@
package de.kentoj.scrow.corevelocity.serverregistration;
import com.google.common.hash.Hashing;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Closeable;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.stream.Stream;
import java.util.List;
import java.util.stream.StreamSupport;
public class ConsulV1ServerInstanceScanner implements ServerInstanceScanner, Closeable {
public class ConsulV1ServerInstanceScanner implements Closeable {
private static final Logger log = LoggerFactory.getLogger("server registration");
private final ProxyServer server;
private final String consulUrl;
private final HttpClient client;
public ConsulV1ServerInstanceScanner(String consulUrl) {
// see https://developer.hashicorp.com/consul/api-docs/features/blocking
private long lastIndex = -1;
public ConsulV1ServerInstanceScanner(ProxyServer server, String consulUrl) {
this.server = server;
this.consulUrl = consulUrl;
this.client = HttpClient.newHttpClient();
}
@Override
// FIXME query cluster-wide
public Stream<ServerInfo> queryMinecraftServers() throws IOException, InterruptedException {
var url = consulUrl + "/v1/agent/services/?filter=" + URLEncoder.encode("\"minecraft\" in Tags", StandardCharsets.UTF_8);
public void start() {
while (!Thread.currentThread().isInterrupted()) {
try {
log.info("Querying servers...");
var knownServers = server.getAllServers().stream()
.map(RegisteredServer::getServerInfo)
.toList();
var currentServers = queryMinecraftServers();
registerNewServers(knownServers, currentServers);
unregisterDeadServers(knownServers, currentServers);
} catch (IOException e) {
throw new RuntimeException("failed querying Minecraft servers", e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
private void unregisterDeadServers(List<ServerInfo> knownServers, List<ServerInfo> currentServers) {
var currentServerIds = currentServers.stream().map(ServerInfo::getName).toList();
knownServers.stream()
.filter(s -> !currentServerIds.contains(s.getName()))
.forEach(s -> {
server.unregisterServer(s);
log.info("Unregistered server {}", s.getName());
});
}
private void registerNewServers(List<ServerInfo> knownServers, List<ServerInfo> currentServers) {
var knownServerIds = knownServers.stream()
.map(ServerInfo::getName)
.toList();
currentServers.forEach(s -> {
if (knownServerIds.contains(s.getName()))
return;
server.registerServer(s);
log.info("registered server {}", s.getName());
});
}
private List<ServerInfo> queryMinecraftServers() throws IOException, InterruptedException {
var url = consulUrl + "/v1/health/service/minecraft?passing=true";
if (lastIndex >= 0)
url += "&index=" + lastIndex;
var request = HttpRequest.newBuilder(URI.create(url))
.GET()
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
var jsonResponse = JsonParser.parseString(response.body()).getAsJsonObject();
return jsonResponse.entrySet().stream()
.map(Map.Entry::getValue)
.map(JsonElement::getAsJsonObject)
var jsonResponse = JsonParser.parseString(response.body()).getAsJsonArray();
lastIndex = response.headers().firstValueAsLong("X-Consul-Index").orElseThrow();
return StreamSupport.stream(jsonResponse.spliterator(), false)
.map(j -> j.getAsJsonObject().get("Service").getAsJsonObject())
.map(service -> {
var name = toServerName(service.get("Service").getAsString(), service.get("ID").getAsString());
var host = InetSocketAddress.createUnresolved(service.get("Address").getAsString(),
service.get("Port").getAsInt());
return new ServerInfo(name, host);
});
var gamemodeName = service.get("Meta").getAsJsonObject().get("mode").getAsString();
var address = InetSocketAddress.createUnresolved(
service.get("Address").getAsString(), service.get("Port").getAsInt());
var id = toServerName(gamemodeName, service.get("ID").getAsString());
return new ServerInfo(id, address);
})
.toList();
}
private String toServerName(String serviceName, String id) {
@ -54,7 +109,7 @@ public class ConsulV1ServerInstanceScanner implements ServerInstanceScanner, Clo
}
@Override
public void close() throws IOException {
public void close() {
client.close();
}
}

View file

@ -0,0 +1,22 @@
package de.kentoj.scrow.corevelocity.serverregistration;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.player.PlayerChooseInitialServerEvent;
import com.velocitypowered.api.proxy.ProxyServer;
public class PlayerTryJoinLobbyListener {
private final ProxyServer server;
public PlayerTryJoinLobbyListener(ProxyServer server) {
this.server = server;
}
@Subscribe
private void onChooseInitialServer(PlayerChooseInitialServerEvent ev) {
var lobby = server.getAllServers().stream()
.filter(n -> n.getServerInfo().getName().startsWith("lobby-"))
.findAny();
lobby.ifPresent(ev::setInitialServer);
}
}

View file

@ -1,29 +0,0 @@
package de.kentoj.scrow.corevelocity.serverregistration;
import com.velocitypowered.api.proxy.ProxyServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
public class RegistrationTask implements Runnable {
private static final Logger log = LoggerFactory.getLogger(RegistrationTask.class);
private final ProxyServer server;
private final ServerInstanceScanner watcher;
public RegistrationTask(ProxyServer server, ServerInstanceScanner watcher) {
this.server = server;
this.watcher = watcher;
}
@Override
public void run() {
try {
watcher.queryMinecraftServers().forEach(server::registerServer);
} catch (IOException | InterruptedException e) {
throw new RuntimeException("Failed querying available servers", e);
}
}
}

View file

@ -1,11 +0,0 @@
package de.kentoj.scrow.corevelocity.serverregistration;
import com.velocitypowered.api.proxy.server.ServerInfo;
import java.io.IOException;
import java.util.stream.Stream;
public interface ServerInstanceScanner {
Stream<ServerInfo> queryMinecraftServers() throws IOException, InterruptedException;
}

View file

@ -8,10 +8,7 @@
"com.google.j2objc:j2objc-annotations": 2003271689,
"com.leakyabstractions:result": 1655671314,
"com.leakyabstractions:result-api": -741055074,
"com.velocitypowered:velocity-api": 598211634,
"de.kentoj.scrow:kencommandapi-bukkit": -2022880473,
"de.kentoj.scrow:kencommandapi-core": 112982056,
"de.kentoj.scrow:kencommandapi-velocity": 10985446,
"com.velocitypowered:velocity-api": -596354110,
"io.nats:jnats": 1953137185,
"io.papermc.paper:paper-api": -1677464331,
"net.kyori:adventure-api": 1030187247,
@ -24,87 +21,90 @@
"org.postgresql:postgresql": 524160786,
"org.slf4j:slf4j-api": -2005163028,
"org.slf4j:slf4j-simple": 1999565066,
"repositories": 1054740373
"repositories": 1947988996,
"site.lab0x13.scrow:commands-bukkit": -62834474,
"site.lab0x13.scrow:commands-common": -2092194647,
"site.lab0x13.scrow:commands-velocity": 576878071
},
"__RESOLVED_ARTIFACTS_HASH": {
"aopalliance:aopalliance": 1403132272,
"com.github.ben-manes.caffeine:caffeine": 436159489,
"com.google.code.findbugs:jsr305": 870839855,
"com.google.code.gson:gson": -641501239,
"com.google.errorprone:error_prone_annotations": 577932745,
"com.google.guava:failureaccess": 1715931538,
"com.google.guava:guava": -24633313,
"com.google.guava:listenablefuture": 1079558157,
"com.google.inject:guice": 894286452,
"com.google.j2objc:j2objc-annotations": -1008747351,
"com.leakyabstractions:result": -226801672,
"com.leakyabstractions:result-api": -651535813,
"com.moandjiezana.toml:toml4j": 2067114335,
"aopalliance:aopalliance": 1434507571,
"com.github.ben-manes.caffeine:caffeine": 1421648842,
"com.google.code.findbugs:jsr305": 1862677076,
"com.google.code.gson:gson": 1379142432,
"com.google.errorprone:error_prone_annotations": 1910407674,
"com.google.guava:failureaccess": 1052373329,
"com.google.guava:guava": 809448928,
"com.google.guava:listenablefuture": -777871306,
"com.google.inject:guice": -239057743,
"com.google.j2objc:j2objc-annotations": 1851322138,
"com.leakyabstractions:result": -1858809852,
"com.leakyabstractions:result-api": -382801976,
"com.moandjiezana.toml:toml4j": 508480266,
"com.mojang:brigadier": 913620533,
"com.velocitypowered:velocity-api": 965888822,
"com.velocitypowered:velocity-api": -1579746067,
"com.velocitypowered:velocity-brigadier": -1261075963,
"commons-codec:commons-codec": -1411194476,
"de.kentoj.scrow:kencommandapi-bukkit": -1110763167,
"de.kentoj.scrow:kencommandapi-core": 772231973,
"de.kentoj.scrow:kencommandapi-velocity": 39000638,
"io.leangen.geantyref:geantyref": 669182600,
"io.nats:jnats": 549130756,
"io.papermc.paper:paper-api": -97577052,
"it.unimi.dsi:fastutil": 1739877374,
"jakarta.inject:jakarta.inject-api": 188991469,
"javax.inject:javax.inject": 698155243,
"net.kyori:adventure-api": 1766228173,
"commons-codec:commons-codec": 577559951,
"io.leangen.geantyref:geantyref": 277437211,
"io.nats:jnats": 76423921,
"io.papermc.paper:paper-api": -202770527,
"it.unimi.dsi:fastutil": 1795699813,
"jakarta.inject:jakarta.inject-api": -689154986,
"javax.inject:javax.inject": 132675352,
"net.kyori:adventure-api": 951482800,
"net.kyori:adventure-bom": 1472851752,
"net.kyori:adventure-key": -1110227447,
"net.kyori:adventure-text-logger-slf4j": -1327104502,
"net.kyori:adventure-text-minimessage": 397844782,
"net.kyori:adventure-text-serializer-ansi": -1565160095,
"net.kyori:adventure-text-serializer-commons": -1221427884,
"net.kyori:adventure-text-serializer-gson": 115363333,
"net.kyori:adventure-text-serializer-json": 799049496,
"net.kyori:adventure-text-serializer-legacy": -1920918334,
"net.kyori:adventure-text-serializer-plain": -791487701,
"net.kyori:ansi": 997964596,
"net.kyori:option": -134523688,
"net.luckperms:api": 476490203,
"net.md-5:bungeecord-chat": 2047504207,
"org.apache.commons:commons-lang3": -1070155819,
"org.apache.httpcomponents:httpclient": -1780430011,
"org.apache.httpcomponents:httpcore": 67453319,
"org.apache.logging.log4j:log4j-api": -79106511,
"org.apache.maven.resolver:maven-resolver-api": -274344430,
"org.apache.maven.resolver:maven-resolver-connector-basic": -1819010895,
"org.apache.maven.resolver:maven-resolver-impl": 988241953,
"org.apache.maven.resolver:maven-resolver-named-locks": -663305356,
"org.apache.maven.resolver:maven-resolver-spi": 2054051643,
"org.apache.maven.resolver:maven-resolver-transport-http": -1829861066,
"org.apache.maven.resolver:maven-resolver-util": 1240367164,
"org.apache.maven:maven-artifact": -1775316664,
"org.apache.maven:maven-builder-support": -2045756754,
"org.apache.maven:maven-model": -1477170202,
"org.apache.maven:maven-model-builder": -312842796,
"org.apache.maven:maven-repository-metadata": -1092475520,
"org.apache.maven:maven-resolver-provider": -241093259,
"org.bouncycastle:bcprov-lts8on": -8124988,
"org.checkerframework:checker-qual": -1521111878,
"org.codehaus.plexus:plexus-interpolation": -455118382,
"org.codehaus.plexus:plexus-utils": 37123609,
"org.eclipse.sisu:org.eclipse.sisu.inject": 1305442139,
"org.jdbi:jdbi3-core": -576523574,
"org.jdbi:jdbi3-postgres": 419487850,
"org.jetbrains:annotations": -1687668980,
"org.joml:joml": -564433831,
"org.jspecify:jspecify": 117231129,
"org.mongodb:bson": 1783866955,
"org.postgresql:postgresql": -1607497519,
"org.slf4j:jcl-over-slf4j": 498129285,
"org.slf4j:slf4j-api": 500377983,
"org.slf4j:slf4j-simple": -1055624668,
"org.spongepowered:configurate-core": -1474651178,
"org.spongepowered:configurate-gson": 284154998,
"org.spongepowered:configurate-hocon": 1862397725,
"org.spongepowered:configurate-yaml": -859469457,
"org.yaml:snakeyaml": 1308413731
"net.kyori:adventure-key": 1723611760,
"net.kyori:adventure-text-logger-slf4j": 1685198185,
"net.kyori:adventure-text-minimessage": -1417678707,
"net.kyori:adventure-text-serializer-ansi": -632322135,
"net.kyori:adventure-text-serializer-commons": 1111905531,
"net.kyori:adventure-text-serializer-gson": -496856431,
"net.kyori:adventure-text-serializer-json": -2093423733,
"net.kyori:adventure-text-serializer-legacy": -1926708191,
"net.kyori:adventure-text-serializer-plain": 921342090,
"net.kyori:ansi": 967735279,
"net.kyori:option": 1219025611,
"net.luckperms:api": -446182360,
"net.md-5:bungeecord-chat": -1895309617,
"org.apache.commons:commons-lang3": -1165348498,
"org.apache.httpcomponents:httpclient": 2047177206,
"org.apache.httpcomponents:httpcore": -1947336196,
"org.apache.logging.log4j:log4j-api": 802684562,
"org.apache.maven.resolver:maven-resolver-api": 1715320017,
"org.apache.maven.resolver:maven-resolver-connector-basic": 100049798,
"org.apache.maven.resolver:maven-resolver-impl": 421281398,
"org.apache.maven.resolver:maven-resolver-named-locks": -1957834767,
"org.apache.maven.resolver:maven-resolver-spi": -1888553111,
"org.apache.maven.resolver:maven-resolver-transport-http": -115815877,
"org.apache.maven.resolver:maven-resolver-util": -776482680,
"org.apache.maven:maven-artifact": 1332968914,
"org.apache.maven:maven-builder-support": -162686027,
"org.apache.maven:maven-model": -1118138882,
"org.apache.maven:maven-model-builder": -918833418,
"org.apache.maven:maven-repository-metadata": 506128932,
"org.apache.maven:maven-resolver-provider": -1075865842,
"org.bouncycastle:bcprov-lts8on": -1005412513,
"org.checkerframework:checker-qual": -684653783,
"org.codehaus.plexus:plexus-interpolation": 729223441,
"org.codehaus.plexus:plexus-utils": 1392395178,
"org.eclipse.sisu:org.eclipse.sisu.inject": -872173912,
"org.jdbi:jdbi3-core": -488012747,
"org.jdbi:jdbi3-postgres": -850946846,
"org.jetbrains:annotations": 915498150,
"org.joml:joml": 387749226,
"org.jspecify:jspecify": -659362902,
"org.mongodb:bson": 1197817272,
"org.postgresql:postgresql": -790235150,
"org.slf4j:jcl-over-slf4j": 33502784,
"org.slf4j:slf4j-api": -1239545596,
"org.slf4j:slf4j-simple": 1518912321,
"org.spongepowered:configurate-core": 784735666,
"org.spongepowered:configurate-gson": -58090930,
"org.spongepowered:configurate-hocon": -1372729557,
"org.spongepowered:configurate-yaml": -1304688999,
"org.yaml:snakeyaml": -1320689696,
"site.lab0x13.scrow:commands-bukkit": 1630649671,
"site.lab0x13.scrow:commands-common": 716919454,
"site.lab0x13.scrow:commands-velocity": -238206298
},
"artifacts": {
"aopalliance:aopalliance": {
@ -193,9 +193,9 @@
},
"com.velocitypowered:velocity-api": {
"shasums": {
"jar": "f5835a4a6191f909005b695ccc07b915e8dadeff4ab69c82a7cac1c9e4c8e6ce"
"jar": "faf296a44b39573002590a2c7172c6adea2eb0f65760b452f78a75c9eb308d37"
},
"version": "4.1.0-20260803.131214-10"
"version": "4.0.0"
},
"com.velocitypowered:velocity-brigadier": {
"shasums": {
@ -209,24 +209,6 @@
},
"version": "1.16.0"
},
"de.kentoj.scrow:kencommandapi-bukkit": {
"shasums": {
"jar": null
},
"version": "0.42-SNAPSHOT"
},
"de.kentoj.scrow:kencommandapi-core": {
"shasums": {
"jar": null
},
"version": "0.42-SNAPSHOT"
},
"de.kentoj.scrow:kencommandapi-velocity": {
"shasums": {
"jar": null
},
"version": "0.42-SNAPSHOT"
},
"io.leangen.geantyref:geantyref": {
"shasums": {
"jar": "386b535c079be7d65ddbe0ad9c00955155b7862225aa92b4c6553ab2b1ea95f9"
@ -241,9 +223,9 @@
},
"io.papermc.paper:paper-api": {
"shasums": {
"jar": "b35f0f979731d960a6f9db1c0925eeb9f4511b1b1d8c60c2609dca8cfd2d1163"
"jar": "167237534a28a64b22f2bca1af0809e1b0ee689e9d4b8653bdd17c4a4c7c4b17"
},
"version": "26.2.build.111-stable"
"version": "26.2-rc-2.build.9-alpha"
},
"it.unimi.dsi:fastutil": {
"shasums": {
@ -499,9 +481,9 @@
},
"org.jetbrains:annotations": {
"shasums": {
"jar": "ebc7aec252ed0c7d2d04c039d7f00e69f7b86b1f493c741d67b3ef31b986b054"
"jar": "2037be378980d3ba9333e97955f3b2cde392aa124d04ca73ce2eee6657199297"
},
"version": "26.1.0"
"version": "26.0.2-1"
},
"org.joml:joml": {
"shasums": {
@ -574,6 +556,24 @@
"jar": "e6682acf1ace77508ef13649cbf4f8d09d2cf5457bdb61d25ffb6ac0233d78dd"
},
"version": "2.5"
},
"site.lab0x13.scrow:commands-bukkit": {
"shasums": {
"jar": "88d8f281f3e00a94111268bce29d0e3df62376d2cbd72563ea2312874a2ac087"
},
"version": "1.2.0"
},
"site.lab0x13.scrow:commands-common": {
"shasums": {
"jar": "19c1c025e77ed9c9e44a20540041caab7c402568af94c7f8aec768586d4b41b3"
},
"version": "1.2.0"
},
"site.lab0x13.scrow:commands-velocity": {
"shasums": {
"jar": "02a0a1eff84f1757f5c42f58fda6851c807d95801af8623ffab9e5e482392489"
},
"version": "1.2.0"
}
},
"conflict_resolution": {
@ -581,14 +581,13 @@
"com.google.guava:guava:31.0.1-jre": "com.google.guava:guava:33.6.0-jre",
"com.google.j2objc:j2objc-annotations:2.8": "com.google.j2objc:j2objc-annotations:3.1",
"io.leangen.geantyref:geantyref:1.3.16": "io.leangen.geantyref:geantyref:2.0.1",
"io.papermc.paper:paper-api:[26.2.build,)": "io.papermc.paper:paper-api:26.2.build.111-stable",
"net.kyori:adventure-key": "net.kyori:adventure-key:5.2.0",
"io.papermc.paper:paper-api:[26.2.build,)": "io.papermc.paper:paper-api:26.2-rc-2.build.9-alpha",
"net.kyori:adventure-bom:4.26.1": "net.kyori:adventure-bom:5.2.0",
"net.kyori:adventure-text-logger-slf4j": "net.kyori:adventure-text-logger-slf4j:5.2.0",
"net.kyori:adventure-text-serializer-ansi": "net.kyori:adventure-text-serializer-ansi:5.2.0",
"net.kyori:adventure-text-serializer-gson": "net.kyori:adventure-text-serializer-gson:5.2.0",
"net.kyori:adventure-text-serializer-legacy": "net.kyori:adventure-text-serializer-legacy:5.2.0",
"net.kyori:adventure-text-serializer-plain": "net.kyori:adventure-text-serializer-plain:5.2.0",
"org.jetbrains:annotations:26.0.2-1": "org.jetbrains:annotations:26.1.0",
"org.yaml:snakeyaml:2.2": "org.yaml:snakeyaml:2.5"
},
"dependencies": {
@ -639,24 +638,6 @@
"org.spongepowered:configurate-yaml",
"org.yaml:snakeyaml"
],
"de.kentoj.scrow:kencommandapi-bukkit": [
"de.kentoj.scrow:kencommandapi-core",
"io.papermc.paper:paper-api",
"org.jetbrains:annotations"
],
"de.kentoj.scrow:kencommandapi-core": [
"com.google.guava:guava",
"com.leakyabstractions:result",
"com.leakyabstractions:result-api",
"net.kyori:adventure-api",
"org.jetbrains:annotations",
"org.slf4j:slf4j-api"
],
"de.kentoj.scrow:kencommandapi-velocity": [
"com.velocitypowered:velocity-api",
"de.kentoj.scrow:kencommandapi-core",
"org.jetbrains:annotations"
],
"io.nats:jnats": [
"org.bouncycastle:bcprov-lts8on",
"org.jspecify:jspecify"
@ -668,7 +649,6 @@
"it.unimi.dsi:fastutil",
"net.kyori:adventure-api",
"net.kyori:adventure-bom",
"net.kyori:adventure-key",
"net.kyori:adventure-text-logger-slf4j",
"net.kyori:adventure-text-minimessage",
"net.kyori:adventure-text-serializer-gson",
@ -823,6 +803,31 @@
],
"org.spongepowered:configurate-yaml": [
"org.spongepowered:configurate-core"
],
"site.lab0x13.scrow:commands-bukkit": [
"com.google.guava:guava",
"com.leakyabstractions:result",
"com.leakyabstractions:result-api",
"io.papermc.paper:paper-api",
"net.kyori:adventure-api",
"org.jetbrains:annotations",
"site.lab0x13.scrow:commands-common"
],
"site.lab0x13.scrow:commands-common": [
"com.google.guava:guava",
"com.leakyabstractions:result",
"com.leakyabstractions:result-api",
"net.kyori:adventure-api",
"org.jetbrains:annotations"
],
"site.lab0x13.scrow:commands-velocity": [
"com.google.guava:guava",
"com.leakyabstractions:result",
"com.leakyabstractions:result-api",
"com.velocitypowered:velocity-api",
"net.kyori:adventure-api",
"org.jetbrains:annotations",
"site.lab0x13.scrow:commands-common"
]
},
"packages": {
@ -955,26 +960,6 @@
"org.apache.commons.codec.language.bm",
"org.apache.commons.codec.net"
],
"de.kentoj.scrow:kencommandapi-bukkit": [
"de.kentoj.kencommandapi",
"de.kentoj.kencommandapi.suggestionprovider",
"de.kentoj.kencommandapi.type"
],
"de.kentoj.scrow:kencommandapi-core": [
"de.kentoj.kencommandapi.api",
"de.kentoj.kencommandapi.api.argument",
"de.kentoj.kencommandapi.api.argument.types",
"de.kentoj.kencommandapi.api.invocation",
"de.kentoj.kencommandapi.api.literal",
"de.kentoj.kencommandapi.api.platform",
"de.kentoj.kencommandapi.api.suggestion",
"de.kentoj.kencommandapi.internal"
],
"de.kentoj.scrow:kencommandapi-velocity": [
"de.kentoj.kencommandapi",
"de.kentoj.kencommandapi.suggestionprovider",
"de.kentoj.kencommandapi.type"
],
"io.leangen.geantyref:geantyref": [
"io.leangen.geantyref"
],
@ -1908,10 +1893,28 @@
"org.yaml.snakeyaml.serializer",
"org.yaml.snakeyaml.tokens",
"org.yaml.snakeyaml.util"
],
"site.lab0x13.scrow:commands-bukkit": [
"site.lab0x13.scrow.commands.bukkit",
"site.lab0x13.scrow.commands.bukkit.suggestionprovider",
"site.lab0x13.scrow.commands.bukkit.type"
],
"site.lab0x13.scrow:commands-common": [
"site.lab0x13.scrow.commands",
"site.lab0x13.scrow.commands.model",
"site.lab0x13.scrow.commands.model.argument",
"site.lab0x13.scrow.commands.model.argument.types",
"site.lab0x13.scrow.commands.model.literal",
"site.lab0x13.scrow.commands.parser"
],
"site.lab0x13.scrow:commands-velocity": [
"site.lab0x13.scrow.commands.velocity",
"site.lab0x13.scrow.commands.velocity.suggestionprovider",
"site.lab0x13.scrow.commands.velocity.type"
]
},
"repositories": {
"https://repo1.maven.org/maven2/": [
"https://repo.maven.apache.org/maven2/": [
"aopalliance:aopalliance",
"com.github.ben-manes.caffeine:caffeine",
"com.google.code.findbugs:jsr305",
@ -1983,9 +1986,9 @@
"org.yaml:snakeyaml"
],
"https://git.lab0x13.site/api/packages/scrow/maven/": [
"de.kentoj.scrow:kencommandapi-bukkit",
"de.kentoj.scrow:kencommandapi-core",
"de.kentoj.scrow:kencommandapi-velocity"
"site.lab0x13.scrow:commands-bukkit",
"site.lab0x13.scrow:commands-common",
"site.lab0x13.scrow:commands-velocity"
],
"https://repo.papermc.io/repository/maven-public/": [
"aopalliance:aopalliance",

View file

@ -23,7 +23,7 @@ fetch_file(
fetch_file(
name = "luckperms",
filename = "LuckPerms.jar",
url = "https://download.luckperms.net/1652/bukkit/loader/LuckPerms-Bukkit-5.5.65.jar",
url = "https://download.luckperms.net/1668/bukkit/loader/LuckPerms-Bukkit-5.5.81.jar",
)
fetch_file(
name = "viaversion",