BattleSessionSetupCoordinator.kt
package io.github.lishangbu.avalon.game.battle.engine.core.session
import io.github.lishangbu.avalon.game.battle.engine.core.model.BattleLifecycle
import io.github.lishangbu.avalon.game.battle.engine.core.model.BattleType
import io.github.lishangbu.avalon.game.battle.engine.core.model.SideState
import io.github.lishangbu.avalon.game.battle.engine.core.model.UnitState
import io.github.lishangbu.avalon.game.battle.engine.core.runtime.flow.BattleRuntimeSnapshot
/**
* BattleSession 建局与状态恢复协调器。
*
* 设计意图:
* - 把 `start/register/configure/restore/settle` 这一组初始化与会话外壳管理逻辑
* 从 `BattleSession` 主体中拆出去;
* - 让主类把注意力放在“回合执行”和“生命周期推进”上;
* - 保持现有公开 API 不变,仅调整内部职责分布。
*/
internal class BattleSessionSetupCoordinator(
private val session: BattleSession,
) {
/**
* 导出当前可持久化状态。
*/
fun exportState(): BattleSessionState =
BattleSessionState(
snapshot = session.currentSnapshot,
pendingActions = session.pendingActions(),
replacementRequests = session.pendingReplacementRequests(),
resourceLedger = session.resourceLedger(),
battleLogs = session.battleLogs(),
eventLogs = session.eventLogs(),
)
/**
* 用已持久化状态恢复当前 session。
*/
fun restoreState(state: BattleSessionState): BattleRuntimeSnapshot {
session.currentSnapshot = state.snapshot
session.actionQueue.replaceAll(state.pendingActions)
session.replacementRequests.clear()
session.replacementRequests += state.replacementRequests
session.resourceLedger.clear()
session.resourceLedger += state.resourceLedger
session.battleLogs.clear()
session.battleLogs += state.battleLogs
session.eventLogs.clear()
session.eventLogs += state.eventLogs
return session.currentSnapshot
}
/**
* 启动 battle session。
*/
fun start(): BattleRuntimeSnapshot {
session.ensureInitializing()
// 一旦 start,整场 battle 就从结构搭建阶段切到正式运行阶段。
val battle =
session.currentSnapshot.battle.copy(
turn = 1,
lifecycle = BattleLifecycle.RUNNING,
)
session.currentSnapshot = session.currentSnapshot.copy(battle = battle)
session.recordLog("Battle ${battle.id} started at turn ${battle.turn}.")
session.recordEvent(BattleSessionStartedPayload)
return session.currentSnapshot
}
/**
* 注册一个 side。
*/
fun registerSide(sideId: String): BattleRuntimeSnapshot {
session.ensureInitializing()
val nextSides = session.currentSnapshot.sides + (sideId to SideState(id = sideId))
session.currentSnapshot = session.currentSnapshot.copy(sides = nextSides)
session.recordLog("Registered side $sideId.")
session.recordEvent(BattleSessionSideRegisteredPayload(sideId = sideId))
return session.currentSnapshot
}
/**
* 配置当前 battle 的业务语义。
*/
fun configureBattle(
battleKind: BattleType,
capturableSideId: String? = null,
): BattleRuntimeSnapshot {
session.ensureInitializing()
session.currentSnapshot =
session.currentSnapshot.copy(
battle =
session.currentSnapshot.battle.copy(
battleKind = battleKind,
capturableSideId = capturableSideId,
),
)
session.recordLog("Configured battle kind=${battleKind.name} capturableSideId=$capturableSideId.")
return session.currentSnapshot
}
/**
* 注册一个单位并挂到指定 side。
*/
fun registerUnit(
sideId: String,
unit: UnitState,
active: Boolean = true,
): BattleRuntimeSnapshot {
session.ensureInitializing()
val side =
requireNotNull(session.currentSnapshot.sides[sideId]) {
"Side '$sideId' must be registered before units can be added."
}
val nextUnits = session.currentSnapshot.units + (unit.id to unit)
val nextSide =
if (active) {
side.copy(
unitIds = (side.unitIds + unit.id).distinct(),
activeUnitIds = (side.activeUnitIds + unit.id).distinct(),
)
} else {
side.copy(unitIds = (side.unitIds + unit.id).distinct())
}
session.currentSnapshot =
session.currentSnapshot.copy(
units = nextUnits,
sides = session.currentSnapshot.sides + (sideId to nextSide),
)
session.recordLog("Registered unit ${unit.id} to side $sideId.")
session.recordEvent(
BattleSessionUnitRegisteredPayload(
sideId = sideId,
unitId = unit.id,
active = active,
),
)
return session.currentSnapshot
}
/**
* 标记当前 battle 已完成结算。
*/
fun markSettled(): BattleRuntimeSnapshot {
session.ensureEndedUnsettled()
// 只有“已结束但未结算”的 battle 才允许推进到最终结算完成态。
session.currentSnapshot =
session.currentSnapshot.copy(
battle =
session.currentSnapshot.battle.copy(
lifecycle = BattleLifecycle.SETTLED,
),
)
session.recordLog("Battle settlement completed.")
return session.currentSnapshot
}
}