grue/dialogue/
mod.rs

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			//
139		}
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}