Autism-Client/src/main/java/autismclient/commands/AutismCommands.java

223 lines
10 KiB
Java
Raw Normal View History

2026-06-15 06:11:26 +02:00
package autismclient.commands;
import autismclient.AutismClientAddon;
import autismclient.api.AddonRegistrationResult;
import autismclient.modules.PackHideState;
import autismclient.util.AutismClientMessaging;
import autismclient.util.AutismCompatManager;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Locale;
import java.util.Set;
public final class AutismCommands {
private static final CommandDispatcher<AutismCommandSource> DISPATCHER = new CommandDispatcher<>();
private static final List<Command> ALL = new ArrayList<>();
private static final Map<String, Command> BY_NAME = new LinkedHashMap<>();
private static final Map<String, String> ADDON_COMMAND_OWNERS = new LinkedHashMap<>();
private static final Map<Command, String> ADDON_COMMAND_OBJECT_OWNERS = new IdentityHashMap<>();
private static final Set<String> DISABLED_ADDON_COMMAND_NAMES = new HashSet<>();
private static boolean initialized = false;
private AutismCommands() {}
public static synchronized void init() {
if (initialized) return;
initialized = true;
register(new autismclient.commands.impl.ToggleCommand());
register(new autismclient.commands.impl.MacroCommand());
register(new autismclient.commands.impl.DelayCommand());
register(new autismclient.commands.impl.SendCommand());
register(new autismclient.commands.impl.VClipCommand());
register(new autismclient.commands.impl.HClipCommand());
register(new autismclient.commands.impl.NbtCommand());
register(new autismclient.commands.impl.ServerCommand());
register(new autismclient.commands.impl.PluginsCommand());
register(new autismclient.commands.impl.PrefixCommand());
register(new autismclient.commands.impl.CommandsCommand());
register(new autismclient.commands.impl.HelpCommand());
register(new autismclient.commands.impl.ModulesCommand());
register(new autismclient.commands.impl.BindsCommand());
register(new autismclient.commands.impl.BindCommand());
register(new autismclient.commands.impl.DismountCommand());
register(new autismclient.commands.impl.DisconnectCommand());
register(new autismclient.commands.impl.SayCommand());
register(new autismclient.commands.impl.DropCommand());
register(new autismclient.commands.impl.GamemodeCommand());
register(new autismclient.commands.impl.GiveCommand());
register(new autismclient.commands.impl.DamageCommand());
register(new autismclient.commands.impl.XCarryCommand());
}
private static void register(Command command) {
registerWithName(command, command.name(), true);
}
private static List<String> registerWithName(Command command, String primaryName, boolean registerAliases) {
List<String> registeredNames = new ArrayList<>();
ALL.add(command);
LiteralArgumentBuilder<AutismCommandSource> primary = LiteralArgumentBuilder.literal(primaryName);
command.build(primary);
DISPATCHER.register(primary);
BY_NAME.put(primaryName.toLowerCase(Locale.ROOT), command);
DISABLED_ADDON_COMMAND_NAMES.remove(primaryName.toLowerCase(Locale.ROOT));
registeredNames.add(primaryName.toLowerCase(Locale.ROOT));
if (!registerAliases) return registeredNames;
for (String alias : command.aliases()) {
if (alias == null || alias.isBlank()) continue;
if (BY_NAME.containsKey(alias.toLowerCase(Locale.ROOT))) continue;
LiteralArgumentBuilder<AutismCommandSource> aliasBuilder = LiteralArgumentBuilder.literal(alias);
command.build(aliasBuilder);
DISPATCHER.register(aliasBuilder);
BY_NAME.put(alias.toLowerCase(Locale.ROOT), command);
DISABLED_ADDON_COMMAND_NAMES.remove(alias.toLowerCase(Locale.ROOT));
registeredNames.add(alias.toLowerCase(Locale.ROOT));
}
return registeredNames;
}
public static synchronized void registerAddonCommand(Command command, String addonId) {
registerAddonCommandDetailed(command, addonId);
}
public static synchronized AddonRegistrationResult registerAddonCommandDetailed(Command command, String addonId) {
if (command == null) return AddonRegistrationResult.rejected("command", "", "command was null");
if (addonId == null || addonId.isBlank()) {
return rejectAddonCommand(addonId, "", "registration outside an addon lifecycle");
}
String name = command.name();
if (name == null || name.isBlank()) {
return rejectAddonCommand(addonId, "", "blank command name");
}
List<String> registered;
boolean collision = BY_NAME.containsKey(name.toLowerCase(Locale.ROOT));
if (collision) {
String namespaced = (addonId == null || addonId.isBlank() ? "addon" : addonId) + ":" + name;
AutismClientAddon.LOG.warn("[Commands] Command name '{}' from addon '{}' collides with an existing "
+ "command; registering it as '{}' instead", name, addonId, namespaced);
registered = registerWithName(command, namespaced, false);
} else {
registered = registerWithName(command, name, true);
}
ADDON_COMMAND_OBJECT_OWNERS.put(command, addonId);
for (String registeredName : registered) {
ADDON_COMMAND_OWNERS.put(registeredName, addonId);
}
String id = registered.isEmpty() ? name : registered.get(0);
autismclient.addons.AddonManager.recordAcceptedRegistration("command", id);
return AddonRegistrationResult.accepted("command", id);
}
private static AddonRegistrationResult rejectAddonCommand(String addonId, String id, String reason) {
AutismClientAddon.LOG.warn("[Commands] Rejecting addon command '{}': {}", id, reason);
autismclient.addons.AddonManager.recordRejectedRegistration(addonId, "command", id, reason);
return AddonRegistrationResult.rejected("command", id, reason);
}
public static synchronized void unregisterAddonCommands(String addonId) {
if (addonId == null || addonId.isBlank()) return;
List<String> removeNames = new ArrayList<>();
for (Map.Entry<String, String> owner : ADDON_COMMAND_OWNERS.entrySet()) {
if (addonId.equals(owner.getValue())) removeNames.add(owner.getKey());
}
for (String name : removeNames) {
BY_NAME.remove(name);
ADDON_COMMAND_OWNERS.remove(name);
DISABLED_ADDON_COMMAND_NAMES.add(name);
}
ALL.removeIf(command -> addonId.equals(ADDON_COMMAND_OBJECT_OWNERS.get(command)));
ADDON_COMMAND_OBJECT_OWNERS.entrySet().removeIf(entry -> addonId.equals(entry.getValue()));
}
public static CommandDispatcher<AutismCommandSource> dispatcher() { return DISPATCHER; }
public static List<Command> all() { return Collections.unmodifiableList(ALL); }
public static Command find(String nameOrAlias) {
if (nameOrAlias == null) return null;
return BY_NAME.get(nameOrAlias.trim().toLowerCase(Locale.ROOT));
}
public static String effectivePrefix() { return AutismCompatManager.effectiveCommandPrefix(); }
public static boolean isAutismCommandMessage(String message) {
if (commandsBlockedByPanic()) return false;
if (message == null || message.isBlank()) return false;
String trimmed = message.trim();
String prefix = effectivePrefix();
return !prefix.isEmpty() && trimmed.startsWith(prefix);
}
public static boolean commandsBlockedByPanic() {
return PackHideState.isActive();
}
public static boolean isBlockedPanicCommandMessage(String message) {
return commandsBlockedByPanic() && isAutismCommandMessage(message);
}
public static String commandBody(String message) {
if (!isAutismCommandMessage(message)) return "";
String trimmed = message.trim();
int prefixLength = effectivePrefix().length();
return trimmed.length() <= prefixLength ? "" : trimmed.substring(prefixLength).trim();
}
public static boolean dispatch(String body) {
if (commandsBlockedByPanic()) return true;
if (body == null) return false;
String trimmed = body.trim();
if (trimmed.isEmpty()) return false;
if (DISABLED_ADDON_COMMAND_NAMES.contains(firstToken(trimmed).toLowerCase(Locale.ROOT))) {
sendSyntaxError(trimmed, CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownCommand().create());
return true;
}
try {
DISPATCHER.execute(trimmed, AutismCommandSource.INSTANCE);
return true;
} catch (CommandSyntaxException e) {
sendSyntaxError(trimmed, e);
return true;
} catch (Exception e) {
AutismClientAddon.LOG.warn("[Commands] dispatch failed for '{}'", trimmed, e);
AutismClientMessaging.sendPrefixed("§cCommand error: "
+ (e.getMessage() == null ? e.getClass().getSimpleName() : e.getMessage()));
return true;
}
}
private static void sendSyntaxError(String body, CommandSyntaxException e) {
String first = firstToken(body);
Command command = find(first);
String prefix = effectivePrefix();
if (command == null) {
AutismClientMessaging.sendPrefixed("§cUnknown AUTISM command: §f" + first);
AutismClientMessaging.sendPrefixed("§7Use §f" + prefix + "commands §7or §f" + prefix + "help§7.");
return;
}
String message = e.getMessage();
if (message == null || message.isBlank()) message = "Incomplete or invalid command.";
AutismClientMessaging.sendPrefixed("§c" + message);
AutismClientMessaging.sendPrefixed("§7Use §f" + prefix + "help " + command.name() + "§7.");
}
private static String firstToken(String body) {
if (body == null) return "";
String trimmed = body.trim();
if (trimmed.isEmpty()) return "";
int space = trimmed.indexOf(' ');
return space < 0 ? trimmed : trimmed.substring(0, space);
}
}