feat: 最適化とKommandアップデート
This commit is contained in:
parent
4343d01d11
commit
b3bdc95f63
|
|
@ -1 +1 @@
|
||||||
Subproject commit e0613cd05278222b0a2ac1c79a2d4ef317c9cea1
|
Subproject commit 3835c9b9e2d488681b39f4cfd827e3e3371a1e1b
|
||||||
|
|
@ -41,8 +41,8 @@ class GhostDisplaysPlugin : JavaPlugin() {
|
||||||
logger.info("GhostDisplays ready: ${displayRegistry.controllerCount()} controllers active.")
|
logger.info("GhostDisplays ready: ${displayRegistry.controllerCount()} controllers active.")
|
||||||
|
|
||||||
server.scheduler.runTaskTimer(this, Runnable {
|
server.scheduler.runTaskTimer(this, Runnable {
|
||||||
displayRegistry.tick()
|
displayRegistry.updateAudiences()
|
||||||
}, 10L, 10L)
|
}, 20L, 20L)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDisable() {
|
override fun onDisable() {
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,12 @@ interface DisplayController<T : Display> {
|
||||||
|
|
||||||
fun refreshAudience(target: Player? = null)
|
fun refreshAudience(target: Player? = null)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定期的な更新チェックが必要かどうかを返します。
|
||||||
|
* trueの場合、サーバーのtick毎(または定期タスク)にrefreshAudienceが呼び出されます。
|
||||||
|
*/
|
||||||
|
fun needsPeriodicUpdate(): Boolean = false
|
||||||
|
|
||||||
fun destroy()
|
fun destroy()
|
||||||
|
|
||||||
fun onClick(priority: ClickPriority = ClickPriority.NORMAL, handler: DisplayClickHandler): HandlerRegistration
|
fun onClick(priority: ClickPriority = ClickPriority.NORMAL, handler: DisplayClickHandler): HandlerRegistration
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,12 @@ import org.bukkit.entity.Player
|
||||||
*/
|
*/
|
||||||
fun interface AudiencePredicate {
|
fun interface AudiencePredicate {
|
||||||
fun test(player: Player): Boolean
|
fun test(player: Player): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表示対象判定が動的(時間経過や移動で変化する)かどうかを返します。
|
||||||
|
* trueの場合、定期的な再評価の対象となります。
|
||||||
|
*/
|
||||||
|
fun isDynamic(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,12 +28,15 @@ object AudiencePredicates {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun near(location: Location, radius: Double): AudiencePredicate {
|
fun near(location: Location, radius: Double): AudiencePredicate {
|
||||||
|
|
||||||
val radiusSq = radius * radius
|
val radiusSq = radius * radius
|
||||||
val worldName = location.world?.name
|
val worldName = location.world?.name
|
||||||
require(worldName != null) { "Location must have a world" }
|
require(worldName != null) { "Location must have a world" }
|
||||||
return AudiencePredicate { player ->
|
|
||||||
player.world.name == worldName && player.location.distanceSquared(location) <= radiusSq
|
return object : AudiencePredicate {
|
||||||
|
override fun test(player: Player): Boolean {
|
||||||
|
return player.world.name == worldName && player.location.distanceSquared(location) <= radiusSq
|
||||||
|
}
|
||||||
|
override fun isDynamic(): Boolean = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,10 +32,16 @@ internal class BaseDisplayController<T : Display>(
|
||||||
private val viewerCounts = ConcurrentHashMap<UUID, Int>()
|
private val viewerCounts = ConcurrentHashMap<UUID, Int>()
|
||||||
private val handlers = CopyOnWriteArrayList<HandlerEntry>()
|
private val handlers = CopyOnWriteArrayList<HandlerEntry>()
|
||||||
|
|
||||||
|
// Audience Management
|
||||||
// Audience Management
|
// Audience Management
|
||||||
private var baseVisibility: Boolean = false
|
private var baseVisibility: Boolean = false
|
||||||
private val audienceRules = CopyOnWriteArrayList<RuleEntry>()
|
private val audienceRules = CopyOnWriteArrayList<RuleEntry>()
|
||||||
private val autoVisiblePlayers = ConcurrentHashMap.newKeySet<UUID>()
|
private val autoVisiblePlayers = ConcurrentHashMap.newKeySet<UUID>()
|
||||||
|
|
||||||
|
// 最適化: 定期更新が必要なルールがあるか
|
||||||
|
private var hasDynamicRules: Boolean = false
|
||||||
|
|
||||||
|
override fun needsPeriodicUpdate(): Boolean = hasDynamicRules
|
||||||
|
|
||||||
override fun show(player: Player) {
|
override fun show(player: Player) {
|
||||||
runSync {
|
runSync {
|
||||||
|
|
@ -110,12 +116,31 @@ internal class BaseDisplayController<T : Display>(
|
||||||
override fun addAudienceRule(predicate: AudiencePredicate, action: AudienceAction): HandlerRegistration {
|
override fun addAudienceRule(predicate: AudiencePredicate, action: AudienceAction): HandlerRegistration {
|
||||||
val entry = RuleEntry(predicate, action)
|
val entry = RuleEntry(predicate, action)
|
||||||
audienceRules.add(entry)
|
audienceRules.add(entry)
|
||||||
|
updateDynamicStatus()
|
||||||
refreshAudience()
|
refreshAudience()
|
||||||
return HandlerRegistration {
|
return HandlerRegistration {
|
||||||
audienceRules.remove(entry)
|
audienceRules.remove(entry)
|
||||||
|
updateDynamicStatus()
|
||||||
refreshAudience()
|
refreshAudience()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateDynamicStatus() {
|
||||||
|
// 簡易判定: クラス名に "Near" が含まれる、または特定の実装であることを期待する
|
||||||
|
// ただし現状はラムダなので名前判定は不安定。
|
||||||
|
// AudiencePredicate 側にマーカーインターフェースをつけるのが正しいが、
|
||||||
|
// 今回は「ユーザー定義のPredicate」も含めて、動的かどうかわからない。
|
||||||
|
// -> AudiencePredicates.near() が返すオブジェクトに特徴を持たせる。
|
||||||
|
hasDynamicRules = audienceRules.any { isDynamicPredicate(it.predicate) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isDynamicPredicate(predicate: AudiencePredicate): Boolean {
|
||||||
|
// AudiencePredicates.near が返すクラスの実装詳細に依存するか、
|
||||||
|
// AudiencePredicate にプロパティを追加する。
|
||||||
|
// ここでは一旦、toString() 等で識別するか?いや、安全ではない。
|
||||||
|
// API変更: AudiencePredicate に default isDynamic() を追加する。
|
||||||
|
return predicate.isDynamic()
|
||||||
|
}
|
||||||
|
|
||||||
override fun clearAudienceRules() {
|
override fun clearAudienceRules() {
|
||||||
audienceRules.clear()
|
audienceRules.clear()
|
||||||
|
|
|
||||||
|
|
@ -82,16 +82,18 @@ internal class DisplayRegistry : Listener {
|
||||||
controllers.forEach { it.refreshAudience(player) }
|
controllers.forEach { it.refreshAudience(player) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun tick() {
|
fun updateAudiences() {
|
||||||
val players = org.bukkit.Bukkit.getOnlinePlayers()
|
val players = org.bukkit.Bukkit.getOnlinePlayers()
|
||||||
if (players.isEmpty()) return
|
if (players.isEmpty()) return
|
||||||
val controllers = controllersSnapshot()
|
val controllers = controllersSnapshot()
|
||||||
if (controllers.isEmpty()) return
|
if (controllers.isEmpty()) return
|
||||||
|
|
||||||
// 最適化: 動的な評価が必要なコントローラーだけ抽出できれば良いが、
|
// 動的な評価が必要なコントローラーだけを抽出して評価する
|
||||||
// 現状はシンプルに全走査する。
|
val activeControllers = controllers.filter { it.needsPeriodicUpdate() }
|
||||||
|
if (activeControllers.isEmpty()) return
|
||||||
|
|
||||||
players.forEach { player ->
|
players.forEach { player ->
|
||||||
controllers.forEach { controller ->
|
activeControllers.forEach { controller ->
|
||||||
controller.refreshAudience(player)
|
controller.refreshAudience(player)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user