import { default_regex } from "./i18n.js"; import { default_priority } from "./ue_properties.js"; import { node_graph, visible_graph } from "./use_everywhere_subgraph_utils.js"; import { nodes_in_my_group, nodes_not_in_my_group, nodes_my_color, nodes_not_my_color, nodes_in_groups_matching } from "./use_everywhere_ui.js"; import { Logger, node_is_live, get_real_node, get_connection } from "./use_everywhere_utilities.js"; export function display_name(node) { if (node?.title) return node.title; if (node?.type) return node.type; if (node?.properties['Node name for S&R']) return node.properties['Node name for S&R']; return "un-nameable node"; } function regex_for(node, k) { try { const w0 = node.properties.ue_properties[`${k}_regex`] return (w0 && w0!='.*') ? new RegExp(w0) : null; } catch (e) { return null } } /* The UseEverywhere object represents a single 'broadcast'. It generally contains controller - the UE node that controls the broadcase control_node_input_index - the input on that node type - the data type output - the output that is being rebroadcast as a list (node_id, output_index) title_regex, input_regex - the UE? matching rules priority - priorty :) graph - the graph or subgraph */ class UseEverywhere { constructor() { this.sending_to = []; Object.assign(this, arguments[0]); if (this.priority === undefined) this.priority = 0; if (this.graph === undefined) this.graph = visible_graph(); const from_node = get_real_node(this?.output[0], this.graph); const to_node = get_real_node(this?.controller.id, this.graph) try { if (this.output[0]==-10) { this.description = `source subgraph input slot ${this?.output[1]} ` + `-> control "${display_name(to_node)}", ${to_node.inputs[this?.control_node_input_index].name} (${this?.controller.id}.${this?.control_node_input_index}) ` + `"${this.type}" <- (priority ${this.priority})`; } else if (this.control_node_input_index>=0) { this.description = `source "${display_name(from_node)}", ${from_node.outputs[this?.output[1]].name} (${this?.output[0]}.${this?.output[1]}) ` + `-> control "${display_name(to_node)}", ${to_node.inputs[this?.control_node_input_index].name} (${this?.controller.id}.${this?.control_node_input_index}) ` + `"${this.type}" <- (priority ${this.priority})`; } else { this.description = `source "${display_name(from_node)}", ${from_node.outputs[this?.output[1]].name} (${this?.output[0]}.${this?.output[1]}) ` + `"${this.type}" <- (priority ${this.priority})`; } } catch (e) { // for breakpointing throw e; } if (this.title_regex) this.description += ` - node title regex '${this.title_regex.source}'`; if (this.input_regex) this.description += ` - input name regex '${this.input_regex.source}'`; } sending_differs_from(another_ue) { if (this.sending_to.length != another_ue.sending_to.length) return true; for (var i=0; i n.name==input.name); this.sending_to.push({node:node, input:input, input_index:input_index}) } describe_sending(){ var description = " Linked to:"; this.sending_to.forEach((st) => description += `\n -> ${display_name(st.node)}, ${st.input.name}`); if (this.sending_to.length===0) description += ' nothing'; return description; } describe() { return this.description + "\n" + this.describe_sending(); } } function validity_errors(params) { if (!node_is_live(params.controller)) return `UE node ${params.controller.id} is not alive`; if (params.output[0]!=-10 && !node_is_live(get_real_node(params.output[0], params.graph))) return `upstream node ${params.output[0]} is not alive`; return ""; } export class UseEverywhereList { constructor() { this.ues = []; this.unmatched_inputs = []; } differs_from(another_uel) { if (!another_uel || !another_uel.ues || !this.ues) return true; if (this.ues.length != another_uel.ues.length) return true; for (var i=0; i ( candidate.matches(node, input) )); if (matches.length==0) { Logger.log_detail(`'${display_name(node)}' optional input '${input.name}' unmatched`) return undefined; } if (matches.length>1) { matches.sort((a,b) => b.priority-a.priority); if(matches[0].priority == matches[1].priority) { const msg = `'${display_name(node)}' (${node.id}) input '${input.name}' matches multiple Use Everwhere sources:`; _ambiguity_messages.push(msg); for (var i=0; i { ue.sending_to.forEach((st) => { if (st.node.id == for_node.id) { ue_connections.push({ type : ue.type, input_index : st.input_index, control_node : get_real_node(ue.controller.id, ue.graph), control_node_input_index : ue.control_node_input_index, sending_to : st.node, }); } }); }); return ue_connections; } all_ue_connections() { const ue_connections = []; this.ues.forEach((ue) => { ue.sending_to.forEach((st) => { ue_connections.push({ type : ue.type, input_index : st.input_index, control_node : get_real_node(ue.controller.id, ue.graph), control_node_input_index : ue.control_node_input_index, sending_to : st.node, graph: ue.graph, }); }); }); return ue_connections; } add_ue_from_node(node) { if (node.properties.ue_properties.seed_inputs) { this.add_ue(node, -1, "INT", [node.id.toString(),0], regex_for(node, 'input')); } else { for (var i=0; i