外观
SealItems API 类型参考
先阅读开发者接入教程。本页列出 sealitems-api 1.0.0 的真实公开类型;调用方必须 compileOnly,不能把 API JAR 打进自己的插件,也不能把它单独放进服务端 plugins/。
使用规则
- GUI 与玩家状态方法按注释在 Bukkit 主线程调用。
- API 不会替错误线程自动调度,也不会替调用方阻塞等待。
- 所有状态枚举都应完整处理;不要只检查布尔值后忽略
reason。 - 事件数据和 View 是只读快照,不应通过反射修改。
SealItemsApi.kt
kotlin
package cn.sealplugins.items.api
import java.util.UUID
data class IdentificationOpenResponse(
val opened: Boolean,
val reason: String? = null,
)
data class EnhancementOpenResponse(
val opened: Boolean,
val reason: String? = null,
)
data class DecompositionOpenResponse(
val opened: Boolean,
val reason: String? = null,
)
interface SealItemsApi {
fun openIdentification(playerUuid: UUID): IdentificationOpenResponse
/** Must be called on the Bukkit primary thread. */
fun openEnhancement(playerUuid: UUID): EnhancementOpenResponse
/** Opens the configured decomposition GUI. Must be called on the Bukkit primary thread. */
fun openDecomposition(playerUuid: UUID): DecompositionOpenResponse
}CraftingApiModels.kt
kotlin
package cn.sealplugins.items.api
import java.util.UUID
enum class CraftingActionStatus {
OPENED,
APPLIED,
DISABLED,
RECIPE_UNAVAILABLE,
PLAYER_OFFLINE,
NO_SPACE,
STOPPED,
WRONG_THREAD,
INVALID_AMOUNT,
BUSY,
}
data class CraftingOpenResponse(
val status: CraftingActionStatus,
val reason: String? = null,
) {
val opened: Boolean
get() = status == CraftingActionStatus.OPENED
}
data class CraftingBlueprintGiveResponse(
val status: CraftingActionStatus,
val requestedAmount: Int,
val deliveredAmount: Int,
val reason: String? = null,
) {
val successful: Boolean
get() = status == CraftingActionStatus.APPLIED
}
/**
* Platform-neutral crafting service. Implementations never schedule or block an incorrect caller thread.
*/
interface SealItemsCraftingApi {
fun openCrafting(playerUuid: UUID): CraftingOpenResponse
fun giveBlueprint(
playerUuid: UUID,
recipeId: String,
amount: Int,
): CraftingBlueprintGiveResponse
}
enum class CraftingConditionStatus {
PASS,
FAIL,
UNAVAILABLE,
}
class CraftingExternalCondition(
val requestId: String,
val recipeId: String,
val key: String,
arguments: Map<String, String>,
) {
val arguments: Map<String, String> = java.util.Map.copyOf(arguments)
}
class CraftingConditionBatchRequest(
val playerUuid: UUID,
conditions: List<CraftingExternalCondition>,
) {
val conditions: List<CraftingExternalCondition> = java.util.List.copyOf(conditions)
}
data class CraftingConditionEvaluation(
val status: CraftingConditionStatus,
val messageKey: String? = null,
)
class CraftingConditionBatchResult(
evaluations: Map<String, CraftingConditionEvaluation>,
) {
val evaluations: Map<String, CraftingConditionEvaluation> = java.util.Map.copyOf(evaluations)
}
/**
* Must be fast, main-thread safe and free of blocking I/O. Provider IDs are stable `namespace:path` values.
*/
interface CraftingConditionProvider {
val providerId: String
fun evaluate(request: CraftingConditionBatchRequest): CraftingConditionBatchResult
}SealItemsSetsApi.kt
kotlin
package cn.sealplugins.items.api
import java.util.UUID
enum class SetsActionStatus {
OPENED,
DISABLED,
PLAYER_OFFLINE,
NOT_READY,
STOPPED,
WRONG_THREAD,
}
data class SetsOpenResponse(
val status: SetsActionStatus,
val reason: String? = null,
) {
val opened: Boolean
get() = status == SetsActionStatus.OPENED
}
enum class SetCatalogCollectionFilter {
ALL,
UNSTARTED,
COLLECTING,
COMPLETED,
}
data class SetCatalogQuery(
val categoryId: String? = null,
val collectionFilter: SetCatalogCollectionFilter = SetCatalogCollectionFilter.ALL,
val text: String = "",
) {
init {
require(text.length <= 64) { "catalog search text must not exceed 64 characters" }
require(categoryId == null || Regex("[a-z0-9][a-z0-9_-]{0,63}").matches(categoryId)) { "category id is invalid" }
}
}
class SetCatalogView(entries: List<SetCatalogEntryView>) {
val entries: List<SetCatalogEntryView> = java.util.List.copyOf(entries)
}
class SetDefinitionsView(definitions: List<SetDefinitionView>) {
val definitions: List<SetDefinitionView> = java.util.List.copyOf(definitions)
}
class SetCategoriesView(categories: List<SetCategoryView>) {
val categories: List<SetCategoryView> = java.util.List.copyOf(categories)
}
class SetAcquisitionSourcesView(
val itemId: String,
sources: List<SetAcquisitionSourceView>,
) {
val sources: List<SetAcquisitionSourceView> = java.util.List.copyOf(sources)
}
/**
* Read-only sets service published separately from [SealItemsApi].
* Player-state methods and [openSets] must be called on the Bukkit primary thread; implementations never schedule or
* block an incorrect caller thread. Static definition and acquisition-source views are immutable publication reads.
*/
interface SealItemsSetsApi {
fun openSets(playerUuid: UUID): SetsOpenResponse
fun currentState(playerUuid: UUID): PlayerSetStateView
fun currentCollection(playerUuid: UUID): PlayerCollectionView
fun catalog(
playerUuid: UUID,
query: SetCatalogQuery,
): SetCatalogView
fun acquisitionSources(itemId: String): SetAcquisitionSourcesView
fun definitions(): SetDefinitionsView
fun categories(): SetCategoriesView
fun isMechanicActive(
playerUuid: UUID,
mechanicId: String,
): Boolean
}SetsApiModels.kt
kotlin
package cn.sealplugins.items.api
import java.time.Instant
enum class SetCountingModeView {
DISTINCT_MEMBERS,
EQUIPPED_SLOTS,
}
enum class SetRewardModeView {
CUMULATIVE,
HIGHEST_ONLY,
}
enum class SetAttributeOperationView {
ADD,
TOTAL_PERCENT,
}
data class SetIconView(
val material: String,
val customModelData: Int? = null,
)
data class SetAttributeContributionView(
val attributeId: String,
val operation: SetAttributeOperationView,
val value: String,
)
class SetRewardView(
attributes: List<SetAttributeContributionView>,
mechanicIds: Set<String>,
) {
val attributes: List<SetAttributeContributionView> = java.util.List.copyOf(attributes)
val mechanicIds: Set<String> = java.util.Set.copyOf(mechanicIds)
}
class SetMemberView(
val itemId: String,
slotIds: Set<String>,
) {
val slotIds: Set<String> = java.util.Set.copyOf(slotIds)
}
class SetNodeView(
val id: String,
val pieces: Int,
val displayName: String,
description: List<String>,
val rewards: SetRewardView,
) {
val description: List<String> = java.util.List.copyOf(description)
}
class SetDefinitionView(
val id: String,
val categoryId: String,
val order: Int,
val displayName: String,
description: List<String>,
val iconItemId: String,
val countingMode: SetCountingModeView,
val rewardMode: SetRewardModeView,
members: List<SetMemberView>,
nodes: List<SetNodeView>,
) {
val description: List<String> = java.util.List.copyOf(description)
val members: List<SetMemberView> = java.util.List.copyOf(members)
val nodes: List<SetNodeView> = java.util.List.copyOf(nodes)
}
enum class PlayerSetStateStatus {
DISABLED,
LOADING,
READY,
UNAVAILABLE,
STOPPED,
}
class PlayerSetProgressView(
val setId: String,
val pieceCount: Int,
equippedItemIds: Set<String>,
equippedSlotIds: Set<String>,
reachedNodeIds: Set<String>,
activeNodeIds: Set<String>,
) {
val equippedItemIds: Set<String> = java.util.Set.copyOf(equippedItemIds)
val equippedSlotIds: Set<String> = java.util.Set.copyOf(equippedSlotIds)
val reachedNodeIds: Set<String> = java.util.Set.copyOf(reachedNodeIds)
val activeNodeIds: Set<String> = java.util.Set.copyOf(activeNodeIds)
}
class PlayerSetStateView(
val publicationRevision: Long,
val status: PlayerSetStateStatus,
progress: List<PlayerSetProgressView>,
activeLinkageIds: Set<String>,
mechanicIds: Set<String>,
val detail: String? = null,
) {
val progress: List<PlayerSetProgressView> = java.util.List.copyOf(progress)
val activeLinkageIds: Set<String> = java.util.Set.copyOf(activeLinkageIds)
val mechanicIds: Set<String> = java.util.Set.copyOf(mechanicIds)
}
class SetCategoryView(
val id: String,
val order: Int,
val displayName: String,
description: List<String>,
val icon: SetIconView,
) {
val description: List<String> = java.util.List.copyOf(description)
}
enum class SetCollectionStatusView {
UNSTARTED,
COLLECTING,
COMPLETED,
}
class SetCatalogEntryView(
val setId: String,
val categoryId: String,
val order: Int,
val displayName: String,
description: List<String>,
val iconItemId: String,
val equippedPieces: Int,
reachedNodeIds: Set<String>,
activeNodeIds: Set<String>,
val collectedPieces: Int,
val totalPieces: Int,
val collectionStatus: SetCollectionStatusView,
) {
val description: List<String> = java.util.List.copyOf(description)
val reachedNodeIds: Set<String> = java.util.Set.copyOf(reachedNodeIds)
val activeNodeIds: Set<String> = java.util.Set.copyOf(activeNodeIds)
}
enum class PlayerCollectionStatus {
DISABLED,
LOADING,
READY,
UNAVAILABLE,
}
enum class PlayerCollectionReasonCode {
NONE,
DISABLED_BY_CONFIG,
INITIAL_LOADING,
DATABASE_UNAVAILABLE,
RETRYING,
OUTBOX_PROTECTED,
STOPPED,
}
class PlayerCollectionView(
val status: PlayerCollectionStatus,
confirmedItemIds: Set<String>,
pendingItemIds: Set<String>,
firstDiscoveredAt: Map<String, Instant>,
val generation: Long,
val reasonCode: PlayerCollectionReasonCode,
val detail: String? = null,
) {
val confirmedItemIds: Set<String> = java.util.Set.copyOf(confirmedItemIds)
val pendingItemIds: Set<String> = java.util.Set.copyOf(pendingItemIds)
val firstDiscoveredAt: Map<String, Instant> = java.util.Map.copyOf(firstDiscoveredAt)
}
enum class SetAcquisitionSourceTypeView {
CRAFTING,
VANILLA_LOOT,
DECOMPOSITION,
MYTHIC_MOBS,
QUEST,
SHOP,
DUNGEON,
BOSS,
EVENT,
OTHER,
}
class SetAcquisitionSourceView(
val id: String,
val type: SetAcquisitionSourceTypeView,
val automatic: Boolean,
val displayName: String,
description: List<String>,
val icon: SetIconView?,
) {
val description: List<String> = java.util.List.copyOf(description)
}
class SetMechanicDescriptor(
val id: String,
val displayName: String,
description: List<String>,
val owner: String,
) {
val description: List<String> = java.util.List.copyOf(description)
init {
require(namespacedMechanicIdPattern.matches(id)) { "mechanic id must use namespace:path" }
require(displayName.isNotBlank()) { "mechanic display name must not be blank" }
require(this.description.none(String::isBlank)) { "mechanic description must not contain blank lines" }
require(owner.isNotBlank()) { "mechanic owner must not be blank" }
}
}
class SetMechanicProviderSnapshot(
val providerId: String,
val generation: Long,
descriptors: List<SetMechanicDescriptor>,
) {
val descriptors: List<SetMechanicDescriptor> = java.util.List.copyOf(descriptors)
init {
require(providerIdPattern.matches(providerId)) { "provider id must be a stable lowercase namespace" }
require(generation >= 0) { "provider generation must not be negative" }
require(this.descriptors.map(SetMechanicDescriptor::id).distinct().size == this.descriptors.size) {
"mechanic descriptor ids must be unique"
}
require(this.descriptors.all { it.id.substringBefore(':') == providerId }) {
"mechanic descriptor namespace must equal provider id"
}
}
}
/**
* Platform-neutral descriptor provider. The returned snapshot must be cheap to obtain and must not perform blocking I/O.
* It exposes no player state, event callback, script or mutable parameter map.
*/
interface SealItemsSetMechanicProvider {
fun snapshot(): SetMechanicProviderSnapshot
}
private val providerIdPattern = Regex("[a-z0-9][a-z0-9_.-]{0,62}")
private val namespacedMechanicIdPattern = Regex("[a-z0-9][a-z0-9_.-]{0,62}:[a-z0-9][a-z0-9_./-]{0,126}")EnhancementApiModels.kt
kotlin
package cn.sealplugins.items.api
import java.util.UUID
data class EnhancementFailureOutcome(
val rawDowngrade: Int,
val finalLevel: Int,
val probabilityUnits: Long,
val protectedLevels: Int,
)
enum class EnhancementItemCostKind {
SEAL_ITEM,
VANILLA,
ENHANCEMENT_MATERIAL,
}
enum class EnhancementItemCostRole {
REQUIRED,
LUCK,
PROTECTION,
BOOST,
}
data class EnhancementItemCost(
val kind: EnhancementItemCostKind,
val id: String,
val amount: Int,
val role: EnhancementItemCostRole = EnhancementItemCostRole.REQUIRED,
)
enum class EnhancementCurrencyCostKind {
VAULT,
PLAYER_POINTS,
}
data class EnhancementCurrencyCost(
val kind: EnhancementCurrencyCostKind,
val amount: String,
)
/** Immutable, platform-neutral facts exposed immediately before the one random roll. */
class EnhancementPreparedAttempt(
val requestId: UUID,
val playerId: UUID,
val itemInstanceId: UUID,
val itemId: String,
val beforeLevel: Int,
val targetLevel: Int,
val schemeId: String,
val failureCount: Int,
val successChanceUnits: Long,
val hardGuaranteeAt: Int?,
val luckBonusUnits: Long,
val protectionCapacity: Int,
val progressKey: String,
itemCosts: List<EnhancementItemCost>,
val currencyCost: EnhancementCurrencyCost?,
val currentCheckpoint: Int,
failureOutcomes: List<EnhancementFailureOutcome>,
) {
val itemCosts: List<EnhancementItemCost> = java.util.List.copyOf(itemCosts)
val failureOutcomes: List<EnhancementFailureOutcome> = java.util.List.copyOf(failureOutcomes)
}
enum class EnhancementResultStatus {
APPLIED,
CONFLICT,
PROTECTED,
BLOCKED,
INSUFFICIENT_COST,
ECONOMY_REJECTED,
ECONOMY_UNKNOWN,
FAILED,
}
/** Immutable, platform-neutral terminal result. UNKNOWN never claims that external currency was charged. */
class EnhancementResult(
val requestId: UUID,
val playerId: UUID,
val itemInstanceId: UUID,
val status: EnhancementResultStatus,
val reason: String?,
val successful: Boolean?,
val beforeLevel: Int?,
val afterLevel: Int?,
val highestCheckpoint: Int?,
val schemeId: String?,
val rawDowngrade: Int?,
val protectedLevels: Int?,
localCosts: List<EnhancementItemCost>,
val economyClassification: String?,
val requestedCurrency: EnhancementCurrencyCost?,
val balanceBefore: String?,
val balanceAfter: String?,
milestones: List<String>,
finalContributions: List<String>,
) {
val localCosts: List<EnhancementItemCost> = java.util.List.copyOf(localCosts)
val milestones: List<String> = java.util.List.copyOf(milestones)
val finalContributions: List<String> = java.util.List.copyOf(finalContributions)
}