1use indextree::Arena;
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4
5pub type NodeId = u32;
6pub type NodeRef<'a> = &'a indextree::Node<Node>;
7pub type VariableKey = String;
8pub type VariableVal = String;
9
10#[allow(unused_variables)]
11pub trait NodeEvents {
12 fn on_visit(&self, dlg: &Dialogue, node_ref: NodeRef) {}
13 fn on_text(&self, dlg: &Dialogue, id: NodeId, text: &str) {}
14 fn on_choice(
15 &self,
16 dlg: &Dialogue,
17 node_ref: NodeRef,
18 text: &str,
19 choices: &[NodeId],
20 ) -> Option<NodeId> {
21 None
22 }
23 fn on_set(&self, dlg: &Dialogue, key: &str, value: &str) {}
24 fn on_get(&self, dlg: &Dialogue, key: &str) -> Option<String> {
25 None
26 }
27}
28
29#[derive(Clone, Debug, Serialize, Deserialize)]
30pub enum NodeVariant {
31 Text((Option<NodeId>, String)),
32 Choice((String, Vec<NodeId>)),
33 Set((Option<NodeId>, VariableKey, VariableVal)),
34 Branch((VariableKey, HashMap<VariableVal, NodeId>)),
35}
36
37#[derive(Clone, Debug, Serialize, Deserialize)]
38pub struct Node {
39 pub id: NodeId,
40 pub label: String,
41 pub variant: NodeVariant,
42}
43
44impl Node {
45 pub fn new_text(id: NodeId, label: &str, next: Option<NodeId>, text: &str) -> Node {
46 Node {
47 id,
48 label: label.to_owned(),
49 variant: NodeVariant::Text((next, text.to_owned())),
50 }
51 }
52
53 pub fn new_choice(id: NodeId, label: &str, text: &str, choices: &[NodeId]) -> Node {
54 Node {
55 id,
56 label: label.to_owned(),
57 variant: NodeVariant::Choice((text.to_owned(), choices.to_owned())),
58 }
59 }
60
61 pub fn new_set(id: NodeId, label: &str, next: Option<NodeId>, key: &str, val: &str) -> Node {
62 Node {
63 id,
64 label: label.to_owned(),
65 variant: NodeVariant::Set((next, key.to_owned(), val.to_owned())),
66 }
67 }
68
69 pub fn new_branch(id: NodeId, label: &str, key: &str, branches: &[(&str, NodeId)]) -> Node {
70 let mut mapping = HashMap::new();
71 for branch in branches {
72 mapping.insert(branch.0.to_owned(), branch.1);
73 }
74 Node {
75 id,
76 label: label.to_owned(),
77 variant: NodeVariant::Branch((key.to_owned(), mapping)),
78 }
79 }
80}
81
82#[derive(Clone, Debug, Serialize, Deserialize)]
83pub struct NodeGraph {
84 pub nodes: Vec<Node>,
85}
86
87impl NodeGraph {
88 pub fn export(&self) -> String {
89 serde_yaml::to_string(&self.nodes).expect("failed to serialize node graph")
90 }
91}
92
93pub struct Dialogue {
94 node_arena: Arena<Node>,
95 node_lookup: HashMap<NodeId, indextree::NodeId>,
96 events: Option<Box<dyn NodeEvents>>,
97}
98
99impl Default for Dialogue {
100 fn default() -> Self {
101 Self::new()
102 }
103}
104
105impl Dialogue {
106 pub fn new() -> Self {
107 Dialogue {
108 node_arena: Arena::new(),
109 node_lookup: HashMap::new(),
110 events: None,
111 }
112 }
113
114 pub fn insert_node(&mut self, node: Node) {
115 let node_id = node.id;
116 let arena_id = self.node_arena.new_node(node);
117 self.node_lookup.insert(node_id, arena_id);
118 }
119
120 pub fn remove_node(&mut self, _node: NodeId) {}
121
122 pub fn get_node(&self, id: NodeId) -> Option<NodeRef> {
123 match self.node_lookup.get(&id) {
124 Some(node_id) => match self.node_arena.get(*node_id) {
125 Some(node) => Some(node),
126 None => None,
127 },
128 None => None,
129 }
130 }
131
132 pub fn set_events<E: NodeEvents + 'static>(&mut self, events: E) {
133 self.events = Some(Box::new(events));
134 }
135
136 pub fn validate(&self) {
137 for _node in self.node_arena.iter() {
138 }
140 }
141
142 pub fn step(&self, id: NodeId) -> Option<NodeId> {
143 match self.get_node(id) {
144 Some(ref node_ref) => {
145 if let Some(ref events) = self.events {
146 events.on_visit(self, node_ref);
147 }
148 match node_ref.data.variant {
149 NodeVariant::Text((next, ref text)) => {
150 if let Some(ref events) = self.events {
151 events.on_text(self, node_ref.data.id, text);
152 }
153 next
154 }
155 NodeVariant::Choice((ref text, ref choices)) => {
156 if let Some(ref events) = self.events {
157 events.on_choice(self, node_ref, &text, &choices)
158 } else {
159 None
160 }
161 }
162 NodeVariant::Set((next, ref key, ref val)) => {
163 if let Some(ref events) = self.events {
164 events.on_set(self, &key, &val);
165 }
166 next
167 }
168 NodeVariant::Branch((ref key, ref branches)) => {
169 if let Some(ref events) = self.events {
170 let value = events.on_get(self, &key);
171 match value {
172 Some(value) => match branches.get(&value) {
173 Some(node_id) => Some(*node_id),
174 None => None,
175 },
176 None => None,
177 }
178 } else {
179 None
180 }
181 }
182 }
183 }
184 None => None,
185 }
186 }
187
188 pub fn export(&self) -> NodeGraph {
189 NodeGraph {
190 nodes: self.node_arena.iter().map(|x| x.data.clone()).collect(),
191 }
192 }
193}