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
# Ignore Gradle build output directory
bin
build

View File

@ -39,6 +39,12 @@ class GhostDisplaysPlugin : JavaPlugin() {
instance = this
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() {

View File

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

View File

@ -79,7 +79,7 @@ class DisplayManager(
ensureIdAvailable(normalized)
val safeLocation = location.clone()
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(
id = normalized,
controller = controller,
@ -115,7 +115,7 @@ class DisplayManager(
fun updateItem(id: String, itemStack: ItemStack) {
val display = requireItem(id)
val clone = itemStack.clone()
display.controller.applyEntityUpdate { it.itemStack = clone }
display.controller.applyEntityUpdate { it.setItemStack(clone) }
display.itemStack = clone
}

View File

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

View File

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

View File

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

View File

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