wicked-waifus-rs/wicked-waifus-game-server/src/logic/components/fsm.rs
xavo95 ab868a158a 2.2.2 (#3)
Ongoing changes for 2.2.2

Reviewed-on: WutheringSlaves/wicked-waifus-rs#3
2025-03-09 09:10:08 +00:00

116 lines
No EOL
4.5 KiB
Rust

use std::string::ToString;
use std::sync::OnceLock;
use indexmap::IndexMap;
use wicked_waifus_protocol::{DFsm, DFsmBlackBoard, EntityComponentPb, EntityFsmComponentPb, FsmCustomBlackboardDatas};
use wicked_waifus_protocol::entity_component_pb::ComponentPb;
use wicked_waifus_data::{ai_base_data, ai_state_machine_config_data, AiStateMachineConfigData, StateMachineJson, StateMachineNode, StateMachineNodeCommon};
use crate::logic::ecs::component::Component;
static COMMON_FSM: OnceLock<AiStateMachineConfigData> = OnceLock::new();
#[derive(Default)]
pub struct Fsm {
pub hash_code: i32,
pub common_hash_code: i32,
pub state_list: Vec<i32>,
pub node_list: IndexMap<i32, StateMachineNodeCommon>,
}
impl Component for Fsm {
fn set_pb_data(&self, pb: &mut wicked_waifus_protocol::EntityPb) {
pb.component_pbs.push(EntityComponentPb {
component_pb: Some(ComponentPb::EntityFsmComponentPb(EntityFsmComponentPb {
fsms: self.get_initial_fsm(),
hash_code: self.hash_code,
common_hash_code: self.common_hash_code,
black_board: self.get_black_board(),
fsm_custom_blackboard_datas: self.get_fsm_custom_blackboard_datas(),
})),
})
}
}
impl Fsm {
pub fn from_ai_id(ai_id: i32) -> Self {
let ai_base = ai_base_data::get(&ai_id);
let Some(base) = ai_base else {
tracing::error!("Ai Base not found for AI ID: {}", ai_id);
return Self::default();
};
let common_state_machine: &StateMachineJson = &get_common_fsm().state_machine_json;
// Should always be defined since it comes from bindata
let Some(state_machine_config_data) = ai_state_machine_config_data::get(&base.state_machine) else {
tracing::error!("State machine config not found for AI ID: {}", ai_id);
return Self::default();
};
let state_machine_config: &StateMachineJson = &state_machine_config_data.state_machine_json;
let mut fsm_tree: IndexMap<i32, StateMachineNodeCommon> = IndexMap::with_capacity(state_machine_config.nodes.len());
for state_machine in &state_machine_config.state_machines {
for node in &state_machine_config.nodes {
match node {
StateMachineNode::Reference(_node) => {
// TODO:
// common_state_machine.nodes.iter()
// .filter_map(|state_machine_node| match state_machine_node {
// StateMachineNode::Reference(_) => None,
// StateMachineNode::Override(_) => None,
// StateMachineNode::Custom(custom) => Some(custom)
// })
// .find()
}
StateMachineNode::Override(node) => {
// TODO:
tracing::warn!(
"FSM: {state_machine} with override node {} for {} unimplemented",
node.common.uuid,
node.override_common_uuid
);
}
StateMachineNode::Custom(node) => {
fsm_tree.insert(node.common.uuid, node.common.clone());
}
}
}
}
Self {
hash_code: state_machine_config.version as i32,
common_hash_code: common_state_machine.version as i32,
state_list: state_machine_config.state_machines.clone(),
node_list: fsm_tree,
}
}
fn get_initial_fsm(&self) -> Vec<DFsm> {
self.node_list.iter()
.filter_map(|(&id, node)| {
self.state_list.contains(&id).then(|| DFsm {
fsm_id: id,
current_state: node.children.as_ref()
.and_then(|c| c.get(0).cloned())
.unwrap_or_default(),
flag: 0, // TODO:
k_ts: 0, // TODO:
})
}).collect::<Vec<_>>()
}
fn get_black_board(&self) -> Vec<DFsmBlackBoard> {
vec![]
}
fn get_fsm_custom_blackboard_datas(&self) -> Option<FsmCustomBlackboardDatas> {
None
}
}
fn get_common_fsm() -> &'static AiStateMachineConfigData {
COMMON_FSM.get_or_init(|| {
let name = "SM_Common".to_string();
// Common shall be always defined
ai_state_machine_config_data::get(&name).cloned().unwrap()
})
}