pub mod behavior;
pub mod emotion;
pub mod intent;
pub mod bindings;
pub mod utils {
use std::collections::HashMap;
use std::time::Duration;
use serde::{Deserialize, Serialize};
use tokio::time::sleep;
use crate::agent::Agent;
use crate::Result;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EntityType {
Player,
NPC,
Item,
Structure,
Trigger,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Position {
pub x: f32,
pub y: f32,
pub z: Option<f32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Entity {
pub id: String,
pub entity_type: EntityType,
pub name: String,
pub position: Position,
pub properties: HashMap<String, serde_json::Value>,
}
pub fn distance(a: &Position, b: &Position) -> f32 {
let dx = a.x - b.x;
let dy = a.y - b.y;
let dz = match (a.z, b.z) {
(Some(az), Some(bz)) => az - bz,
_ => 0.0,
};
(dx*dx + dy*dy + dz*dz).sqrt()
}
pub fn move_towards(entity: &mut Entity, target: &Position, speed: f32, delta_time: f32) -> Position {
let dist = distance(&entity.position, target);
if dist < 0.001 {
return entity.position.clone();
}
let scale = (speed * delta_time) / dist;
let dx = (target.x - entity.position.x) * scale;
let dy = (target.y - entity.position.y) * scale;
let dz = match (entity.position.z, target.z) {
(Some(ez), Some(tz)) => Some((tz - ez) * scale),
_ => None,
};
let new_pos = Position {
x: entity.position.x + dx,
y: entity.position.y + dy,
z: dz.map(|dz| entity.position.z.unwrap() + dz),
};
entity.position = new_pos.clone();
new_pos
}
pub async fn run_agent_loop<F>(
agent: &Agent,
mut update_fn: F,
fps: u32,
) -> Result<()>
where
F: FnMut(&Agent) -> Result<()>,
{
let frame_time = Duration::from_secs_f32(1.0 / fps as f32);
agent.start().await?;
loop {
let start = std::time::Instant::now();
update_fn(agent)?;
let elapsed = start.elapsed();
if elapsed < frame_time {
sleep(frame_time - elapsed).await;
}
}
}
}