From 9673e1e6e9a50182604ecbce08459413e1d3f31f Mon Sep 17 00:00:00 2001 From: Hare Date: Wed, 11 Mar 2026 17:15:56 +0900 Subject: [PATCH] feat: Folia support --- .../bukkit/AttachmentSynchronizer.kt | 4 ++-- .../permits_lib/util/ThreadChecks.kt | 23 +++++++++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/net/hareworks/permits_lib/bukkit/AttachmentSynchronizer.kt b/src/main/kotlin/net/hareworks/permits_lib/bukkit/AttachmentSynchronizer.kt index d96c0b9..c4064ed 100644 --- a/src/main/kotlin/net/hareworks/permits_lib/bukkit/AttachmentSynchronizer.kt +++ b/src/main/kotlin/net/hareworks/permits_lib/bukkit/AttachmentSynchronizer.kt @@ -25,7 +25,7 @@ class AttachmentSynchronizer( permissible: Permissible, patch: AttachmentPatch, ) { - ThreadChecks.ensurePrimaryThread("AttachmentSynchronizer.applyPatch") + ThreadChecks.ensureRegionThread("AttachmentSynchronizer.applyPatch", permissible) if (patch.changes.isEmpty()) return val handle = ensureHandle(permissible) patch.changes.forEach { (id, value) -> @@ -58,7 +58,7 @@ class AttachmentSynchronizer( } fun clear(permissible: Permissible) { - ThreadChecks.ensurePrimaryThread("AttachmentSynchronizer.clear") + ThreadChecks.ensureRegionThread("AttachmentSynchronizer.clear", permissible) handles.remove(permissible)?.attachment?.remove() } diff --git a/src/main/kotlin/net/hareworks/permits_lib/util/ThreadChecks.kt b/src/main/kotlin/net/hareworks/permits_lib/util/ThreadChecks.kt index b2f380a..b1e7afa 100644 --- a/src/main/kotlin/net/hareworks/permits_lib/util/ThreadChecks.kt +++ b/src/main/kotlin/net/hareworks/permits_lib/util/ThreadChecks.kt @@ -1,11 +1,30 @@ package net.hareworks.permits_lib.util import org.bukkit.Bukkit +import org.bukkit.entity.Player +import org.bukkit.permissions.Permissible internal object ThreadChecks { + /** + * For Bukkit-global operations (e.g. PluginManager permission registration). + * In Folia there is no single primary thread; callers should ensure they run + * on the global region scheduler (e.g. during onEnable / onDisable). + */ fun ensurePrimaryThread(action: String) { - check(Bukkit.isPrimaryThread()) { - "$action must be invoked from the primary server thread." + // no-op for global ops: Folia has no single primary thread. + // PluginManager operations are safe when called from onEnable/onDisable + // or from the global region scheduler. + } + + /** + * For player-bound operations (e.g. PermissionAttachment mutation). + * Verifies that the current thread owns the region for the given [permissible]. + * Non-player permissibles are skipped since they have no region owner. + */ + fun ensureRegionThread(action: String, permissible: Permissible) { + val player = permissible as? Player ?: return + check(Bukkit.isOwnedByCurrentRegion(player)) { + "Action '$action' must be called on the owning region thread for ${player.name}" } } }