pabitell_lib/
lib.rs

1#[cfg(feature = "with_cli")]
2pub mod cli;
3pub mod conditions;
4pub mod data;
5pub mod events;
6pub mod items;
7pub mod protocol;
8pub mod scenes;
9pub mod translations;
10pub mod updates;
11#[cfg(feature = "with_webapp")]
12pub mod webapp;
13
14use anyhow::{anyhow, Result};
15use fluent::FluentArgs;
16use serde::{Deserialize, Serialize};
17use std::{any::Any, collections::HashMap, fmt};
18use uuid::Uuid;
19
20use conditions::Check;
21
22pub trait AsAny: Any {
23    fn as_any(&self) -> &dyn Any;
24    fn as_any_mut(&mut self) -> &mut dyn Any;
25}
26
27#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
28pub enum ItemState {
29    Owned(String),
30    InScene(String),
31    Unassigned,
32}
33
34#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Copy)]
35pub struct GeoLocation(f64, f64);
36
37impl Default for ItemState {
38    fn default() -> Self {
39        Self::Unassigned
40    }
41}
42
43impl Dumpable for ItemState {
44    fn dump(&self) -> serde_json::Value {
45        match self {
46            Self::Owned(character) => serde_json::json!({"kind": "character", "value": character}),
47            Self::InScene(scene) => serde_json::json!({"kind": "scene", "value": scene}),
48            Self::Unassigned => serde_json::Value::Null,
49        }
50    }
51    fn load(&mut self, data: serde_json::Value) -> Result<()> {
52        let new = match data {
53            serde_json::Value::Null => Self::Unassigned,
54            serde_json::Value::Object(mut inner) => {
55                let value = if let serde_json::Value::String(value) = inner
56                    .remove("value")
57                    .ok_or_else(|| anyhow!("missing value while parsing ItemState"))?
58                {
59                    value
60                } else {
61                    return Err(anyhow!("Mismatched type in ItemValue"));
62                };
63                match inner
64                    .remove("kind")
65                    .ok_or_else(|| anyhow!("missing kind while parsing ItemState"))?
66                {
67                    serde_json::Value::String(kind) if kind == "character" => Self::Owned(value),
68                    serde_json::Value::String(kind) if kind == "scene" => Self::InScene(value),
69                    e => return Err(anyhow!("Unknown kind `{}`", e)),
70                }
71            }
72            _ => return Err(anyhow!("Failed to deserialize ItemState")),
73        };
74        *self = new;
75
76        Ok(())
77    }
78}
79
80pub trait Tagged {
81    fn get_tags(&self) -> Vec<String> {
82        vec![]
83    }
84    fn set_tags(&mut self, _tags: Vec<String>) {}
85}
86
87pub trait Named {
88    /// unique name within world
89    fn name(&self) -> &'static str;
90}
91
92pub trait Music {
93    /// Name of background music file
94    fn music(&self) -> Option<String> {
95        None
96    }
97}
98
99pub trait Clean {
100    /// Reset to original state
101    fn clean(&mut self) {}
102}
103
104pub trait Description: Named {
105    fn long(&self, world: &dyn World) -> String {
106        world.get_message(&format!("{}-{}-long", world.name(), self.name()), None)
107    }
108    fn short(&self, world: &dyn World) -> String {
109        world.get_message(&format!("{}-{}-short", world.name(), self.name()), None)
110    }
111}
112
113pub trait Dumpable {
114    fn dump(&self) -> serde_json::Value;
115    fn load(&mut self, data: serde_json::Value) -> Result<()>;
116}
117
118pub trait Item: Named + Tagged + AsAny + Description + Dumpable + fmt::Debug + Clean {
119    fn state(&self) -> &ItemState;
120    fn set_state(&mut self, state: ItemState);
121    fn last_event(&self) -> Option<usize>;
122    fn set_last_event(&mut self, event: usize);
123}
124
125pub trait Character: Named + Tagged + AsAny + Description + Dumpable + fmt::Debug + Clean {
126    fn scene(&self) -> &Option<String>;
127    fn set_scene(&mut self, scene: Option<String>);
128}
129
130pub trait Scene:
131    Named + Tagged + AsAny + Description + Dumpable + Music + fmt::Debug + Clean
132{
133    fn dialog(&self) -> Option<usize> {
134        None
135    }
136    fn next_dialog(&mut self) {}
137    fn geo_location(&self) -> Option<GeoLocation> {
138        None
139    }
140    fn set_geo_location(&mut self, _location: Option<GeoLocation>) {}
141}
142
143pub trait Event: Tagged + AsAny + fmt::Debug + PartialEq<[u8]> {
144    fn kind(&self) -> &str {
145        std::any::type_name::<Self>()
146            .rsplitn(2, "::")
147            .collect::<Vec<&str>>()[0]
148    }
149    fn name(&self) -> &str;
150    fn can_be_triggered(&self, world: &dyn World) -> bool {
151        self.get_condition().check(world).unwrap()
152    }
153    fn trigger(&mut self, world: &mut dyn World) {
154        for update in self.get_world_updates() {
155            update.change(world).unwrap();
156            for item in self.items() {
157                let last_event = world.event_count();
158                let item = world.items_mut().get_mut(&item).unwrap();
159                item.set_last_event(last_event);
160            }
161        }
162        world.event_inc();
163    }
164    fn perform(&mut self, world: &mut dyn World) -> bool {
165        if self.can_be_triggered(world) {
166            self.trigger(world);
167            true
168        } else {
169            false
170        }
171    }
172    fn action_text(&self, world: &dyn World) -> String {
173        let msg = format!("{}-action", self.msg_base(world));
174        world.get_message(&msg, None)
175    }
176    fn success_text(&self, world: &dyn World) -> String {
177        let msg = format!("{}-success", self.msg_base(world));
178        world.get_message(&msg, None)
179    }
180    fn fail_text(&self, world: &dyn World) -> String {
181        let msg = format!("{}-fail", self.msg_base(world));
182        world.get_message(&msg, None)
183    }
184    fn set_world_updates(&mut self, updates: Vec<Box<dyn updates::Change>>);
185    fn set_condition(&mut self, condition: conditions::Condition);
186
187    fn msg_base(&self, world: &dyn World) -> String {
188        format!("{}-{}", world.name(), self.name())
189    }
190
191    fn get_world_updates(&self) -> &[Box<dyn updates::Change>];
192    fn get_condition(&self) -> &conditions::Condition;
193
194    fn initiator(&self) -> String;
195    fn set_initiator(&mut self, initiator: String);
196    fn dump(&self) -> serde_json::Value;
197    fn matches(&self, value: &serde_json::Value) -> bool;
198
199    fn items(&self) -> Vec<String>;
200    fn characters(&self) -> Vec<String>;
201
202    fn sort_key(&self, world: &dyn World) -> (usize, String, String, String) {
203        let max_event_idx = self
204            .items()
205            .iter()
206            .map(|e| {
207                if let Some(item) = world.items().get(e) {
208                    item.last_event().unwrap_or(0)
209                } else {
210                    0
211                }
212            })
213            .max()
214            .unwrap_or(0);
215
216        let max_item_name = self.items().into_iter().max().unwrap_or_default();
217        (
218            max_event_idx,
219            max_item_name,
220            self.characters().into_iter().max().unwrap_or_default(),
221            self.name().to_string(),
222        )
223    }
224
225    /// Can be event be triggered by moving to given geo location
226    fn geo_location(&self, _world: &dyn World) -> Option<(String, Option<String>, GeoLocation)> {
227        None
228    }
229}
230
231pub trait WorldBuilder<S>
232where
233    S: World,
234{
235    fn character(self, character: Box<dyn Character>) -> Self;
236    fn item(self, item: Box<dyn Item>) -> Self;
237    fn scene(self, scene: Box<dyn Scene>) -> Self;
238    fn build(self) -> Result<S>;
239    fn make_world() -> Result<S>;
240}
241
242pub trait World: Named + Dumpable + Clean {
243    fn available_languages(&self) -> Vec<String>;
244    fn lang(&self) -> &str;
245    fn set_lang(&mut self, lang: &str) -> bool;
246    fn description(&self) -> Box<dyn Description>;
247    fn scenes(&self) -> &HashMap<String, Box<dyn Scene>>;
248    fn scenes_mut(&mut self) -> &mut HashMap<String, Box<dyn Scene>>;
249    fn characters(&self) -> &HashMap<String, Box<dyn Character>>;
250    fn characters_mut(&mut self) -> &mut HashMap<String, Box<dyn Character>>;
251    fn items(&self) -> &HashMap<String, Box<dyn Item>>;
252    fn items_mut(&mut self) -> &mut HashMap<String, Box<dyn Item>>;
253    fn setup(&mut self, new_id: bool);
254    fn reset(&mut self) {
255        self.clean_world();
256        self.setup(false);
257    }
258    fn clean_world(&mut self) {
259        self.clean();
260        self.characters_mut().values_mut().for_each(|e| e.clean());
261        self.items_mut().values_mut().for_each(|e| e.clean());
262        self.scenes_mut().values_mut().for_each(|e| e.clean());
263    }
264    fn randomize_id(&mut self) {
265        self.set_id(Uuid::new_v4());
266    }
267    fn finished(&self) -> bool;
268    fn event_count(&self) -> usize;
269    fn event_inc(&mut self);
270
271    fn id(&self) -> &Uuid;
272    fn set_id(&mut self, id: Uuid);
273    fn get_message(&self, msgid: &str, _args: Option<FluentArgs>) -> String {
274        msgid.to_string()
275    }
276
277    /// Format of the world
278    ///
279    /// when the format of stored world changes
280    /// this number should be bumped as well
281    fn version(&self) -> usize {
282        1
283    }
284}
285
286pub trait Narrator {
287    fn all_events(&self, world: &dyn World) -> Vec<Box<dyn Event>>;
288    fn available_events(&self, world: &dyn World) -> Vec<Box<dyn Event>> {
289        self.all_events(world)
290            .into_iter()
291            .filter(|e| e.can_be_triggered(world))
292            .collect()
293    }
294    fn parse_event(&self, world: &dyn World, value: serde_json::Value) -> Option<Box<dyn Event>>;
295    fn available_events_sorted(&self, world: &dyn World) -> Vec<Box<dyn Event>> {
296        let mut events = self.available_events(world);
297        events.sort_by_key(|e| e.sort_key(world));
298        events
299    }
300}
301
302#[cfg(test)]
303pub mod test {
304    use super::{
305        conditions, updates, AsAny, Character, Clean, Description, Dumpable, Event, Item,
306        ItemState, Music, Named, Scene, Tagged, World, WorldBuilder,
307    };
308    use anyhow::{anyhow, Result};
309    use std::{any::Any, collections::HashMap};
310    use uuid::Uuid;
311
312    #[derive(Debug, Default)]
313    struct TestCharacter {
314        scene: Option<String>,
315    }
316
317    impl Tagged for TestCharacter {}
318
319    impl Named for TestCharacter {
320        fn name(&self) -> &'static str {
321            "test_character"
322        }
323    }
324
325    impl Description for TestCharacter {}
326
327    impl AsAny for TestCharacter {
328        fn as_any(&self) -> &dyn Any {
329            self
330        }
331        fn as_any_mut(&mut self) -> &mut dyn Any {
332            self
333        }
334    }
335
336    impl Clean for TestCharacter {
337        fn clean(&mut self) {}
338    }
339
340    impl Character for TestCharacter {
341        fn scene(&self) -> &Option<String> {
342            &self.scene
343        }
344        fn set_scene(&mut self, scene: Option<String>) {
345            self.scene = scene
346        }
347    }
348
349    impl Dumpable for TestCharacter {
350        fn dump(&self) -> serde_json::Value {
351            serde_json::json!(
352                {
353                    "name": self.name(),
354                }
355            )
356        }
357
358        fn load(&mut self, _data: serde_json::Value) -> Result<()> {
359            Ok(())
360        }
361    }
362
363    #[derive(Debug, Default)]
364    struct TestItem {
365        state: ItemState,
366        last_event: Option<usize>,
367    }
368
369    impl Tagged for TestItem {}
370
371    impl Named for TestItem {
372        fn name(&self) -> &'static str {
373            "test_item"
374        }
375    }
376
377    impl Clean for TestItem {
378        fn clean(&mut self) {}
379    }
380
381    impl Description for TestItem {}
382
383    impl AsAny for TestItem {
384        fn as_any(&self) -> &dyn Any {
385            self
386        }
387        fn as_any_mut(&mut self) -> &mut dyn Any {
388            self
389        }
390    }
391
392    impl Dumpable for TestItem {
393        fn dump(&self) -> serde_json::Value {
394            serde_json::json!(
395                {
396                    "name": self.name(),
397                }
398            )
399        }
400
401        fn load(&mut self, _data: serde_json::Value) -> Result<()> {
402            Ok(())
403        }
404    }
405
406    impl Item for TestItem {
407        fn state(&self) -> &ItemState {
408            &self.state
409        }
410        fn set_state(&mut self, state: ItemState) {
411            self.state = state;
412        }
413        fn last_event(&self) -> Option<usize> {
414            self.last_event
415        }
416        fn set_last_event(&mut self, event: usize) {
417            self.last_event = Some(event);
418        }
419    }
420
421    #[derive(Debug, Default)]
422    struct TestScene {}
423
424    impl Tagged for TestScene {}
425
426    impl Named for TestScene {
427        fn name(&self) -> &'static str {
428            "test_scene"
429        }
430    }
431
432    impl Description for TestScene {}
433
434    impl Clean for TestScene {
435        fn clean(&mut self) {}
436    }
437
438    impl AsAny for TestScene {
439        fn as_any(&self) -> &dyn Any {
440            self
441        }
442        fn as_any_mut(&mut self) -> &mut dyn Any {
443            self
444        }
445    }
446
447    impl Dumpable for TestScene {
448        fn dump(&self) -> serde_json::Value {
449            serde_json::json!(
450                {
451                    "name": self.name(),
452                }
453            )
454        }
455
456        fn load(&mut self, _data: serde_json::Value) -> Result<()> {
457            Ok(())
458        }
459    }
460
461    impl Music for TestScene {}
462
463    impl Scene for TestScene {}
464
465    #[derive(Clone, Debug)]
466    struct TestDescription;
467    impl Named for TestDescription {
468        fn name(&self) -> &'static str {
469            "test_description"
470        }
471    }
472
473    impl Description for TestDescription {}
474
475    #[derive(Debug)]
476    struct TestEvent {
477        #[allow(dead_code)]
478        description: TestDescription,
479        condition: conditions::Condition,
480    }
481    impl Tagged for TestEvent {}
482    impl Named for TestEvent {
483        fn name(&self) -> &'static str {
484            "test_event"
485        }
486    }
487    impl AsAny for TestEvent {
488        fn as_any(&self) -> &dyn Any {
489            self
490        }
491        fn as_any_mut(&mut self) -> &mut dyn Any {
492            self
493        }
494    }
495    impl PartialEq<[u8]> for TestEvent {
496        fn eq(&self, _other: &[u8]) -> bool {
497            false
498        }
499    }
500    impl Event for TestEvent {
501        fn trigger(&mut self, _world: &mut dyn World) {}
502
503        fn can_be_triggered(&self, _world: &dyn World) -> bool {
504            true
505        }
506
507        fn name(&self) -> &str {
508            "test_event"
509        }
510
511        fn action_text(&self, _: &dyn World) -> String {
512            "action".into()
513        }
514
515        fn success_text(&self, _: &dyn World) -> String {
516            "success".into()
517        }
518
519        fn fail_text(&self, _: &dyn World) -> String {
520            "fail".into()
521        }
522
523        fn set_world_updates(&mut self, _updates: Vec<Box<dyn updates::Change>>) {}
524        fn set_condition(&mut self, _condition: conditions::Condition) {}
525        fn get_world_updates(&self) -> &[Box<dyn updates::Change>] {
526            &[]
527        }
528        fn get_condition(&self) -> &conditions::Condition {
529            &self.condition
530        }
531
532        fn initiator(&self) -> String {
533            "test_character".into()
534        }
535
536        fn set_initiator(&mut self, _initiator: String) {}
537
538        fn dump(&self) -> serde_json::Value {
539            serde_json::json!({})
540        }
541
542        fn matches(&self, _value: &serde_json::Value) -> bool {
543            false
544        }
545
546        fn items(&self) -> Vec<String> {
547            vec![]
548        }
549
550        fn characters(&self) -> Vec<String> {
551            vec!["test_character".to_owned()]
552        }
553    }
554
555    #[derive(Debug, Default)]
556    struct TestWorld {
557        id: Uuid,
558        lang: String,
559        items: HashMap<String, Box<dyn Item>>,
560        scenes: HashMap<String, Box<dyn Scene>>,
561        characters: HashMap<String, Box<dyn Character>>,
562        event_count: usize,
563    }
564
565    impl Named for TestWorld {
566        fn name(&self) -> &'static str {
567            "test_world"
568        }
569    }
570
571    impl Clean for TestWorld {
572        fn clean(&mut self) {}
573    }
574
575    impl World for TestWorld {
576        fn description(&self) -> Box<dyn Description> {
577            Box::new(TestDescription)
578        }
579
580        fn scenes(&self) -> &HashMap<String, Box<dyn Scene>> {
581            &self.scenes
582        }
583
584        fn scenes_mut(&mut self) -> &mut HashMap<String, Box<dyn Scene>> {
585            &mut self.scenes
586        }
587
588        fn characters(&self) -> &HashMap<String, Box<dyn Character>> {
589            &self.characters
590        }
591
592        fn characters_mut(&mut self) -> &mut HashMap<String, Box<dyn Character>> {
593            &mut self.characters
594        }
595
596        fn items(&self) -> &HashMap<String, Box<dyn Item>> {
597            &self.items
598        }
599
600        fn items_mut(&mut self) -> &mut HashMap<String, Box<dyn Item>> {
601            &mut self.items
602        }
603
604        fn lang(&self) -> &str {
605            &self.lang
606        }
607
608        fn set_lang(&mut self, lang: &str) -> bool {
609            self.lang = lang.into();
610            true
611        }
612
613        fn available_languages(&self) -> Vec<String> {
614            vec!["en-US".to_string()]
615        }
616
617        fn setup(&mut self, _new_id: bool) {}
618
619        fn finished(&self) -> bool {
620            true
621        }
622
623        fn event_count(&self) -> usize {
624            self.event_count
625        }
626
627        fn event_inc(&mut self) {
628            self.event_count += 1;
629        }
630
631        fn id(&self) -> &Uuid {
632            &self.id
633        }
634
635        fn set_id(&mut self, id: Uuid) {
636            self.id = id
637        }
638    }
639
640    impl Dumpable for TestWorld {
641        fn dump(&self) -> serde_json::Value {
642            serde_json::json!({
643                "characters": self.characters.iter().map(|(k, v)| (k.clone(), v.dump())).collect::<HashMap<String, serde_json::Value>>(),
644                "items": self.items.iter().map(|(k, v)| (k.clone(), v.dump())).collect::<HashMap<String, serde_json::Value>>(),
645                "scenes": self.scenes.iter().map(|(k, v)| (k.clone(), v.dump())).collect::<HashMap<String, serde_json::Value>>(),
646                "event_count": self.event_count
647            })
648        }
649        fn load(&mut self, data: serde_json::Value) -> Result<()> {
650            match data {
651                // TODO it might be required to check whether all characters, itemsand scenes exist
652                // before loading data
653                serde_json::Value::Object(root) => {
654                    for item in root {
655                        match item {
656                            (k, v) if k == "characters" => {
657                                if let serde_json::Value::Object(characters) = v {
658                                    for (name, data) in characters.into_iter() {
659                                        let character = self
660                                            .characters_mut()
661                                            .get_mut(&name)
662                                            .ok_or_else(|| anyhow!(""))?;
663                                        character.load(data)?;
664                                    }
665                                } else {
666                                    return Err(anyhow!(""));
667                                }
668                            }
669                            (k, v) if k == "items" => {
670                                if let serde_json::Value::Object(items) = v {
671                                    for (name, data) in items.into_iter() {
672                                        let item = self
673                                            .characters_mut()
674                                            .get_mut(&name)
675                                            .ok_or_else(|| anyhow!(""))?;
676                                        item.load(data)?;
677                                    }
678                                } else {
679                                    return Err(anyhow!(""));
680                                }
681                            }
682                            (k, v) if k == "scenes" => {
683                                if let serde_json::Value::Object(scenes) = v {
684                                    for (name, data) in scenes.into_iter() {
685                                        let scene = self
686                                            .characters_mut()
687                                            .get_mut(&name)
688                                            .ok_or_else(|| anyhow!(""))?;
689                                        scene.load(data)?;
690                                    }
691                                } else {
692                                    return Err(anyhow!(""));
693                                }
694                            }
695                            (k, v) if k == "event_count" => {
696                                if let serde_json::Value::Number(num) = v {
697                                    if let Some(count) = num.as_u64() {
698                                        self.event_count = count as usize;
699                                    } else {
700                                        return Err(anyhow!(""));
701                                    }
702                                } else {
703                                    return Err(anyhow!(""));
704                                }
705                            }
706                            _ => return Err(anyhow!("")),
707                        }
708                    }
709                }
710                _ => return Err(anyhow!("")),
711            }
712            Ok(())
713        }
714    }
715
716    #[derive(Default)]
717    struct TestWorldBuilder {
718        characters: Vec<Box<dyn Character>>,
719        items: Vec<Box<dyn Item>>,
720        scenes: Vec<Box<dyn Scene>>,
721    }
722
723    impl WorldBuilder<TestWorld> for TestWorldBuilder {
724        fn character(mut self, character: Box<dyn Character>) -> Self {
725            self.characters.push(character);
726            self
727        }
728
729        fn item(mut self, item: Box<dyn Item>) -> Self {
730            self.items.push(item);
731            self
732        }
733
734        fn scene(mut self, item: Box<dyn Scene>) -> Self {
735            self.scenes.push(item);
736            self
737        }
738
739        fn build(self) -> Result<TestWorld> {
740            Ok(TestWorld {
741                lang: "en-US".into(),
742                characters: self
743                    .characters
744                    .into_iter()
745                    .map(|e| (e.name().into(), e))
746                    .collect(),
747                items: self
748                    .items
749                    .into_iter()
750                    .map(|e| (e.name().into(), e))
751                    .collect(),
752                scenes: self
753                    .scenes
754                    .into_iter()
755                    .map(|e| (e.name().into(), e))
756                    .collect(),
757                ..Default::default()
758            })
759        }
760
761        fn make_world() -> Result<TestWorld> {
762            Self::default().build()
763        }
764    }
765
766    #[test]
767    fn linear() {
768        let world = TestWorldBuilder::default()
769            .character(Box::new(TestCharacter::default()))
770            .character(Box::new(TestCharacter::default()))
771            .item(Box::new(TestItem::default()))
772            .item(Box::new(TestItem::default()))
773            .item(Box::new(TestItem::default()))
774            .item(Box::new(TestItem::default()))
775            .scene(Box::new(TestScene::default()))
776            .scene(Box::new(TestScene::default()))
777            .scene(Box::new(TestScene::default()));
778
779        assert!(world.build().is_ok());
780    }
781}