forked from public-mirrors/HuskSync
refactor: use Uniform for native command support (#323)
* refactor: use Uniform for commands * refactor: remove commodore * fix: update Uniform, fix commands * fix: bump uniform, fix commands on fabric * feat: use new Uniform command permission system * test: target 1.21feat/data-edit-commands
parent
69d68de5c0
commit
0e706d36c4
@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of HuskSync, licensed under the Apache License 2.0.
|
|
||||||
*
|
|
||||||
* Copyright (c) William278 <will27528@gmail.com>
|
|
||||||
* Copyright (c) contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.william278.husksync.command;
|
|
||||||
|
|
||||||
import me.lucko.commodore.CommodoreProvider;
|
|
||||||
import me.lucko.commodore.file.CommodoreFileReader;
|
|
||||||
import net.william278.husksync.BukkitHuskSync;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
public class BrigadierUtil {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Uses commodore to register command completions.
|
|
||||||
*
|
|
||||||
* @param plugin instance of the registering Bukkit plugin
|
|
||||||
* @param bukkitCommand the Bukkit PluginCommand to register completions for
|
|
||||||
* @param command the {@link Command} to register completions for
|
|
||||||
*/
|
|
||||||
protected static void registerCommodore(@NotNull BukkitHuskSync plugin,
|
|
||||||
@NotNull org.bukkit.command.Command bukkitCommand,
|
|
||||||
@NotNull Command command) {
|
|
||||||
final InputStream commodoreFile = plugin.getResource(
|
|
||||||
"commodore/" + bukkitCommand.getName() + ".commodore"
|
|
||||||
);
|
|
||||||
if (commodoreFile == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
CommodoreProvider.getCommodore(plugin).register(bukkitCommand,
|
|
||||||
CommodoreFileReader.INSTANCE.parse(commodoreFile),
|
|
||||||
player -> player.hasPermission(command.getPermission()));
|
|
||||||
} catch (IOException e) {
|
|
||||||
plugin.log(Level.SEVERE, String.format(
|
|
||||||
"Failed to read command commodore completions for %s", bukkitCommand.getName()), e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,164 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of HuskSync, licensed under the Apache License 2.0.
|
|
||||||
*
|
|
||||||
* Copyright (c) William278 <will27528@gmail.com>
|
|
||||||
* Copyright (c) contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.william278.husksync.command;
|
|
||||||
|
|
||||||
|
|
||||||
import me.lucko.commodore.CommodoreProvider;
|
|
||||||
import net.william278.husksync.BukkitHuskSync;
|
|
||||||
import net.william278.husksync.user.BukkitUser;
|
|
||||||
import net.william278.husksync.user.CommandUser;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.permissions.Permission;
|
|
||||||
import org.bukkit.permissions.PermissionDefault;
|
|
||||||
import org.bukkit.plugin.PluginManager;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
public class BukkitCommand extends org.bukkit.command.Command {
|
|
||||||
|
|
||||||
private final BukkitHuskSync plugin;
|
|
||||||
private final Command command;
|
|
||||||
|
|
||||||
public BukkitCommand(@NotNull Command command, @NotNull BukkitHuskSync plugin) {
|
|
||||||
super(command.getName(), command.getDescription(), command.getUsage(), command.getAliases());
|
|
||||||
this.command = command;
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
|
|
||||||
this.command.onExecuted(sender instanceof Player p ? BukkitUser.adapt(p, plugin) : plugin.getConsole(), args);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias,
|
|
||||||
@NotNull String[] args) throws IllegalArgumentException {
|
|
||||||
if (!(this.command instanceof TabProvider provider)) {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
final CommandUser user = sender instanceof Player p ? BukkitUser.adapt(p, plugin) : plugin.getConsole();
|
|
||||||
if (getPermission() == null || user.hasPermission(getPermission())) {
|
|
||||||
return provider.getSuggestions(user, args);
|
|
||||||
}
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void register() {
|
|
||||||
// Register with bukkit
|
|
||||||
plugin.getCommandRegistrar().getServerCommandMap().register("husksync", this);
|
|
||||||
|
|
||||||
// Register permissions
|
|
||||||
BukkitCommand.addPermission(
|
|
||||||
plugin,
|
|
||||||
command.getPermission(),
|
|
||||||
command.getUsage(),
|
|
||||||
BukkitCommand.getPermissionDefault(command.isOperatorCommand())
|
|
||||||
);
|
|
||||||
final List<Permission> childNodes = command.getAdditionalPermissions()
|
|
||||||
.entrySet().stream()
|
|
||||||
.map((entry) -> BukkitCommand.addPermission(
|
|
||||||
plugin,
|
|
||||||
entry.getKey(),
|
|
||||||
"",
|
|
||||||
BukkitCommand.getPermissionDefault(entry.getValue()))
|
|
||||||
)
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.toList();
|
|
||||||
if (!childNodes.isEmpty()) {
|
|
||||||
BukkitCommand.addPermission(
|
|
||||||
plugin,
|
|
||||||
command.getPermission("*"),
|
|
||||||
command.getUsage(),
|
|
||||||
PermissionDefault.FALSE,
|
|
||||||
childNodes.toArray(new Permission[0])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register commodore TAB completion
|
|
||||||
if (CommodoreProvider.isSupported() && plugin.getSettings().isBrigadierTabCompletion()) {
|
|
||||||
BrigadierUtil.registerCommodore(plugin, this, command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
protected static Permission addPermission(@NotNull BukkitHuskSync plugin, @NotNull String node,
|
|
||||||
@NotNull String description, @NotNull PermissionDefault permissionDefault,
|
|
||||||
@NotNull Permission... children) {
|
|
||||||
final Map<String, Boolean> childNodes = Arrays.stream(children)
|
|
||||||
.map(Permission::getName)
|
|
||||||
.collect(HashMap::new, (map, child) -> map.put(child, true), HashMap::putAll);
|
|
||||||
|
|
||||||
final PluginManager manager = plugin.getServer().getPluginManager();
|
|
||||||
if (manager.getPermission(node) != null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Permission permission;
|
|
||||||
if (description.isEmpty()) {
|
|
||||||
permission = new Permission(node, permissionDefault, childNodes);
|
|
||||||
} else {
|
|
||||||
permission = new Permission(node, description, permissionDefault, childNodes);
|
|
||||||
}
|
|
||||||
manager.addPermission(permission);
|
|
||||||
|
|
||||||
return permission;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
protected static PermissionDefault getPermissionDefault(boolean isOperatorCommand) {
|
|
||||||
return isOperatorCommand ? PermissionDefault.OP : PermissionDefault.TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Commands available on the Bukkit HuskSync implementation
|
|
||||||
*/
|
|
||||||
public enum Type {
|
|
||||||
|
|
||||||
HUSKSYNC_COMMAND(HuskSyncCommand::new),
|
|
||||||
USERDATA_COMMAND(UserDataCommand::new),
|
|
||||||
INVENTORY_COMMAND(InventoryCommand::new),
|
|
||||||
ENDER_CHEST_COMMAND(EnderChestCommand::new);
|
|
||||||
|
|
||||||
public final Function<BukkitHuskSync, Command> commandSupplier;
|
|
||||||
|
|
||||||
Type(@NotNull Function<BukkitHuskSync, Command> supplier) {
|
|
||||||
this.commandSupplier = supplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public Command createCommand(@NotNull BukkitHuskSync plugin) {
|
|
||||||
return commandSupplier.apply(plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void registerCommands(@NotNull BukkitHuskSync plugin) {
|
|
||||||
Arrays.stream(values())
|
|
||||||
.map((type) -> type.createCommand(plugin))
|
|
||||||
.forEach((command) -> new BukkitCommand(command, plugin).register());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
inventory {
|
|
||||||
name brigadier:string single_word;
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
husksync {
|
|
||||||
update;
|
|
||||||
about;
|
|
||||||
status;
|
|
||||||
reload;
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
enderchest {
|
|
||||||
name brigadier:string single_word;
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
userdata {
|
|
||||||
view {
|
|
||||||
name brigadier:string single_word {
|
|
||||||
version brigadier:string single_word;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list {
|
|
||||||
name brigadier:string single_word {
|
|
||||||
page brigadier:integer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete {
|
|
||||||
name brigadier:string single_word {
|
|
||||||
version brigadier:string single_word;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
restore {
|
|
||||||
name brigadier:string single_word {
|
|
||||||
version brigadier:string single_word;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pin {
|
|
||||||
name brigadier:string single_word {
|
|
||||||
version brigadier:string single_word;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dump {
|
|
||||||
name brigadier:string single_word {
|
|
||||||
version brigadier:string single_word {
|
|
||||||
web;
|
|
||||||
file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of HuskSync, licensed under the Apache License 2.0.
|
|
||||||
*
|
|
||||||
* Copyright (c) William278 <will27528@gmail.com>
|
|
||||||
* Copyright (c) contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.william278.husksync.command;
|
|
||||||
|
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
import net.william278.husksync.HuskSync;
|
|
||||||
import net.william278.husksync.user.CommandUser;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public abstract class Command extends Node {
|
|
||||||
|
|
||||||
private final String usage;
|
|
||||||
private final Map<String, Boolean> additionalPermissions;
|
|
||||||
|
|
||||||
protected Command(@NotNull String name, @NotNull List<String> aliases, @NotNull String usage,
|
|
||||||
@NotNull HuskSync plugin) {
|
|
||||||
super(name, aliases, plugin);
|
|
||||||
this.usage = usage;
|
|
||||||
this.additionalPermissions = Maps.newHashMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void onExecuted(@NotNull CommandUser executor, @NotNull String[] args) {
|
|
||||||
if (!executor.hasPermission(getPermission())) {
|
|
||||||
plugin.getLocales().getLocale("error_no_permission")
|
|
||||||
.ifPresent(executor::sendMessage);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
plugin.runAsync(() -> this.execute(executor, args));
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void execute(@NotNull CommandUser executor, @NotNull String[] args);
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
protected String[] removeFirstArg(@NotNull String[] args) {
|
|
||||||
if (args.length <= 1) {
|
|
||||||
return new String[0];
|
|
||||||
}
|
|
||||||
String[] newArgs = new String[args.length - 1];
|
|
||||||
System.arraycopy(args, 1, newArgs, 0, args.length - 1);
|
|
||||||
return newArgs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public final String getRawUsage() {
|
|
||||||
return usage;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public final String getUsage() {
|
|
||||||
return "/" + getName() + " " + getRawUsage();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void addAdditionalPermissions(@NotNull Map<String, Boolean> permissions) {
|
|
||||||
permissions.forEach((permission, value) -> this.additionalPermissions.put(getPermission(permission), value));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public final Map<String, Boolean> getAdditionalPermissions() {
|
|
||||||
return additionalPermissions;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public String getDescription() {
|
|
||||||
return plugin.getLocales().getRawLocale(getName() + "_command_description")
|
|
||||||
.orElse(getUsage());
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public final HuskSync getPlugin() {
|
|
||||||
return plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of HuskSync, licensed under the Apache License 2.0.
|
|
||||||
*
|
|
||||||
* Copyright (c) William278 <will27528@gmail.com>
|
|
||||||
* Copyright (c) contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.william278.husksync.command;
|
|
||||||
|
|
||||||
import net.william278.husksync.user.CommandUser;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
public interface Executable {
|
|
||||||
|
|
||||||
void onExecuted(@NotNull CommandUser executor, @NotNull String[] args);
|
|
||||||
|
|
||||||
}
|
|
@ -1,105 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of HuskSync, licensed under the Apache License 2.0.
|
|
||||||
*
|
|
||||||
* Copyright (c) William278 <will27528@gmail.com>
|
|
||||||
* Copyright (c) contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.william278.husksync.command;
|
|
||||||
|
|
||||||
import net.william278.husksync.HuskSync;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.StringJoiner;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public abstract class Node implements Executable {
|
|
||||||
|
|
||||||
protected static final String PERMISSION_PREFIX = "husksync.command";
|
|
||||||
|
|
||||||
protected final HuskSync plugin;
|
|
||||||
private final String name;
|
|
||||||
private final List<String> aliases;
|
|
||||||
private boolean operatorCommand = false;
|
|
||||||
|
|
||||||
protected Node(@NotNull String name, @NotNull List<String> aliases, @NotNull HuskSync plugin) {
|
|
||||||
if (name.isBlank()) {
|
|
||||||
throw new IllegalArgumentException("Command name cannot be blank");
|
|
||||||
}
|
|
||||||
this.name = name;
|
|
||||||
this.aliases = aliases;
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public List<String> getAliases() {
|
|
||||||
return aliases;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public String getPermission(@NotNull String... child) {
|
|
||||||
final StringJoiner joiner = new StringJoiner(".")
|
|
||||||
.add(PERMISSION_PREFIX)
|
|
||||||
.add(getName());
|
|
||||||
for (final String node : child) {
|
|
||||||
joiner.add(node);
|
|
||||||
}
|
|
||||||
return joiner.toString().trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOperatorCommand() {
|
|
||||||
return operatorCommand;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOperatorCommand(boolean operatorCommand) {
|
|
||||||
this.operatorCommand = operatorCommand;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Optional<String> parseStringArg(@NotNull String[] args, int index) {
|
|
||||||
if (args.length > index) {
|
|
||||||
return Optional.of(args[index]);
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Optional<Integer> parseIntArg(@NotNull String[] args, int index) {
|
|
||||||
return parseStringArg(args, index).flatMap(arg -> {
|
|
||||||
try {
|
|
||||||
return Optional.of(Integer.parseInt(arg));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Optional<UUID> parseUUIDArg(@NotNull String[] args, int index) {
|
|
||||||
return parseStringArg(args, index).flatMap(arg -> {
|
|
||||||
try {
|
|
||||||
return Optional.of(UUID.fromString(arg));
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of HuskSync, licensed under the Apache License 2.0.
|
||||||
|
*
|
||||||
|
* Copyright (c) William278 <will27528@gmail.com>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.william278.husksync.command;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
|
import net.william278.husksync.HuskSync;
|
||||||
|
import net.william278.husksync.user.CommandUser;
|
||||||
|
import net.william278.husksync.user.User;
|
||||||
|
import net.william278.uniform.BaseCommand;
|
||||||
|
import net.william278.uniform.Command;
|
||||||
|
import net.william278.uniform.Permission;
|
||||||
|
import net.william278.uniform.element.ArgumentElement;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public abstract class PluginCommand extends Command {
|
||||||
|
|
||||||
|
protected final HuskSync plugin;
|
||||||
|
|
||||||
|
protected PluginCommand(@NotNull String name, @NotNull List<String> aliases,
|
||||||
|
@NotNull Permission.Default permissionDefault, @NotNull HuskSync plugin) {
|
||||||
|
super(name, aliases, getDescription(plugin, name), new Permission(createPermission(name), permissionDefault));
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getDescription(@NotNull HuskSync plugin, @NotNull String name) {
|
||||||
|
return plugin.getLocales().getRawLocale("%s_command_description".formatted(name)).orElse("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static String createPermission(@NotNull String name, @NotNull String... sub) {
|
||||||
|
return "husksync.command." + name + (sub.length > 0 ? "." + String.join(".", sub) : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
protected String getPermission(@NotNull String... sub) {
|
||||||
|
return createPermission(this.getName(), sub);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
protected CommandUser user(@NotNull BaseCommand base, @NotNull CommandContext context) {
|
||||||
|
return adapt(base.getUser(context.getSource()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
protected Permission needsOp(@NotNull String... nodes) {
|
||||||
|
return new Permission(getPermission(nodes), Permission.Default.IF_OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
protected CommandUser adapt(net.william278.uniform.CommandUser user) {
|
||||||
|
return user.getUuid() == null ? plugin.getConsole() : plugin.getOnlineUser(user.getUuid()).orElseThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
protected <S> ArgumentElement<S, User> user(@NotNull String name) {
|
||||||
|
return new ArgumentElement<>(name, reader -> {
|
||||||
|
final String username = reader.readString();
|
||||||
|
return plugin.getDatabase().getUserByName(username).orElseThrow(
|
||||||
|
() -> CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().createWithContext(reader)
|
||||||
|
);
|
||||||
|
}, (context, builder) -> {
|
||||||
|
plugin.getOnlineUsers().forEach(u -> builder.suggest(u.getUsername()));
|
||||||
|
return builder.buildFuture();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
protected <S> ArgumentElement<S, UUID> uuid(@NotNull String name) {
|
||||||
|
return new ArgumentElement<>(name, reader -> {
|
||||||
|
try {
|
||||||
|
return UUID.fromString(reader.readString());
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().createWithContext(reader);
|
||||||
|
}
|
||||||
|
}, (context, builder) -> builder.buildFuture());
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
|
||||||
|
HUSKSYNC_COMMAND(HuskSyncCommand::new),
|
||||||
|
USERDATA_COMMAND(UserDataCommand::new),
|
||||||
|
INVENTORY_COMMAND(InventoryCommand::new),
|
||||||
|
ENDER_CHEST_COMMAND(EnderChestCommand::new);
|
||||||
|
|
||||||
|
public final Function<HuskSync, PluginCommand> commandSupplier;
|
||||||
|
|
||||||
|
Type(@NotNull Function<HuskSync, PluginCommand> supplier) {
|
||||||
|
this.commandSupplier = supplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public PluginCommand supply(@NotNull HuskSync plugin) {
|
||||||
|
return commandSupplier.apply(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static PluginCommand[] create(@NotNull HuskSync plugin) {
|
||||||
|
return Arrays.stream(values()).map(type -> type.supply(plugin)).toArray(PluginCommand[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of HuskSync, licensed under the Apache License 2.0.
|
|
||||||
*
|
|
||||||
* Copyright (c) William278 <will27528@gmail.com>
|
|
||||||
* Copyright (c) contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.william278.husksync.command;
|
|
||||||
|
|
||||||
import net.william278.husksync.user.CommandUser;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public interface TabProvider {
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
List<String> suggest(@NotNull CommandUser user, @NotNull String[] args);
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
default List<String> getSuggestions(@NotNull CommandUser user, @NotNull String[] args) {
|
|
||||||
List<String> suggestions = suggest(user, args);
|
|
||||||
if (suggestions == null) {
|
|
||||||
suggestions = List.of();
|
|
||||||
}
|
|
||||||
return filter(suggestions, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
default List<String> filter(@NotNull List<String> suggestions, @NotNull String[] args) {
|
|
||||||
return suggestions.stream()
|
|
||||||
.filter(suggestion -> args.length == 0 || suggestion.toLowerCase()
|
|
||||||
.startsWith(args[args.length - 1].toLowerCase().trim()))
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,153 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of HuskSync, licensed under the Apache License 2.0.
|
|
||||||
*
|
|
||||||
* Copyright (c) William278 <will27528@gmail.com>
|
|
||||||
* Copyright (c) contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.william278.husksync.command;
|
|
||||||
|
|
||||||
import com.mojang.brigadier.CommandDispatcher;
|
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
|
||||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
|
||||||
import me.lucko.fabric.api.permissions.v0.PermissionCheckEvent;
|
|
||||||
import me.lucko.fabric.api.permissions.v0.Permissions;
|
|
||||||
import net.fabricmc.fabric.api.util.TriState;
|
|
||||||
import net.minecraft.server.command.ServerCommandSource;
|
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
|
||||||
import net.william278.husksync.FabricHuskSync;
|
|
||||||
import net.william278.husksync.HuskSync;
|
|
||||||
import net.william278.husksync.user.CommandUser;
|
|
||||||
import net.william278.husksync.user.FabricUser;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
|
|
||||||
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
|
|
||||||
import static net.minecraft.server.command.CommandManager.argument;
|
|
||||||
import static net.minecraft.server.command.CommandManager.literal;
|
|
||||||
|
|
||||||
public class FabricCommand {
|
|
||||||
|
|
||||||
private final FabricHuskSync plugin;
|
|
||||||
private final Command command;
|
|
||||||
|
|
||||||
public FabricCommand(@NotNull Command command, @NotNull FabricHuskSync plugin) {
|
|
||||||
this.command = command;
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void register(@NotNull CommandDispatcher<ServerCommandSource> dispatcher) {
|
|
||||||
// Register brigadier command
|
|
||||||
final Predicate<ServerCommandSource> predicate = Permissions
|
|
||||||
.require(command.getPermission(), command.isOperatorCommand() ? 3 : 0);
|
|
||||||
final LiteralArgumentBuilder<ServerCommandSource> builder = literal(command.getName())
|
|
||||||
.requires(predicate).executes(getBrigadierExecutor());
|
|
||||||
plugin.getPermissions().put(command.getPermission(), command.isOperatorCommand());
|
|
||||||
if (!command.getRawUsage().isBlank()) {
|
|
||||||
builder.then(argument(command.getRawUsage().replaceAll("[<>\\[\\]]", ""), greedyString())
|
|
||||||
.executes(getBrigadierExecutor())
|
|
||||||
.suggests(getBrigadierSuggester()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register additional permissions
|
|
||||||
final Map<String, Boolean> permissions = command.getAdditionalPermissions();
|
|
||||||
permissions.forEach((permission, isOp) -> plugin.getPermissions().put(permission, isOp));
|
|
||||||
PermissionCheckEvent.EVENT.register((player, node) -> {
|
|
||||||
if (permissions.containsKey(node) && permissions.get(node) && player.hasPermissionLevel(3)) {
|
|
||||||
return TriState.TRUE;
|
|
||||||
}
|
|
||||||
return TriState.DEFAULT;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Register aliases
|
|
||||||
final LiteralCommandNode<ServerCommandSource> node = dispatcher.register(builder);
|
|
||||||
dispatcher.register(literal("husksync:" + command.getName())
|
|
||||||
.requires(predicate).executes(getBrigadierExecutor()).redirect(node));
|
|
||||||
command.getAliases().forEach(alias -> dispatcher.register(literal(alias)
|
|
||||||
.requires(predicate).executes(getBrigadierExecutor()).redirect(node)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private com.mojang.brigadier.Command<ServerCommandSource> getBrigadierExecutor() {
|
|
||||||
return (context) -> {
|
|
||||||
command.onExecuted(
|
|
||||||
resolveExecutor(context.getSource()),
|
|
||||||
command.removeFirstArg(context.getInput().split(" "))
|
|
||||||
);
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private com.mojang.brigadier.suggestion.SuggestionProvider<ServerCommandSource> getBrigadierSuggester() {
|
|
||||||
if (!(command instanceof TabProvider provider)) {
|
|
||||||
return (context, builder) -> com.mojang.brigadier.suggestion.Suggestions.empty();
|
|
||||||
}
|
|
||||||
return (context, builder) -> {
|
|
||||||
final String[] args = command.removeFirstArg(context.getInput().split(" ", -1));
|
|
||||||
provider.getSuggestions(resolveExecutor(context.getSource()), args).stream()
|
|
||||||
.map(suggestion -> {
|
|
||||||
final String completedArgs = String.join(" ", args);
|
|
||||||
int lastIndex = completedArgs.lastIndexOf(" ");
|
|
||||||
if (lastIndex == -1) {
|
|
||||||
return suggestion;
|
|
||||||
}
|
|
||||||
return completedArgs.substring(0, lastIndex + 1) + suggestion;
|
|
||||||
})
|
|
||||||
.forEach(builder::suggest);
|
|
||||||
return builder.buildFuture();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private CommandUser resolveExecutor(@NotNull ServerCommandSource source) {
|
|
||||||
if (source.getEntity() instanceof ServerPlayerEntity player) {
|
|
||||||
return FabricUser.adapt(player, plugin);
|
|
||||||
}
|
|
||||||
return plugin.getConsole();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Commands available on the Fabric HuskSync implementation.
|
|
||||||
*/
|
|
||||||
public enum Type {
|
|
||||||
|
|
||||||
HUSKSYNC_COMMAND(HuskSyncCommand::new),
|
|
||||||
USERDATA_COMMAND(UserDataCommand::new),
|
|
||||||
INVENTORY_COMMAND(InventoryCommand::new),
|
|
||||||
ENDER_CHEST_COMMAND(EnderChestCommand::new);
|
|
||||||
|
|
||||||
private final Function<HuskSync, Command> supplier;
|
|
||||||
|
|
||||||
Type(@NotNull Function<HuskSync, Command> supplier) {
|
|
||||||
this.supplier = supplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public Command createCommand(@NotNull HuskSync plugin) {
|
|
||||||
return supplier.apply(plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static List<Command> getCommands(@NotNull FabricHuskSync plugin) {
|
|
||||||
return Arrays.stream(values()).map(type -> type.createCommand(plugin)).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue