mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-28 21:35:42 +00:00
Print selected command templates (#8454)
This commit is contained in:
@@ -37,7 +37,7 @@ commands
|
||||
commands-json
|
||||
```
|
||||
|
||||
`state` is the concise map and owned-province view. `state-json` prints the complete view. `commands-json` includes the exact fields, IDs, resource amounts, and command choices currently accepted by the server.
|
||||
`state` is the concise map and owned-province view. `state-json` prints the complete view. `commands-json` includes the exact fields, IDs, resource amounts, and command choices currently accepted by the server. Each entry also includes a `post-json` template for its corresponding selected command.
|
||||
|
||||
Generated text is stored locally during the client process. Use `text <text-id>` for a text ID without spaces, such as `text hn_105`. Province leaders in `state` are resolved through this store when their names have been received.
|
||||
|
||||
@@ -49,6 +49,12 @@ Use the available-command data from `commands-json` to select a command, then po
|
||||
post-json <province-id> <SelectedCommandType> <JSON>
|
||||
```
|
||||
|
||||
Templates contain the accepted JSON field names and default values. Replace zero
|
||||
IDs, `UNKNOWN` enum values, empty collections, and other placeholders with a legal
|
||||
choice from the available-command payload before posting. Where a selected command
|
||||
must echo server data, such as a ransom offer, the client copies that data into the
|
||||
template automatically.
|
||||
|
||||
For example:
|
||||
|
||||
```text
|
||||
@@ -57,7 +63,7 @@ post-rest 13
|
||||
post-feast 13
|
||||
```
|
||||
|
||||
The client has shortcuts for `post-rest`, `post-return`, `post-feast`, riot decisions, and battle aftermath. Other selected-command JSON schemas are defined in:
|
||||
The client has shortcuts for `post-rest`, `post-return`, `post-feast`, riot decisions, and battle aftermath. The authoritative selected-command schemas are defined in:
|
||||
|
||||
```text
|
||||
src/main/protobuf/net/eagle0/eagle/api/selected_command.proto
|
||||
|
||||
@@ -13,6 +13,7 @@ import io.grpc.{ManagedChannel, ManagedChannelBuilder, Metadata}
|
||||
import io.grpc.stub.{MetadataUtils, StreamObserver}
|
||||
import net.eagle0.eagle.api.available_command.AvailableCommand as AvailableCommandProto
|
||||
import net.eagle0.eagle.api.available_command.MarchAvailableCommand
|
||||
import net.eagle0.eagle.api.available_command as ac
|
||||
import net.eagle0.eagle.api.command.AvailableCommands
|
||||
import net.eagle0.eagle.api.eagle.*
|
||||
import net.eagle0.eagle.api.eagle.EagleGrpc.EagleStub
|
||||
@@ -28,7 +29,7 @@ import net.eagle0.eagle.views.province_view.{FullProvinceInfo, FullProvinceInfoD
|
||||
import net.eagle0.shardok.api.command_descriptor.{AvailableCommands as ShardokAvailableCommands, CommandDescriptor}
|
||||
import net.eagle0.shardok.api.unit_view.UnitView
|
||||
import scalapb.{GeneratedMessage, GeneratedMessageCompanion}
|
||||
import scalapb.json4s.JsonFormat
|
||||
import scalapb.json4s.{JsonFormat, Printer}
|
||||
|
||||
object EagleTextClient {
|
||||
private val AuthorizationKey: Metadata.Key[String] =
|
||||
@@ -1030,7 +1031,11 @@ final class ClientState {
|
||||
val commandLines = oneProvince.commands.zipWithIndex.map {
|
||||
case (cmd, index) =>
|
||||
val prefix = s" [$index] ${commandName(cmd)}"
|
||||
if rawJson then s"$prefix ${commandJson(cmd)}" else prefix
|
||||
if rawJson then
|
||||
val (selectedType, json) = selectedCommandTemplate(cmd)
|
||||
val template = s"\n post-json $provinceId $selectedType $json"
|
||||
s"$prefix ${commandJson(cmd)}$template"
|
||||
else prefix
|
||||
}
|
||||
s"province $provinceId suggested=${oneProvince.suggestedCommandIndex}" +: commandLines
|
||||
}
|
||||
@@ -1114,6 +1119,32 @@ final class ClientState {
|
||||
private def toJson(message: GeneratedMessage): String =
|
||||
JsonFormat.toJsonString(message)
|
||||
|
||||
private def selectedCommandTemplate(command: AvailableCommandProto): (String, String) = {
|
||||
val selectedType = commandName(command).replace("AvailableCommand", "SelectedCommand")
|
||||
val selected = command match {
|
||||
case ransom: ac.ResolveRansomOfferAvailableCommand =>
|
||||
ransom.offers.headOption
|
||||
.map(offer =>
|
||||
sc.ResolveRansomOfferSelectedCommand(
|
||||
offeringFactionId = offer.originatingFactionId,
|
||||
ransomOffer = Some(offer),
|
||||
resolution = offer.status
|
||||
)
|
||||
)
|
||||
.getOrElse(selectedCommandDefault(selectedType))
|
||||
case _ => selectedCommandDefault(selectedType)
|
||||
}
|
||||
|
||||
selectedType -> Printer().includingDefaultValueFields.print(selected)
|
||||
}
|
||||
|
||||
private def selectedCommandDefault(selectedType: String): GeneratedMessage =
|
||||
Try {
|
||||
val companionClass = Class.forName(s"net.eagle0.eagle.api.selected_command.$selectedType$$")
|
||||
val companion = companionClass.getField("MODULE$").get(null).asInstanceOf[GeneratedMessageCompanion[?]]
|
||||
companion.defaultInstance.asInstanceOf[GeneratedMessage]
|
||||
}.getOrElse(throw new IllegalArgumentException(s"No selected-command type found for $selectedType"))
|
||||
|
||||
private def shardokCommandSummary(command: CommandDescriptor, rawJson: Boolean): String = {
|
||||
val actor = command.actor.map(_.toString).getOrElse("-")
|
||||
val target = command.target.map(c => s"(${c.row},${c.column})").getOrElse("-")
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package net.eagle0.eagle.text_client
|
||||
|
||||
import net.eagle0.eagle.api.available_command.{ImproveAvailableCommand, ResolveRansomOfferAvailableCommand}
|
||||
import net.eagle0.eagle.api.command.{AvailableCommands as EagleAvailableCommands, OneProvinceAvailableCommands}
|
||||
import net.eagle0.eagle.api.eagle.{ActionResultResponse, GameUpdate, ShardokActionResultResponse, UpdateStreamResponse}
|
||||
import net.eagle0.eagle.common.diplomacy_offer.DiplomacyOffer
|
||||
import net.eagle0.eagle.common.diplomacy_offer_status.DiplomacyOfferStatus
|
||||
import net.eagle0.eagle.views.action_result_view.ActionResultView
|
||||
import net.eagle0.eagle.views.game_state_view.{GameStateView, GameStateViewDiff}
|
||||
import net.eagle0.eagle.views.province_view.{ProvinceView, ProvinceViewDiff}
|
||||
@@ -52,6 +56,28 @@ class ClientStateTest extends AnyFlatSpec with Matchers {
|
||||
currentCommand = Vector(CommandDescriptor(player = 3))
|
||||
)
|
||||
|
||||
private def eagleCommandsUpdate(commands: Vector[net.eagle0.eagle.api.available_command.AvailableCommand]) =
|
||||
UpdateStreamResponse(
|
||||
UpdateStreamResponse.ResponseDetails.GameUpdate(
|
||||
GameUpdate(
|
||||
gameId = 1L,
|
||||
gameUpdateDetails = GameUpdate.GameUpdateDetails.ActionResultResponse(
|
||||
ActionResultResponse(
|
||||
unfilteredResultCountAfter = 1,
|
||||
availableCommands = Some(
|
||||
EagleAvailableCommands(
|
||||
token = 1L,
|
||||
commandsByProvince = Map(
|
||||
12 -> OneProvinceAvailableCommands(provinceId = 12, commands = commands)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
"ClientTextStore" should "resume UTF-8 streaming text from byte offsets" in {
|
||||
val store = new ClientTextStore
|
||||
|
||||
@@ -174,4 +200,41 @@ class ClientStateTest extends AnyFlatSpec with Matchers {
|
||||
state.describeShardokCommands(rawJson = false) shouldBe "No Shardok battles yet."
|
||||
state.shardokCommandPost(Some("battle-1"), index = 0) shouldBe None
|
||||
}
|
||||
|
||||
it should "include selected command templates in JSON command output" in {
|
||||
val state = new ClientState
|
||||
state.handle(startingState())
|
||||
state.handle(eagleCommandsUpdate(Vector(ImproveAvailableCommand(actingProvinceId = 12))))
|
||||
|
||||
val output = state.describeCommands(rawJson = true)
|
||||
output should include("post-json 12 ImproveSelectedCommand")
|
||||
output should include("\"actingHeroId\":0")
|
||||
output should include("\"lockType\":false")
|
||||
}
|
||||
|
||||
it should "copy a ransom offer into its selected command template" in {
|
||||
val state = new ClientState
|
||||
state.handle(startingState())
|
||||
state.handle(
|
||||
eagleCommandsUpdate(
|
||||
Vector(
|
||||
ResolveRansomOfferAvailableCommand(
|
||||
offers = Vector(
|
||||
DiplomacyOffer(
|
||||
originatingFactionId = 2,
|
||||
targetFactionId = 3,
|
||||
status = DiplomacyOfferStatus.DIPLOMACY_OFFER_STATUS_UNRESOLVED
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val output = state.describeCommands(rawJson = true)
|
||||
output should include("post-json 12 ResolveRansomOfferSelectedCommand")
|
||||
output should include("\"offeringFactionId\":2")
|
||||
output should include("\"ransomOffer\":{")
|
||||
output should include("\"originatingFactionId\":2")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user