DefaultBattleSessionActionSortingStrategy.kt
package io.github.lishangbu.avalon.game.battle.engine.core.session
import io.github.lishangbu.avalon.game.battle.engine.core.runtime.flow.BattleRuntimeSnapshot
/**
* 默认 battle session action 排序策略。
*
* 设计意图:
* - 在保留现有 `priority` 语义的基础上,把速度排序升级为可读取当前快照的有效速度;
* - 先接入 `tailwind / trick-room` 这组最常见速度规则;
* - 为后续继续补 battle type 差异化排序、随机 tie-break 与更完整优先级系统预留入口。
*/
class DefaultBattleSessionActionSortingStrategy(
private val actionSpeedResolver: BattleSessionActionSpeedResolver = BattleSessionActionSpeedResolver(),
) : BattleSessionActionSortingStrategy {
/**
* 对当前队列中的 action 进行排序。
*/
override fun sort(
snapshot: BattleRuntimeSnapshot,
actions: List<QueuedBattleSessionMoveAction>,
): List<BattleSessionAction> {
val reverseSpeedOrder = actionSpeedResolver.isSpeedOrderReversed(snapshot)
val sideOrderById =
snapshot.sides.keys
.withIndex()
.associate { indexed -> indexed.value to indexed.index }
return actions
.sortedWith { left, right ->
compareValuesBy(
left,
right,
{ queued -> -queued.action.priority },
{ queued ->
val speed = actionSpeedResolver.resolveEffectiveSpeed(snapshot, queued.action)
if (reverseSpeedOrder) speed else -speed
},
{ queued -> queued.action.kind.sortOrder },
{ queued -> sideOrder(snapshot, queued.action, sideOrderById) },
{ queued -> activeSlotOrder(snapshot, queued.action) },
QueuedBattleSessionMoveAction::enqueueOrder,
)
}.map(QueuedBattleSessionMoveAction::action)
}
private fun sideOrder(
snapshot: BattleRuntimeSnapshot,
action: BattleSessionAction,
sideOrderById: Map<String, Int>,
): Int {
val sideId =
when (action) {
is BattleSessionSideAction -> {
action.sideId
}
is BattleSessionSubmittingAction -> {
snapshot.sides.values
.firstOrNull { side -> action.submittingUnitId in side.unitIds }
?.id
}
else -> {
null
}
}
return sideId?.let { resolved -> sideOrderById[resolved] } ?: Int.MAX_VALUE
}
private fun activeSlotOrder(
snapshot: BattleRuntimeSnapshot,
action: BattleSessionAction,
): Int {
val unitId =
when (action) {
is BattleSessionSubmittingAction -> action.submittingUnitId
else -> null
} ?: return Int.MAX_VALUE
val side = snapshot.sides.values.firstOrNull { current -> unitId in current.unitIds } ?: return Int.MAX_VALUE
return side.activeUnitIds.indexOf(unitId).let { index -> if (index >= 0) index else Int.MAX_VALUE }
}
}