102 lines
3.8 KiB
Kotlin
102 lines
3.8 KiB
Kotlin
package net.hareworks.ghostdisplays.internal
|
|
|
|
import java.util.concurrent.CompletableFuture
|
|
import java.util.concurrent.CopyOnWriteArraySet
|
|
import net.hareworks.ghostdisplays.api.DisplayController
|
|
import net.hareworks.ghostdisplays.api.DisplayService
|
|
import net.hareworks.ghostdisplays.api.InteractionOptions
|
|
import net.hareworks.ghostdisplays.internal.controller.BaseDisplayController
|
|
import net.hareworks.ghostdisplays.internal.controller.DisplayRegistry
|
|
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
|
|
import org.bukkit.inventory.ItemStack
|
|
import org.bukkit.plugin.java.JavaPlugin
|
|
|
|
internal class DefaultDisplayService(
|
|
private val plugin: JavaPlugin,
|
|
private val registry: DisplayRegistry
|
|
) : DisplayService {
|
|
private val controllers = CopyOnWriteArraySet<BaseDisplayController<out Display>>()
|
|
|
|
override fun createTextDisplay(
|
|
location: Location,
|
|
interaction: InteractionOptions,
|
|
builder: TextDisplay.() -> Unit
|
|
): DisplayController<TextDisplay> = spawnDisplay(location, TextDisplay::class.java, interaction) {
|
|
builder(it)
|
|
}
|
|
|
|
override fun createBlockDisplay(
|
|
location: Location,
|
|
interaction: InteractionOptions,
|
|
builder: BlockDisplay.() -> Unit
|
|
): DisplayController<BlockDisplay> = spawnDisplay(location, BlockDisplay::class.java, interaction) {
|
|
builder(it)
|
|
}
|
|
|
|
override fun createItemDisplay(
|
|
location: Location,
|
|
itemStack: ItemStack,
|
|
interaction: InteractionOptions,
|
|
builder: ItemDisplay.() -> Unit
|
|
): DisplayController<ItemDisplay> = spawnDisplay(location, ItemDisplay::class.java, interaction) {
|
|
it.itemStack = itemStack.clone()
|
|
builder(it)
|
|
}
|
|
|
|
override fun destroyAll() {
|
|
controllers.forEach { it.destroy() }
|
|
controllers.clear()
|
|
}
|
|
|
|
private fun <T : Display> spawnDisplay(
|
|
location: Location,
|
|
type: Class<T>,
|
|
interactionOptions: InteractionOptions,
|
|
afterSpawn: (T) -> Unit
|
|
): DisplayController<T> {
|
|
val entity = callSync {
|
|
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) }
|
|
val interaction = if (interactionOptions.enabled) spawnInteraction(location, interactionOptions) else null
|
|
val controller = BaseDisplayController(plugin, entity, interaction, registry)
|
|
controllers += controller
|
|
registry.register(controller)
|
|
return controller
|
|
}
|
|
|
|
private fun spawnInteraction(location: Location, options: InteractionOptions): Interaction =
|
|
callSync {
|
|
val world = location.world ?: throw IllegalArgumentException("Location must have a world")
|
|
world.spawn(location, Interaction::class.java) { interaction ->
|
|
interaction.setPersistent(false)
|
|
interaction.setInvisible(true)
|
|
interaction.setVisibleByDefault(false)
|
|
interaction.setResponsive(options.responsive)
|
|
interaction.setInteractionWidth(options.effectiveWidth().toFloat())
|
|
interaction.setInteractionHeight(options.effectiveHeight().toFloat())
|
|
}
|
|
}
|
|
|
|
private fun <T> callSync(action: () -> T): T {
|
|
return if (Bukkit.isPrimaryThread()) {
|
|
action()
|
|
} else {
|
|
val future = CompletableFuture<T>()
|
|
Bukkit.getScheduler().runTask(plugin) { future.complete(action()) }
|
|
future.join()
|
|
}
|
|
}
|
|
}
|