From 5e7fd556c654bd43dcd29e93a734c06726495741 Mon Sep 17 00:00:00 2001 From: QueenOfSquiggles <8940604+QueenOfSquiggles@users.noreply.github.com> Date: Thu, 18 Jan 2024 17:18:29 -0600 Subject: [PATCH] Stabilized several dialog systems as well as interaction::do_interact --- squiggles_core.gdextension | 38 +++++++++++----------- src/scene/dialog/core_dialog.rs | 22 ++++++++++--- src/scene/dialog/dialog_blackboard.rs | 19 ++++++----- src/scene/dialog/dialog_gui.rs | 45 ++++++++++++++++++++++----- src/scene/interaction.rs | 6 ++-- 5 files changed, 89 insertions(+), 41 deletions(-) diff --git a/squiggles_core.gdextension b/squiggles_core.gdextension index af3862f..3d9517b 100644 --- a/squiggles_core.gdextension +++ b/squiggles_core.gdextension @@ -6,39 +6,39 @@ reloadable = true [libraries] ;; Debug Binaries -linux.debug.x86_64 = "res://addons/squiggles_core/target/debug/libsquiggles_core.so" -windows.debug.x86_64 = "res://addons/squiggles_core/target/debug/squiggles_core.dll" -macos.debug = "res://addons/squiggles_core/target/debug/libsquiggles_core.dylib" -macos.debug.arm64 = "res://addons/squiggles_core/target/debug/libsquiggles_core.dylib" +linux.debug.x86_64 = "res://addons/squiggles-core/target/debug/libsquiggles_core.so" +windows.debug.x86_64 = "res://addons/squiggles-core/target/debug/squiggles_core.dll" +macos.debug = "res://addons/squiggles-core/target/debug/libsquiggles_core.dylib" +macos.debug.arm64 = "res://addons/squiggles-core/target/debug/libsquiggles_core.dylib" ;; Release Binaries -linux.release.x86_64 = "res://addons/squiggles_core/target/release/libsquiggles_core.so" -windows.release.x86_64 = "res://addons/squiggles_core/target/release/squiggles_core.dll" -macos.release = "res://addons/squiggles_core/target/release/libsquiggles_core.dylib" -macos.release.arm64 = "res://addons/squiggles_core/target/release/libsquiggles_core.dylib" +linux.release.x86_64 = "res://addons/squiggles-core/target/release/libsquiggles_core.so" +windows.release.x86_64 = "res://addons/squiggles-core/target/release/squiggles_core.dll" +macos.release = "res://addons/squiggles-core/target/release/libsquiggles_core.dylib" +macos.release.arm64 = "res://addons/squiggles-core/target/release/libsquiggles_core.dylib" [icons] ;; camera.rs -CameraBrain3D = "res://addons/squiggles_core/assets/icons/camera_brain.svg" -VirtualCamera3D = "res://addons/squiggles_core/assets/icons/virtual_camera.svg" +CameraBrain3D = "res://addons/squiggles-core/assets/icons/camera_brain.svg" +VirtualCamera3D = "res://addons/squiggles-core/assets/icons/virtual_camera.svg" ;; interaction.rs -InteractRaycast3D = "res://addons/squiggles_core/assets/icons/interaction_raycast3d.svg" -InteractArea3D = "res://addons/squiggles_core/assets/icons/interaction_area3d.svg" -InteractionObjectArea3D = "res://addons/squiggles_core/assets/icons/interact_object_area3d.svg" -InteractionObjectStaticBody3D = "res://addons/squiggles_core/assets/icons/interact_object_static3d.svg" -InteractionObjectCharacterBody3D = "res://addons/squiggles_core/assets/icons/interact_object_character3d.svg" +InteractRaycast3D = "res://addons/squiggles-core/assets/icons/interaction_raycast3d.svg" +InteractArea3D = "res://addons/squiggles-core/assets/icons/interaction_area3d.svg" +InteractionObjectArea3D = "res://addons/squiggles-core/assets/icons/interact_object_area3d.svg" +InteractionObjectStaticBody3D = "res://addons/squiggles-core/assets/icons/interact_object_static3d.svg" +InteractionObjectCharacterBody3D = "res://addons/squiggles-core/assets/icons/interact_object_character3d.svg" ;; state_machine.rs -FiniteStateMachine = "res://addons/squiggles_core/assets/icons/fsm.svg" -FiniteState = "res://addons/squiggles_core/assets/icons/fsm_state.svg" -FiniteSubStateMachine = "res://addons/squiggles_core/assets/icons/fsm_sub_state.svg" +FiniteStateMachine = "res://addons/squiggles-core/assets/icons/fsm.svg" +FiniteState = "res://addons/squiggles-core/assets/icons/fsm_state.svg" +FiniteSubStateMachine = "res://addons/squiggles-core/assets/icons/fsm_sub_state.svg" ;; utility_nodes/gui_interact.rs -GuiInteract = "res://addons/squiggles_core/assets/icons/gui_interact.svg" +GuiInteract = "res://addons/squiggles-core/assets/icons/gui_interact.svg" diff --git a/src/scene/dialog/core_dialog.rs b/src/scene/dialog/core_dialog.rs index dc46d61..e8598df 100644 --- a/src/scene/dialog/core_dialog.rs +++ b/src/scene/dialog/core_dialog.rs @@ -1,7 +1,7 @@ use std::collections::VecDeque; use godot::{ - engine::{Engine, Json}, + engine::{self, Engine, Json}, prelude::*, }; @@ -154,8 +154,15 @@ impl CoreDialog { StringName::from(DialogEvents::SIGNAL_TRACK_SIGNAL), &[ name.to_variant(), - Array::from_iter(args.iter().map(|s| Json::parse_string(s.to_godot()))) - .to_variant(), + Array::from_iter(args.iter().map(|s| { + let mut json = Json::new_gd(); + if json.parse(s.to_godot()) != engine::global::Error::OK { + // handle invalid types as a simple string value + return s.to_variant(); + } + json.get_data() + })) + .to_variant(), ], ); } @@ -169,8 +176,12 @@ impl CoreDialog { pub fn blackboard_action(&mut self, action: GString) { self.blackboard.parse_action(action.to_string()); let Some((event_name, event_arg)) = self.blackboard.get_event() else { + if let Some(gui) = &mut self.gui { + gui.bind_mut().mark_event_handled(); + } return; }; + godot_print!("Processing event: {}({:#?})", event_name, event_arg); match event_name.as_str() { // TODO handle events with pub const value "end" => { @@ -183,7 +194,7 @@ impl CoreDialog { let Entry::Number(index) = event_arg else { return; }; - let index = (index.floor() - 1f32) as usize; + let index = (index.floor()) as usize; let Some(gui) = &mut self.gui else { return; }; @@ -197,6 +208,9 @@ impl CoreDialog { _ => godot_error!("Unhandled internal event! event: \"{}\"", event_name), } self.blackboard.mark_event_handled(); + if let Some(gui) = &mut self.gui { + gui.bind_mut().mark_event_handled(); + } } #[func] diff --git a/src/scene/dialog/dialog_blackboard.rs b/src/scene/dialog/dialog_blackboard.rs index 437e3e9..e4946cd 100644 --- a/src/scene/dialog/dialog_blackboard.rs +++ b/src/scene/dialog/dialog_blackboard.rs @@ -77,9 +77,10 @@ impl Default for Blackboard { impl Blackboard { /// Parses the action string pub fn parse_action(&mut self, code: String) { - // godot_print!("Running action(s): {}", code); + if code.is_empty() { + return; + } for action in code.split(';') { - // godot_print!("Running sub-action: {}", action); let mut parts = VecDeque::from_iter(action.trim().split(' ').map(|dirty| dirty.trim())); let command = parts.pop_front().unwrap_or(""); let mut callback: Option<_> = None; @@ -114,12 +115,9 @@ impl Blackboard { } pub fn parse_query(&mut self, code: String) -> bool { - // godot_print!("Running quer(y/ies): {}", code); for query in code.split("and") { let mut chunk_val = false; for options in query.split("or") { - // godot_print!("Running sub-query: {}", options); - let parts = Vec::from_iter(options.split_whitespace()); if parts.len() != 3 { if query.contains('\"') { @@ -141,7 +139,6 @@ impl Blackboard { fn parse_query_value(&mut self, query: (&str, &str, &str)) -> bool { let arg1 = self.get_numeric_value(query.0); let arg2 = self.get_numeric_value(query.2); - // godot_print!("Running internal comparison: {} {} {}", arg1, query.1, arg2); match query.1 { "==" => arg1 == arg2, "!=" => arg1 != arg2, @@ -168,7 +165,6 @@ impl Blackboard { return; }; self.entries.insert(key.to_string(), entry.clone()); - // godot_print!("Set value: {} = {}. Enum value: {}", key, value, entry); } pub fn unset(&mut self, key: &str) { @@ -387,6 +383,14 @@ impl Blackboard { Some(self.entries.get(key)?.clone()) } + pub fn has_entry(&self, key: &str) -> bool { + self.entries.contains_key(key) + } + + pub fn has_event(&self) -> bool { + self.has_entry(Self::EVENT_KEY) + } + pub fn debug_print(&self) { let mappings: Vec = self .entries @@ -399,7 +403,6 @@ impl Blackboard { buffer += "\n"; } buffer += " }"; - // godot_print!("{}", buffer); } } diff --git a/src/scene/dialog/dialog_gui.rs b/src/scene/dialog/dialog_gui.rs index 18bc5b1..32cdae0 100644 --- a/src/scene/dialog/dialog_gui.rs +++ b/src/scene/dialog/dialog_gui.rs @@ -21,6 +21,16 @@ use super::{ dialog_track::{ChoiceOptionEntry, Line}, }; +/// The current state of the Dialog GUI, +#[derive(Debug, Default, PartialEq)] +enum DialogState { + /// Active meaning we are actively processing nodes and pushing data to be visible + #[default] + Active, + /// Pending meaning we are currently waiting on an external process and don't want to create a degenerate reference to CoreDialog by forcing a push + Pending, +} + #[derive(GodotClass)] #[class(init, base=CanvasLayer)] pub struct DialogGUI { @@ -30,6 +40,7 @@ pub struct DialogGUI { dialog_text: Option>, options_root: Option>, current_index: usize, + state: DialogState, #[base] base: Base, } @@ -44,7 +55,7 @@ impl ICanvasLayer for DialogGUI { self.create_structure(); if let Some(line) = self.get_next_text_line() { self.load_line(&line); - } else { + } else if self.state != DialogState::Pending { godot_warn!( "No text nodes found in dialog track on load. Something must have gone wrong?" ); @@ -73,6 +84,13 @@ impl ICanvasLayer for DialogGUI { self.load_next_line(); } } + fn process(&mut self, _delta: f64) { + if self.state != DialogState::Pending { + return; + } + // downtime should only be for 2-3 frames MAX! so this aaggresive polling ***shouldn't*** have a big effect on the performance?? + self.load_next_line(); + } fn exit_tree(&mut self) { //pass @@ -211,17 +229,18 @@ impl DialogGUI { root.add_child(button.clone().upcast()); button.set_text(self.parse_text(&option.text).into()); let action = option.action.clone(); + if !action.is_empty() { + self.state = DialogState::Pending; + } button .connect_ex( "pressed".into(), Callable::from_fn( format!("choice_button_{} ({})", index, option.text), move |_| { - if !action.is_empty() { - CoreDialog::singleton() - .bind_mut() - .blackboard_action(action.clone().into()); - } + CoreDialog::singleton() + .bind_mut() + .blackboard_action(action.clone().into()); let Some(gui) = &mut CoreDialog::singleton().bind().gui.clone() else { godot_error!( "Failed to find instance of the CoreDialog's DialogGUI" @@ -341,9 +360,11 @@ impl DialogGUI { options, } => Some(line), Line::Action { action } => { + self.state = DialogState::Pending; + godot_print!("Pending processing for action {}", action); CoreDialog::singleton() .call_deferred("blackboard_action".into(), &[action.to_variant()]); - continue; + return None; // force break to allow processing events } Line::Signal { name, args } => { CoreDialog::singleton() @@ -417,12 +438,15 @@ impl DialogGUI { } fn load_next_line(&mut self) { + if self.state == DialogState::Pending { + return; + } + let Some(margin) = self.base().get_child(0) else { godot_error!("Failed to access child of DialogGUI!"); return; }; let margin = margin.cast::(); - if let Some(line) = self.get_next_text_line() { self.load_line(&line); } else { @@ -444,6 +468,11 @@ impl DialogGUI { } } + pub fn mark_event_handled(&mut self) { + godot_print!("Action marked as handled"); + self.state = DialogState::Active; + } + fn parse_text(&self, in_text: &String) -> String { let trans = self.base().tr(in_text.into()).into(); CoreDialog::singleton().bind().blackboard_parse(trans) diff --git a/src/scene/interaction.rs b/src/scene/interaction.rs index 0854d6a..3a23009 100644 --- a/src/scene/interaction.rs +++ b/src/scene/interaction.rs @@ -106,8 +106,10 @@ impl InteractRaycast3D { #[func] fn do_interact(&mut self) { - if let Some(mut target) = self.target.clone() { - target.call_deferred(StringName::from(METHOD_INTERACT), &[]); + if let Some(target) = self.target.as_mut() { + if target.is_instance_valid() { + target.call_deferred(StringName::from(METHOD_INTERACT), &[]); + } } } }