1use rapier2d::prelude::*;
11
12use crate::nav::navigation::NavigationSystem;
13use crate::nav::spatial::SpatialGrid;
14use crate::config::{EngineConfig, PLAYER_STATE_LEN};
15use crate::events::CoreEvent;
16use crate::map::GameMap;
17use crate::rng::Rng;
18use crate::snapshot::Block;
19
20pub trait GameDef: Sized {
24 type Config: serde::de::DeserializeOwned;
25 type Sim: GameSim<Self>;
26}
27
28pub struct SimCtx<'a> {
30 pub world: &'a mut PhysicsWorld,
31 pub cfg: &'a EngineConfig,
32 pub map: &'a Option<GameMap>,
33 pub nav: &'a Option<NavigationSystem>,
34 pub spatial: &'a mut SpatialGrid,
35 pub rng: &'a mut Rng,
36 pub events: &'a mut Vec<CoreEvent>,
37 pub bodies_to_destroy: &'a mut Vec<RigidBodyHandle>,
38}
39
40#[allow(clippy::too_many_arguments)]
48pub trait GameSim<G: GameDef>: Sized {
49 fn new(cfg: &G::Config, engine_cfg: &EngineConfig) -> Self;
53
54 fn spawn_actor(
55 &mut self,
56 world: &mut PhysicsWorld,
57 events: &mut Vec<CoreEvent>,
58 game_id: u32,
59 model_name: &str,
60 team_id: u8,
61 x: f32,
62 y: f32,
63 angle_deg: f32,
64 ) -> Result<(), String>;
65 fn remove_actor(&mut self, world: &mut PhysicsWorld, game_id: u32);
66 fn reset_actor(&mut self, world: &mut PhysicsWorld, game_id: u32, team_id: u8, x: f32, y: f32, angle_deg: f32);
67 fn reset_all_vitals(&mut self, events: &mut Vec<CoreEvent>);
68 fn spawn_scripted_actor(
69 &mut self,
70 world: &mut PhysicsWorld,
71 rng: &mut Rng,
72 events: &mut Vec<CoreEvent>,
73 game_id: u32,
74 model_name: &str,
75 team_id: u8,
76 x: f32,
77 y: f32,
78 angle_deg: f32,
79 ) -> Result<(), String>;
80 fn remove_scripted_actor(&mut self, world: &mut PhysicsWorld, game_id: u32);
81
82 fn apply_input(&mut self, game_id: u32, seq: u32, action: &str, key_name: &str);
83
84 fn apply_aim(&mut self, _game_id: u32, _seq: u32, _x: f32, _y: f32, _flags: u32) {}
89 fn last_input_seq(&self, game_id: u32) -> u32;
90 fn is_alive(&self, game_id: u32) -> bool;
91 fn actor_position(&self, world: &PhysicsWorld, game_id: u32) -> Option<[f32; 2]>;
92 fn prediction_state(&self, world: &PhysicsWorld, game_id: u32) -> Option<([f32; PLAYER_STATE_LEN], bool)>;
93 fn alive_players_flat(&self, world: &PhysicsWorld) -> Vec<f32>;
94 fn players_json(&self) -> String;
95
96 fn on_fixed_step(&mut self, ctx: &mut SimCtx, dt: f32);
99 fn on_contacts(&mut self, ctx: &mut SimCtx, pairs: &[(ColliderHandle, ColliderHandle)]);
101 fn on_before_destroy(&mut self, world: &PhysicsWorld, handle: RigidBodyHandle);
104 fn on_ai_tick(&mut self, ctx: &mut SimCtx, dt: f32);
106
107 fn refresh_cached(&mut self, world: &PhysicsWorld);
108 fn build_snapshot_blocks(&mut self) -> (Vec<(String, Block)>, bool);
111
112 fn remove_players_and_shots(&mut self, world: &mut PhysicsWorld) -> Vec<String>;
113 fn clear(&mut self);
114
115 fn serialize(&self) -> serde_json::Value;
116 fn deserialize(&mut self, value: serde_json::Value) -> Result<(), String>;
117 fn rebuild_spatial_grid(&self, world: &PhysicsWorld, spatial: &mut SpatialGrid);
118}