Loading...
Loading...
Compare original and translation side by side
| Type | Location | Description |
|---|---|---|
| Core Plugins | Registered programmatically | Built-in server functionality |
| Builtin Plugins | | Shipped with server |
| External Plugins | | User-installed plugins |
| Early Plugins | | Bytecode transformers (advanced) |
| 类型 | 位置 | 描述 |
|---|---|---|
| 核心插件 | 以编程方式注册 | 服务器内置功能 |
| 内置插件 | | 随服务器一同发布 |
| 外部插件 | | 用户自行安装的插件 |
| 早期插件 | | 字节码转换器(高级功能) |
NONE -> SETUP -> START -> ENABLED -> SHUTDOWN -> DISABLEDNONE -> SETUP -> START -> ENABLED -> SHUTDOWN -> DISABLEDmy-plugin/
├── src/
│ └── main/
│ ├── java/
│ │ └── com/example/myplugin/
│ │ ├── MyPlugin.java
│ │ ├── commands/
│ │ ├── events/
│ │ ├── components/
│ │ └── systems/
│ └── resources/
│ ├── manifest.json
│ └── assets/ # Optional asset pack
│ └── Server/
│ └── Content/
├── build.gradle
└── settings.gradlemy-plugin/
├── src/
│ └── main/
│ ├── java/
│ │ └── com/example/myplugin/
│ │ ├── MyPlugin.java
│ │ ├── commands/
│ │ ├── events/
│ │ ├── components/
│ │ └── systems/
│ └── resources/
│ ├── manifest.json
│ └── assets/ # 可选资源包
│ └── Server/
│ └── Content/
├── build.gradle
└── settings.gradle{
"Group": "com.example",
"Name": "MyPlugin",
"Version": "1.0.0",
"Description": "My awesome Hytale plugin",
"Authors": [
{
"Name": "Author Name",
"Email": "author@example.com",
"Url": "https://example.com"
}
],
"Website": "https://example.com/myplugin",
"Main": "com.example.myplugin.MyPlugin",
"ServerVersion": ">=1.0.0",
"Dependencies": {
"Hytale:NPCPlugin": ">=1.0.0"
},
"OptionalDependencies": {
"Hytale:TeleportPlugin": "*"
},
"LoadBefore": {
"Hytale:SomeOtherPlugin": "*"
},
"DisabledByDefault": false,
"IncludesAssetPack": true
}{
"Group": "com.example",
"Name": "MyPlugin",
"Version": "1.0.0",
"Description": "My awesome Hytale plugin",
"Authors": [
{
"Name": "Author Name",
"Email": "author@example.com",
"Url": "https://example.com"
}
],
"Website": "https://example.com/myplugin",
"Main": "com.example.myplugin.MyPlugin",
"ServerVersion": ">=1.0.0",
"Dependencies": {
"Hytale:NPCPlugin": ">=1.0.0"
},
"OptionalDependencies": {
"Hytale:TeleportPlugin": "*"
},
"LoadBefore": {
"Hytale:SomeOtherPlugin": "*"
},
"DisabledByDefault": false,
"IncludesAssetPack": true
}| Field | Required | Description |
|---|---|---|
| No | Organization/namespace identifier |
| Yes | Plugin name (1-64 chars) |
| No | Semantic version string |
| No | Human-readable description |
| No | Array of author info objects |
| Yes | Fully qualified main class name |
| No | Required server version constraint |
| No | Required plugins with version constraints |
| No | Optional plugins with version constraints |
| No | Plugins this should load before |
| No | Start disabled (default: false) |
| No | Has embedded assets (default: false) |
| 字段 | 是否必填 | 描述 |
|---|---|---|
| 否 | 组织/命名空间标识符 |
| 是 | 插件名称(1-64个字符) |
| 否 | 语义化版本字符串 |
| 否 | 人类可读的插件描述 |
| 否 | 作者信息对象数组 |
| 是 | 完整限定的主类名称 |
| 否 | 所需的服务器版本约束 |
| 否 | 带版本约束的必填插件 |
| 否 | 带版本约束的可选插件 |
| 否 | 本插件需要优先加载的插件 |
| 否 | 默认是否禁用(默认值:false) |
| 否 | 是否包含嵌入式资源包(默认值:false) |
JavaPluginpackage com.example.myplugin;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
import javax.annotation.Nonnull;
public class MyPlugin extends JavaPlugin {
// Required constructor
public MyPlugin(@Nonnull JavaPluginInit init) {
super(init);
}
@Override
protected void setup() {
// Called after config load
// Register: commands, events, components, systems, codecs
getLogger().atInfo().log("MyPlugin setup complete!");
}
@Override
protected void start() {
// Called after all plugins complete setup
// Safe to interact with other plugins
getLogger().atInfo().log("MyPlugin started!");
}
@Override
protected void shutdown() {
// Called before disable (in reverse load order)
// Cleanup resources
getLogger().atInfo().log("MyPlugin shutting down!");
}
}JavaPluginpackage com.example.myplugin;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
import javax.annotation.Nonnull;
public class MyPlugin extends JavaPlugin {
// 必填构造函数
public MyPlugin(@Nonnull JavaPluginInit init) {
super(init);
}
@Override
protected void setup() {
// 配置加载完成后调用
// 注册:命令、事件、组件、系统、编解码器
getLogger().atInfo().log("MyPlugin setup complete!");
}
@Override
protected void start() {
// 所有插件完成setup后调用
// 可安全与其他插件交互
getLogger().atInfo().log("MyPlugin started!");
}
@Override
protected void shutdown() {
// 禁用前调用(按反向加载顺序)
// 清理资源
getLogger().atInfo().log("MyPlugin shutting down!");
}
}PluginBase| Registry | Method | Purpose |
|---|---|---|
| Commands | | Register slash commands |
| Events | | Register event listeners |
| Tasks | | Register async tasks |
| Block States | | Register block state types |
| Entities | | Register entity types |
| Client Features | | Register client features |
| Assets | | Register asset stores |
| Entity Components | | Register ECS components/systems |
| Chunk Components | | Register chunk components/systems |
| Codecs | | Register serializable types |
PluginBase| 注册中心 | 方法 | 用途 |
|---|---|---|
| 命令 | | 注册斜杠命令 |
| 事件 | | 注册事件监听器 |
| 任务 | | 注册异步任务 |
| 方块状态 | | 注册方块状态类型 |
| 实体 | | 注册实体类型 |
| 客户端功能 | | 注册客户端功能 |
| 资源 | | 注册资源存储 |
| 实体组件 | | 注册ECS组件/系统 |
| 区块组件 | | 注册区块组件/系统 |
| 编解码器 | | 注册可序列化类型 |
@Override
protected void setup() {
getCommandRegistry().registerCommand(new MyCommand());
}
// Command class
public class MyCommand extends Command {
public MyCommand() {
super("mycommand", "My command description");
// Add arguments
addArg(EntityArg.player("target"));
addArg(IntArg.number("amount", 1, 100));
}
@Override
public void execute(CommandContext ctx) {
Player target = ctx.get("target");
int amount = ctx.get("amount");
ctx.sendMessage("Executed on " + target.getName() + " with " + amount);
}
}@Override
protected void setup() {
getCommandRegistry().registerCommand(new MyCommand());
}
// 命令类
public class MyCommand extends Command {
public MyCommand() {
super("mycommand", "My command description");
// 添加参数
addArg(EntityArg.player("target"));
addArg(IntArg.number("amount", 1, 100));
}
@Override
public void execute(CommandContext ctx) {
Player target = ctx.get("target");
int amount = ctx.get("amount");
ctx.sendMessage("Executed on " + target.getName() + " with " + amount);
}
}@Override
protected void setup() {
// Global listener (all events of this type)
getEventRegistry().registerGlobal(PlayerConnectEvent.class, this::onPlayerConnect);
// Keyed listener (specific world/key)
getEventRegistry().register(AddPlayerToWorldEvent.class, "world_name", this::onPlayerAddToWorld);
// Priority listener
getEventRegistry().registerGlobal(EventPriority.FIRST, SomeEvent.class, this::onSomeEvent);
}
private void onPlayerConnect(PlayerConnectEvent event) {
getLogger().atInfo().log("Player connected: %s", event.getPlayer().getName());
}@Override
protected void setup() {
// 全局监听器(监听该类型的所有事件)
getEventRegistry().registerGlobal(PlayerConnectEvent.class, this::onPlayerConnect);
// 键控监听器(特定世界/键)
getEventRegistry().register(AddPlayerToWorldEvent.class, "world_name", this::onPlayerAddToWorld);
// 优先级监听器
getEventRegistry().registerGlobal(EventPriority.FIRST, SomeEvent.class, this::onSomeEvent);
}
private void onPlayerConnect(PlayerConnectEvent event) {
getLogger().atInfo().log("Player connected: %s", event.getPlayer().getName());
}@Override
protected void setup() {
// Register a component type
ComponentType<EntityStore, MyComponent> myComponentType =
getEntityStoreRegistry().registerComponent(
MyComponent.class,
MyComponent::new
);
// Register with serialization codec
ComponentType<EntityStore, MyComponent> myComponentType =
getEntityStoreRegistry().registerComponent(
MyComponent.class,
"myComponentName",
MyComponent.CODEC
);
// Register a system
getEntityStoreRegistry().registerSystem(new MySystem());
}@Override
protected void setup() {
// 注册组件类型
ComponentType<EntityStore, MyComponent> myComponentType =
getEntityStoreRegistry().registerComponent(
MyComponent.class,
MyComponent::new
);
// 带序列化编解码器的注册
ComponentType<EntityStore, MyComponent> myComponentType =
getEntityStoreRegistry().registerComponent(
MyComponent.class,
"myComponentName",
MyComponent.CODEC
);
// 注册系统
getEntityStoreRegistry().registerSystem(new MySystem());
}@Override
protected void setup() {
// Register custom interaction type
getCodecRegistry(Interaction.CODEC)
.register("MyInteraction", MyInteraction.class, MyInteraction.CODEC);
// Register custom action type
getCodecRegistry(Action.CODEC)
.register("MyAction", MyAction.class, MyAction.CODEC);
}@Override
protected void setup() {
// 注册自定义交互类型
getCodecRegistry(Interaction.CODEC)
.register("MyInteraction", MyInteraction.class, MyInteraction.CODEC);
// 注册自定义动作类型
getCodecRegistry(Action.CODEC)
.register("MyAction", MyAction.class, MyAction.CODEC);
}withConfig()public class MyPlugin extends JavaPlugin {
private final Config<MyConfig> config;
public MyPlugin(@Nonnull JavaPluginInit init) {
super(init);
this.config = withConfig(MyConfig.CODEC);
}
@Override
protected void setup() {
MyConfig cfg = config.get();
getLogger().atInfo().log("Config value: %s", cfg.someValue());
}
}
// Config class
public record MyConfig(
String someValue,
int maxPlayers,
boolean enableFeature
) {
public static final BuilderCodec<MyConfig> CODEC = BuilderCodec.builder(
Codec.STRING.required().fieldOf("SomeValue"),
Codec.INT.required().fieldOf("MaxPlayers"),
Codec.BOOL.optionalFieldOf("EnableFeature", true)
).constructor(MyConfig::new);
}config/{PluginGroup}.{PluginName}/config.jsonwithConfig()public class MyPlugin extends JavaPlugin {
private final Config<MyConfig> config;
public MyPlugin(@Nonnull JavaPluginInit init) {
super(init);
this.config = withConfig(MyConfig.CODEC);
}
@Override
protected void setup() {
MyConfig cfg = config.get();
getLogger().atInfo().log("Config value: %s", cfg.someValue());
}
}
// 配置类
public record MyConfig(
String someValue,
int maxPlayers,
boolean enableFeature
) {
public static final BuilderCodec<MyConfig> CODEC = BuilderCodec.builder(
Codec.STRING.required().fieldOf("SomeValue"),
Codec.INT.required().fieldOf("MaxPlayers"),
Codec.BOOL.optionalFieldOf("EnableFeature", true)
).constructor(MyConfig::new);
}config/{PluginGroup}.{PluginName}/config.json// Get the server instance
HytaleServer server = HytaleServer.get();
// Get the universe (world container)
Universe universe = server.getUniverse();
// Get a specific world
World world = universe.getWorld("world_name");
// Get the event bus
IEventBus eventBus = server.getEventBus();
// Get player by name
Optional<Player> player = server.getPlayerByName("PlayerName");
// Get asset registry
AssetRegistry assetRegistry = server.getAssetRegistry();@Override
protected void start() {
// 获取可选依赖
PluginBase teleportPlugin = getPluginManager()
.getPlugin(PluginIdentifier.of("Hytale", "TeleportPlugin"))
.orElse(null);
if (teleportPlugin != null) {
// 使用 teleport 插件功能
}
}@Override
protected void start() {
// Get optional dependency
PluginBase teleportPlugin = getPluginManager()
.getPlugin(PluginIdentifier.of("Hytale", "TeleportPlugin"))
.orElse(null);
if (teleportPlugin != null) {
// Use teleport plugin features
}
}plugins {
id 'java'
}
group = 'com.example'
version = '1.0.0'
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
repositories {
mavenCentral()
// 若可用,添加Hytale仓库
}
dependencies {
compileOnly 'com.hypixel.hytale:hytale-server-api:1.0.0'
}
jar {
from('src/main/resources') {
include 'manifest.json'
include 'assets/**'
}
}plugins {
id 'java'
}
group = 'com.example'
version = '1.0.0'
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
repositories {
mavenCentral()
// Add Hytale repository if available
}
dependencies {
compileOnly 'com.hypixel.hytale:hytale-server-api:1.0.0'
}
jar {
from('src/main/resources') {
include 'manifest.json'
include 'assets/**'
}
}@Override
protected void setup() {
try {
getCommandRegistry().registerCommand(new MyCommand());
} catch (Exception e) {
getLogger().atSevere().withCause(e).log("Failed to register command");
}
}@Override
protected void setup() {
try {
getCommandRegistry().registerCommand(new MyCommand());
} catch (Exception e) {
getLogger().atSevere().withCause(e).log("Failed to register command");
}
}// 使用内置的流式API日志器
getLogger().atInfo().log("Information message");
getLogger().atWarning().log("Warning message");
getLogger().atSevere().log("Error message"); // 或 atSevere().withCause(exception).log("Error message")
getLogger().atFine().log("Debug message");
// 带字符串格式化
getLogger().atInfo().log("Player %s connected", playerName);
// 带异常信息
getLogger().atSevere().withCause(exception).log("Failed to process request");.info().warn().error().atLevel().log("message")// Use the built-in logger with fluent API
getLogger().atInfo().log("Information message");
getLogger().atWarning().log("Warning message");
getLogger().atSevere().log("Error message"); // or atSevere().withCause(exception).log("Error message")
getLogger().atFine().log("Debug message");
// With string formatting
getLogger().atInfo().log("Player %s connected", playerName);
// With exception
getLogger().atSevere().withCause(exception).log("Failed to process request");.info().warn().error().atLevel().log("message")private ScheduledFuture<?> task;
@Override
protected void start() {
task = scheduler.scheduleAtFixedRate(this::doWork, 0, 1, TimeUnit.SECONDS);
}
@Override
protected void shutdown() {
if (task != null) {
task.cancel(false);
}
}private ScheduledFuture<?> task;
@Override
protected void start() {
task = scheduler.scheduleAtFixedRate(this::doWork, 0, 1, TimeUnit.SECONDS);
}
@Override
protected void shutdown() {
if (task != null) {
task.cancel(false);
}
}manifest.jsonMainmanifest.jsonMaincompileOnlyDependenciesLoadBeforecompileOnlyDependenciesLoadBeforesetup()setup()undefinedundefinedundefinedundefined:: 交互模式(提示输入所有参数)
scripts\create-plugin.bat
:: 带参数执行
scripts\create-plugin.bat <PluginName> [Group] [Version] [Author] [Description]
:: 示例
scripts\create-plugin.bat MyAwesomePlugin com.mycompany 1.0.0 "John Doe" "A cool plugin":: Interactive mode (prompts for all values)
scripts\create-plugin.bat
:: With arguments
scripts\create-plugin.bat <PluginName> [Group] [Version] [Author] [Description]
:: Example
scripts\create-plugin.bat MyAwesomePlugin com.mycompany 1.0.0 "John Doe" "A cool plugin"my-plugin/
├── src/main/java/com/example/myplugin/
│ ├── MyPlugin.java # 包含生命周期方法的主插件类
│ ├── commands/
│ │ └── ExampleCommand.java # 示例命令实现
│ ├── events/
│ │ └── PlayerEventHandler.java # 示例事件处理器
│ ├── components/ # ECS组件目录
│ └── systems/ # ECS系统目录
├── src/main/resources/
│ ├── manifest.json # 包含元数据的插件清单
│ └── assets/Server/Content/ # 资源包目录(可选)
├── build.gradle # Gradle构建配置(Java 21)
├── settings.gradle # Gradle项目设置
└── .gitignore # Git忽略规则my-plugin/
├── src/main/java/com/example/myplugin/
│ ├── MyPlugin.java # Main plugin class with lifecycle methods
│ ├── commands/
│ │ └── ExampleCommand.java # Example command implementation
│ ├── events/
│ │ └── PlayerEventHandler.java # Example event handler
│ ├── components/ # Directory for ECS components
│ └── systems/ # Directory for ECS systems
├── src/main/resources/
│ ├── manifest.json # Plugin manifest with metadata
│ └── assets/Server/Content/ # Asset pack directory (optional)
├── build.gradle # Gradle build configuration (Java 21)
├── settings.gradle # Gradle project settings
└── .gitignore # Git ignore rules| 参数 | 是否必填 | 默认值 | 描述 |
|---|---|---|---|
| PluginName | 是 | - | 插件名称(1-64个字母数字字符,以字母开头) |
| Group | 否 | | Maven组/Java包前缀 |
| Version | 否 | | 语义化版本字符串 |
| Author | 否 | | 插件作者名称 |
| Description | 否 | (空) | 人类可读的插件描述 |
references/plugin-lifecycle.mdreferences/registry-patterns.md| Parameter | Required | Default | Description |
|---|---|---|---|
| PluginName | Yes | - | Name of the plugin (1-64 alphanumeric chars, starts with letter) |
| Group | No | | Maven group/Java package prefix |
| Version | No | | Semantic version string |
| Author | No | | Plugin author name |
| Description | No | (empty) | Human-readable plugin description |
references/plugin-lifecycle.mdreferences/registry-patterns.md