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 Hooks {
7 events: HashMap<String, Vec<Hook>>
8}
9
10impl Hooks {
11 pub fn new() -> Self {
12 Self {
13 events: HashMap::new()
14 }
15 }
16
17 pub fn on<F>(&mut self, event: String, callback: F)
18 where
19 F: Fn(&Value) + 'static + Send + Sync
20 {
21 self.events.entry(event)
22 .or_insert_with(Vec::new)
23 .push(Hook::new(callback, false));
24 }
25
26 pub fn once<F>(&mut self, event: String, callback: F)
27 where
28 F: Fn(&Value) + 'static + Send + Sync
29 {
30 self.events.entry(event)
31 .or_insert_with(Vec::new)
32 .push(Hook::new(callback, true));
33 }
34
35 pub fn emit(&mut self, event: String, data: &Value) {
36 if let Some(event_list) = self.events.get_mut(&event) {
37 for event in event_list.iter_mut() {
38 event.call(data);
39 }
40 }
41 }
42}
43
44#[wasm_bindgen]
45pub struct Hook {
46 func: Box<dyn Fn(&Value) -> () + Sync + Send>,
47 once: bool,
48 called: bool
49}
50
51impl Hook {
52 pub fn new<F>(callback: F, once: bool) -> Self
53 where
54 F: Fn(&Value) -> () + 'static + Send + Sync
55 {
56 Self {
57 func: Box::new(callback),
58 once,
59 called: false
60 }
61 }
62
63 pub fn call(&mut self, data: &Value) {
64 if self.once {
65 if !self.called {
66 (self.func)(data);
67 self.called = true;
68 }
69 } else {
70 (self.func)(data);
71 }
72 }
73}