this repo has no description

Compare changes

Choose any two refs to compare.

+4 -1
.gitignore
··· 1 1 node_modules 2 2 dist 3 3 builds 4 - target 4 + target 5 + 6 + .vscode/ 7 + .idea/
-8
.idea/.gitignore
··· 1 - # Default ignored files 2 - /shelf/ 3 - /workspace.xml 4 - # Editor-based HTTP Client requests 5 - /httpRequests/ 6 - # Datasource local storage ignored files 7 - /dataSources/ 8 - /dataSources.local.xml
-11
.idea/VRCMacros-UI.iml
··· 1 - <?xml version="1.0" encoding="UTF-8"?> 2 - <module type="EMPTY_MODULE" version="4"> 3 - <component name="NewModuleRootManager"> 4 - <content url="file://$MODULE_DIR$"> 5 - <sourceFolder url="file://$MODULE_DIR$/src-tauri/src" isTestSource="false" /> 6 - <excludeFolder url="file://$MODULE_DIR$/src-tauri/target" /> 7 - </content> 8 - <orderEntry type="inheritedJdk" /> 9 - <orderEntry type="sourceFolder" forTests="false" /> 10 - </component> 11 - </module>
-8
.idea/modules.xml
··· 1 - <?xml version="1.0" encoding="UTF-8"?> 2 - <project version="4"> 3 - <component name="ProjectModuleManager"> 4 - <modules> 5 - <module fileurl="file://$PROJECT_DIR$/.idea/VRCMacros-UI.iml" filepath="$PROJECT_DIR$/.idea/VRCMacros-UI.iml" /> 6 - </modules> 7 - </component> 8 - </project>
-6
.idea/vcs.xml
··· 1 - <?xml version="1.0" encoding="UTF-8"?> 2 - <project version="4"> 3 - <component name="VcsDirectoryMappings"> 4 - <mapping directory="" vcs="Git" /> 5 - </component> 6 - </project>
-3
.vscode/extensions.json
··· 1 - { 2 - "recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"] 3 - }
+3 -1
src/App.tsx
··· 15 15 import * as keybinds from './keybinds'; 16 16 import { listen } from "@tauri-apps/api/event"; 17 17 18 + // TODO: Only allow one node to input on non-flow inputs 19 + 18 20 let App = () => { 19 21 let [ selectedNodes, setSelectedNodes ] = createSignal<Node[]>([], { equals: false }); 20 22 let [ mousePos, setMousePos ] = createSignal<[ number, number ]>([ 0, 0 ]); ··· 402 404 isMouseDown = false; 403 405 } 404 406 405 - keybinds.load(mousePos, selectedNodes, setSelectedNodes); 407 + keybinds.load(canvas, mousePos, selectedNodes, setSelectedNodes); 406 408 requestAnimationFrame(update); 407 409 408 410 let unlisten_0 = await listen('hide-window', () => {
+31 -2
src/Mangers/NodeManager.tsx
··· 27 27 setInterval(() => { 28 28 let tabs = Object.values(this._tabs).filter(x => x.needSync); 29 29 for(let tab of tabs){ 30 - invoke('sync_tab', { graph: this._generateTabGraph(tab.id)[0], id: tab.id, name: tab.name, location: tab.saveLocation }); 30 + invoke('sync_tab', { 31 + graph: this._generateTabGraph(tab.id)[0], 32 + id: tab.id, 33 + name: tab.name, 34 + location: tab.saveLocation, 35 + saveState: tab.needsSave() 36 + }); 37 + 31 38 tab.needSync = false; 32 39 } 33 40 }, 1000); ··· 40 47 let version = await getVersion(); 41 48 42 49 for(let tab of Object.entries<any>(tabs)){ 43 - await this._loadFromConfig(tab[1][2], tab[0], JSON.stringify({ 50 + let loaded_tab = await this._loadFromConfig(tab[1][2], tab[0], JSON.stringify({ 44 51 tab_name: tab[1][1], 45 52 version, 46 53 graph: tab[1][0] 47 54 })); 55 + 56 + if(loaded_tab) 57 + loaded_tab.setNeedsSave(tab[1][3]); 48 58 }; 49 59 50 60 this.UpdateConfig(); ··· 336 346 337 347 tab.needSync = false; 338 348 if(!id)this.UpdateConfig(false); 349 + 350 + return tab; 339 351 } 340 352 341 353 private _generateTabGraph( tabId: string | null ): [ any, Tab | null ]{ ··· 351 363 let node = tab.nodes[i]; 352 364 353 365 let nodeOutputs = []; 366 + let nodeInputs = []; 354 367 355 368 for (let j = 0; j < node.outputs.length; j++) { 356 369 let output = node.outputs[j]; ··· 367 380 }) 368 381 } 369 382 383 + for (let j = 0; j < node.inputs.length; j++) { 384 + let input = node.inputs[j]; 385 + 386 + nodeInputs.push({ 387 + name: input.name, 388 + type: input.type, 389 + connections: input.connections.map(x => { return { 390 + name: x.name, 391 + node: x.parent.id, 392 + index: x.index, 393 + type: x.type 394 + }}) 395 + }) 396 + } 397 + 370 398 nodesToSave.push({ 371 399 name: node.name, 372 400 id: node.id, 373 401 typeId: node.typeId, 374 402 pos: [ node.x, node.y ], 375 403 outputs: nodeOutputs, 404 + inputs: nodeInputs, 376 405 statics: node.statics 377 406 }) 378 407 }
-1
src/Nodes/Conditional/IfEqual.tsx
··· 9 9 typeId: 'ifequal', 10 10 11 11 w: 220, 12 - h: 150, 13 12 14 13 statics: [{ 15 14 type: NodeType.Label,
-1
src/Nodes/Conditional/IfFalse.tsx
··· 9 9 typeId: 'iffalse', 10 10 11 11 w: 220, 12 - h: 120, 13 12 14 13 statics: [{ 15 14 type: NodeType.Label,
-1
src/Nodes/Conditional/IfTrue.tsx
··· 9 9 typeId: 'iftrue', 10 10 11 11 w: 220, 12 - h: 120, 13 12 14 13 statics: [{ 15 14 type: NodeType.Label,
-1
src/Nodes/Debug.tsx
··· 9 9 typeId: 'debug', 10 10 11 11 w: 200, 12 - h: 110, 13 12 14 13 statics: [ 15 14 {
+1 -2
src/Nodes/Nodes.tsx
··· 17 17 onStaticsUpdate?: ( node: Node ) => Promise<void>, 18 18 // build?: ( pos: [ number, number ], onStaticsUpdate: ( node: Node ) => void ) => Promise<Node>, 19 19 w?: number, 20 - h?: number, 21 20 statics?: NodeStatic[], 22 21 inputs?: { name: string, type: NodeType }[], 23 22 outputs?: { name: string, type: NodeType }[], ··· 29 28 [details: string] : NodeDefinition; 30 29 } 31 30 32 - // TODO: (Node Additions) Pressing keyboard keys 31 + // TODO: (Node Additions) Pressing keyboard keys (like to do linux, but has extra steps) 33 32 // TODO: (Node Additions) Getting media state from os 34 33 // TODO: (Node Additions) Sending custom OSC messages 35 34 // TODO: (Node Additions) Sending HTTP requests?
-1
src/Nodes/OSCActions/Send Chatbox.tsx
··· 9 9 typeId: 'oscsendchatbox', 10 10 11 11 w: 200, 12 - h: 120, 13 12 14 13 statics: [{ 15 14 type: NodeType.Label,
+25 -10
src/Nodes/OSCTrigger.tsx
··· 12 12 typeId: 'osctrigger', 13 13 14 14 w: 200, 15 - h: 50, 16 15 17 16 statics: [ 18 17 { ··· 41 40 } 42 41 } 43 42 44 - node.outputs.map(output => { 45 - output.connections.map(partner => { 46 - partner.connections = partner.connections.filter(x => x != output); 47 - }) 48 - }) 49 - node.outputs = []; 43 + let tempOutputs = []; 50 44 51 - node.outputs.push({ 45 + tempOutputs.push({ 52 46 name: 'Flow', 53 47 type: NodeType.Flow, 54 48 connections: [], ··· 75 69 } 76 70 77 71 if(type){ 78 - node.outputs.push({ 72 + tempOutputs.push({ 79 73 name: dat.desc === '' ? dat.type : dat.desc, 80 74 type: type, 81 75 connections: [], ··· 85 79 } 86 80 }); 87 81 88 - node.h = 60 + (parameters.length + 1) * 30; 82 + let hasChanged = false; 83 + 84 + for(let i in tempOutputs){ 85 + if( 86 + node.outputs[i] === undefined || 87 + tempOutputs[i].type != node.outputs[i].type 88 + ){ 89 + hasChanged = true; 90 + } 91 + } 92 + 93 + if(hasChanged){ 94 + node.outputs.map(output => { 95 + output.connections.map(partner => { 96 + partner.connections = partner.connections.filter(x => x != output); 97 + }) 98 + }) 99 + 100 + node.outputs = tempOutputs; 101 + node.updateSize(); 102 + } 103 + 89 104 NodeManager.Instance.UpdateConfig(); 90 105 } 91 106 };
-1
src/Nodes/PressKey.tsx
··· 9 9 typeId: 'presskey', 10 10 11 11 w: 200, 12 - h: 80, 13 12 14 13 statics: [ 15 14 {
-1
src/Nodes/Shell.tsx
··· 9 9 typeId: 'shellcommand', 10 10 11 11 w: 200, 12 - h: 120, 13 12 14 13 statics: [], 15 14
-1
src/Nodes/Statics/Float.tsx
··· 9 9 typeId: 'staticfloat', 10 10 11 11 w: 200, 12 - h: 80, 13 12 14 13 statics: [{ 15 14 type: NodeType.Float,
-1
src/Nodes/Statics/Int.tsx
··· 9 9 typeId: 'staticint', 10 10 11 11 w: 200, 12 - h: 80, 13 12 14 13 statics: [{ 15 14 type: NodeType.Int,
-1
src/Nodes/Statics/String.tsx
··· 9 9 typeId: 'staticstring', 10 10 11 11 w: 200, 12 - h: 80, 13 12 14 13 statics: [{ 15 14 type: NodeType.String,
+9 -4
src/keybinds.ts
··· 6 6 7 7 let isKeyDown: any = {}; 8 8 9 - export let load = ( mousePos: Accessor<[ number, number ]>, selectedNode: Accessor<Node[]>, setSelectedNode: Setter<Node[]> ) => { 9 + export let load = ( canvas: HTMLCanvasElement, mousePos: Accessor<[ number, number ]>, selectedNode: Accessor<Node[]>, setSelectedNode: Setter<Node[]> ) => { 10 10 // TODO: Add undo / redo -ing 11 11 12 - window.onkeydown = async ( e ) => { 13 - isKeyDown[e.key] = true; 14 - 12 + canvas.onkeydown = async ( e ) => { 15 13 switch(e.key){ 16 14 case 'Delete': 17 15 let nodes = selectedNode(); ··· 33 31 34 32 setSelectedNode([]); 35 33 break; 34 + } 35 + } 36 + 37 + window.onkeydown = async ( e ) => { 38 + isKeyDown[e.key] = true; 39 + 40 + switch(e.key){ 36 41 case 's': 37 42 if(e.ctrlKey){ 38 43 let currentTab = NodeManager.Instance.CurrentTab();
+7 -2
src/structs/node.ts
··· 20 20 this.typeId = node.typeId!; 21 21 this.x = pos[0]; 22 22 this.y = pos[1]; 23 - this.w = node.w!; 24 - this.h = node.h!; 25 23 26 24 this.inputs = node.inputs ? node.inputs.map(( x, indx ) => { 27 25 return { ··· 43 41 } 44 42 }) : []; 45 43 44 + this.w = node.w || 200; 45 + this.h = 50 + Math.max(this.outputs.length, this.inputs.length) * 30; 46 + 46 47 this.selected = false; 47 48 this.statics = node.statics!, 48 49 this.onStaticsUpdate = node.onStaticsUpdate!; 50 + } 51 + 52 + updateSize(){ 53 + this.h = 50 + Math.max(this.outputs.length, this.inputs.length) * 30; 49 54 } 50 55 } 51 56
+3
src-tauri/Cargo.lock
··· 7 7 version = "0.1.0" 8 8 dependencies = [ 9 9 "anyhow", 10 + "chrono", 10 11 "crossbeam-channel", 11 12 "dirs", 12 13 "enigo", ··· 519 520 checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" 520 521 dependencies = [ 521 522 "iana-time-zone", 523 + "js-sys", 522 524 "num-traits", 523 525 "serde", 526 + "wasm-bindgen", 524 527 "windows-link 0.2.1", 525 528 ] 526 529
+2 -1
src-tauri/Cargo.toml
··· 31 31 tauri-plugin-clipboard-manager = "2" 32 32 tauri-plugin-os = "2" 33 33 34 - [target.'cfg(windows)'.dependencies] 34 + # [target.'cfg(windows)'.dependencies] 35 35 enigo = { version = "0.6.1" } 36 + chrono = "0.4.42" 36 37
+1 -1
src-tauri/src/frontend_calls/load_previous_tabs.rs
··· 8 8 pub fn load_previous_tabs( 9 9 window: Window, 10 10 conf: State<Config>, 11 - ) -> HashMap<String, (Vec<Node>, String, Option<String>)> { 11 + ) -> HashMap<String, (Vec<Node>, String, Option<String>, bool)> { 12 12 let config = conf.store.lock().unwrap(); 13 13 14 14 if !config.hide_editor_on_start {
+5 -1
src-tauri/src/frontend_calls/sync_tab.rs
··· 1 + use chrono::Utc; 1 2 use crossbeam_channel::Sender; 2 3 3 4 use tauri::State; ··· 9 10 graph: Vec<Node>, 10 11 id: String, 11 12 name: String, 13 + save_state: bool, 12 14 location: Option<String>, 13 15 cmd: State<Sender<RuntimeCommand>>, 14 16 conf: State<Config>, ··· 18 20 .unwrap(); 19 21 20 22 let mut config = conf.store.lock().unwrap(); 21 - config.loaded_tabs.insert(id, (graph, name, location)); // TODO: When loading a tab into config, store the save state of it too 23 + config.loaded_tabs.insert(id, (graph, name, location, save_state)); 24 + 25 + conf.save_prelocked(config); 22 26 } 23 27 24 28 #[tauri::command]
+5 -4
src-tauri/src/lib.rs
··· 3 3 use crossbeam_channel::bounded; 4 4 use frontend_calls::*; 5 5 6 - use crate::{osc::OSCMessage, setup::setup, utils::config::Config}; 6 + use crate::{osc::OSCMessage, setup::setup, utils::{config::Config, vrchat_builtin_parameters}}; 7 7 8 8 mod frontend_calls; 9 9 mod osc; ··· 11 11 mod setup; 12 12 mod structs; 13 13 mod utils; 14 - 15 - // TODO: Add built-in OSC endpoints 16 - // TODO: Read avatar paramaters from file 17 14 18 15 #[cfg_attr(mobile, tauri::mobile_entry_point)] 19 16 #[tokio::main] ··· 35 32 let conf = Config::new(conf_file); 36 33 37 34 static ADDRESSES: Mutex<Vec<OSCMessage>> = Mutex::new(Vec::new()); 35 + 36 + let mut addresses = ADDRESSES.lock().unwrap(); 37 + addresses.append(&mut vrchat_builtin_parameters::get_read_addresses()); 38 + drop(addresses); 38 39 39 40 let (runtime_sender, runtime_receiver) = bounded(1024); 40 41
+3 -1
src-tauri/src/main.rs
··· 3 3 4 4 fn main() { 5 5 #[cfg(target_os = "linux")] 6 - std::env::set_var("WEBKIT_DISABLE_DMABUF_RENDERER", "1"); // Fix webkit being shit 6 + unsafe{ 7 + std::env::set_var("WEBKIT_DISABLE_DMABUF_RENDERER", "1"); // Fix webkit being shit 8 + } 7 9 8 10 vrcmacros_lib::run() 9 11 }
+21 -38
src-tauri/src/runtime/nodes/conditional/ifequal.rs
··· 5 5 6 6 pub struct ConditionalIfEqual { 7 7 outputs: Vec<Vec<(String, isize, isize)>>, 8 - value1: ParameterType, 9 - value2: ParameterType, 8 + inputs: Vec<Option<(String, isize, isize)>>, 10 9 } 11 10 12 11 impl ConditionalIfEqual { 13 12 pub fn new(node: Node) -> Box<Self> { 14 13 Box::new(Self { 15 - outputs: node 16 - .outputs 17 - .iter() 18 - .map(|x| { 19 - x.connections 20 - .iter() 21 - .map(|x| (x.node.clone(), x.index, x.value_type)) 22 - .collect() 23 - }) 24 - .collect(), 25 - value1: ParameterType::None, 26 - value2: ParameterType::None, 14 + outputs: node.outputs.iter().map(|x| { 15 + x.connections.iter() 16 + .map(|x| (x.node.clone(), x.index, x.value_type)).collect()}).collect(), 17 + 18 + inputs: node.inputs.iter().map(|x| { 19 + let y = x.connections.get(0); 20 + if let Some(y) = y{ 21 + Some((y.node.clone(), y.index, y.value_type)) 22 + } else{ 23 + None 24 + } 25 + }).collect(), 27 26 }) 28 27 } 29 28 } ··· 31 30 impl RuntimeNode for ConditionalIfEqual { 32 31 fn outputs(&self) -> Vec<Vec<(String, isize, isize)>> { 33 32 self.outputs.clone() 34 - } 35 - fn execute_dry(&mut self, _: &Vec<ParameterType>) -> Option<Vec<ParameterType>> { 36 - Some(vec![]) 37 33 } 38 34 39 - fn execute(&mut self) -> Option<Vec<ParameterType>> { 40 - if self.value1 == ParameterType::None && self.value2 == ParameterType::None { 41 - None 42 - } else { 43 - let equal = self.value1 == self.value2; 44 - Some(vec![ 45 - ParameterType::Flow(equal), 46 - ParameterType::Flow(!equal), 47 - ]) 48 - } 35 + fn inputs(&self) -> Vec<Option<(String, isize, isize)>> { 36 + self.inputs.clone() 49 37 } 50 38 51 - fn update_arg(&mut self, index: usize, arg: ParameterType) -> bool { 52 - match index { 53 - 1 => { 54 - self.value1 = arg; 55 - } 56 - 2 => { 57 - self.value2 = arg; 58 - } 59 - _ => {} 60 - } 39 + fn execute(&mut self, args: Vec<ParameterType>) -> Vec<ParameterType> { 40 + let is_equal = args[1] == args[2]; 61 41 62 - false 42 + vec![ 43 + ParameterType::Flow(is_equal), 44 + ParameterType::Flow(!is_equal), 45 + ] 63 46 } 64 47 65 48 fn is_entrypoint(&self) -> bool {
+22 -28
src-tauri/src/runtime/nodes/conditional/iffalse.rs
··· 5 5 6 6 pub struct ConditionalIfFalse { 7 7 outputs: Vec<Vec<(String, isize, isize)>>, 8 - runtime_active: bool, 8 + inputs: Vec<Option<(String, isize, isize)>>, 9 9 } 10 10 11 11 impl ConditionalIfFalse { 12 12 pub fn new(node: Node) -> Box<Self> { 13 13 Box::new(Self { 14 - outputs: node 15 - .outputs 16 - .iter() 17 - .map(|x| { 18 - x.connections 19 - .iter() 20 - .map(|x| (x.node.clone(), x.index, x.value_type)) 21 - .collect() 22 - }) 23 - .collect(), 24 - runtime_active: false, 14 + outputs: node.outputs.iter().map(|x| { 15 + x.connections.iter() 16 + .map(|x| (x.node.clone(), x.index, x.value_type)).collect()}).collect(), 17 + 18 + inputs: node.inputs.iter().map(|x| { 19 + let y = x.connections.get(0); 20 + if let Some(y) = y{ 21 + Some((y.node.clone(), y.index, y.value_type)) 22 + } else{ 23 + None 24 + } 25 + }).collect(), 25 26 }) 26 27 } 27 28 } ··· 30 31 fn outputs(&self) -> Vec<Vec<(String, isize, isize)>> { 31 32 self.outputs.clone() 32 33 } 33 - fn execute_dry(&mut self, _: &Vec<ParameterType>) -> Option<Vec<ParameterType>> { 34 - Some(vec![]) 34 + 35 + fn inputs(&self) -> Vec<Option<(String, isize, isize)>> { 36 + self.inputs.clone() 35 37 } 36 38 37 - fn execute(&mut self) -> Option<Vec<ParameterType>> { 38 - Some(vec![ 39 - ParameterType::Flow(!self.runtime_active), 40 - ParameterType::Flow(self.runtime_active), 41 - ]) 42 - } 39 + fn execute(&mut self, args: Vec<ParameterType>) -> Vec<ParameterType> { 40 + let is_false = !args[1].as_bool().unwrap(); 43 41 44 - fn update_arg(&mut self, _: usize, arg: ParameterType) -> bool { 45 - if arg.as_bool().unwrap() { 46 - self.runtime_active = true; 47 - true 48 - } else { 49 - self.runtime_active = false; 50 - false 51 - } 42 + vec![ 43 + ParameterType::Flow(is_false), 44 + ParameterType::Flow(!is_false), 45 + ] 52 46 } 53 47 54 48 fn is_entrypoint(&self) -> bool {
+22 -28
src-tauri/src/runtime/nodes/conditional/iftrue.rs
··· 5 5 6 6 pub struct ConditionalIfTrue { 7 7 outputs: Vec<Vec<(String, isize, isize)>>, 8 - runtime_active: bool, 8 + inputs: Vec<Option<(String, isize, isize)>>, 9 9 } 10 10 11 11 impl ConditionalIfTrue { 12 12 pub fn new(node: Node) -> Box<Self> { 13 13 Box::new(Self { 14 - outputs: node 15 - .outputs 16 - .iter() 17 - .map(|x| { 18 - x.connections 19 - .iter() 20 - .map(|x| (x.node.clone(), x.index, x.value_type)) 21 - .collect() 22 - }) 23 - .collect(), 24 - runtime_active: false, 14 + outputs: node.outputs.iter().map(|x| { 15 + x.connections.iter() 16 + .map(|x| (x.node.clone(), x.index, x.value_type)).collect()}).collect(), 17 + 18 + inputs: node.inputs.iter().map(|x| { 19 + let y = x.connections.get(0); 20 + if let Some(y) = y{ 21 + Some((y.node.clone(), y.index, y.value_type)) 22 + } else{ 23 + None 24 + } 25 + }).collect(), 25 26 }) 26 27 } 27 28 } ··· 30 31 fn outputs(&self) -> Vec<Vec<(String, isize, isize)>> { 31 32 self.outputs.clone() 32 33 } 33 - fn execute_dry(&mut self, _: &Vec<ParameterType>) -> Option<Vec<ParameterType>> { 34 - Some(vec![]) 34 + 35 + fn inputs(&self) -> Vec<Option<(String, isize, isize)>> { 36 + self.inputs.clone() 35 37 } 36 38 37 - fn execute(&mut self) -> Option<Vec<ParameterType>> { 38 - Some(vec![ 39 - ParameterType::Flow(self.runtime_active), 40 - ParameterType::Flow(!self.runtime_active), 41 - ]) 42 - } 39 + fn execute(&mut self, args: Vec<ParameterType>) -> Vec<ParameterType> { 40 + let is_true = args[1].as_bool().unwrap(); 43 41 44 - fn update_arg(&mut self, _: usize, arg: ParameterType) -> bool { 45 - if arg.as_bool().unwrap() { 46 - self.runtime_active = true; 47 - true 48 - } else { 49 - self.runtime_active = false; 50 - false 51 - } 42 + vec![ 43 + ParameterType::Flow(is_true), 44 + ParameterType::Flow(!is_true), 45 + ] 52 46 } 53 47 54 48 fn is_entrypoint(&self) -> bool {
+23 -19
src-tauri/src/runtime/nodes/debug.rs
··· 4 4 }; 5 5 6 6 pub struct Debug { 7 - to_log: Option<ParameterType>, 7 + outputs: Vec<Vec<(String, isize, isize)>>, 8 + inputs: Vec<Option<(String, isize, isize)>> 8 9 } 9 10 10 11 impl Debug { 11 - pub fn new(_: Node) -> Box<Self> { 12 - Box::new(Self { to_log: None }) 12 + pub fn new(node: Node) -> Box<Self> { 13 + Box::new(Self { 14 + outputs: node.outputs.iter().map(|x| { 15 + x.connections.iter() 16 + .map(|x| (x.node.clone(), x.index, x.value_type)).collect()}).collect(), 17 + 18 + inputs: node.inputs.iter().map(|x| { 19 + let y = x.connections.get(0); 20 + if let Some(y) = y{ 21 + Some((y.node.clone(), y.index, y.value_type)) 22 + } else{ 23 + None 24 + } 25 + }).collect(), 26 + }) 13 27 } 14 28 } 15 29 16 30 impl RuntimeNode for Debug { 17 31 fn outputs(&self) -> Vec<Vec<(String, isize, isize)>> { 18 - vec![] 19 - } 20 - fn execute_dry(&mut self, _: &Vec<ParameterType>) -> Option<Vec<ParameterType>> { 21 - Some(vec![]) 32 + self.outputs.clone() 22 33 } 23 34 24 - fn execute(&mut self) -> Option<Vec<ParameterType>> { 25 - dbg!(&self.to_log); // TODO: Debug to actual UI instead of console 26 - self.to_log = None; 27 - 28 - None 35 + fn inputs(&self) -> Vec<Option<(String, isize, isize)>> { 36 + self.inputs.clone() 29 37 } 30 38 31 - fn update_arg(&mut self, index: usize, value: ParameterType) -> bool { 32 - if index == 1 { 33 - self.to_log = Some(value); 34 - true 35 - } else { 36 - false 37 - } 39 + fn execute(&mut self, args: Vec<ParameterType>) -> Vec<ParameterType> { 40 + dbg!(&args); // TODO: Debug to actual UI instead of console 41 + vec![] 38 42 } 39 43 40 44 fn is_entrypoint(&self) -> bool {
+33 -25
src-tauri/src/runtime/nodes/oscactions/sendchatbox.rs
··· 7 7 }; 8 8 9 9 pub struct OSCActionsSendChatbox { 10 - to_log: String, 10 + outputs: Vec<Vec<(String, isize, isize)>>, 11 + inputs: Vec<Option<(String, isize, isize)>>, 11 12 } 12 13 13 14 impl OSCActionsSendChatbox { 14 - pub fn new(_: Node) -> Box<Self> { 15 - Box::new(Self { to_log: "".into() }) 15 + pub fn new(node: Node) -> Box<Self> { 16 + Box::new(Self { 17 + outputs: node.outputs.iter().map(|x| { 18 + x.connections.iter() 19 + .map(|x| (x.node.clone(), x.index, x.value_type)).collect()}).collect(), 20 + 21 + inputs: node.inputs.iter().map(|x| { 22 + let y = x.connections.get(0); 23 + if let Some(y) = y{ 24 + Some((y.node.clone(), y.index, y.value_type)) 25 + } else{ 26 + None 27 + } 28 + }).collect(), 29 + }) 16 30 } 17 31 } 18 32 19 33 impl RuntimeNode for OSCActionsSendChatbox { 20 34 fn outputs(&self) -> Vec<Vec<(String, isize, isize)>> { 21 - vec![] 22 - } 23 - fn execute_dry(&mut self, _: &Vec<ParameterType>) -> Option<Vec<ParameterType>> { 24 - Some(vec![]) 35 + self.outputs.clone() 25 36 } 26 37 27 - fn execute(&mut self) -> Option<Vec<ParameterType>> { 28 - osc::send_message( 29 - "/chatbox/input", 30 - vec![ 31 - ParameterType::String(self.to_log.clone()), 32 - ParameterType::Boolean(true), 33 - ParameterType::Boolean(false), 34 - ], 35 - "127.0.0.1:9000", 36 - ); 37 - 38 - None 38 + fn inputs(&self) -> Vec<Option<(String, isize, isize)>> { 39 + self.inputs.clone() 39 40 } 40 41 41 - fn update_arg(&mut self, index: usize, value: ParameterType) -> bool { 42 - if index == 1 { 43 - self.to_log = value.as_string().unwrap(); 44 - true 45 - } else { 46 - false 42 + fn execute(&mut self, args: Vec<ParameterType>) -> Vec<ParameterType> { 43 + if let Ok(msg) = args[1].as_string(){ 44 + osc::send_message( 45 + "/chatbox/input", 46 + vec![ 47 + ParameterType::String(msg.clone()), 48 + ParameterType::Boolean(true), 49 + ParameterType::Boolean(false), 50 + ], 51 + "127.0.0.1:9000", 52 + ); 47 53 } 54 + 55 + vec![] 48 56 } 49 57 50 58 fn is_entrypoint(&self) -> bool {
+32 -42
src-tauri/src/runtime/nodes/osctrigger.rs
··· 5 5 6 6 pub struct OSCTrigger { 7 7 outputs: Vec<Vec<(String, isize, isize)>>, 8 - address: Option<String>, 9 - runtime_active: bool, 8 + inputs: Vec<Option<(String, isize, isize)>>, 9 + 10 + address: Option<String> 10 11 } 11 12 12 13 impl OSCTrigger { ··· 14 15 let value = &node.statics[0].value; 15 16 16 17 Box::new(Self { 18 + outputs: node.outputs.iter().map(|x| { 19 + x.connections.iter() 20 + .map(|x| (x.node.clone(), x.index, x.value_type)).collect()}).collect(), 21 + 22 + inputs: node.inputs.iter().map(|x| { 23 + let y = x.connections.get(0); 24 + if let Some(y) = y{ 25 + Some((y.node.clone(), y.index, y.value_type)) 26 + } else{ 27 + None 28 + } 29 + }).collect(), 30 + 17 31 address: if value.is_null() { 18 32 None 19 33 } else { 20 34 Some(value.as_str().unwrap().to_owned()) 21 35 }, 22 - outputs: node 23 - .outputs 24 - .iter() 25 - .map(|x| { 26 - x.connections 27 - .iter() 28 - .map(|x| (x.node.clone(), x.index, x.value_type)) 29 - .collect() 30 - }) 31 - .collect(), 32 - runtime_active: false, 33 36 }) 34 37 } 35 38 } ··· 39 42 self.outputs.clone() 40 43 } 41 44 42 - fn execute_dry(&mut self, msg: &Vec<ParameterType>) -> Option<Vec<ParameterType>> { 43 - if self.address.is_none() { 44 - self.runtime_active = false; 45 - return None; 46 - } 47 - 48 - if let ParameterType::String(address) = &msg[0] { 49 - if *address == *self.address.as_ref().unwrap() { 50 - self.runtime_active = true; 51 - Some(msg.clone()) 52 - // The first value is technically the address value, 53 - // but this value gets ignored as the first output of 54 - // the osctrigger node is a flow output which gets ignored 55 - // on dry runs. 56 - } else { 57 - self.runtime_active = false; 58 - None 59 - } 60 - } else { 61 - self.runtime_active = false; 62 - None 63 - } 45 + fn inputs(&self) -> Vec<Option<(String, isize, isize)>> { 46 + self.inputs.clone() 64 47 } 65 48 66 - fn execute(&mut self) -> Option<Vec<ParameterType>> { 67 - let execute = self.runtime_active; 68 - self.runtime_active = false; 49 + fn execute(&mut self, mut args: Vec<ParameterType>) -> Vec<ParameterType> { 50 + if args.len() == 0{ return args } 51 + 52 + let execute = if let Some(internal_address) = &self.address { 53 + if let Ok(address) = args[0].as_string() { 54 + address == *internal_address 55 + } else{ 56 + false 57 + } 58 + } else{ 59 + false 60 + }; 69 61 70 - Some(vec![ParameterType::Flow(execute)]) 62 + args[0] = ParameterType::Flow(execute); 63 + args 71 64 } 72 65 73 - fn update_arg(&mut self, _: usize, _: ParameterType) -> bool { 74 - false 75 - } 76 66 fn is_entrypoint(&self) -> bool { 77 67 true 78 68 }
+22 -9
src-tauri/src/runtime/nodes/press_key.rs
··· 8 8 }; 9 9 10 10 pub struct PressKey { 11 + outputs: Vec<Vec<(String, isize, isize)>>, 12 + inputs: Vec<Option<(String, isize, isize)>>, 13 + 11 14 key: Option<char>, 12 15 enigo: Arc<Mutex<Enigo>>, 13 16 } ··· 17 20 let value = &node.statics[0].value; 18 21 19 22 Box::new(Self { 23 + outputs: node.outputs.iter().map(|x| { 24 + x.connections.iter() 25 + .map(|x| (x.node.clone(), x.index, x.value_type)).collect()}).collect(), 26 + 27 + inputs: node.inputs.iter().map(|x| { 28 + let y = x.connections.get(0); 29 + if let Some(y) = y{ 30 + Some((y.node.clone(), y.index, y.value_type)) 31 + } else{ 32 + None 33 + } 34 + }).collect(), 35 + 20 36 enigo, 21 37 key: if value.is_null() { 22 38 None ··· 35 51 36 52 impl RuntimeNode for PressKey { 37 53 fn outputs(&self) -> Vec<Vec<(String, isize, isize)>> { 38 - vec![] 54 + self.outputs.clone() 39 55 } 40 - fn execute_dry(&mut self, _: &Vec<ParameterType>) -> Option<Vec<ParameterType>> { 41 - Some(vec![]) 56 + 57 + fn inputs(&self) -> Vec<Option<(String, isize, isize)>> { 58 + self.inputs.clone() 42 59 } 43 60 44 - fn execute(&mut self) -> Option<Vec<ParameterType>> { 61 + fn execute(&mut self, _: Vec<ParameterType>) -> Vec<ParameterType> { 45 62 if self.key.is_some() { 46 63 let mut enigo = self.enigo.lock().unwrap(); 47 64 enigo.key(Key::MediaPlayPause, Direction::Click).unwrap(); 48 65 } 49 66 50 - None 51 - } 52 - 53 - fn update_arg(&mut self, _: usize, _: ParameterType) -> bool { 54 - false 67 + vec![] 55 68 } 56 69 57 70 fn is_entrypoint(&self) -> bool {
+37 -31
src-tauri/src/runtime/nodes/shell.rs
··· 1 - use std::process::Command; 1 + use std::{io::Stdin, process::{Command, Stdio}}; 2 2 3 3 use crate::{ 4 4 runtime::nodes::RuntimeNode, ··· 6 6 }; 7 7 8 8 pub struct ShellCommand { 9 - cmd: String 9 + outputs: Vec<Vec<(String, isize, isize)>>, 10 + inputs: Vec<Option<(String, isize, isize)>> 10 11 } 11 12 12 13 impl ShellCommand { 13 14 pub fn new(node: Node) -> Box<Self> { 14 15 Box::new(Self { 15 - cmd: "".to_owned() 16 + outputs: node.outputs.iter().map(|x| { 17 + x.connections.iter() 18 + .map(|x| (x.node.clone(), x.index, x.value_type)).collect()}).collect(), 19 + 20 + inputs: node.inputs.iter().map(|x| { 21 + let y = x.connections.get(0); 22 + if let Some(y) = y{ 23 + Some((y.node.clone(), y.index, y.value_type)) 24 + } else{ 25 + None 26 + } 27 + }).collect() 16 28 }) 17 29 } 18 30 } 19 31 20 32 impl RuntimeNode for ShellCommand { 21 33 fn outputs(&self) -> Vec<Vec<(String, isize, isize)>> { 22 - vec![] 34 + self.outputs.clone() 23 35 } 24 - fn execute_dry(&mut self, _: &Vec<ParameterType>) -> Option<Vec<ParameterType>> { 25 - Some(vec![]) 36 + 37 + fn inputs(&self) -> Vec<Option<(String, isize, isize)>> { 38 + self.inputs.clone() 26 39 } 27 40 28 - fn execute(&mut self) -> Option<Vec<ParameterType>> { 29 - dbg!(&self.cmd); 30 - 31 - if self.cmd != ""{ 32 - let mut split_cmd = self.cmd.split(" "); 33 - 34 - let mut cmd = Command::new(split_cmd.nth(0).unwrap()); 35 - if split_cmd.clone().count() > 0{ cmd.args(split_cmd); } 41 + fn execute(&mut self, args: Vec<ParameterType>) -> Vec<ParameterType> { 42 + if let Ok(cmd) = args[1].as_string(){ 43 + if cmd != ""{ 44 + let mut split_cmd = cmd.split(" "); 36 45 37 - let child = cmd.spawn().unwrap(); 38 - let output = child.wait_with_output().unwrap(); 46 + let mut cmd = Command::new(split_cmd.nth(0).unwrap()); 47 + if split_cmd.clone().count() > 0{ cmd.args(split_cmd); } 39 48 40 - self.cmd = "".to_owned(); 49 + cmd.stdout(Stdio::piped()); 50 + cmd.stderr(Stdio::piped()); 41 51 42 - Some(vec![ 43 - ParameterType::Flow(true), 44 - ParameterType::String(str::from_utf8(&output.stdout).unwrap().to_owned()) 45 - ]) 46 - } else{ 47 - None 48 - } 49 - } 52 + let child = cmd.spawn().unwrap(); 53 + let output = child.wait_with_output().unwrap(); 50 54 51 - fn update_arg(&mut self, index: usize, arg: ParameterType) -> bool { 52 - if index == 1{ 53 - if let ParameterType::String(cmd) = arg { 54 - self.cmd = cmd; 55 + vec![ 56 + ParameterType::Flow(true), 57 + ParameterType::String(str::from_utf8(&output.stdout).unwrap().to_owned()) 58 + ] 59 + } else{ 60 + vec![ ParameterType::Flow(false) ] 55 61 } 62 + } else{ 63 + vec![ ParameterType::Flow(false) ] 56 64 } 57 - 58 - false 59 65 } 60 66 61 67 fn is_entrypoint(&self) -> bool {
+24 -22
src-tauri/src/runtime/nodes/statics/float.rs
··· 5 5 6 6 pub struct StaticFloat { 7 7 outputs: Vec<Vec<(String, isize, isize)>>, 8 + inputs: Vec<Option<(String, isize, isize)>>, 9 + 8 10 value: Option<f32>, 9 11 } 10 12 ··· 13 15 let value = &node.statics[0].value; 14 16 15 17 Box::new(Self { 18 + outputs: node.outputs.iter().map(|x| { 19 + x.connections.iter() 20 + .map(|x| (x.node.clone(), x.index, x.value_type)).collect()}).collect(), 21 + 22 + inputs: node.inputs.iter().map(|x| { 23 + let y = x.connections.get(0); 24 + if let Some(y) = y{ 25 + Some((y.node.clone(), y.index, y.value_type)) 26 + } else{ 27 + None 28 + } 29 + }).collect(), 30 + 16 31 value: if value.is_null() { 17 32 None 18 33 } else { 19 34 Some(value.as_f64().unwrap() as f32) 20 - }, 21 - outputs: node 22 - .outputs 23 - .iter() 24 - .map(|x| { 25 - x.connections 26 - .iter() 27 - .map(|x| (x.node.clone(), x.index, x.value_type)) 28 - .collect() 29 - }) 30 - .collect(), 35 + } 31 36 }) 32 37 } 33 38 } ··· 37 42 self.outputs.clone() 38 43 } 39 44 40 - fn execute_dry(&mut self, _: &Vec<ParameterType>) -> Option<Vec<ParameterType>> { 45 + fn inputs(&self) -> Vec<Option<(String, isize, isize)>> { 46 + self.inputs.clone() 47 + } 48 + 49 + fn execute(&mut self, _: Vec<ParameterType>) -> Vec<ParameterType> { 41 50 if self.value.is_some() { 42 - Some(vec![ParameterType::Float(self.value.clone().unwrap())]) 51 + vec![ParameterType::Float(self.value.clone().unwrap())] 43 52 } else { 44 - None 53 + vec![ParameterType::Float(0.0)] 45 54 } 46 55 } 47 56 48 - fn execute(&mut self) -> Option<Vec<ParameterType>> { 49 - None 50 - } 51 - 52 - fn update_arg(&mut self, _: usize, _: ParameterType) -> bool { 57 + fn is_entrypoint(&self) -> bool { 53 58 false 54 - } 55 - fn is_entrypoint(&self) -> bool { 56 - true 57 59 } 58 60 }
+24 -22
src-tauri/src/runtime/nodes/statics/int.rs
··· 5 5 6 6 pub struct StaticInt { 7 7 outputs: Vec<Vec<(String, isize, isize)>>, 8 + inputs: Vec<Option<(String, isize, isize)>>, 9 + 8 10 value: Option<i32>, 9 11 } 10 12 ··· 13 15 let value = &node.statics[0].value; 14 16 15 17 Box::new(Self { 18 + outputs: node.outputs.iter().map(|x| { 19 + x.connections.iter() 20 + .map(|x| (x.node.clone(), x.index, x.value_type)).collect()}).collect(), 21 + 22 + inputs: node.inputs.iter().map(|x| { 23 + let y = x.connections.get(0); 24 + if let Some(y) = y{ 25 + Some((y.node.clone(), y.index, y.value_type)) 26 + } else{ 27 + None 28 + } 29 + }).collect(), 30 + 16 31 value: if value.is_null() { 17 32 None 18 33 } else { 19 34 Some(value.as_i64().unwrap() as i32) 20 - }, 21 - outputs: node 22 - .outputs 23 - .iter() 24 - .map(|x| { 25 - x.connections 26 - .iter() 27 - .map(|x| (x.node.clone(), x.index, x.value_type)) 28 - .collect() 29 - }) 30 - .collect(), 35 + } 31 36 }) 32 37 } 33 38 } ··· 37 42 self.outputs.clone() 38 43 } 39 44 40 - fn execute_dry(&mut self, _: &Vec<ParameterType>) -> Option<Vec<ParameterType>> { 45 + fn inputs(&self) -> Vec<Option<(String, isize, isize)>> { 46 + self.inputs.clone() 47 + } 48 + 49 + fn execute(&mut self, _: Vec<ParameterType>) -> Vec<ParameterType> { 41 50 if self.value.is_some() { 42 - Some(vec![ParameterType::Int(self.value.clone().unwrap())]) 51 + vec![ParameterType::Int(self.value.clone().unwrap())] 43 52 } else { 44 - None 53 + vec![ParameterType::Int(0)] 45 54 } 46 55 } 47 56 48 - fn execute(&mut self) -> Option<Vec<ParameterType>> { 49 - None 50 - } 51 - 52 - fn update_arg(&mut self, _: usize, _: ParameterType) -> bool { 57 + fn is_entrypoint(&self) -> bool { 53 58 false 54 - } 55 - fn is_entrypoint(&self) -> bool { 56 - true 57 59 } 58 60 }
+24 -22
src-tauri/src/runtime/nodes/statics/string.rs
··· 5 5 6 6 pub struct StaticString { 7 7 outputs: Vec<Vec<(String, isize, isize)>>, 8 + inputs: Vec<Option<(String, isize, isize)>>, 9 + 8 10 value: Option<String>, 9 11 } 10 12 ··· 13 15 let value = &node.statics[0].value; 14 16 15 17 Box::new(Self { 18 + outputs: node.outputs.iter().map(|x| { 19 + x.connections.iter() 20 + .map(|x| (x.node.clone(), x.index, x.value_type)).collect()}).collect(), 21 + 22 + inputs: node.inputs.iter().map(|x| { 23 + let y = x.connections.get(0); 24 + if let Some(y) = y{ 25 + Some((y.node.clone(), y.index, y.value_type)) 26 + } else{ 27 + None 28 + } 29 + }).collect(), 30 + 16 31 value: if value.is_null() { 17 32 None 18 33 } else { 19 34 Some(value.as_str().unwrap().to_owned()) 20 - }, 21 - outputs: node 22 - .outputs 23 - .iter() 24 - .map(|x| { 25 - x.connections 26 - .iter() 27 - .map(|x| (x.node.clone(), x.index, x.value_type)) 28 - .collect() 29 - }) 30 - .collect(), 35 + } 31 36 }) 32 37 } 33 38 } ··· 37 42 self.outputs.clone() 38 43 } 39 44 40 - fn execute_dry(&mut self, _: &Vec<ParameterType>) -> Option<Vec<ParameterType>> { 45 + fn inputs(&self) -> Vec<Option<(String, isize, isize)>> { 46 + self.inputs.clone() 47 + } 48 + 49 + fn execute(&mut self, _: Vec<ParameterType>) -> Vec<ParameterType> { 41 50 if self.value.is_some() { 42 - Some(vec![ParameterType::String(self.value.clone().unwrap())]) 51 + vec![ParameterType::String(self.value.clone().unwrap())] 43 52 } else { 44 - None 53 + vec![ParameterType::String("".to_owned())] 45 54 } 46 55 } 47 56 48 - fn execute(&mut self) -> Option<Vec<ParameterType>> { 49 - None 50 - } 51 - 52 - fn update_arg(&mut self, _: usize, _: ParameterType) -> bool { 57 + fn is_entrypoint(&self) -> bool { 53 58 false 54 - } 55 - fn is_entrypoint(&self) -> bool { 56 - true 57 59 } 58 60 }
+9 -9
src-tauri/src/runtime/nodes.rs
··· 3 3 sync::{Arc, Mutex}, 4 4 }; 5 5 6 - #[cfg(target_os = "windows")] 6 + // #[cfg(target_os = "windows")] 7 7 use enigo::Enigo; 8 8 9 9 use crate::{ ··· 15 15 structs::{nodes::Node, parameter_types::ParameterType}, 16 16 }; 17 17 18 - #[cfg(target_os = "windows")] 18 + // #[cfg(target_os = "windows")] 19 19 use crate::runtime::nodes::press_key::PressKey; 20 20 21 21 mod conditional; ··· 25 25 mod statics; 26 26 mod shell; 27 27 28 - #[cfg(target_os = "windows")] 28 + // #[cfg(target_os = "windows")] 29 29 mod press_key; 30 30 31 31 pub struct RuntimeNodeTree { ··· 35 35 unsafe impl Send for RuntimeNodeTree {} 36 36 37 37 impl RuntimeNodeTree { 38 - pub fn from(tree: Vec<Node>, #[cfg(target_os = "windows")] enigo: Arc<Mutex<Enigo>>) -> Self { 38 + pub fn from(tree: Vec<Node>, /*#[cfg(target_os = "windows")]*/ enigo: Arc<Mutex<Enigo>>) -> Self { 39 39 let mut runtime_nodes: HashMap<String, Box<dyn RuntimeNode>> = HashMap::new(); 40 40 for node in tree { 41 41 match node.type_id.as_str() { ··· 71 71 runtime_nodes.insert(node.id.clone(), Debug::new(node)); 72 72 } 73 73 74 - #[cfg(target_os = "windows")] 74 + // #[cfg(target_os = "windows")] 75 75 "presskey" => { 76 76 runtime_nodes.insert(node.id.clone(), PressKey::new(node, enigo.clone())); 77 77 } ··· 92 92 93 93 pub trait RuntimeNode { 94 94 fn outputs(&self) -> Vec<Vec<(String, isize, isize)>>; // Node ID, input index, output value type 95 - fn execute_dry(&mut self, msg: &Vec<ParameterType>) -> Option<Vec<ParameterType>>; // Only update values on the first loop through 96 - fn execute(&mut self) -> Option<Vec<ParameterType>>; // Then call functions on the second loop 97 - fn update_arg(&mut self, index: usize, value: ParameterType) -> bool; 95 + fn inputs(&self) -> Vec<Option<(String, isize, isize)>>; // Node ID, input index, output value type 96 + 97 + fn execute(&mut self, args: Vec<ParameterType>) -> Vec<ParameterType>; // Then call functions on the second loop 98 98 fn is_entrypoint(&self) -> bool; 99 - } 99 + }
+60 -51
src-tauri/src/runtime.rs
··· 1 + use std::collections::HashMap; 2 + 1 3 use anyhow::{bail, Result}; 2 4 3 5 use crate::{runtime::nodes::RuntimeNodeTree, structs::parameter_types::ParameterType}; ··· 5 7 pub mod commands; 6 8 pub mod nodes; 7 9 8 - // This is horrible. I know, I'm sorry. 9 - 10 10 // TODO: Variables 11 11 12 - pub fn runtime_dry( 13 - entry: String, 14 - parameters: &Vec<ParameterType>, 15 - tab: &mut RuntimeNodeTree, 16 - ) -> Result<()> { 17 - let node = tab.nodes.get_mut(&entry); 18 - if node.is_none() { 19 - bail!("Cannot find node"); 20 - } 12 + pub fn recurse_runtime(entry: String, tab: &mut RuntimeNodeTree, args: Vec<ParameterType>) -> Result<()>{ 13 + let ( out_args, output_map ) = runtime(entry, tab, args)?; 21 14 22 - let node = node.unwrap(); 15 + let mut next_node_args: HashMap<String, Vec<ParameterType>> = HashMap::new(); 23 16 24 - let output_map = node.outputs(); 25 - let args = node.execute_dry(parameters); 17 + for i in 0..out_args.len(){ 18 + if output_map.len() <= i { break; } 19 + let links = &output_map[i]; 26 20 27 - if args.is_some() { 28 - let args = args.unwrap(); 21 + for ( id, link_index, _ ) in links{ 22 + let link_index = link_index.clone() as usize; 29 23 30 - for i in 0..args.len() { 31 - let arg = &args[i]; 24 + if next_node_args.contains_key(id){ 25 + let args: &mut _ = next_node_args.get_mut(id).unwrap(); 26 + while args.len() < link_index{ args.push(ParameterType::None); } 32 27 33 - for output in &output_map[i] { 34 - if output.2 == 5 { 35 - break; 36 - } // Ignore flow outputs 28 + args.push(out_args[i].clone()); 29 + } else{ 30 + let mut args = vec![ParameterType::None; link_index]; 31 + args.push(out_args[i].clone()); 37 32 38 - let next_node = tab.nodes.get_mut(&output.0); 39 - if next_node.is_none() { 40 - bail!("Cannot find node {}", output.0) 41 - } 33 + next_node_args.insert(id.clone(), args); 34 + } 35 + } 36 + } 42 37 43 - let next_node = next_node.unwrap(); 44 - let can_update = next_node.update_arg(output.1 as usize, arg.clone()); 38 + for i in 0..out_args.len(){ 39 + if let ParameterType::Flow(next) = out_args[i]{ 40 + if next{ 41 + let links = &output_map[i]; 45 42 46 - if can_update { 47 - runtime_dry(output.0.clone(), &vec![], tab)?; 43 + for ( id, _, _ ) in links{ 44 + let args = next_node_args.remove(id).unwrap(); 45 + recurse_runtime(id.clone(), tab, args)?; 48 46 } 49 47 } 50 48 } ··· 53 51 Ok(()) 54 52 } 55 53 56 - pub fn runtime(entry: String, tab: &mut RuntimeNodeTree) -> Result<()> { 54 + pub fn runtime(entry: String, tab: &mut RuntimeNodeTree, mut args: Vec<ParameterType>) -> Result<(Vec<ParameterType>, Vec<Vec<(String, isize, isize)>>)> { 57 55 let node = tab.nodes.get_mut(&entry); 58 - if node.is_none() { 59 - bail!("Cannot find node"); 60 - } 56 + if node.is_none() { bail!("Cannot find node"); } 61 57 62 58 let node = node.unwrap(); 59 + let inputs = node.inputs(); 63 60 64 - let next = node.execute(); 65 - if next.is_some() { 66 - let next = next.unwrap(); 61 + let mut needed_input_nodes = HashMap::new(); 67 62 68 - let outputs = node.outputs(); 63 + for i in 0..inputs.len(){ 64 + if i >= args.len() || args[i] == ParameterType::None{ 65 + if let Some(input) = &inputs[i]{ 66 + if !needed_input_nodes.contains_key(&input.0){ 67 + needed_input_nodes.insert(input.0.clone(), vec![(input.1.clone(), i.clone())]); 68 + } else{ 69 + needed_input_nodes.get_mut(&input.0).unwrap().push((input.1.clone(), i.clone())); 70 + } 71 + } 72 + } 73 + } 74 + 75 + for ( id, needed ) in needed_input_nodes{ 76 + let (out_args, _) = runtime(id, tab, vec![]).unwrap(); 69 77 70 - for i in 0..next.len() { 71 - let arg = &next[i]; 72 - if i >= outputs.len() { 73 - break; 74 - } 78 + for ( output, input ) in needed{ 79 + let arg = &out_args[output as usize]; 75 80 76 - for output in &outputs[i] { 77 - if let ParameterType::Flow(next) = arg { 78 - if *next { 79 - // This is a flow output, continue 80 - runtime(output.0.clone(), tab)?; 81 - } 82 - } 81 + if args.len() >= input{ 82 + while args.len() < input{ args.push(ParameterType::None); } 83 + args.push(arg.clone()); 84 + } else{ 85 + args[input] = arg.clone(); 83 86 } 84 87 } 85 88 } 86 89 87 - Ok(()) 90 + let node = tab.nodes.get_mut(&entry); // TODO: Find a way to only do this lookup once 91 + if node.is_none() { bail!("Cannot find node"); } 92 + 93 + let node = node.unwrap(); 94 + 95 + let output = node.execute(args); 96 + Ok((output, node.outputs())) 88 97 }
+27 -28
src-tauri/src/setup.rs
··· 11 11 use tauri::{App, Emitter, Listener, Manager, WindowEvent}; 12 12 13 13 use crate::{ 14 - osc::{self, OSCMessage}, 15 - runtime::{commands::RuntimeCommand, nodes::RuntimeNodeTree, runtime, runtime_dry}, 16 - structs::parameter_types::ParameterType, 17 - utils::setup_traymenu::setup_traymenu, 14 + osc::{self, OSCMessage}, runtime::{commands::RuntimeCommand, nodes::RuntimeNodeTree, recurse_runtime}, structs::parameter_types::ParameterType, utils::{setup_traymenu::setup_traymenu, vrchat_builtin_parameters} 18 15 }; 19 16 20 17 pub fn setup( ··· 26 23 window.hide().unwrap(); 27 24 28 25 let win_handle = window.clone(); 26 + 29 27 window.on_window_event(move |event| match event { 30 28 WindowEvent::CloseRequested { api, .. } => { 31 29 api.prevent_close(); 32 - 33 - win_handle.hide().unwrap(); 34 - win_handle.emit("hide-window", ()).unwrap(); 30 + win_handle.emit("prompt_to_close", ()).unwrap(); 31 + } 32 + WindowEvent::Resized(_) => { 33 + let minimised = win_handle.is_minimized().unwrap(); 34 + if minimised{ 35 + win_handle.hide().unwrap(); 36 + win_handle.emit("hide-window", ()).unwrap(); 37 + win_handle.unminimize().unwrap(); 38 + } 35 39 } 36 40 _ => {} 37 41 }); ··· 85 89 addrs.push(msg); 86 90 } 87 91 92 + if message.address == "/avatar/change".to_owned(){ 93 + *addrs = vrchat_builtin_parameters::get_read_addresses(); 94 + 95 + // TODO: Read avatar paramaters from file 96 + } 97 + 88 98 runtime_sender 89 99 .send(RuntimeCommand::OSCMessage(message)) 90 100 .unwrap(); ··· 92 102 }); 93 103 94 104 // TODO: Run tabs in seperate threads (really not looking forward to this... thanks rust) 95 - // TODO: Support multiple flow inputs on a node 96 105 97 106 tokio::spawn(async move { 98 107 let mut tabs: HashMap<String, RuntimeNodeTree> = HashMap::new(); 99 108 100 - #[cfg(target_os = "windows")] 101 - let enigo = Arc::new(Mutex::new(Enigo::new(&Settings::default()).unwrap())); 109 + // #[cfg(target_os = "windows")] 110 + let enigo = Arc::new(Mutex::new(enigo::Enigo::new(&enigo::Settings::default()).unwrap())); 102 111 103 112 loop { 104 113 let cmd = runtime_receiver.recv().unwrap(); ··· 108 117 for (_, mut tab) in &mut tabs { 109 118 let keys: Vec<String> = tab.nodes.keys().map(|x| x.clone()).collect(); 110 119 111 - for id in keys.clone() { 120 + for id in keys { 112 121 let entry = tab.nodes[&id].is_entrypoint(); 113 122 114 123 if entry { 115 - let args = vec![ 116 - vec![ParameterType::String(msg.address.clone())], 117 - msg.values.clone(), 118 - ] 119 - .concat(); 124 + let mut args = vec![ ParameterType::String(msg.address.clone())]; 125 + let mut values = msg.values.clone(); 120 126 121 - runtime_dry(id.clone(), &args, &mut tab).unwrap(); 122 - } 123 - } 124 - 125 - for id in keys { 126 - let entry = tab.nodes[&id].is_entrypoint(); 127 - 128 - if entry { 129 - let _ = runtime(id.clone(), &mut tab); 127 + args.append(&mut values); 128 + let _ = recurse_runtime(id.clone(), &mut tab, args); 130 129 } 131 130 } 132 131 } 133 132 } 134 133 135 134 RuntimeCommand::AddTab(graph, id) => { 136 - #[cfg(target_os = "windows")] 135 + // #[cfg(target_os = "windows")] 137 136 tabs.insert(id, RuntimeNodeTree::from(graph, enigo.clone())); 138 137 139 - #[cfg(target_os = "linux")] 140 - tabs.insert(id, RuntimeNodeTree::from(graph)); 138 + // #[cfg(target_os = "linux")] 139 + // tabs.insert(id, RuntimeNodeTree::from(graph)); 141 140 } 142 141 RuntimeCommand::RemoveTab(id) => { 143 142 tabs.remove(&id);
+3 -2
src-tauri/src/structs/nodes.rs
··· 5 5 pub struct Node { 6 6 pub id: String, 7 7 pub name: String, 8 - pub outputs: Vec<NodeOutput>, 8 + pub outputs: Vec<NodeIO>, 9 + pub inputs: Vec<NodeIO>, 9 10 pub pos: [f32; 2], 10 11 pub statics: Vec<NodeStatic>, 11 12 ··· 23 24 } 24 25 25 26 #[derive(Serialize, Deserialize, Debug, Clone)] 26 - pub struct NodeOutput { 27 + pub struct NodeIO { 27 28 pub name: String, 28 29 29 30 #[serde(rename = "type")]
+16 -6
src-tauri/src/utils/config.rs
··· 3 3 fs::File, 4 4 io::{Read, Write}, 5 5 path::PathBuf, 6 - sync::Mutex, 6 + sync::{Mutex, MutexGuard}, 7 7 }; 8 8 9 + use chrono::Utc; 9 10 use flate2::{read::GzDecoder, write::GzEncoder, Compression}; 10 11 use serde::{Deserialize, Serialize}; 11 12 ··· 14 15 #[derive(Clone, Serialize, Deserialize, Debug)] 15 16 pub struct ConfigValues { 16 17 #[serde(default)] 17 - pub loaded_tabs: HashMap<String, (Vec<Node>, String, Option<String>)>, 18 + pub loaded_tabs: HashMap<String, (Vec<Node>, String, Option<String>, bool)>, 18 19 19 20 #[serde(default)] 20 21 pub hide_editor_on_start: bool, ··· 39 40 40 41 let json: ConfigValues = serde_json::from_str(&json_string).unwrap(); 41 42 42 - dbg!(&json); 43 - 44 43 Config { 45 44 store: Mutex::new(json), 46 45 path: path, ··· 48 47 } 49 48 50 49 pub fn save(&self) { 51 - let dat = serde_json::to_string(&self.store.lock().unwrap().clone()).unwrap(); 52 - dbg!(&dat); 50 + let mut dat = self.store.lock().unwrap(); 51 + 52 + let dat = serde_json::to_string(&*dat).unwrap(); 53 + 54 + let file = File::create(&self.path).unwrap(); 55 + let mut encoder = GzEncoder::new(file, Compression::default()); 56 + 57 + encoder.write_all(dat.as_bytes()).unwrap(); 58 + encoder.finish().unwrap(); 59 + } 60 + 61 + pub fn save_prelocked(&self, mut dat: MutexGuard<'_, ConfigValues>) { 62 + let dat = serde_json::to_string(&*dat).unwrap(); 53 63 54 64 let file = File::create(&self.path).unwrap(); 55 65 let mut encoder = GzEncoder::new(file, Compression::default());
+1
src-tauri/src/utils/mod.rs
··· 1 1 pub mod config; 2 2 pub mod setup_traymenu; 3 + pub mod vrchat_builtin_parameters;
+7 -13
src-tauri/src/utils/setup_traymenu.rs
··· 11 11 .build(handle) 12 12 .unwrap(); 13 13 14 - let hide = MenuItemBuilder::new("Hide / Show Editor") 15 - .id("hide") 14 + let show = MenuItemBuilder::new("Show Editor") 15 + .id("show") 16 16 .build(handle) 17 17 .unwrap(); 18 18 19 19 let tray_menu = MenuBuilder::new(handle) 20 - .items(&[&quit, &hide]) 20 + .items(&[&quit, &show]) 21 21 .build() 22 22 .unwrap(); 23 23 ··· 30 30 "quit" => { 31 31 app.emit("prompt_to_close", ()).unwrap(); 32 32 } 33 - "hide" => { 33 + "show" => { 34 34 let window = app.get_webview_window("main").unwrap(); 35 35 36 - if window.is_visible().unwrap() { 37 - window.hide().unwrap(); 38 - 39 - window.emit("hide-window", ()).unwrap(); 40 - } else { 41 - window.show().unwrap(); 42 - window.set_focus().unwrap(); 36 + window.show().unwrap(); 37 + window.set_focus().unwrap(); 43 38 44 - window.emit("show-window", ()).unwrap(); 45 - } 39 + window.emit("show-window", ()).unwrap(); 46 40 } 47 41 _ => {} 48 42 })
+315
src-tauri/src/utils/vrchat_builtin_parameters.rs
··· 1 + use crate::{osc::OSCMessage, structs::parameter_types::ParameterType}; 2 + 3 + pub fn get_read_addresses() -> Vec<OSCMessage>{ 4 + vec![ 5 + // Avatar Parameters 6 + OSCMessage { 7 + address: "/avatar/change".into(), 8 + values: vec![ ParameterType::String("".into()) ] 9 + }, 10 + 11 + OSCMessage { 12 + address: "/avatar/parameters/VRCEmote".into(), 13 + values: vec![ ParameterType::Int(0) ] 14 + }, 15 + OSCMessage { 16 + address: "/avatar/parameters/VRCFaceBlendV".into(), 17 + values: vec![ ParameterType::Float(0.0) ] 18 + }, 19 + OSCMessage { 20 + address: "/avatar/parameters/VRCFaceBlendH".into(), 21 + values: vec![ ParameterType::Float(0.0) ] 22 + }, 23 + OSCMessage { 24 + address: "/avatar/parameters/PreviewMode".into(), 25 + values: vec![ ParameterType::Int(0) ] 26 + }, 27 + OSCMessage { 28 + address: "/avatar/parameters/IsAnimatorEnabled".into(), 29 + values: vec![ ParameterType::Boolean(true) ] 30 + }, 31 + 32 + OSCMessage { 33 + address: "/avatar/parameters/GestureRightWeight".into(), 34 + values: vec![ ParameterType::Float(0.0) ] 35 + }, 36 + OSCMessage { 37 + address: "/avatar/parameters/GestureLeftWeight".into(), 38 + values: vec![ ParameterType::Float(0.0) ] 39 + }, 40 + OSCMessage { 41 + address: "/avatar/parameters/GestureRight".into(), 42 + values: vec![ ParameterType::Int(0) ] 43 + }, 44 + OSCMessage { 45 + address: "/avatar/parameters/GestureLeft".into(), 46 + values: vec![ ParameterType::Int(0) ] 47 + }, 48 + 49 + OSCMessage { 50 + address: "/avatar/parameters/ScaleModified".into(), 51 + values: vec![ ParameterType::Boolean(true) ] 52 + }, 53 + OSCMessage { 54 + address: "/avatar/parameters/ScaleFactor".into(), 55 + values: vec![ ParameterType::Float(1.0) ] 56 + }, 57 + OSCMessage { 58 + address: "/avatar/parameters/ScaleFactorInverse".into(), 59 + values: vec![ ParameterType::Float(1.0) ] 60 + }, 61 + OSCMessage { 62 + address: "/avatar/parameters/EyeHeightAsPercent".into(), 63 + values: vec![ ParameterType::Float(1.0) ] 64 + }, 65 + 66 + OSCMessage { 67 + address: "/avatar/parameters/Viseme".into(), 68 + values: vec![ ParameterType::Int(0) ] 69 + }, 70 + OSCMessage { 71 + address: "/avatar/parameters/Voice".into(), 72 + values: vec![ ParameterType::Float(0.0) ] 73 + }, 74 + OSCMessage { 75 + address: "/avatar/parameters/Earmuffs".into(), 76 + values: vec![ ParameterType::Boolean(true) ] 77 + }, 78 + OSCMessage { 79 + address: "/avatar/parameters/MuteSelf".into(), 80 + values: vec![ ParameterType::Boolean(true) ] 81 + }, 82 + 83 + OSCMessage { 84 + address: "/avatar/parameters/AFK".into(), 85 + values: vec![ ParameterType::Boolean(true) ] 86 + }, 87 + OSCMessage { 88 + address: "/avatar/parameters/InStation".into(), 89 + values: vec![ ParameterType::Boolean(true) ] 90 + }, 91 + OSCMessage { 92 + address: "/avatar/parameters/Seated".into(), 93 + values: vec![ ParameterType::Boolean(true) ] 94 + }, 95 + OSCMessage { 96 + address: "/avatar/parameters/VRMode".into(), 97 + values: vec![ ParameterType::Int(0) ] 98 + }, 99 + OSCMessage { 100 + address: "/avatar/parameters/TrackingType".into(), 101 + values: vec![ ParameterType::Int(0) ] 102 + }, 103 + 104 + OSCMessage { 105 + address: "/avatar/parameters/Grounded".into(), 106 + values: vec![ ParameterType::Boolean(true) ] 107 + }, 108 + OSCMessage { 109 + address: "/avatar/parameters/Upright".into(), 110 + values: vec![ ParameterType::Float(1.0) ] 111 + }, 112 + OSCMessage { 113 + address: "/avatar/parameters/AngularY".into(), 114 + values: vec![ ParameterType::Float(1.0) ] 115 + }, 116 + OSCMessage { 117 + address: "/avatar/parameters/VelocityX".into(), 118 + values: vec![ ParameterType::Float(1.0) ] 119 + }, 120 + OSCMessage { 121 + address: "/avatar/parameters/VelocityY".into(), 122 + values: vec![ ParameterType::Float(1.0) ] 123 + }, 124 + OSCMessage { 125 + address: "/avatar/parameters/VelocityZ".into(), 126 + values: vec![ ParameterType::Float(1.0) ] 127 + }, 128 + OSCMessage { 129 + address: "/avatar/parameters/VelocityMagnitude".into(), 130 + values: vec![ ParameterType::Float(1.0) ] 131 + }, 132 + 133 + // User Camera 134 + OSCMessage { 135 + address: "/usercamera/Mode".into(), 136 + values: vec![ ParameterType::Int(0) ] 137 + }, 138 + OSCMessage { 139 + address: "/usercamera/Pose".into(), 140 + values: vec![ 141 + ParameterType::Float(0.0), 142 + ParameterType::Float(0.0), 143 + ParameterType::Float(0.0), 144 + 145 + ParameterType::Float(0.0), 146 + ParameterType::Float(0.0), 147 + ParameterType::Float(0.0) 148 + ] 149 + }, 150 + 151 + OSCMessage { 152 + address: "/usercamera/ShowUIInCamera".into(), 153 + values: vec![ ParameterType::Boolean(true) ] 154 + }, 155 + OSCMessage { 156 + address: "/usercamera/LocalPlayer".into(), 157 + values: vec![ ParameterType::Boolean(true) ] 158 + }, 159 + OSCMessage { 160 + address: "/usercamera/RemotePlayer".into(), 161 + values: vec![ ParameterType::Boolean(true) ] 162 + }, 163 + OSCMessage { 164 + address: "/usercamera/Environment".into(), 165 + values: vec![ ParameterType::Boolean(true) ] 166 + }, 167 + OSCMessage { 168 + address: "/usercamera/GreenScreen".into(), 169 + values: vec![ ParameterType::Boolean(true) ] 170 + }, 171 + OSCMessage { 172 + address: "/usercamera/Lock".into(), 173 + values: vec![ ParameterType::Boolean(true) ] 174 + }, 175 + OSCMessage { 176 + address: "/usercamera/SmoothMovement".into(), 177 + values: vec![ ParameterType::Boolean(true) ] 178 + }, 179 + OSCMessage { 180 + address: "/usercamera/LookAtMe".into(), 181 + values: vec![ ParameterType::Boolean(true) ] 182 + }, 183 + OSCMessage { 184 + address: "/usercamera/AutoLevelRoll".into(), 185 + values: vec![ ParameterType::Boolean(true) ] 186 + }, 187 + OSCMessage { 188 + address: "/usercamera/AutoLevelPitch".into(), 189 + values: vec![ ParameterType::Boolean(true) ] 190 + }, 191 + OSCMessage { 192 + address: "/usercamera/Flying".into(), 193 + values: vec![ ParameterType::Boolean(true) ] 194 + }, 195 + OSCMessage { 196 + address: "/usercamera/TriggerTakesPhotos".into(), 197 + values: vec![ ParameterType::Boolean(true) ] 198 + }, 199 + OSCMessage { 200 + address: "/usercamera/DollyPathsStayVisible".into(), 201 + values: vec![ ParameterType::Boolean(true) ] 202 + }, 203 + OSCMessage { 204 + address: "/usercamera/AudioFromCamera".into(), 205 + values: vec![ ParameterType::Boolean(true) ] 206 + }, 207 + OSCMessage { 208 + address: "/usercamera/ShowFocus".into(), 209 + values: vec![ ParameterType::Boolean(true) ] 210 + }, 211 + OSCMessage { 212 + address: "/usercamera/Streaming".into(), 213 + values: vec![ ParameterType::Boolean(true) ] 214 + }, 215 + OSCMessage { 216 + address: "/usercamera/RollWhileFlying".into(), 217 + values: vec![ ParameterType::Boolean(true) ] 218 + }, 219 + OSCMessage { 220 + address: "/usercamera/OrientationIsLandscape".into(), 221 + values: vec![ ParameterType::Boolean(true) ] 222 + }, 223 + 224 + OSCMessage { 225 + address: "/usercamera/Zoom".into(), 226 + values: vec![ ParameterType::Float(0.0) ] 227 + }, 228 + OSCMessage { 229 + address: "/usercamera/Exposure".into(), 230 + values: vec![ ParameterType::Float(0.0) ] 231 + }, 232 + OSCMessage { 233 + address: "/usercamera/Aperture".into(), 234 + values: vec![ ParameterType::Float(0.0) ] 235 + }, 236 + OSCMessage { 237 + address: "/usercamera/Hue".into(), 238 + values: vec![ ParameterType::Float(0.0) ] 239 + }, 240 + OSCMessage { 241 + address: "/usercamera/Saturation".into(), 242 + values: vec![ ParameterType::Float(0.0) ] 243 + }, 244 + OSCMessage { 245 + address: "/usercamera/Lightness".into(), 246 + values: vec![ ParameterType::Float(0.0) ] 247 + }, 248 + OSCMessage { 249 + address: "/usercamera/LookAtMeXOffset".into(), 250 + values: vec![ ParameterType::Float(0.0) ] 251 + }, 252 + OSCMessage { 253 + address: "/usercamera/LookAtMeYOffset".into(), 254 + values: vec![ ParameterType::Float(0.0) ] 255 + }, 256 + OSCMessage { 257 + address: "/usercamera/FlySpeed".into(), 258 + values: vec![ ParameterType::Float(0.0) ] 259 + }, 260 + OSCMessage { 261 + address: "/usercamera/TurnSpeed".into(), 262 + values: vec![ ParameterType::Float(0.0) ] 263 + }, 264 + OSCMessage { 265 + address: "/usercamera/SmoothStrength".into(), 266 + values: vec![ ParameterType::Float(0.0) ] 267 + }, 268 + OSCMessage { 269 + address: "/usercamera/PhotoRate".into(), 270 + values: vec![ ParameterType::Float(0.0) ] 271 + }, 272 + OSCMessage { 273 + address: "/usercamera/Duration".into(), 274 + values: vec![ ParameterType::Float(0.0) ] 275 + }, 276 + 277 + // Trackers 278 + OSCMessage { 279 + address: "/tracking/vrsystem/head/pose".into(), 280 + values: vec![ 281 + ParameterType::Float(0.0), 282 + ParameterType::Float(0.0), 283 + ParameterType::Float(0.0), 284 + 285 + ParameterType::Float(0.0), 286 + ParameterType::Float(0.0), 287 + ParameterType::Float(0.0), 288 + ] 289 + }, 290 + OSCMessage { 291 + address: "/tracking/vrsystem/rightwrist/pose".into(), 292 + values: vec![ 293 + ParameterType::Float(0.0), 294 + ParameterType::Float(0.0), 295 + ParameterType::Float(0.0), 296 + 297 + ParameterType::Float(0.0), 298 + ParameterType::Float(0.0), 299 + ParameterType::Float(0.0), 300 + ] 301 + }, 302 + OSCMessage { 303 + address: "/tracking/vrsystem/leftwrist/pose".into(), 304 + values: vec![ 305 + ParameterType::Float(0.0), 306 + ParameterType::Float(0.0), 307 + ParameterType::Float(0.0), 308 + 309 + ParameterType::Float(0.0), 310 + ParameterType::Float(0.0), 311 + ParameterType::Float(0.0), 312 + ] 313 + }, 314 + ] 315 + }