feat(api-gdext): Introduce suggest endpoints in player_api.rs for GDExt simulator autocompletion

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
autocommit 2026-05-20 18:12:13 -07:00
parent d968ecb2ca
commit d19db31ccd

View file

@ -25,7 +25,8 @@
use godot::prelude::*;
use mc_ai::tactical::state::{TacticalBuildingSpec, TacticalUnitSpec};
use mc_player_api::{
apply_action, project_view, ActionError, PlayerAction, PlayerView, PlayerId,
apply_action, project_view, suggest_actions, ActionError, PlayerAction, PlayerView,
PlayerId,
};
use mc_turn::game_state::GameState;
@ -221,6 +222,37 @@ impl GdPlayerApi {
Err(e) => error_envelope(&e),
}
}
/// Stage 6.1.6 — compute the scripted controller's action chain for
/// `player` against the CURRENT held state, WITHOUT applying any
/// action or advancing the turn.
///
/// Returns a `{"ok":true,"actions":[<PlayerAction>,...]}` envelope
/// (JSON). The `actions` list uses the same `PlayerAction` JSON shape
/// `apply_action_json` accepts, so a recorder can replay each action
/// straight back through `apply_action_json`.
///
/// Read-only: this never mutates the held `GameState`. Two calls in
/// a row return identical results and leave `view_json` unchanged.
#[func]
pub fn suggest_json(&self, player: i32) -> GString {
let player_id = match clamp_player(player) {
Ok(p) => p,
Err(e) => return error_envelope(&e),
};
let actions: Vec<PlayerAction> = suggest_actions(&self.state, player_id);
let envelope = serde_json::json!({
"ok": true,
"actions": actions,
});
serde_json::to_string(&envelope)
.unwrap_or_else(|e| {
format!(
r#"{{"ok":false,"error":{{"code":"internal","message":"{e}"}}}}"#
)
})
.into()
}
}
/// Normalize integer-valued floats (`2.0`, `-3.0`) back to integer form