Events

Register listener objects with the EventBus. Methods annotated with @EventHandler and a single Event parameter are invoked when posted.

class ExampleListener {
@EventHandler
fun onEvent(event: Event) {
// handle event
}
}

Registration:

context.eventBus.register(ExampleListener())

To stop listening, call unregister with the same listener instance.

Mod metadata

Metadata is provided via @LineageModInfo on the mod main class.

Fields:

  • id: lowercase identifier, 1-32 chars, [a-z0-9_-]+

  • name: human name, 1-64 chars, [A-Za-z0-9 _.-]+

  • version: MAJOR.MINOR.PATCH

  • apiVersion: MAJOR.MINOR.PATCH

  • authors: list of author names

  • description: optional text

  • dependencies: required dependencies

  • softDependencies: optional dependencies

  • website, license: optional strings

Dependency entries accept version constraints:

core
core>=1.2.0
worlds^2.0.0

If a required dependency is missing or does not satisfy the constraint, the mod will not load.

Players

PlayerManager exposes online proxy sessions. Each ProxyPlayer represents a connected player and can be moved between backends.

val player = context.players.getByName("Example")
player?.sendMessage("Hello from the proxy")

Useful fields:

  • ProxyPlayer.id

  • ProxyPlayer.username

  • ProxyPlayer.state

  • ProxyPlayer.backendId

Transfer example:

player?.transferTo("hub-1")

Scheduler

Schedule work on the proxy runtime with Scheduler.

val handle = context.scheduler.runLater(Duration.ofSeconds(5)) {
context.logger.info("Delayed task")
}

Use runSync, runAsync, or runRepeating depending on your needs. Cancel with handle.cancel().

Getting started

Lineage mods are plain JVM jars. A mod is discovered by scanning for the @LineageModInfo annotation and instantiating the annotated class.

Minimal mod

Kotlin:

@LineageModInfo(
id = "hello",
name = "Hello Mod",
version = "1.0.0",
apiVersion = "0.1.0",
authors = ["YourName"]
)
class HelloMod : LineageMod() {
override fun onEnable() {
context.logger.info("Hello from Lineage!")
}
}

Java:

@LineageModInfo(
id = "hello",
name = "Hello Mod",
version = "1.0.0",
apiVersion = "0.1.0",
authors = {"YourName"}
)
public final class HelloMod extends LineageMod {
@Override
public void onEnable() {
context.getLogger().info("Hello from Lineage!");
}
}

Packaging

  • Build a jar that includes your mod class and resources.

  • Place the jar into mods/ next to the proxy config.toml.

  • Per-mod data is stored under mods/<mod-id>/.

Dependency

Lineage API is published on Maven Central.

Gradle Kotlin DSL:

dependencies {
implementation("ru.hytalemodding.lineage:api:0.1.0")
}

Gradle Groovy DSL:

dependencies {
implementation "ru.hytalemodding.lineage:api:0.1.0"
}

Maven:

<dependency>
<groupId>ru.hytalemodding.lineage</groupId>
<artifactId>api</artifactId>
<version>0.1.0</version>
</dependency>

You can still build from source and depend on the local :api module when needed.

Backends

BackendRegistry exposes the configured backend servers.

for (backend in context.backends.all()) {
context.logger.info("Backend {} -> {}:{}", backend.id, backend.host, backend.port)
}

You can move a player to a backend by id:

player.transferTo("hub-1")

Messaging

Messaging provides UDP channels for proxy and backend communication.

Raw channel:

val channel = context.messaging.registerChannel("mods:hello") { message ->
val text = message.payload.toString(Charsets.UTF_8)
context.logger.info("Got: {}", text)
}
channel.send("hi".toByteArray())

Typed channel:

val typed = MessagingChannels.registerTyped(
context.messaging,
"mods:chat",
Codecs.UTF8_STRING
) { message ->
context.logger.info("Got: {}", message.payload)
}
typed.send("hello")

Configuration

Each mod gets its own data folder under mods/<mod-id>/. Use ConfigManager to create or load TOML files in that directory.

val config = context.configManager.config(
name = "settings",
createIfMissing = true
) {
"""
enabled = true
greeting = "hello"
""".trimIndent()
}

Paths are relative to the mod folder. If name has no file extension, .toml is appended automatically.

Examples:

  • settings ->mods/<id>/settings.toml

  • nested/chat ->mods/<id>/nested/chat.toml

Services

ServiceRegistry lets mods share instances with each other.

val key = ServiceKey(MyService::class.java)
context.serviceRegistry.register(key, MyService())

Retrieve later:

val service = context.serviceRegistry.get(key)

Lifecycle

LineageMod exposes three lifecycle hooks:

  • onLoad(context): called once after the mod is constructed and the ModContext is ready.

  • onEnable(): called after all mods are loaded and dependency order is resolved.

  • onDisable(): called during shutdown or reload.

Use onLoad for wiring services and onEnable for runtime logic.

Commands

Commands are registered through CommandRegistry.

class PingCommand : Command {
override val name = "ping"
override val aliases = listOf("pong")
override val description = "Basic connectivity test."
override val permission: String? = null

override fun execute(context: CommandContext) {
context.sender.sendMessage("pong")
}

override fun suggest(context: CommandContext): List<String> = emptyList()
}

Register from your mod:

context.commandRegistry.register(PingCommand())

Use CommandContext.hasPermission(...) if you want to handle permission checks manually. CommandSender.type is CONSOLE, PLAYER, or SYSTEM.

Permissions

Use PermissionChecker to evaluate permission strings against a subject.

if (context.permissionChecker.hasPermission(sender, "lineage.example.use")) {
sender.sendMessage("Allowed")
}

CommandSender implements PermissionSubject, so it can be checked directly.

Lineage Modding

This documentation covers the public API used to build Lineage mods. The same Markdown files are used for Dokka and GitHub docs to keep them in sync.

Contents

  • getting-started.md

  • mod-metadata.md

  • lifecycle.md

  • commands.md

  • events.md

  • players.md

  • messaging.md

  • config.md

  • permissions.md

  • scheduler.md

  • services.md

  • backends.md

All modules:

Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard