Skip to main content

dreamwell_engine/waymark/
functions.rs

1use super::errors::{AuthoringError, WaymarkError};
2use crate::physics::properties::PropertyValue;
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
7pub enum FunctionScope {
8    Universe,
9    Galaxy,
10    Sector,
11    World,
12    Realm,
13    Region,
14    Area,
15    Location,
16    Room,
17    Point,
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
21pub enum FunctionCategory {
22    Physics,
23    Traversal,
24    Combat,
25    Simulation,
26    Dreamwell,
27    Topology,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct UniversalFunction {
32    pub key: String,
33    pub category: FunctionCategory,
34    pub scope: FunctionScope,
35    pub default_value: PropertyValue,
36    pub description: String,
37}
38
39#[derive(Debug, Clone, Default)]
40pub struct FunctionRegistry {
41    functions: Vec<UniversalFunction>,
42    key_index: HashMap<String, usize>,
43}
44
45impl FunctionRegistry {
46    pub fn new() -> Self {
47        Self::default()
48    }
49
50    pub fn with_builtins() -> Self {
51        let mut reg = Self::new();
52        let builtins = vec![
53            (
54                "gravity.local",
55                FunctionCategory::Physics,
56                FunctionScope::Region,
57                PropertyValue::Float(9.81),
58                "Local gravity acceleration",
59            ),
60            (
61                "gravity.planetary",
62                FunctionCategory::Physics,
63                FunctionScope::World,
64                PropertyValue::Float(9.81),
65                "Planetary gravity",
66            ),
67            (
68                "atmosphere.density",
69                FunctionCategory::Physics,
70                FunctionScope::World,
71                PropertyValue::Float(1.0),
72                "Atmospheric density multiplier",
73            ),
74            (
75                "pressure.local",
76                FunctionCategory::Physics,
77                FunctionScope::Room,
78                PropertyValue::Float(1.0),
79                "Local air pressure",
80            ),
81            (
82                "temperature.ambient",
83                FunctionCategory::Physics,
84                FunctionScope::Region,
85                PropertyValue::Float(20.0),
86                "Ambient temperature",
87            ),
88            (
89                "fluid.viscosity",
90                FunctionCategory::Physics,
91                FunctionScope::Area,
92                PropertyValue::Float(1.0),
93                "Fluid viscosity multiplier",
94            ),
95            (
96                "pathing.walkability",
97                FunctionCategory::Traversal,
98                FunctionScope::Area,
99                PropertyValue::Float(1.0),
100                "Walkability multiplier",
101            ),
102            (
103                "pathing.flightAllowed",
104                FunctionCategory::Traversal,
105                FunctionScope::Region,
106                PropertyValue::Bool(false),
107                "Flight allowed",
108            ),
109            (
110                "pathing.swimAllowed",
111                FunctionCategory::Traversal,
112                FunctionScope::Area,
113                PropertyValue::Bool(false),
114                "Swimming allowed",
115            ),
116            (
117                "damage.falloff",
118                FunctionCategory::Combat,
119                FunctionScope::Area,
120                PropertyValue::Float(1.0),
121                "Damage falloff rate",
122            ),
123            (
124                "shield.rechargeRate",
125                FunctionCategory::Combat,
126                FunctionScope::Region,
127                PropertyValue::Float(1.0),
128                "Shield recharge rate",
129            ),
130            (
131                "projectile.arcScale",
132                FunctionCategory::Combat,
133                FunctionScope::Region,
134                PropertyValue::Float(1.0),
135                "Projectile arc scale",
136            ),
137            (
138                "time.flow",
139                FunctionCategory::Simulation,
140                FunctionScope::Universe,
141                PropertyValue::Float(1.0),
142                "Time flow rate",
143            ),
144            (
145                "time.scale",
146                FunctionCategory::Simulation,
147                FunctionScope::Realm,
148                PropertyValue::Float(1.0),
149                "Time scale multiplier",
150            ),
151            (
152                "weather.pattern",
153                FunctionCategory::Simulation,
154                FunctionScope::Region,
155                PropertyValue::String("clear".into()),
156                "Weather pattern",
157            ),
158            (
159                "resource.respawnRate",
160                FunctionCategory::Simulation,
161                FunctionScope::Region,
162                PropertyValue::Float(1.0),
163                "Resource respawn rate",
164            ),
165            (
166                "corruption.spreadRate",
167                FunctionCategory::Dreamwell,
168                FunctionScope::Region,
169                PropertyValue::Float(0.0),
170                "Corruption spread rate",
171            ),
172            (
173                "dreammatter.condenseRate",
174                FunctionCategory::Dreamwell,
175                FunctionScope::Realm,
176                PropertyValue::Float(0.0),
177                "Dreammatter condensation rate",
178            ),
179            (
180                "timeline.branchPolicy",
181                FunctionCategory::Dreamwell,
182                FunctionScope::Universe,
183                PropertyValue::String("signed_canonical".into()),
184                "Timeline branch policy",
185            ),
186            (
187                "attestation.visibility",
188                FunctionCategory::Dreamwell,
189                FunctionScope::Universe,
190                PropertyValue::Bool(true),
191                "Attestation visibility",
192            ),
193            (
194                "topology.transitionMode",
195                FunctionCategory::Topology,
196                FunctionScope::Location,
197                PropertyValue::String("seamless_stream".into()),
198                "Topology transition mode",
199            ),
200            (
201                "topology.scalePresentation",
202                FunctionCategory::Topology,
203                FunctionScope::Area,
204                PropertyValue::String("continuous".into()),
205                "Scale presentation mode",
206            ),
207            (
208                "topology.sceneBinding",
209                FunctionCategory::Topology,
210                FunctionScope::Location,
211                PropertyValue::String("default".into()),
212                "Scene binding mode",
213            ),
214        ];
215        for (key, cat, scope, val, desc) in builtins {
216            let _ = reg.register(UniversalFunction {
217                key: key.into(),
218                category: cat,
219                scope,
220                default_value: val,
221                description: desc.into(),
222            });
223        }
224        reg
225    }
226
227    pub fn register(&mut self, func: UniversalFunction) -> Result<(), WaymarkError> {
228        if self.key_index.contains_key(&func.key) {
229            return Err(WaymarkError::Authoring(AuthoringError::UnknownFunction(format!(
230                "duplicate function key: {}",
231                func.key
232            ))));
233        }
234        let idx = self.functions.len();
235        self.key_index.insert(func.key.clone(), idx);
236        self.functions.push(func);
237        Ok(())
238    }
239
240    pub fn find(&self, key: &str) -> Option<&UniversalFunction> {
241        self.key_index.get(key).map(|&i| &self.functions[i])
242    }
243
244    pub fn by_category(&self, cat: FunctionCategory) -> Vec<&UniversalFunction> {
245        self.functions.iter().filter(|f| f.category == cat).collect()
246    }
247
248    pub fn by_scope(&self, scope: FunctionScope) -> Vec<&UniversalFunction> {
249        self.functions.iter().filter(|f| f.scope == scope).collect()
250    }
251
252    pub fn validate_key(&self, key: &str) -> Result<(), WaymarkError> {
253        if self.key_index.contains_key(key) {
254            Ok(())
255        } else {
256            Err(WaymarkError::Authoring(AuthoringError::UnknownFunction(key.into())))
257        }
258    }
259
260    pub fn len(&self) -> usize {
261        self.functions.len()
262    }
263    pub fn is_empty(&self) -> bool {
264        self.functions.is_empty()
265    }
266}
267
268impl FunctionScope {
269    pub const ALL: &[FunctionScope] = &[
270        Self::Universe,
271        Self::Galaxy,
272        Self::Sector,
273        Self::World,
274        Self::Realm,
275        Self::Region,
276        Self::Area,
277        Self::Location,
278        Self::Room,
279        Self::Point,
280    ];
281}
282
283impl FunctionCategory {
284    pub const ALL: &[FunctionCategory] = &[
285        Self::Physics,
286        Self::Traversal,
287        Self::Combat,
288        Self::Simulation,
289        Self::Dreamwell,
290        Self::Topology,
291    ];
292}
293
294#[cfg(test)]
295mod tests {
296    use super::*;
297
298    #[test]
299    fn builtins_count() {
300        let reg = FunctionRegistry::with_builtins();
301        assert_eq!(reg.len(), 23);
302    }
303
304    #[test]
305    fn find_gravity() {
306        let reg = FunctionRegistry::with_builtins();
307        let f = reg.find("gravity.local").unwrap();
308        assert_eq!(f.category, FunctionCategory::Physics);
309    }
310
311    #[test]
312    fn by_category_physics() {
313        let reg = FunctionRegistry::with_builtins();
314        let phys = reg.by_category(FunctionCategory::Physics);
315        assert_eq!(phys.len(), 6);
316    }
317
318    #[test]
319    fn validate_key_valid() {
320        let reg = FunctionRegistry::with_builtins();
321        assert!(reg.validate_key("gravity.local").is_ok());
322    }
323
324    #[test]
325    fn validate_key_invalid() {
326        let reg = FunctionRegistry::with_builtins();
327        assert!(reg.validate_key("nonexistent.key").is_err());
328    }
329
330    #[test]
331    fn scope_all_count() {
332        assert_eq!(FunctionScope::ALL.len(), 10);
333    }
334
335    #[test]
336    fn category_all_count() {
337        assert_eq!(FunctionCategory::ALL.len(), 6);
338    }
339}