+4
-1
.gitignore
+4
-1
.gitignore
-8
.idea/.gitignore
-8
.idea/.gitignore
-11
.idea/VRCMacros-UI.iml
-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
-8
.idea/modules.xml
-6
.idea/vcs.xml
-6
.idea/vcs.xml
-3
.vscode/extensions.json
-3
.vscode/extensions.json
+3
-1
src/App.tsx
+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
+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
-1
src/Nodes/Conditional/IfEqual.tsx
-1
src/Nodes/Conditional/IfFalse.tsx
-1
src/Nodes/Conditional/IfFalse.tsx
-1
src/Nodes/Conditional/IfTrue.tsx
-1
src/Nodes/Conditional/IfTrue.tsx
-1
src/Nodes/Debug.tsx
-1
src/Nodes/Debug.tsx
+1
-2
src/Nodes/Nodes.tsx
+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
-1
src/Nodes/OSCActions/Send Chatbox.tsx
+25
-10
src/Nodes/OSCTrigger.tsx
+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
-1
src/Nodes/PressKey.tsx
-1
src/Nodes/Shell.tsx
-1
src/Nodes/Shell.tsx
-1
src/Nodes/Statics/Float.tsx
-1
src/Nodes/Statics/Float.tsx
-1
src/Nodes/Statics/Int.tsx
-1
src/Nodes/Statics/Int.tsx
-1
src/Nodes/Statics/String.tsx
-1
src/Nodes/Statics/String.tsx
+9
-4
src/keybinds.ts
+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
+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
+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
+2
-1
src-tauri/Cargo.toml
+1
-1
src-tauri/src/frontend_calls/load_previous_tabs.rs
+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
+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
+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
-1
src-tauri/src/main.rs
+21
-38
src-tauri/src/runtime/nodes/conditional/ifequal.rs
+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
+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
+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
+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
+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
+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
+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
+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
+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
+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
+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
+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
+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
+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
+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
+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
src-tauri/src/utils/mod.rs
+315
src-tauri/src/utils/vrchat_builtin_parameters.rs
+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
+
}