A framework for the Godot engine to create TTRPG games for Advanced 5th Edition, Pathfinder 2nd Edition, and more
1use std::collections::HashMap;
2use wasm_bindgen::prelude::*;
3use rmpv::Value;
4
5#[wasm_bindgen]
6pub struct DiceWire {
7 hooks: Hooks
8}
9
10impl DiceWire {
11 pub fn new() -> Self {
12 Self {
13 hooks: Hooks::new()
14 }
15 }
16}
17
18#[wasm_bindgen]
19pub struct Hooks {
20 events: HashMap<String, Vec<Hook>>
21}
22
23impl Hooks {
24 pub fn new() -> Self {
25 Self {
26 events: HashMap::new()
27 }
28 }
29
30 pub fn on<F>(&mut self, event: String, callback: F)
31 where
32 F: Fn(&Value) + 'static + Send + Sync
33 {
34 self.events.entry(event)
35 .or_insert_with(Vec::new)
36 .push(Hook::new(callback, false));
37 }
38
39 pub fn once<F>(&mut self, event: String, callback: F)
40 where
41 F: Fn(&Value) + 'static + Send + Sync
42 {
43 self.events.entry(event)
44 .or_insert_with(Vec::new)
45 .push(Hook::new(callback, true));
46 }
47
48 pub fn emit(&mut self, event: String, data: &Value) {
49 if let Some(event_list) = self.events.get_mut(&event) {
50 for event in event_list.iter_mut() {
51 event.call(data);
52 }
53 }
54 }
55}
56
57#[wasm_bindgen]
58pub struct Hook {
59 func: Box<dyn Fn(&Value) -> () + Sync + Send>,
60 once: bool,
61 called: bool
62}
63
64impl Hook {
65 pub fn new<F>(callback: F, once: bool) -> Self
66 where
67 F: Fn(&Value) -> () + 'static + Send + Sync
68 {
69 Self {
70 func: Box::new(callback),
71 once,
72 called: false
73 }
74 }
75
76 pub fn call(&mut self, data: &Value) {
77 if self.once {
78 if !self.called {
79 (self.func)(data);
80 self.called = true;
81 }
82 } else {
83 (self.func)(data);
84 }
85 }
86}