hytale-commands
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseHytale Custom Commands
Hytale 自定义命令
Complete guide for creating custom server commands with arguments, permissions, tab completion, and execution handling.
这是一份创建包含参数、权限、自动补全和执行处理的自定义服务器命令的完整指南。
When to use this skill
何时使用本技能
Use this skill when:
- Creating new slash commands for players or admins
- Adding command arguments (required, optional, flags)
- Setting up command permissions
- Creating command collections/groups
- Implementing async commands for long-running operations
- Adding tab completion for arguments
在以下场景使用本技能:
- 为玩家或管理员创建新的斜杠命令
- 添加命令参数(必填、可选、标记)
- 设置命令权限
- 创建命令集合/组
- 为长时间运行的操作实现异步命令
- 为参数添加自动补全功能
Command Architecture Overview
命令架构概述
Hytale uses a command system based on abstract command classes with typed arguments. Commands are registered through the plugin's and managed by the singleton.
CommandRegistryCommandManagerHytale 使用基于抽象命令类的命令系统,支持类型化参数。命令通过插件的 注册,并由 单例管理。
CommandRegistryCommandManagerCommand Class Hierarchy
命令类层级结构
AbstractCommand
├── CommandBase # Base for simple commands
├── AbstractAsyncCommand # For async execution
├── AbstractPlayerCommand # Requires player sender
├── AbstractWorldCommand # Requires world context
├── AbstractTargetPlayerCommand # Target another player
└── AbstractCommandCollection # Group of subcommandsAbstractCommand
├── CommandBase # 简单命令的基类
├── AbstractAsyncCommand # 用于异步执行
├── AbstractPlayerCommand # 要求发送者为玩家
├── AbstractWorldCommand # 要求世界上下文
├── AbstractTargetPlayerCommand # 以其他玩家为目标
└── AbstractCommandCollection # 子命令组Command Flow
命令执行流程
Player Input -> CommandManager -> Parse Arguments -> Check Permissions -> Execute玩家输入 -> CommandManager -> 解析参数 -> 检查权限 -> 执行命令Basic Command Implementation
基础命令实现
Simple Command
简单命令
java
package com.example.myplugin.commands;
import com.hypixel.hytale.server.core.command.CommandBase;
import com.hypixel.hytale.server.core.command.CommandContext;
public class HelloCommand extends CommandBase {
public HelloCommand() {
super("hello", "Says hello to the world");
}
@Override
protected void execute(CommandContext ctx) {
ctx.sendSuccess("Hello, World!");
}
}java
package com.example.myplugin.commands;
import com.hypixel.hytale.server.core.command.CommandBase;
import com.hypixel.hytale.server.core.command.CommandContext;
public class HelloCommand extends CommandBase {
public HelloCommand() {
super("hello", "Says hello to the world");
}
@Override
protected void execute(CommandContext ctx) {
ctx.sendSuccess("Hello, World!");
}
}Registration in Plugin
在插件中注册命令
java
@Override
protected void setup() {
getCommandRegistry().registerCommand(new HelloCommand());
getCommandRegistry().registerCommand(new SpawnCommand());
getCommandRegistry().registerCommand(new TeleportCommand());
}java
@Override
protected void setup() {
getCommandRegistry().registerCommand(new HelloCommand());
getCommandRegistry().registerCommand(new SpawnCommand());
getCommandRegistry().registerCommand(new TeleportCommand());
}Command Arguments
命令参数
Argument Types
参数类型
| ArgType | Description | Example Value |
|---|---|---|
| Text string | |
| Whole number | |
| Decimal number | |
| True/false | |
| Online player | |
| World name | |
| Item identifier | |
| Block identifier | |
| Entity type | |
| Block position | |
| Precise position | |
| Direction vector | |
| Time duration | |
| JSON object | |
| Rest of input | |
| 参数类型 | 描述 | 示例值 |
|---|---|---|
| 文本字符串 | |
| 整数 | |
| 小数 | |
| 布尔值 | |
| 在线玩家 | |
| 世界名称 | |
| 物品标识符 | |
| 方块标识符 | |
| 实体类型 | |
| 方块位置 | |
| 精确位置 | |
| 方向向量 | |
| 时长 | |
| JSON对象 | |
| 剩余全部输入 | |
Argument Kinds
参数种类
java
// Required argument - must be provided
RequiredArg<String> nameArg = new RequiredArg<>("name", ArgType.STRING);
// Optional argument - can be omitted
OptionalArg<Integer> countArg = new OptionalArg<>("count", ArgType.INTEGER);
// Default argument - uses default if omitted
DefaultArg<Integer> amountArg = new DefaultArg<>("amount", ArgType.INTEGER, 1);
// Flag argument - boolean switch
FlagArg silentFlag = new FlagArg("silent", "s");java
// 必填参数 - 必须提供
RequiredArg<String> nameArg = new RequiredArg<>("name", ArgType.STRING);
// 可选参数 - 可省略
OptionalArg<Integer> countArg = new OptionalArg<>("count", ArgType.INTEGER);
// 默认参数 - 省略时使用默认值
DefaultArg<Integer> amountArg = new DefaultArg<>("amount", ArgType.INTEGER, 1);
// 标记参数 - 布尔开关
FlagArg silentFlag = new FlagArg("silent", "s");Command with Arguments
带参数的命令
java
public class GiveCommand extends CommandBase {
private static final RequiredArg<PlayerRef> TARGET =
new RequiredArg<>("target", ArgType.PLAYER_REF);
private static final RequiredArg<ItemId> ITEM =
new RequiredArg<>("item", ArgType.ITEM_ID);
private static final DefaultArg<Integer> AMOUNT =
new DefaultArg<>("amount", ArgType.INTEGER, 1);
private static final FlagArg SILENT =
new FlagArg("silent", "s");
public GiveCommand() {
super("give", "Give items to a player");
addArg(TARGET);
addArg(ITEM);
addArg(AMOUNT);
addArg(SILENT);
}
@Override
protected void execute(CommandContext ctx) {
Player target = ctx.get(TARGET).resolve();
ItemId item = ctx.get(ITEM);
int amount = ctx.get(AMOUNT);
boolean silent = ctx.has(SILENT);
// Give the item
target.getInventory().addItem(item, amount);
if (!silent) {
ctx.sendSuccess("Gave " + amount + "x " + item + " to " + target.getName());
}
}
}java
public class GiveCommand extends CommandBase {
private static final RequiredArg<PlayerRef> TARGET =
new RequiredArg<>("target", ArgType.PLAYER_REF);
private static final RequiredArg<ItemId> ITEM =
new RequiredArg<>("item", ArgType.ITEM_ID);
private static final DefaultArg<Integer> AMOUNT =
new DefaultArg<>("amount", ArgType.INTEGER, 1);
private static final FlagArg SILENT =
new FlagArg("silent", "s");
public GiveCommand() {
super("give", "Give items to a player");
addArg(TARGET);
addArg(ITEM);
addArg(AMOUNT);
addArg(SILENT);
}
@Override
protected void execute(CommandContext ctx) {
Player target = ctx.get(TARGET).resolve();
ItemId item = ctx.get(ITEM);
int amount = ctx.get(AMOUNT);
boolean silent = ctx.has(SILENT);
// 给予物品
target.getInventory().addItem(item, amount);
if (!silent) {
ctx.sendSuccess("Gave " + amount + "x " + item + " to " + target.getName());
}
}
}Specialized Command Classes
专用命令类
Player-Only Command
仅玩家可用命令
Automatically checks that sender is a player. The method receives 5 parameters:
executejava
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.command.system.CommandContext;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractPlayerCommand;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import javax.annotation.Nonnull;
public class FlyCommand extends AbstractPlayerCommand {
public FlyCommand() {
super("fly", "Toggle flight mode");
}
@Override
protected void execute(
@Nonnull CommandContext context,
@Nonnull Store<EntityStore> store,
@Nonnull Ref<EntityStore> ref,
@Nonnull PlayerRef playerRef,
@Nonnull World world
) {
// Access player data through PlayerRef
String username = playerRef.getUsername();
// Execute on world thread for world modifications
world.execute(() -> {
context.sendSuccess("Flight toggled for " + username);
});
}
}自动检查发送者是否为玩家。 方法接收5个参数:
executejava
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.command.system.CommandContext;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractPlayerCommand;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import javax.annotation.Nonnull;
public class FlyCommand extends AbstractPlayerCommand {
public FlyCommand() {
super("fly", "Toggle flight mode");
}
@Override
protected void execute(
@Nonnull CommandContext context,
@Nonnull Store<EntityStore> store,
@Nonnull Ref<EntityStore> ref,
@Nonnull PlayerRef playerRef,
@Nonnull World world
) {
// 通过PlayerRef访问玩家数据
String username = playerRef.getUsername();
// 在世界线程执行以修改世界
world.execute(() -> {
context.sendSuccess("Flight toggled for " + username);
});
}
}World Context Command
世界上下文命令
Requires a world context:
java
public class TimeCommand extends AbstractWorldCommand {
private static final RequiredArg<Integer> TIME =
new RequiredArg<>("time", ArgType.INTEGER);
public TimeCommand() {
super("time", "Set world time");
addArg(TIME);
}
@Override
protected void execute(CommandContext ctx, World world) {
int time = ctx.get(TIME);
world.setTime(time);
ctx.sendSuccess("Set time to " + time + " in " + world.getName());
}
}需要世界上下文:
java
public class TimeCommand extends AbstractWorldCommand {
private static final RequiredArg<Integer> TIME =
new RequiredArg<>("time", ArgType.INTEGER);
public TimeCommand() {
super("time", "Set world time");
addArg(TIME);
}
@Override
protected void execute(CommandContext ctx, World world) {
int time = ctx.get(TIME);
world.setTime(time);
ctx.sendSuccess("Set time to " + time + " in " + world.getName());
}
}Target Player Command
目标玩家命令
For commands that target another player:
java
public class HealCommand extends AbstractTargetPlayerCommand {
public HealCommand() {
super("heal", "Heal a player to full health");
}
@Override
protected void execute(CommandContext ctx, Player target) {
target.setHealth(target.getMaxHealth());
ctx.sendSuccess("Healed " + target.getName());
}
}用于以其他玩家为目标的命令:
java
public class HealCommand extends AbstractTargetPlayerCommand {
public HealCommand() {
super("heal", "Heal a player to full health");
}
@Override
protected void execute(CommandContext ctx, Player target) {
target.setHealth(target.getMaxHealth());
ctx.sendSuccess("Healed " + target.getName());
}
}Async Command
异步命令
For long-running operations:
java
public class BackupCommand extends AbstractAsyncCommand {
public BackupCommand() {
super("backup", "Create world backup");
}
@Override
protected CompletableFuture<Void> executeAsync(CommandContext ctx) {
return CompletableFuture.runAsync(() -> {
ctx.sendMessage("Starting backup...");
// Perform backup operation
performBackup();
ctx.sendSuccess("Backup complete!");
});
}
}用于长时间运行的操作:
java
public class BackupCommand extends AbstractAsyncCommand {
public BackupCommand() {
super("backup", "Create world backup");
}
@Override
protected CompletableFuture<Void> executeAsync(CommandContext ctx) {
return CompletableFuture.runAsync(() -> {
ctx.sendMessage("Starting backup...");
// 执行备份操作
performBackup();
ctx.sendSuccess("Backup complete!");
});
}
}Command Collections (Subcommands)
命令集合(子命令)
Group related commands together:
java
public class AdminCommands extends AbstractCommandCollection {
public AdminCommands() {
super("admin", "Admin commands");
// Register subcommands
addSubCommand(new BanSubCommand());
addSubCommand(new KickSubCommand());
addSubCommand(new MuteSubCommand());
}
// Subcommand implementation
private class BanSubCommand extends CommandBase {
private static final RequiredArg<PlayerRef> TARGET =
new RequiredArg<>("target", ArgType.PLAYER_REF);
private static final OptionalArg<String> REASON =
new OptionalArg<>("reason", ArgType.GREEDY_STRING);
public BanSubCommand() {
super("ban", "Ban a player");
addArg(TARGET);
addArg(REASON);
}
@Override
protected void execute(CommandContext ctx) {
Player target = ctx.get(TARGET).resolve();
String reason = ctx.getOrDefault(REASON, "No reason provided");
// Ban logic
ctx.sendSuccess("Banned " + target.getName() + ": " + reason);
}
}
}Usage:
/admin ban PlayerName Being naughty将相关命令分组:
java
public class AdminCommands extends AbstractCommandCollection {
public AdminCommands() {
super("admin", "Admin commands");
// 注册子命令
addSubCommand(new BanSubCommand());
addSubCommand(new KickSubCommand());
addSubCommand(new MuteSubCommand());
}
// 子命令实现
private class BanSubCommand extends CommandBase {
private static final RequiredArg<PlayerRef> TARGET =
new RequiredArg<>("target", ArgType.PLAYER_REF);
private static final OptionalArg<String> REASON =
new OptionalArg<>("reason", ArgType.GREEDY_STRING);
public BanSubCommand() {
super("ban", "Ban a player");
addArg(TARGET);
addArg(REASON);
}
@Override
protected void execute(CommandContext ctx) {
Player target = ctx.get(TARGET).resolve();
String reason = ctx.getOrDefault(REASON, "No reason provided");
// 封禁逻辑
ctx.sendSuccess("Banned " + target.getName() + ": " + reason);
}
}
}使用方式:
/admin ban PlayerName Being naughtyPermissions
权限
Auto-Generated Permissions
自动生成的权限
Commands automatically get permissions based on plugin identity:
{plugin.group}.{plugin.name}.command.{commandName}Example:
com.example.myplugin.command.give命令会根据插件标识自动生成权限:
{plugin.group}.{plugin.name}.command.{commandName}示例:
com.example.myplugin.command.giveCustom Permissions
自定义权限
java
public class SecretCommand extends CommandBase {
public SecretCommand() {
super("secret", "A secret command");
// Override default permission
setPermission("admin.secret.access");
}
@Override
protected void execute(CommandContext ctx) {
ctx.sendSuccess("You found the secret!");
}
}java
public class SecretCommand extends CommandBase {
public SecretCommand() {
super("secret", "A secret command");
// 覆盖默认权限
setPermission("admin.secret.access");
}
@Override
protected void execute(CommandContext ctx) {
ctx.sendSuccess("You found the secret!");
}
}Permission Checks in Execution
执行时的权限检查
java
@Override
protected void execute(CommandContext ctx) {
if (!ctx.hasPermission("special.feature")) {
ctx.sendError("You don't have permission for this feature!");
return;
}
// Execute feature
}java
@Override
protected void execute(CommandContext ctx) {
if (!ctx.hasPermission("special.feature")) {
ctx.sendError("You don't have permission for this feature!");
return;
}
// 执行功能
}Command Context
命令上下文
The provides access to sender info and utilities:
CommandContextjava
@Override
protected void execute(CommandContext ctx) {
// Get sender info
CommandSender sender = ctx.getSender();
boolean isPlayer = ctx.isPlayer();
boolean isConsole = ctx.isConsole();
// Get player if sender is player
Optional<Player> player = ctx.getPlayerSender();
// Get world context
Optional<World> world = ctx.getWorld();
// Send messages
ctx.sendMessage("Plain message");
ctx.sendSuccess("Success message"); // Green
ctx.sendError("Error message"); // Red
ctx.sendWarning("Warning message"); // Yellow
// Get argument values
String name = ctx.get(NAME_ARG);
int count = ctx.getOrDefault(COUNT_ARG, 10);
boolean hasFlag = ctx.has(SOME_FLAG);
// Check permissions
boolean canUse = ctx.hasPermission("some.permission");
}CommandContextjava
@Override
protected void execute(CommandContext ctx) {
// 获取发送者信息
CommandSender sender = ctx.getSender();
boolean isPlayer = ctx.isPlayer();
boolean isConsole = ctx.isConsole();
// 如果发送者是玩家,获取玩家对象
Optional<Player> player = ctx.getPlayerSender();
// 获取世界上下文
Optional<World> world = ctx.getWorld();
// 发送消息
ctx.sendMessage("Plain message");
ctx.sendSuccess("Success message"); // 绿色
ctx.sendError("Error message"); // 红色
ctx.sendWarning("Warning message"); // 黄色
// 获取参数值
String name = ctx.get(NAME_ARG);
int count = ctx.getOrDefault(COUNT_ARG, 10);
boolean hasFlag = ctx.has(SOME_FLAG);
// 检查权限
boolean canUse = ctx.hasPermission("some.permission");
}Tab Completion
自动补全
Arguments provide automatic tab completion. Custom completion:
java
public class CustomArg extends RequiredArg<String> {
public CustomArg() {
super("mode", ArgType.STRING);
}
@Override
public List<String> getSuggestions(CommandContext ctx, String partial) {
return List.of("easy", "medium", "hard")
.stream()
.filter(s -> s.startsWith(partial.toLowerCase()))
.toList();
}
}参数会自动提供补全功能。自定义补全:
java
public class CustomArg extends RequiredArg<String> {
public CustomArg() {
super("mode", ArgType.STRING);
}
@Override
public List<String> getSuggestions(CommandContext ctx, String partial) {
return List.of("easy", "medium", "hard")
.stream()
.filter(s -> s.startsWith(partial.toLowerCase()))
.toList();
}
}Complete Example Plugin
完整插件示例
java
package com.example.admintools;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
import javax.annotation.Nonnull;
public class AdminToolsPlugin extends JavaPlugin {
public AdminToolsPlugin(@Nonnull JavaPluginInit init) {
super(init);
}
@Override
protected void setup() {
// Register individual commands
getCommandRegistry().registerCommand(new HealCommand());
getCommandRegistry().registerCommand(new FlyCommand());
getCommandRegistry().registerCommand(new TeleportCommand());
// Register command collection
getCommandRegistry().registerCommand(new AdminCommands());
getLogger().atInfo().log("AdminTools commands registered!");
}
}java
package com.example.admintools;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
import javax.annotation.Nonnull;
public class AdminToolsPlugin extends JavaPlugin {
public AdminToolsPlugin(@Nonnull JavaPluginInit init) {
super(init);
}
@Override
protected void setup() {
// 注册单个命令
getCommandRegistry().registerCommand(new HealCommand());
getCommandRegistry().registerCommand(new FlyCommand());
getCommandRegistry().registerCommand(new TeleportCommand());
// 注册命令集合
getCommandRegistry().registerCommand(new AdminCommands());
getLogger().atInfo().log("AdminTools commands registered!");
}
}Best Practices
最佳实践
Argument Validation
参数验证
java
@Override
protected void execute(CommandContext ctx) {
int amount = ctx.get(AMOUNT);
// Validate ranges
if (amount < 1 || amount > 64) {
ctx.sendError("Amount must be between 1 and 64");
return;
}
// Continue execution
}java
@Override
protected void execute(CommandContext ctx) {
int amount = ctx.get(AMOUNT);
// 验证范围
if (amount < 1 || amount > 64) {
ctx.sendError("Amount must be between 1 and 64");
return;
}
// 继续执行
}Error Handling
错误处理
java
@Override
protected void execute(CommandContext ctx) {
try {
Player target = ctx.get(TARGET).resolve();
if (target == null) {
ctx.sendError("Player not found!");
return;
}
// Execute command
} catch (Exception e) {
ctx.sendError("An error occurred: " + e.getMessage());
getLogger().atSevere().withCause(e).log("Command error");
}
}java
@Override
protected void execute(CommandContext ctx) {
try {
Player target = ctx.get(TARGET).resolve();
if (target == null) {
ctx.sendError("Player not found!");
return;
}
// 执行命令
} catch (Exception e) {
ctx.sendError("An error occurred: " + e.getMessage());
getLogger().atSevere().withCause(e).log("Command error");
}
}Feedback Messages
反馈消息
java
@Override
protected void execute(CommandContext ctx) {
// Always provide feedback
ctx.sendMessage("Processing...");
// Do work
// Report result
if (success) {
ctx.sendSuccess("Operation completed!");
} else {
ctx.sendError("Operation failed: " + reason);
}
}java
@Override
protected void execute(CommandContext ctx) {
// 始终提供反馈
ctx.sendMessage("Processing...");
// 执行操作
// 报告结果
if (success) {
ctx.sendSuccess("Operation completed!");
} else {
ctx.sendError("Operation failed: " + reason);
}
}Troubleshooting
故障排除
Command Not Found
命令未找到
- Verify command is registered in
setup() - Check command name doesn't conflict with existing commands
- Ensure plugin is loading correctly
- 验证命令是否在 中注册
setup() - 检查命令名称是否与现有命令冲突
- 确保插件正确加载
Permission Denied
权限不足
- Check player has the auto-generated permission
- Verify custom permission is granted
- Check permission node spelling
- 检查玩家是否拥有自动生成的权限
- 验证自定义权限是否已授予
- 检查权限节点拼写
Arguments Not Parsing
参数解析失败
- Verify argument order matches usage
- Check ArgType matches expected input
- Ensure required arguments are provided
- 验证参数顺序是否与使用方式匹配
- 检查参数类型是否与预期输入一致
- 确保提供了所有必填参数
Tab Completion Not Working
自动补全不生效
- Verify argument has suggestions defined
- Check completion returns non-empty list
- Ensure partial matching is implemented
- 验证参数是否定义了补全建议
- 检查补全方法是否返回非空列表
- 确保实现了部分匹配逻辑
Detailed References
详细参考
For comprehensive documentation:
- - Complete argument type reference with all ArgTypes, parsing, validation
references/argument-types.md - - Advanced patterns: cooldowns, confirmations, pagination, wizards
references/command-patterns.md
如需完整文档:
- - 完整的参数类型参考,包含所有ArgType、解析和验证规则
references/argument-types.md - - 高级模式:冷却机制、确认流程、分页、向导式命令
references/command-patterns.md