hytale-plugin-basics

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Hytale Plugin Development Basics

Hytale服务器插件开发基础

Complete guide for creating Hytale server plugins following the official architecture patterns.
遵循官方架构模式创建Hytale服务器插件的完整指南。

When to use this skill

何时使用本技能

Use this skill when:
  • Creating a new Hytale plugin from scratch
  • Setting up plugin project structure
  • Configuring plugin manifest (manifest.json)
  • Understanding plugin lifecycle hooks
  • Registering commands, events, or components
  • Managing plugin dependencies
在以下场景使用本技能:
  • 从零开始创建新的Hytale插件
  • 搭建插件项目结构
  • 配置插件清单(manifest.json)
  • 理解插件生命周期钩子
  • 注册命令、事件或组件
  • 管理插件依赖项

Plugin Architecture Overview

插件架构概述

Hytale plugins are Java-based extensions that run on the server. They follow an ECS (Entity Component System) architecture with lifecycle management.
Hytale插件是运行在服务器上的Java扩展,遵循带有生命周期管理的ECS(实体组件系统)架构。

Plugin Types

插件类型

TypeLocationDescription
Core PluginsRegistered programmaticallyBuilt-in server functionality
Builtin Plugins
server.jar/../builtin/
Shipped with server
External Plugins
mods/
directory
User-installed plugins
Early Plugins
earlyplugins/
Bytecode transformers (advanced)
类型位置描述
核心插件以编程方式注册服务器内置功能
内置插件
server.jar/../builtin/
随服务器一同发布
外部插件
mods/
目录
用户自行安装的插件
早期插件
earlyplugins/
字节码转换器(高级功能)

Plugin Lifecycle States

插件生命周期状态

NONE -> SETUP -> START -> ENABLED -> SHUTDOWN -> DISABLED
NONE -> SETUP -> START -> ENABLED -> SHUTDOWN -> DISABLED

Project Structure

项目结构

my-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.gradle
my-plugin/
├── src/
│   └── main/
│       ├── java/
│       │   └── com/example/myplugin/
│       │       ├── MyPlugin.java
│       │       ├── commands/
│       │       ├── events/
│       │       ├── components/
│       │       └── systems/
│       └── resources/
│           ├── manifest.json
│           └── assets/           # 可选资源包
│               └── Server/
│                   └── Content/
├── build.gradle
└── settings.gradle

Plugin Manifest (manifest.json)

插件清单(manifest.json)

Required file in JAR root defining plugin metadata:
json
{
  "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
}
必填文件,位于JAR包根目录,用于定义插件元数据:
json
{
  "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
}

Manifest Fields

清单字段说明

FieldRequiredDescription
Group
NoOrganization/namespace identifier
Name
YesPlugin name (1-64 chars)
Version
NoSemantic version string
Description
NoHuman-readable description
Authors
NoArray of author info objects
Main
YesFully qualified main class name
ServerVersion
NoRequired server version constraint
Dependencies
NoRequired plugins with version constraints
OptionalDependencies
NoOptional plugins with version constraints
LoadBefore
NoPlugins this should load before
DisabledByDefault
NoStart disabled (default: false)
IncludesAssetPack
NoHas embedded assets (default: false)
字段是否必填描述
Group
组织/命名空间标识符
Name
插件名称(1-64个字符)
Version
语义化版本字符串
Description
人类可读的插件描述
Authors
作者信息对象数组
Main
完整限定的主类名称
ServerVersion
所需的服务器版本约束
Dependencies
带版本约束的必填插件
OptionalDependencies
带版本约束的可选插件
LoadBefore
本插件需要优先加载的插件
DisabledByDefault
默认是否禁用(默认值:false)
IncludesAssetPack
是否包含嵌入式资源包(默认值:false)

Main Plugin Class

主插件类

Extend
JavaPlugin
and implement lifecycle methods:
java
package 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!");
    }
}
继承
JavaPlugin
并实现生命周期方法:
java
package 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!");
    }
}

Available Registries

可用注册中心

Access through
PluginBase
methods:
RegistryMethodPurpose
Commands
getCommandRegistry()
Register slash commands
Events
getEventRegistry()
Register event listeners
Tasks
getTaskRegistry()
Register async tasks
Block States
getBlockStateRegistry()
Register block state types
Entities
getEntityRegistry()
Register entity types
Client Features
getClientFeatureRegistry()
Register client features
Assets
getAssetRegistry()
Register asset stores
Entity Components
getEntityStoreRegistry()
Register ECS components/systems
Chunk Components
getChunkStoreRegistry()
Register chunk components/systems
Codecs
getCodecRegistry(codec)
Register serializable types
通过
PluginBase
方法访问:
注册中心方法用途
命令
getCommandRegistry()
注册斜杠命令
事件
getEventRegistry()
注册事件监听器
任务
getTaskRegistry()
注册异步任务
方块状态
getBlockStateRegistry()
注册方块状态类型
实体
getEntityRegistry()
注册实体类型
客户端功能
getClientFeatureRegistry()
注册客户端功能
资源
getAssetRegistry()
注册资源存储
实体组件
getEntityStoreRegistry()
注册ECS组件/系统
区块组件
getChunkStoreRegistry()
注册区块组件/系统
编解码器
getCodecRegistry(codec)
注册可序列化类型

Command Registration

命令注册

java
@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);
    }
}
java
@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);
    }
}

Event Registration

事件注册

java
@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());
}
java
@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());
}

Component Registration (ECS)

组件注册(ECS)

java
@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());
}
java
@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());
}

Codec Registration

编解码器注册

java
@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);
}
java
@Override
protected void setup() {
    // 注册自定义交互类型
    getCodecRegistry(Interaction.CODEC)
        .register("MyInteraction", MyInteraction.class, MyInteraction.CODEC);
    
    // 注册自定义动作类型
    getCodecRegistry(Action.CODEC)
        .register("MyAction", MyAction.class, MyAction.CODEC);
}

Plugin Configuration

插件配置

Use
withConfig()
for typed configuration:
java
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 files are stored in
config/{PluginGroup}.{PluginName}/config.json
.
使用
withConfig()
实现类型化配置:
java
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
路径下。

Accessing Server Resources

依赖注入模式

java
// 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();
安全访问其他插件:
java
@Override
protected void start() {
    // 获取可选依赖
    PluginBase teleportPlugin = getPluginManager()
        .getPlugin(PluginIdentifier.of("Hytale", "TeleportPlugin"))
        .orElse(null);
    
    if (teleportPlugin != null) {
        // 使用 teleport 插件功能
    }
}

Dependency Injection Pattern

Gradle构建配置

Access other plugins safely:
java
@Override
protected void start() {
    // Get optional dependency
    PluginBase teleportPlugin = getPluginManager()
        .getPlugin(PluginIdentifier.of("Hytale", "TeleportPlugin"))
        .orElse(null);
    
    if (teleportPlugin != null) {
        // Use teleport plugin features
    }
}
groovy
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/**'
    }
}

Gradle Build Configuration

最佳实践

生命周期管理

groovy
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/**'
    }
}
  1. setup():注册所有组件,绝不与游戏状态交互
  2. start():可安全与世界、玩家、其他插件交互
  3. shutdown():清理资源、保存数据、取消任务

Best Practices

错误处理

Lifecycle Management

  1. setup(): Register all components, never interact with game state
  2. start(): Safe to interact with world, players, other plugins
  3. shutdown(): Clean up resources, save data, cancel tasks
java
@Override
protected void setup() {
    try {
        getCommandRegistry().registerCommand(new MyCommand());
    } catch (Exception e) {
        getLogger().atSevere().withCause(e).log("Failed to register command");
    }
}

Error Handling

日志记录

java
@Override
protected void setup() {
    try {
        getCommandRegistry().registerCommand(new MyCommand());
    } catch (Exception e) {
        getLogger().atSevere().withCause(e).log("Failed to register command");
    }
}
Hytale服务器使用流式日志API:
java
// 使用内置的流式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")

Logging

资源清理

The Hytale server uses a fluent logging API:
java
// 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");
Note: The logger does NOT use
.info()
,
.warn()
,
.error()
methods directly. Always use the fluent pattern:
.atLevel().log("message")
.
通过插件注册中心完成的所有注册会在插件禁用时自动清理。对于自定义资源:
java
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);
    }
}

Resource Cleanup

故障排除

插件无法加载

All registrations through plugin registries are automatically cleaned up when the plugin is disabled. For custom resources:
java
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);
    }
}
  1. 检查
    manifest.json
    是否位于JAR包根目录
  2. 验证
    Main
    类路径是否正确
  3. 检查依赖版本是否不匹配
  4. 在服务器日志中查找异常信息

Troubleshooting

类未找到

Plugin Not Loading

  1. Check
    manifest.json
    is in JAR root
  2. Verify
    Main
    class path is correct
  3. Check for dependency version mismatches
  4. Look for exceptions in server logs
  1. 确保依赖项标记为
    compileOnly
  2. 通过
    Dependencies
    /
    LoadBefore
    检查插件加载顺序
  3. 验证JAR包包含所有必需的类

Class Not Found

事件未触发

  1. Ensure dependencies are marked
    compileOnly
  2. Check plugin load order via
    Dependencies
    /
    LoadBefore
  3. Verify JAR contains all required classes
  1. 确认注册操作在
    setup()
    中执行
  2. 检查事件键是否匹配(针对键控事件)
  3. 验证事件优先级顺序
  4. 确保事件未被取消

Events Not Firing

脚手架脚本

  1. Confirm registration happens in
    setup()
  2. Check event key matches (for keyed events)
  3. Verify event priority order
  4. Ensure event isn't being cancelled
使用提供的脚本快速创建包含完整目录结构和模板代码的新插件项目。

Scaffolding Scripts

Linux/macOS

Use the provided scripts to quickly create a new plugin project with the complete directory structure and boilerplate code.
bash
undefined

Linux/macOS

交互模式(提示输入所有参数)

bash
undefined
./scripts/create-plugin.sh

Interactive mode (prompts for all values)

带参数执行

./scripts/create-plugin.sh
./scripts/create-plugin.sh <PluginName> [Group] [Version] [Author] [Description]

With arguments

示例

./scripts/create-plugin.sh <PluginName> [Group] [Version] [Author] [Description]
./scripts/create-plugin.sh MyAwesomePlugin com.mycompany 1.0.0 "John Doe" "A cool plugin"
undefined

Example

Windows

./scripts/create-plugin.sh MyAwesomePlugin com.mycompany 1.0.0 "John Doe" "A cool plugin"
undefined
batch
:: 交互模式(提示输入所有参数)
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"

Windows

生成的结构

batch
:: 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忽略规则

Generated Structure

脚本参数

The scripts create the following project structure:
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
com.example
Maven组/Java包前缀
Version
1.0.0
语义化版本字符串
Author
Author
插件作者名称
Description(空)人类可读的插件描述
如需详细的生命周期文档,请查看
references/plugin-lifecycle.md
。 如需高级注册模式文档,请查看
references/registry-patterns.md

Script Parameters

ParameterRequiredDefaultDescription
PluginNameYes-Name of the plugin (1-64 alphanumeric chars, starts with letter)
GroupNo
com.example
Maven group/Java package prefix
VersionNo
1.0.0
Semantic version string
AuthorNo
Author
Plugin author name
DescriptionNo(empty)Human-readable plugin description
See
references/plugin-lifecycle.md
for detailed lifecycle documentation. See
references/registry-patterns.md
for advanced registration patterns.