Skip to content

扩展与平台投影 API 类型参考

本页是 API baseline 1.3 候选源码的扩展与平台投影公开签名。先阅读第三方插件接入教程;普通 Bukkit 插件与启动期内部扩展是两种不同入口,不要混用。

版本边界

正式交付 1.0.8 与 1.0.12 候选并不等价。依赖版本必须与服务器实际 JAR 配套,并重新编译、在目标服务端验收。

PlatformProjectionSink.kt

kotlin
package cn.sealplugins.attributes.api.platform

/** Bounded collector; acceptance does not apply an entity mutation until the batch is committed. */
public interface PlatformProjectionSink {
    public fun accept(intent: PlatformProjectionIntent): ProjectionAcceptance
}

public enum class ProjectionAcceptance {
    ACCEPTED,
    LIMIT_EXCEEDED,
    NAMESPACE_MISMATCH,
    INVALID_INTENT,
    OWNER_EXPIRED,
}

PlatformProjectionIntent.kt

kotlin
package cn.sealplugins.attributes.api.platform

import cn.sealplugins.attributes.api.internal.requireNamespacedId
import cn.sealplugins.attributes.api.internal.requireFinite

/** One validated platform-neutral numeric projection owned by an extension namespace. */
public class PlatformProjectionIntent(
    projectionId: String,
    public val target: PlatformProjectionTarget,
    public val operation: PlatformProjectionOperation,
    amount: Double,
) {
    public val projectionId: String = requireNamespacedId(projectionId, "projectionId")
    public val amount: Double = requireFinite(amount, "projection amount")

    init {
        if (operation == PlatformProjectionOperation.REMOVE) {
            require(this.amount == 0.0) { "REMOVE projection intents must use amount 0" }
        }
    }
}

/** V1 platform targets deliberately form an allowlist instead of exposing platform classes. */
public enum class PlatformProjectionTarget {
    MAX_HEALTH,
    MOVEMENT_SPEED,
}

public enum class PlatformProjectionOperation {
    UPSERT_ADD,
    UPSERT_TOTAL_PERCENT,
    REMOVE,
}

PlatformProjectionContext.kt

kotlin
package cn.sealplugins.attributes.api.platform

import cn.sealplugins.attributes.api.ApiLimits
import cn.sealplugins.attributes.api.definition.AttributeId
import cn.sealplugins.attributes.api.internal.immutableSet
import cn.sealplugins.attributes.api.subject.AttributeSnapshot
import cn.sealplugins.attributes.api.subject.SubjectKey
import java.util.Optional

/** Immutable committed snapshot transition provided to a platform extension. */
public class PlatformProjectionContext(
    public val subject: SubjectKey,
    public val current: AttributeSnapshot,
    previous: Optional<AttributeSnapshot>,
    changedAttributes: Collection<AttributeId>,
) {
    public val previous: Optional<AttributeSnapshot> = previous
    public val changedAttributes: Set<AttributeId> = immutableSet(
        changedAttributes,
        ApiLimits.MAX_ATTRIBUTES_PER_SNAPSHOT,
        "changed attributes",
    )

    init {
        require(current.state.key == subject) { "current snapshot must belong to subject" }
        require(this.previous.map { it.state.key == subject }.orElse(true)) {
            "previous snapshot must belong to subject"
        }
    }
}

PlatformExtension.kt

kotlin
package cn.sealplugins.attributes.api.platform

import cn.sealplugins.attributes.api.internal.requireNamespacedId
import cn.sealplugins.attributes.api.internal.requirePriority

/**
 * Controlled platform projection extension registered during startup.
 *
 * Projection runs synchronously after a committed snapshot transition on that subject's
 * platform-approved execution context, ordered by `priority`, provider namespace and extension
 * ID. The extension receives no platform object and must use only the provided immutable context
 * and [sink]; I/O, mutable global reads and reentrant SealAttributes mutations are forbidden. The
 * sink buffers a bounded atomic batch. If the extension throws, returns an invalid intent or
 * exceeds the limit, its whole batch is discarded and diagnosed; other extensions still run.
 */
public interface PlatformExtension {
    public fun id(): String
    public fun priority(): Int
    public fun project(context: PlatformProjectionContext, sink: PlatformProjectionSink)
}

public object PlatformExtensionContract {
    @JvmStatic
    public fun requireId(value: String): String = requireNamespacedId(value, "platform extension id")

    @JvmStatic
    public fun validatePriority(value: Int): Int = requirePriority(value)
}

SealAttributeExtension.kt

kotlin
package cn.sealplugins.attributes.api.extension

import cn.sealplugins.attributes.api.definition.DefinitionRegistry

/**
 * Startup-only entry point for one trusted attribute pack loaded from SealAttributes/extensions.
 *
 * Implementations are discovered through the standard JVM service-provider file for this
 * interface. One JAR contains exactly one entry point and owns one provider namespace.
 */
public interface SealAttributeExtension {

    /** Canonical namespace owned by every definition and behavior in this pack. */
    public fun providerId(): String

    /** SealAttributes API baseline required by this pack. */
    public fun apiBaseline(): String

    /** Registers every definition and behavior before the Core registry freezes. */
    public fun register(registry: DefinitionRegistry)
}