feat: pose対応

This commit is contained in:
Keisuke Hirata 2025-12-07 03:22:12 +09:00
parent 4a302f5f6f
commit cf4332ed1a
15 changed files with 72 additions and 15 deletions

4
.gitignore vendored
View File

@ -1,5 +1,3 @@
# Ignore Gradle project-specific cache directory
.gradle .gradle
bin
# Ignore Gradle build output directory
build build

View File

@ -39,6 +39,12 @@ class GhostDisplaysPlugin : JavaPlugin() {
instance = this instance = this
logger.info("GhostDisplays ready: ${displayRegistry.controllerCount()} controllers active.") logger.info("GhostDisplays ready: ${displayRegistry.controllerCount()} controllers active.")
server.scheduler.runTaskTimer(this, Runnable {
server.onlinePlayers.forEach { player ->
displayRegistry.refreshAudiences(player)
}
}, 20L, 20L)
} }
override fun onDisable() { override fun onDisable() {

View File

@ -111,6 +111,9 @@ object CommandRegistrar {
literal("delete") { literal("delete") {
string("id") { string("id") {
suggests { prefix ->
manager.listDisplays().map { it.id }.filter { it.startsWith(prefix, ignoreCase = true) }
}
executes { executes {
val id = argument<String>("id") val id = argument<String>("id")
try { try {
@ -139,6 +142,9 @@ object CommandRegistrar {
literal("info") { literal("info") {
string("id") { string("id") {
suggests { prefix ->
manager.listDisplays().map { it.id }.filter { it.startsWith(prefix, ignoreCase = true) }
}
executes { executes {
val id = argument<String>("id") val id = argument<String>("id")
val display = manager.findDisplay(id) val display = manager.findDisplay(id)
@ -161,6 +167,9 @@ object CommandRegistrar {
literal("viewer") { literal("viewer") {
literal("add") { literal("add") {
string("id") { string("id") {
suggests { prefix ->
manager.listDisplays().map { it.id }.filter { it.startsWith(prefix, ignoreCase = true) }
}
players("targets") { players("targets") {
executes { executes {
val id = argument<String>("id") val id = argument<String>("id")
@ -177,6 +186,9 @@ object CommandRegistrar {
} }
literal("remove") { literal("remove") {
string("id") { string("id") {
suggests { prefix ->
manager.listDisplays().map { it.id }.filter { it.startsWith(prefix, ignoreCase = true) }
}
players("targets") { players("targets") {
executes { executes {
val id = argument<String>("id") val id = argument<String>("id")
@ -193,6 +205,9 @@ object CommandRegistrar {
} }
literal("clear") { literal("clear") {
string("id") { string("id") {
suggests { prefix ->
manager.listDisplays().map { it.id }.filter { it.startsWith(prefix, ignoreCase = true) }
}
executes { executes {
val id = argument<String>("id") val id = argument<String>("id")
try { try {
@ -209,6 +224,12 @@ object CommandRegistrar {
literal("text") { literal("text") {
literal("edit") { literal("edit") {
string("id") { string("id") {
suggests { prefix ->
manager.listDisplays()
.filter { it.kind == DisplayKind.TEXT }
.map { it.id }
.filter { it.startsWith(prefix, ignoreCase = true) }
}
executes { executes {
val player = sender.requirePlayer() ?: return@executes val player = sender.requirePlayer() ?: return@executes
val id = argument<String>("id") val id = argument<String>("id")
@ -224,6 +245,12 @@ object CommandRegistrar {
} }
literal("set") { literal("set") {
string("id") { string("id") {
suggests { prefix ->
manager.listDisplays()
.filter { it.kind == DisplayKind.TEXT }
.map { it.id }
.filter { it.startsWith(prefix, ignoreCase = true) }
}
string("content") { string("content") {
executes { executes {
val id = argument<String>("id") val id = argument<String>("id")
@ -254,6 +281,12 @@ object CommandRegistrar {
literal("block") { literal("block") {
literal("set") { literal("set") {
string("id") { string("id") {
suggests { prefix ->
manager.listDisplays()
.filter { it.kind == DisplayKind.BLOCK }
.map { it.id }
.filter { it.startsWith(prefix, ignoreCase = true) }
}
string("state") { string("state") {
executes { executes {
val id = argument<String>("id") val id = argument<String>("id")
@ -276,6 +309,12 @@ object CommandRegistrar {
literal("item") { literal("item") {
literal("set") { literal("set") {
string("id") { string("id") {
suggests { prefix ->
manager.listDisplays()
.filter { it.kind == DisplayKind.ITEM }
.map { it.id }
.filter { it.startsWith(prefix, ignoreCase = true) }
}
string("material") { string("material") {
executes { executes {
val id = argument<String>("id") val id = argument<String>("id")
@ -301,6 +340,9 @@ object CommandRegistrar {
literal("permission") { literal("permission") {
literal("add") { literal("add") {
string("id") { string("id") {
suggests { prefix ->
manager.listDisplays().map { it.id }.filter { it.startsWith(prefix, ignoreCase = true) }
}
string("permission") { string("permission") {
executes { executes {
val id = argument<String>("id") val id = argument<String>("id")
@ -317,6 +359,9 @@ object CommandRegistrar {
} }
literal("remove") { literal("remove") {
string("id") { string("id") {
suggests { prefix ->
manager.listDisplays().map { it.id }.filter { it.startsWith(prefix, ignoreCase = true) }
}
string("permission") { string("permission") {
executes { executes {
val id = argument<String>("id") val id = argument<String>("id")
@ -337,6 +382,9 @@ object CommandRegistrar {
literal("near") { literal("near") {
literal("set") { literal("set") {
string("id") { string("id") {
suggests { prefix ->
manager.listDisplays().map { it.id }.filter { it.startsWith(prefix, ignoreCase = true) }
}
float("radius", min = 1.0) { float("radius", min = 1.0) {
executes { executes {
val id = argument<String>("id") val id = argument<String>("id")
@ -354,6 +402,9 @@ object CommandRegistrar {
} }
literal("clear") { literal("clear") {
string("id") { string("id") {
suggests { prefix ->
manager.listDisplays().map { it.id }.filter { it.startsWith(prefix, ignoreCase = true) }
}
executes { executes {
val id = argument<String>("id") val id = argument<String>("id")
try { try {
@ -379,8 +430,11 @@ private fun CommandSender.showUsage() {
info(" /ghostdisplay list | info <id> | delete <id>") info(" /ghostdisplay list | info <id> | delete <id>")
} }
private fun Player.anchorLocation(): Location = private fun Player.anchorLocation(): Location {
eyeLocation.clone().add(direction.normalize().multiply(1.5)) val eye = eyeLocation.clone()
val forward = eye.direction.normalize().multiply(1.5)
return eye.add(forward)
}
private fun parseBlockData(state: String): BlockData = private fun parseBlockData(state: String): BlockData =
Bukkit.createBlockData(state) Bukkit.createBlockData(state)

View File

@ -79,7 +79,7 @@ class DisplayManager(
ensureIdAvailable(normalized) ensureIdAvailable(normalized)
val safeLocation = location.clone() val safeLocation = location.clone()
val controller = service.createItemDisplay(safeLocation, itemStack.clone(), INTERACTION_DEFAULT) val controller = service.createItemDisplay(safeLocation, itemStack.clone(), INTERACTION_DEFAULT)
controller.applyEntityUpdate { it.itemStack = itemStack.clone() } controller.applyEntityUpdate { it.setItemStack(itemStack.clone()) }
val managed = ManagedDisplay.Item( val managed = ManagedDisplay.Item(
id = normalized, id = normalized,
controller = controller, controller = controller,
@ -115,7 +115,7 @@ class DisplayManager(
fun updateItem(id: String, itemStack: ItemStack) { fun updateItem(id: String, itemStack: ItemStack) {
val display = requireItem(id) val display = requireItem(id)
val clone = itemStack.clone() val clone = itemStack.clone()
display.controller.applyEntityUpdate { it.itemStack = clone } display.controller.applyEntityUpdate { it.setItemStack(clone) }
display.itemStack = clone display.itemStack = clone
} }

View File

@ -37,7 +37,7 @@ class EditSessionManager(
event.player.sendMessage("GhostDisplays: editing for '$displayId' cancelled.") event.player.sendMessage("GhostDisplays: editing for '$displayId' cancelled.")
return return
} }
Bukkit.getScheduler().runTask(plugin) { Bukkit.getScheduler().runTask(plugin, Runnable {
try { try {
manager.updateText(displayId, message) manager.updateText(displayId, message)
event.player.sendMessage("GhostDisplays: updated text for '$displayId'.") event.player.sendMessage("GhostDisplays: updated text for '$displayId'.")
@ -46,7 +46,7 @@ class EditSessionManager(
} finally { } finally {
sessions.remove(event.player.uniqueId) sessions.remove(event.player.uniqueId)
} }
} })
} }
@EventHandler @EventHandler

View File

@ -46,7 +46,7 @@ internal class DefaultDisplayService(
interaction: InteractionOptions, interaction: InteractionOptions,
builder: ItemDisplay.() -> Unit builder: ItemDisplay.() -> Unit
): DisplayController<ItemDisplay> = spawnDisplay(location, ItemDisplay::class.java, interaction) { ): DisplayController<ItemDisplay> = spawnDisplay(location, ItemDisplay::class.java, interaction) {
it.itemStack = itemStack.clone() it.setItemStack(itemStack.clone())
builder(it) builder(it)
} }
@ -94,7 +94,7 @@ internal class DefaultDisplayService(
action() action()
} else { } else {
val future = CompletableFuture<T>() val future = CompletableFuture<T>()
Bukkit.getScheduler().runTask(plugin) { future.complete(action()) } Bukkit.getScheduler().runTask(plugin, Runnable { future.complete(action()) })
future.join() future.join()
} }
} }

View File

@ -64,7 +64,6 @@ internal class BaseDisplayController<T : Display>(
override fun applyEntityUpdate(mutator: (T) -> Unit) { override fun applyEntityUpdate(mutator: (T) -> Unit) {
callSync { callSync {
mutator(display) mutator(display)
display.updateDisplay(false)
} }
} }
@ -143,7 +142,7 @@ internal class BaseDisplayController<T : Display>(
if (Bukkit.isPrimaryThread()) { if (Bukkit.isPrimaryThread()) {
action() action()
} else { } else {
Bukkit.getScheduler().runTask(plugin, action) Bukkit.getScheduler().runTask(plugin, Runnable { action() })
} }
} }
@ -152,7 +151,7 @@ internal class BaseDisplayController<T : Display>(
action() action()
} else { } else {
val future = CompletableFuture<R>() val future = CompletableFuture<R>()
Bukkit.getScheduler().runTask(plugin) { future.complete(action()) } Bukkit.getScheduler().runTask(plugin, Runnable { future.complete(action()) })
future.join() future.join()
} }
} }

View File

@ -76,7 +76,7 @@ internal class DisplayRegistry : Listener {
private fun controllersSnapshot(): Collection<BaseDisplayController<out Display>> = private fun controllersSnapshot(): Collection<BaseDisplayController<out Display>> =
displayControllers.values.toSet() displayControllers.values.toSet()
private fun refreshAudiences(player: Player) { internal fun refreshAudiences(player: Player) {
val controllers = controllersSnapshot() val controllers = controllersSnapshot()
if (controllers.isEmpty()) return if (controllers.isEmpty()) return
controllers.forEach { it.refreshAudience(player) } controllers.forEach { it.refreshAudience(player) }