feat: folia対応

This commit is contained in:
Keisuke Hirata 2026-03-11 19:38:36 +09:00
parent 15050e98d3
commit b985131011
5 changed files with 16 additions and 13 deletions

View File

@ -33,6 +33,7 @@ paper {
name = "GhostDisplays"
version = project.version as String
apiVersion = "1.21"
foliaSupported = true
description = "Invisible display entity controller library."
authors = listOf("Hareworks")
serverDependencies {

@ -1 +1 @@
Subproject commit 1e2476a27b7ad934c45f309042579a6f821ca24d
Subproject commit 9e1ee75736bbbecc7ef69f229c2bb55a8f4fbce8

View File

@ -35,7 +35,7 @@ class GhostDisplaysPlugin : JavaPlugin() {
instance = this
logger.info("GhostDisplays ready: ${displayRegistry.controllerCount()} controllers active.")
server.scheduler.runTaskTimer(this, Runnable {
server.globalRegionScheduler.runAtFixedRate(this, { _ ->
displayRegistry.updateAudiences()
}, 20L, 20L)
}

View File

@ -11,7 +11,6 @@ import org.bukkit.Bukkit
import org.bukkit.Location
import org.bukkit.entity.BlockDisplay
import org.bukkit.entity.Display
import org.bukkit.entity.Entity
import org.bukkit.entity.Interaction
import org.bukkit.entity.ItemDisplay
import org.bukkit.entity.TextDisplay
@ -61,14 +60,14 @@ internal class DefaultDisplayService(
interactionOptions: InteractionOptions,
afterSpawn: (T) -> Unit
): DisplayController<T> {
val entity = callSync {
val entity = callSync(location) {
val world = location.world ?: throw IllegalArgumentException("Location must have a world")
world.spawn(location, type) { spawned ->
spawned.setPersistent(false)
spawned.setVisibleByDefault(false)
}
}
callSync { afterSpawn(entity) }
callSync(location) { afterSpawn(entity) }
val interaction = if (interactionOptions.enabled) spawnInteraction(location, interactionOptions) else null
val controller = BaseDisplayController(plugin, entity, interaction, registry)
controllers += controller
@ -77,7 +76,7 @@ internal class DefaultDisplayService(
}
private fun spawnInteraction(location: Location, options: InteractionOptions): Interaction =
callSync {
callSync(location) {
val world = location.world ?: throw IllegalArgumentException("Location must have a world")
world.spawn(location, Interaction::class.java) { interaction ->
interaction.setPersistent(false)
@ -89,12 +88,15 @@ internal class DefaultDisplayService(
}
}
private fun <T> callSync(action: () -> T): T {
return if (Bukkit.isPrimaryThread()) {
private fun <T> callSync(location: Location, action: () -> T): T {
val world = location.world ?: throw IllegalArgumentException("Location has no world")
val chunkX = location.blockX shr 4
val chunkZ = location.blockZ shr 4
return if (Bukkit.isOwnedByCurrentRegion(world, chunkX, chunkZ)) {
action()
} else {
val future = CompletableFuture<T>()
Bukkit.getScheduler().runTask(plugin, Runnable { future.complete(action()) })
plugin.server.regionScheduler.run(plugin, location) { _ -> future.complete(action()) }
future.join()
}
}

View File

@ -213,19 +213,19 @@ internal class BaseDisplayController<T : Display>(
}
private fun runSync(action: () -> Unit) {
if (Bukkit.isPrimaryThread()) {
if (Bukkit.isOwnedByCurrentRegion(display)) {
action()
} else {
Bukkit.getScheduler().runTask(plugin, Runnable { action() })
display.scheduler.run(plugin, { action() }, null)
}
}
private fun <R> callSync(action: () -> R): R {
return if (Bukkit.isPrimaryThread()) {
return if (Bukkit.isOwnedByCurrentRegion(display)) {
action()
} else {
val future = CompletableFuture<R>()
Bukkit.getScheduler().runTask(plugin, Runnable { future.complete(action()) })
display.scheduler.run(plugin, { future.complete(action()) }, { future.cancel(false) })
future.join()
}
}