feat(ai): Implement Rust-based AI extension bindings for Godot Engine with GDExtension support

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
autocommit 2026-06-04 09:26:32 -07:00
parent 41f2363ba7
commit 3cf1714ebd

View file

@ -270,7 +270,13 @@ fn decide_strategic_kind(state: &GameState, player_index: usize, seed: u64) -> &
// sets current_player from the GameState's turn-order, not from the caller's
// explicit slot, so align it here.
tactical.current_player = player_slot;
let actions = run_ai_turn(&tactical, player_slot, &weights, seed);
// p1-29h — this FFI probe derives a one-shot strategic-directive string for
// GDScript production priming; it is NOT the persistent live-decision path
// (that is the pure-Rust `mc_player_api::dispatch::drive_ai_slot`, which
// p1-29d measures and which threads the slot's persisted memory). A
// transient per-call memory is correct here.
let mut memory = mc_ai::tactical::TacticalMemory::default();
let actions = run_ai_turn(&tactical, player_slot, &weights, seed, &mut memory);
derive_strategic_kind(&actions)
}
@ -905,7 +911,13 @@ pub fn run_tactical(
seed: u64,
) -> Vec<String> {
let mut rng = XorShift64::new(seed);
let actions: Vec<Action> = decide_tactical_actions(state, weights, &mut rng, None);
// p1-29h — `run_tactical` is the stateless GdAiController FFI shim: it owns
// no GameState and no persistent slot state, so the army-level memory is a
// documented transient here. The persistent army-lock lives on the
// pure-Rust dispatch path (`drive_ai_slot`), the surface p1-29d measures.
let mut memory = mc_ai::tactical::TacticalMemory::default();
let actions: Vec<Action> =
decide_tactical_actions(state, weights, &mut rng, None, &mut memory);
actions
.into_iter()
.filter_map(|a| match serde_json::to_string(&a) {