Stream command results before phase advancement (#6920)

This commit is contained in:
2026-06-03 14:17:05 -07:00
committed by GitHub
parent 488ffbf559
commit 80cbe1b60f
5 changed files with 74 additions and 14 deletions
@@ -57,6 +57,12 @@ trait Engine {
selectedCommand: SelectedCommand
): EngineAndResults
def postCommandWithoutUpdateChecks(
factionId: FactionId,
selectedProvinceId: ProvinceId,
selectedCommand: SelectedCommand
): EngineAndResults
/**
* Rewinds the game to a previous state by truncating history.
* @param targetActionCount
@@ -97,6 +97,20 @@ object EngineImpl {
results = results.map(_.actionResult)
)
)
def appliedResultsWithoutUpdateChecks(
engine: EngineImpl,
results: Vector[ActionResultWithResultingState]
): EngineAndResultsImpl =
EngineAndResultsImpl(
engine = engine.copy(
currentState = results.lastOption
.map(_.resultingState)
.getOrElse(engine.currentState),
history = engine.history.withNewResults(results)
),
results = results.map(_.actionResult)
)
}
final case class EngineAndResultsImpl(
@@ -277,7 +291,20 @@ case class EngineImpl(
factionId: FactionId,
selectedProvinceId: ProvinceId,
selectedCommand: SelectedCommand
): EngineAndResults = {
): EngineAndResults =
EngineImpl.withUpdateChecks(
postCommandWithoutUpdateChecks(
factionId = factionId,
selectedProvinceId = selectedProvinceId,
selectedCommand = selectedCommand
)
)
def postCommandWithoutUpdateChecks(
factionId: FactionId,
selectedProvinceId: ProvinceId,
selectedCommand: SelectedCommand
): EngineAndResultsImpl = {
// Get Scala commands directly from factory
val scalaCommandsByProvince =
availableCommandsFactory.availablePlayerCommands(currentState, factionId)
@@ -333,7 +360,7 @@ case class EngineImpl(
s"Result with type ${firstResult.map(_.actionResultType).getOrElse("unknown")} did not have a player set"
)
appliedResults(
EngineImpl.appliedResultsWithoutUpdateChecks(
engine = this,
results = sequencer.resultsWithStates.newValue
)
@@ -1187,7 +1187,7 @@ class GamesManager(
)
)
synchronizedHandlePostResults(
GameController.performAiCommands(
GameController.performAutomaticContinuation(
GameControllerWithPostResults(
gameController = afterHumanCommand.gameController,
postResults = PostResults(gameState = None, battles = Vector(), results = Vector())
@@ -1244,7 +1244,7 @@ class GamesManager(
this.synchronized {
if gameControllerInfos.contains(gameId) then
synchronizedHandlePostResults(
GameController.performAiCommands(
GameController.performAutomaticContinuation(
GameControllerWithPostResults(
gameController = gameControllerInfos(gameId).controller,
postResults = PostResults(gameState = None, battles = Vector(), results = Vector())
@@ -247,6 +247,20 @@ object GameController {
go(gameControllerWithPostResults)
}
def performAutomaticContinuation(
gameControllerWithPostResults: GameControllerWithPostResults
): GameControllerWithPostResults = {
val automaticUpdates = gameControllerWithPostResults.gameController
.withHandledEngineAndResults(gameControllerWithPostResults.gameController.engine.updated)
performAiCommands(
GameControllerWithPostResults(
gameController = automaticUpdates.gameController,
postResults = gameControllerWithPostResults.postResults.append(automaticUpdates.postResults)
)
)
}
private def humanClientsAfterUpdatingLlmStream(
humanClients: Vector[HumanPlayerClientConnectionState],
updatedText: ClientText,
@@ -591,15 +605,23 @@ final case class GameController(
factionId: FactionId,
selectedProvinceId: ProvinceId,
command: ScalaSelectedCommand,
@unused save: Boolean
@unused save: Boolean,
runUpdateChecks: Boolean = true
): GameControllerWithPostResults =
withHandledEngineAndResults(
engineAndResults = this.engine
.postCommand(
factionId = factionId,
selectedProvinceId = selectedProvinceId,
selectedCommand = command
)
engineAndResults =
if runUpdateChecks then
this.engine.postCommand(
factionId = factionId,
selectedProvinceId = selectedProvinceId,
selectedCommand = command
)
else
this.engine.postCommandWithoutUpdateChecks(
factionId = factionId,
selectedProvinceId = selectedProvinceId,
selectedCommand = command
)
)
def withNewAiClientWithFid(fid: FactionId): GameController =
@@ -1257,7 +1279,8 @@ final case class GameController(
factionId = client.get.factionId,
selectedProvinceId = selectedProvinceId,
command = SelectedCommandConverter.fromProto(command),
save = true
save = true,
runUpdateChecks = false
)
}
@@ -1267,7 +1290,7 @@ final case class GameController(
command: SelectedCommand,
token: Long
): GameControllerWithPostResults =
GameController.performAiCommands(
GameController.performAutomaticContinuation(
postHumanCommandOnly(
userId = userId,
selectedProvinceId = selectedProvinceId,
@@ -169,10 +169,14 @@ class GameControllerTest extends AnyFlatSpec with MockFactory with Matchers with
val command = ReturnSelectedCommand()
val mockEngineAndResults = mock[EngineAndResults]
mockEngine.postCommand
mockEngine.postCommandWithoutUpdateChecks
.expects(7, 0, ScalaSelectedCommand.ReturnSelected)
.returns(mockEngineAndResults)
.anyNumberOfTimes(): Unit
(() => mockEngine.updated)
.expects()
.returns(mockEngineAndResults)
.anyNumberOfTimes(): Unit
(() => mockEngineAndResults.engine)
.expects()
.returns(mockEngine)