/*************************************************************************/ /* visual_script_nodes.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ /* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ /* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ /* the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "visual_script_nodes.h" #include "core/config/engine.h" #include "core/config/project_settings.h" #include "core/core_constants.h" #include "core/input/input.h" #include "core/os/os.h" #include "scene/main/node.h" #include "scene/main/scene_tree.h" ////////////////////////////////////////// ////////////////FUNCTION////////////////// ////////////////////////////////////////// bool VisualScriptFunction::_set(const StringName &p_name, const Variant &p_value) { if (p_name == "argument_count") { int new_argc = p_value; int argc = arguments.size(); if (argc == new_argc) { return true; } arguments.resize(new_argc); for (int i = argc; i < new_argc; i++) { arguments.write[i].name = "arg" + itos(i + 1); arguments.write[i].type = Variant::NIL; } ports_changed_notify(); notify_property_list_changed(); return true; } if (String(p_name).begins_with("argument_")) { int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1; ERR_FAIL_INDEX_V(idx, arguments.size(), false); String what = String(p_name).get_slice("/", 1); if (what == "type") { Variant::Type new_type = Variant::Type(int(p_value)); arguments.write[idx].type = new_type; ports_changed_notify(); return true; } if (what == "name") { arguments.write[idx].name = p_value; ports_changed_notify(); return true; } } if (p_name == "stack/stackless") { set_stack_less(p_value); return true; } if (p_name == "stack/size") { stack_size = p_value; return true; } if (p_name == "rpc/mode") { rpc_mode = MultiplayerAPI::RPCMode(int(p_value)); return true; } if (p_name == "sequenced/sequenced") { sequenced = p_value; ports_changed_notify(); return true; } return false; } bool VisualScriptFunction::_get(const StringName &p_name, Variant &r_ret) const { if (p_name == "argument_count") { r_ret = arguments.size(); return true; } if (String(p_name).begins_with("argument_")) { int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1; ERR_FAIL_INDEX_V(idx, arguments.size(), false); String what = String(p_name).get_slice("/", 1); if (what == "type") { r_ret = arguments[idx].type; return true; } if (what == "name") { r_ret = arguments[idx].name; return true; } } if (p_name == "stack/stackless") { r_ret = stack_less; return true; } if (p_name == "stack/size") { r_ret = stack_size; return true; } if (p_name == "rpc/mode") { r_ret = rpc_mode; return true; } if (p_name == "sequenced/sequenced") { r_ret = sequenced; return true; } return false; } void VisualScriptFunction::_get_property_list(List *p_list) const { p_list->push_back(PropertyInfo(Variant::INT, "argument_count", PROPERTY_HINT_RANGE, "0,256")); String argt = "Any"; for (int i = 1; i < Variant::VARIANT_MAX; i++) { argt += "," + Variant::get_type_name(Variant::Type(i)); } for (int i = 0; i < arguments.size(); i++) { p_list->push_back(PropertyInfo(Variant::INT, "argument_" + itos(i + 1) + "/type", PROPERTY_HINT_ENUM, argt)); p_list->push_back(PropertyInfo(Variant::STRING, "argument_" + itos(i + 1) + "/name")); } p_list->push_back(PropertyInfo(Variant::BOOL, "sequenced/sequenced")); if (!stack_less) { p_list->push_back(PropertyInfo(Variant::INT, "stack/size", PROPERTY_HINT_RANGE, "1,100000")); } p_list->push_back(PropertyInfo(Variant::BOOL, "stack/stackless")); p_list->push_back(PropertyInfo(Variant::INT, "rpc/mode", PROPERTY_HINT_ENUM, "Disabled,Any,Authority")); } int VisualScriptFunction::get_output_sequence_port_count() const { return 1; } bool VisualScriptFunction::has_input_sequence_port() const { return false; } int VisualScriptFunction::get_input_value_port_count() const { return 0; } int VisualScriptFunction::get_output_value_port_count() const { return arguments.size(); } String VisualScriptFunction::get_output_sequence_port_text(int p_port) const { return String(); } PropertyInfo VisualScriptFunction::get_input_value_port_info(int p_idx) const { ERR_FAIL_V(PropertyInfo()); } PropertyInfo VisualScriptFunction::get_output_value_port_info(int p_idx) const { // Need to check it without ERR_FAIL_COND, to prevent warnings from appearing on node creation via dragging. if (p_idx < 0 || p_idx >= arguments.size()) { return PropertyInfo(); } PropertyInfo out; out.type = arguments[p_idx].type; out.name = arguments[p_idx].name; out.hint = arguments[p_idx].hint; out.hint_string = arguments[p_idx].hint_string; return out; } String VisualScriptFunction::get_caption() const { return RTR("Function"); } String VisualScriptFunction::get_text() const { return get_name(); //use name as function name I guess } void VisualScriptFunction::add_argument(Variant::Type p_type, const String &p_name, int p_index, const PropertyHint p_hint, const String &p_hint_string) { Argument arg; arg.name = p_name; arg.type = p_type; arg.hint = p_hint; arg.hint_string = p_hint_string; if (p_index >= 0) { arguments.insert(p_index, arg); } else { arguments.push_back(arg); } ports_changed_notify(); } void VisualScriptFunction::set_argument_type(int p_argidx, Variant::Type p_type) { ERR_FAIL_INDEX(p_argidx, arguments.size()); arguments.write[p_argidx].type = p_type; ports_changed_notify(); } Variant::Type VisualScriptFunction::get_argument_type(int p_argidx) const { ERR_FAIL_INDEX_V(p_argidx, arguments.size(), Variant::NIL); return arguments[p_argidx].type; } void VisualScriptFunction::set_argument_name(int p_argidx, const String &p_name) { ERR_FAIL_INDEX(p_argidx, arguments.size()); arguments.write[p_argidx].name = p_name; ports_changed_notify(); } String VisualScriptFunction::get_argument_name(int p_argidx) const { ERR_FAIL_INDEX_V(p_argidx, arguments.size(), String()); return arguments[p_argidx].name; } void VisualScriptFunction::remove_argument(int p_argidx) { ERR_FAIL_INDEX(p_argidx, arguments.size()); arguments.remove_at(p_argidx); ports_changed_notify(); } int VisualScriptFunction::get_argument_count() const { return arguments.size(); } void VisualScriptFunction::set_rpc_mode(MultiplayerAPI::RPCMode p_mode) { rpc_mode = p_mode; } MultiplayerAPI::RPCMode VisualScriptFunction::get_rpc_mode() const { return rpc_mode; } class VisualScriptNodeInstanceFunction : public VisualScriptNodeInstance { public: VisualScriptFunction *node = nullptr; VisualScriptInstance *instance = nullptr; //virtual int get_working_memory_size() const override { return 0; } virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { int ac = node->get_argument_count(); for (int i = 0; i < ac; i++) { #ifdef DEBUG_ENABLED Variant::Type expected = node->get_argument_type(i); if (expected != Variant::NIL) { if (!Variant::can_convert_strict(p_inputs[i]->get_type(), expected)) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.expected = expected; r_error.argument = i; return 0; } } #endif *p_outputs[i] = *p_inputs[i]; } return 0; } }; VisualScriptNodeInstance *VisualScriptFunction::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceFunction *instance = memnew(VisualScriptNodeInstanceFunction); instance->node = this; instance->instance = p_instance; return instance; } void VisualScriptFunction::reset_state() { arguments.clear(); stack_size = 256; stack_less = false; sequenced = true; rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; } VisualScriptFunction::VisualScriptFunction() { stack_size = 256; stack_less = false; sequenced = true; rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; } void VisualScriptFunction::set_stack_less(bool p_enable) { stack_less = p_enable; notify_property_list_changed(); } bool VisualScriptFunction::is_stack_less() const { return stack_less; } void VisualScriptFunction::set_sequenced(bool p_enable) { sequenced = p_enable; } bool VisualScriptFunction::is_sequenced() const { return sequenced; } void VisualScriptFunction::set_stack_size(int p_size) { ERR_FAIL_COND(p_size < 1 || p_size > 100000); stack_size = p_size; } int VisualScriptFunction::get_stack_size() const { return stack_size; } ////////////////////////////////////////// /////////////////LISTS//////////////////// ////////////////////////////////////////// int VisualScriptLists::get_output_sequence_port_count() const { if (sequenced) { return 1; } return 0; } bool VisualScriptLists::has_input_sequence_port() const { return sequenced; } String VisualScriptLists::get_output_sequence_port_text(int p_port) const { return ""; } int VisualScriptLists::get_input_value_port_count() const { return inputports.size(); } int VisualScriptLists::get_output_value_port_count() const { return outputports.size(); } PropertyInfo VisualScriptLists::get_input_value_port_info(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, inputports.size(), PropertyInfo()); PropertyInfo pi; pi.name = inputports[p_idx].name; pi.type = inputports[p_idx].type; return pi; } PropertyInfo VisualScriptLists::get_output_value_port_info(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, outputports.size(), PropertyInfo()); PropertyInfo pi; pi.name = outputports[p_idx].name; pi.type = outputports[p_idx].type; return pi; } bool VisualScriptLists::is_input_port_editable() const { return ((flags & INPUT_EDITABLE) == INPUT_EDITABLE); } bool VisualScriptLists::is_input_port_name_editable() const { return ((flags & INPUT_NAME_EDITABLE) == INPUT_NAME_EDITABLE); } bool VisualScriptLists::is_input_port_type_editable() const { return ((flags & INPUT_TYPE_EDITABLE) == INPUT_TYPE_EDITABLE); } bool VisualScriptLists::is_output_port_editable() const { return ((flags & OUTPUT_EDITABLE) == OUTPUT_EDITABLE); } bool VisualScriptLists::is_output_port_name_editable() const { return ((flags & INPUT_NAME_EDITABLE) == INPUT_NAME_EDITABLE); } bool VisualScriptLists::is_output_port_type_editable() const { return ((flags & INPUT_TYPE_EDITABLE) == INPUT_TYPE_EDITABLE); } // for the inspector bool VisualScriptLists::_set(const StringName &p_name, const Variant &p_value) { if (p_name == "input_count" && is_input_port_editable()) { int new_argc = p_value; int argc = inputports.size(); if (argc == new_argc) { return true; } inputports.resize(new_argc); for (int i = argc; i < new_argc; i++) { inputports.write[i].name = "arg" + itos(i + 1); inputports.write[i].type = Variant::NIL; } ports_changed_notify(); notify_property_list_changed(); return true; } if (String(p_name).begins_with("input_") && is_input_port_editable()) { int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1; ERR_FAIL_INDEX_V(idx, inputports.size(), false); String what = String(p_name).get_slice("/", 1); if (what == "type") { Variant::Type new_type = Variant::Type(int(p_value)); inputports.write[idx].type = new_type; ports_changed_notify(); return true; } if (what == "name") { inputports.write[idx].name = p_value; ports_changed_notify(); return true; } } if (p_name == "output_count" && is_output_port_editable()) { int new_argc = p_value; int argc = outputports.size(); if (argc == new_argc) { return true; } outputports.resize(new_argc); for (int i = argc; i < new_argc; i++) { outputports.write[i].name = "arg" + itos(i + 1); outputports.write[i].type = Variant::NIL; } ports_changed_notify(); notify_property_list_changed(); return true; } if (String(p_name).begins_with("output_") && is_output_port_editable()) { int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1; ERR_FAIL_INDEX_V(idx, outputports.size(), false); String what = String(p_name).get_slice("/", 1); if (what == "type") { Variant::Type new_type = Variant::Type(int(p_value)); outputports.write[idx].type = new_type; ports_changed_notify(); return true; } if (what == "name") { outputports.write[idx].name = p_value; ports_changed_notify(); return true; } } if (p_name == "sequenced/sequenced") { sequenced = p_value; ports_changed_notify(); return true; } return false; } bool VisualScriptLists::_get(const StringName &p_name, Variant &r_ret) const { if (p_name == "input_count" && is_input_port_editable()) { r_ret = inputports.size(); return true; } if (String(p_name).begins_with("input_") && is_input_port_editable()) { int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1; ERR_FAIL_INDEX_V(idx, inputports.size(), false); String what = String(p_name).get_slice("/", 1); if (what == "type") { r_ret = inputports[idx].type; return true; } if (what == "name") { r_ret = inputports[idx].name; return true; } } if (p_name == "output_count" && is_output_port_editable()) { r_ret = outputports.size(); return true; } if (String(p_name).begins_with("output_") && is_output_port_editable()) { int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1; ERR_FAIL_INDEX_V(idx, outputports.size(), false); String what = String(p_name).get_slice("/", 1); if (what == "type") { r_ret = outputports[idx].type; return true; } if (what == "name") { r_ret = outputports[idx].name; return true; } } if (p_name == "sequenced/sequenced") { r_ret = sequenced; return true; } return false; } void VisualScriptLists::_get_property_list(List *p_list) const { if (is_input_port_editable()) { p_list->push_back(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,256")); String argt = "Any"; for (int i = 1; i < Variant::VARIANT_MAX; i++) { argt += "," + Variant::get_type_name(Variant::Type(i)); } for (int i = 0; i < inputports.size(); i++) { p_list->push_back(PropertyInfo(Variant::INT, "input_" + itos(i + 1) + "/type", PROPERTY_HINT_ENUM, argt)); p_list->push_back(PropertyInfo(Variant::STRING, "input_" + itos(i + 1) + "/name")); } } if (is_output_port_editable()) { p_list->push_back(PropertyInfo(Variant::INT, "output_count", PROPERTY_HINT_RANGE, "0,256")); String argt = "Any"; for (int i = 1; i < Variant::VARIANT_MAX; i++) { argt += "," + Variant::get_type_name(Variant::Type(i)); } for (int i = 0; i < outputports.size(); i++) { p_list->push_back(PropertyInfo(Variant::INT, "output_" + itos(i + 1) + "/type", PROPERTY_HINT_ENUM, argt)); p_list->push_back(PropertyInfo(Variant::STRING, "output_" + itos(i + 1) + "/name")); } } p_list->push_back(PropertyInfo(Variant::BOOL, "sequenced/sequenced")); } // input data port interaction void VisualScriptLists::add_input_data_port(Variant::Type p_type, const String &p_name, int p_index) { if (!is_input_port_editable()) { return; } Port inp; inp.name = p_name; inp.type = p_type; if (p_index >= 0) { inputports.insert(p_index, inp); } else { inputports.push_back(inp); } ports_changed_notify(); notify_property_list_changed(); } void VisualScriptLists::set_input_data_port_type(int p_idx, Variant::Type p_type) { if (!is_input_port_type_editable()) { return; } ERR_FAIL_INDEX(p_idx, inputports.size()); inputports.write[p_idx].type = p_type; ports_changed_notify(); notify_property_list_changed(); } void VisualScriptLists::set_input_data_port_name(int p_idx, const String &p_name) { if (!is_input_port_name_editable()) { return; } ERR_FAIL_INDEX(p_idx, inputports.size()); inputports.write[p_idx].name = p_name; ports_changed_notify(); notify_property_list_changed(); } void VisualScriptLists::remove_input_data_port(int p_argidx) { if (!is_input_port_editable()) { return; } ERR_FAIL_INDEX(p_argidx, inputports.size()); inputports.remove_at(p_argidx); ports_changed_notify(); notify_property_list_changed(); } // output data port interaction void VisualScriptLists::add_output_data_port(Variant::Type p_type, const String &p_name, int p_index) { if (!is_output_port_editable()) { return; } Port out; out.name = p_name; out.type = p_type; if (p_index >= 0) { outputports.insert(p_index, out); } else { outputports.push_back(out); } ports_changed_notify(); notify_property_list_changed(); } void VisualScriptLists::set_output_data_port_type(int p_idx, Variant::Type p_type) { if (!is_output_port_type_editable()) { return; } ERR_FAIL_INDEX(p_idx, outputports.size()); outputports.write[p_idx].type = p_type; ports_changed_notify(); notify_property_list_changed(); } void VisualScriptLists::set_output_data_port_name(int p_idx, const String &p_name) { if (!is_output_port_name_editable()) { return; } ERR_FAIL_INDEX(p_idx, outputports.size()); outputports.write[p_idx].name = p_name; ports_changed_notify(); notify_property_list_changed(); } void VisualScriptLists::remove_output_data_port(int p_argidx) { if (!is_output_port_editable()) { return; } ERR_FAIL_INDEX(p_argidx, outputports.size()); outputports.remove_at(p_argidx); ports_changed_notify(); notify_property_list_changed(); } // sequences void VisualScriptLists::set_sequenced(bool p_enable) { if (sequenced == p_enable) { return; } sequenced = p_enable; ports_changed_notify(); } bool VisualScriptLists::is_sequenced() const { return sequenced; } void VisualScriptLists::reset_state() { inputports.clear(); outputports.clear(); sequenced = false; flags = 0; } VisualScriptLists::VisualScriptLists() { // initialize sequenced = false; flags = 0; } void VisualScriptLists::_bind_methods() { ClassDB::bind_method(D_METHOD("add_input_data_port", "type", "name", "index"), &VisualScriptLists::add_input_data_port); ClassDB::bind_method(D_METHOD("set_input_data_port_name", "index", "name"), &VisualScriptLists::set_input_data_port_name); ClassDB::bind_method(D_METHOD("set_input_data_port_type", "index", "type"), &VisualScriptLists::set_input_data_port_type); ClassDB::bind_method(D_METHOD("remove_input_data_port", "index"), &VisualScriptLists::remove_input_data_port); ClassDB::bind_method(D_METHOD("add_output_data_port", "type", "name", "index"), &VisualScriptLists::add_output_data_port); ClassDB::bind_method(D_METHOD("set_output_data_port_name", "index", "name"), &VisualScriptLists::set_output_data_port_name); ClassDB::bind_method(D_METHOD("set_output_data_port_type", "index", "type"), &VisualScriptLists::set_output_data_port_type); ClassDB::bind_method(D_METHOD("remove_output_data_port", "index"), &VisualScriptLists::remove_output_data_port); } ////////////////////////////////////////// //////////////COMPOSEARRAY//////////////// ////////////////////////////////////////// int VisualScriptComposeArray::get_output_sequence_port_count() const { if (sequenced) { return 1; } return 0; } bool VisualScriptComposeArray::has_input_sequence_port() const { return sequenced; } String VisualScriptComposeArray::get_output_sequence_port_text(int p_port) const { return ""; } int VisualScriptComposeArray::get_input_value_port_count() const { return inputports.size(); } int VisualScriptComposeArray::get_output_value_port_count() const { return 1; } PropertyInfo VisualScriptComposeArray::get_input_value_port_info(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, inputports.size(), PropertyInfo()); PropertyInfo pi; pi.name = inputports[p_idx].name; pi.type = inputports[p_idx].type; return pi; } PropertyInfo VisualScriptComposeArray::get_output_value_port_info(int p_idx) const { PropertyInfo pi; pi.name = "out"; pi.type = Variant::ARRAY; return pi; } String VisualScriptComposeArray::get_caption() const { return RTR("Compose Array"); } String VisualScriptComposeArray::get_text() const { return ""; } class VisualScriptComposeArrayNode : public VisualScriptNodeInstance { public: int input_count = 0; virtual int get_working_memory_size() const override { return 0; } virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (input_count > 0) { Array arr; for (int i = 0; i < input_count; i++) { arr.push_back((*p_inputs[i])); } Variant va = Variant(arr); *p_outputs[0] = va; } return 0; } }; VisualScriptNodeInstance *VisualScriptComposeArray::instantiate(VisualScriptInstance *p_instance) { VisualScriptComposeArrayNode *instance = memnew(VisualScriptComposeArrayNode); instance->input_count = inputports.size(); return instance; } VisualScriptComposeArray::VisualScriptComposeArray() { // initialize stuff here sequenced = false; flags = INPUT_EDITABLE; } ////////////////////////////////////////// ////////////////OPERATOR////////////////// ////////////////////////////////////////// int VisualScriptOperator::get_output_sequence_port_count() const { return 0; } bool VisualScriptOperator::has_input_sequence_port() const { return false; } int VisualScriptOperator::get_input_value_port_count() const { return (op == Variant::OP_BIT_NEGATE || op == Variant::OP_NOT || op == Variant::OP_NEGATE || op == Variant::OP_POSITIVE) ? 1 : 2; } int VisualScriptOperator::get_output_value_port_count() const { return 1; } String VisualScriptOperator::get_output_sequence_port_text(int p_port) const { return String(); } PropertyInfo VisualScriptOperator::get_input_value_port_info(int p_idx) const { static const Variant::Type port_types[Variant::OP_MAX][2] = { { Variant::NIL, Variant::NIL }, //OP_EQUAL, { Variant::NIL, Variant::NIL }, //OP_NOT_EQUAL, { Variant::NIL, Variant::NIL }, //OP_LESS, { Variant::NIL, Variant::NIL }, //OP_LESS_EQUAL, { Variant::NIL, Variant::NIL }, //OP_GREATER, { Variant::NIL, Variant::NIL }, //OP_GREATER_EQUAL, //mathematic { Variant::NIL, Variant::NIL }, //OP_ADD, { Variant::NIL, Variant::NIL }, //OP_SUBTRACT, { Variant::NIL, Variant::NIL }, //OP_MULTIPLY, { Variant::NIL, Variant::NIL }, //OP_DIVIDE, { Variant::NIL, Variant::NIL }, //OP_NEGATE, { Variant::NIL, Variant::NIL }, //OP_POSITIVE, { Variant::INT, Variant::INT }, //OP_MODULE, //bitwise { Variant::INT, Variant::INT }, //OP_SHIFT_LEFT, { Variant::INT, Variant::INT }, //OP_SHIFT_RIGHT, { Variant::INT, Variant::INT }, //OP_BIT_AND, { Variant::INT, Variant::INT }, //OP_BIT_OR, { Variant::INT, Variant::INT }, //OP_BIT_XOR, { Variant::INT, Variant::INT }, //OP_BIT_NEGATE, //logic { Variant::BOOL, Variant::BOOL }, //OP_AND, { Variant::BOOL, Variant::BOOL }, //OP_OR, { Variant::BOOL, Variant::BOOL }, //OP_XOR, { Variant::BOOL, Variant::BOOL }, //OP_NOT, //containment { Variant::NIL, Variant::NIL } //OP_IN, }; ERR_FAIL_INDEX_V(p_idx, 2, PropertyInfo()); PropertyInfo pinfo; pinfo.name = p_idx == 0 ? "A" : "B"; pinfo.type = port_types[op][p_idx]; if (pinfo.type == Variant::NIL) { pinfo.type = typed; } return pinfo; } PropertyInfo VisualScriptOperator::get_output_value_port_info(int p_idx) const { static const Variant::Type port_types[Variant::OP_MAX] = { //comparison Variant::BOOL, //OP_EQUAL, Variant::BOOL, //OP_NOT_EQUAL, Variant::BOOL, //OP_LESS, Variant::BOOL, //OP_LESS_EQUAL, Variant::BOOL, //OP_GREATER, Variant::BOOL, //OP_GREATER_EQUAL, //mathematic Variant::NIL, //OP_ADD, Variant::NIL, //OP_SUBTRACT, Variant::NIL, //OP_MULTIPLY, Variant::NIL, //OP_DIVIDE, Variant::NIL, //OP_NEGATE, Variant::NIL, //OP_POSITIVE, Variant::INT, //OP_MODULE, //bitwise Variant::INT, //OP_SHIFT_LEFT, Variant::INT, //OP_SHIFT_RIGHT, Variant::INT, //OP_BIT_AND, Variant::INT, //OP_BIT_OR, Variant::INT, //OP_BIT_XOR, Variant::INT, //OP_BIT_NEGATE, //logic Variant::BOOL, //OP_AND, Variant::BOOL, //OP_OR, Variant::BOOL, //OP_XOR, Variant::BOOL, //OP_NOT, //containment Variant::BOOL //OP_IN, }; PropertyInfo pinfo; pinfo.name = ""; pinfo.type = port_types[op]; if (pinfo.type == Variant::NIL) { pinfo.type = typed; } return pinfo; } String VisualScriptOperator::get_caption() const { switch (op) { // comparison case Variant::OP_EQUAL: return U"A = B"; case Variant::OP_NOT_EQUAL: return U"A \u2260 B"; case Variant::OP_LESS: return U"A < B"; case Variant::OP_LESS_EQUAL: return U"A \u2264 B"; case Variant::OP_GREATER: return U"A > B"; case Variant::OP_GREATER_EQUAL: return U"A \u2265 B"; // mathematic case Variant::OP_ADD: return U"A + B"; case Variant::OP_SUBTRACT: return U"A - B"; case Variant::OP_MULTIPLY: return U"A \u00D7 B"; case Variant::OP_DIVIDE: return U"A \u00F7 B"; case Variant::OP_NEGATE: return U"\u00AC A"; case Variant::OP_POSITIVE: return U"+ A"; case Variant::OP_MODULE: return U"A mod B"; // bitwise case Variant::OP_SHIFT_LEFT: return U"A << B"; case Variant::OP_SHIFT_RIGHT: return U"A >> B"; case Variant::OP_BIT_AND: return U"A & B"; case Variant::OP_BIT_OR: return U"A | B"; case Variant::OP_BIT_XOR: return U"A ^ B"; case Variant::OP_BIT_NEGATE: return U"~A"; // logic case Variant::OP_AND: return U"A and B"; case Variant::OP_OR: return U"A or B"; case Variant::OP_XOR: return U"A xor B"; case Variant::OP_NOT: return U"not A"; case Variant::OP_IN: return U"A in B"; default: { ERR_FAIL_V_MSG( U"Unknown node", U"Unknown node type encountered, caption not available."); } } } String VisualScriptOperator::get_operator_name(Variant::Operator p_op) { switch (p_op) { // comparison case Variant::OP_EQUAL: return "Are Equal"; case Variant::OP_NOT_EQUAL: return "Are Not Equal"; case Variant::OP_LESS: return "Less Than"; case Variant::OP_LESS_EQUAL: return "Less Than or Equal"; case Variant::OP_GREATER: return "Greater Than"; case Variant::OP_GREATER_EQUAL: return "Greater Than or Equal"; // mathematic case Variant::OP_ADD: return "Add"; case Variant::OP_SUBTRACT: return "Subtract"; case Variant::OP_MULTIPLY: return "Multiply"; case Variant::OP_DIVIDE: return "Divide"; case Variant::OP_NEGATE: return "Negate"; case Variant::OP_POSITIVE: return "Positive"; case Variant::OP_MODULE: return "Remainder"; // bitwise case Variant::OP_SHIFT_LEFT: return "Bit Shift Left"; case Variant::OP_SHIFT_RIGHT: return "Bit Shift Right"; case Variant::OP_BIT_AND: return "Bit And"; case Variant::OP_BIT_OR: return "Bit Or"; case Variant::OP_BIT_XOR: return "Bit Xor"; case Variant::OP_BIT_NEGATE: return "Bit Negate"; // logic case Variant::OP_AND: return "And"; case Variant::OP_OR: return "Or"; case Variant::OP_XOR: return "Xor"; case Variant::OP_NOT: return "Not"; case Variant::OP_IN: return "In"; default: { ERR_FAIL_INDEX_V(p_op, Variant::OP_MAX, ""); return "Unknown Operator"; } } } void VisualScriptOperator::set_operator(Variant::Operator p_op) { if (op == p_op) { return; } op = p_op; ports_changed_notify(); } Variant::Operator VisualScriptOperator::get_operator() const { return op; } void VisualScriptOperator::set_typed(Variant::Type p_op) { if (typed == p_op) { return; } typed = p_op; ports_changed_notify(); } Variant::Type VisualScriptOperator::get_typed() const { return typed; } void VisualScriptOperator::_bind_methods() { ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualScriptOperator::set_operator); ClassDB::bind_method(D_METHOD("get_operator"), &VisualScriptOperator::get_operator); ClassDB::bind_method(D_METHOD("set_typed", "type"), &VisualScriptOperator::set_typed); ClassDB::bind_method(D_METHOD("get_typed"), &VisualScriptOperator::get_typed); String types; for (int i = 0; i < Variant::OP_MAX; i++) { if (i > 0) { types += ","; } types += get_operator_name(static_cast(i)); } String argt = "Any"; for (int i = 1; i < Variant::VARIANT_MAX; i++) { argt += "," + Variant::get_type_name(Variant::Type(i)); } ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, types), "set_operator", "get_operator"); ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_typed", "get_typed"); } class VisualScriptNodeInstanceOperator : public VisualScriptNodeInstance { public: bool unary = false; Variant::Operator op; //virtual int get_working_memory_size() const override { return 0; } virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { bool valid; if (unary) { Variant::evaluate(op, *p_inputs[0], Variant(), *p_outputs[0], valid); } else { Variant::evaluate(op, *p_inputs[0], *p_inputs[1], *p_outputs[0], valid); } if (!valid) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; if (p_outputs[0]->get_type() == Variant::STRING) { r_error_str = *p_outputs[0]; } else { if (unary) { r_error_str = String(Variant::get_operator_name(op)) + ": " + RTR("Invalid argument of type:") + " " + Variant::get_type_name(p_inputs[0]->get_type()); } else { r_error_str = String(Variant::get_operator_name(op)) + ": " + RTR("Invalid arguments:") + " A: " + Variant::get_type_name(p_inputs[0]->get_type()) + ", B: " + Variant::get_type_name(p_inputs[1]->get_type()); } } } return 0; } }; VisualScriptNodeInstance *VisualScriptOperator::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceOperator *instance = memnew(VisualScriptNodeInstanceOperator); instance->unary = get_input_value_port_count() == 1; instance->op = op; return instance; } VisualScriptOperator::VisualScriptOperator() { op = Variant::OP_ADD; typed = Variant::NIL; } template static Ref create_op_node(const String &p_name) { Ref node; node.instantiate(); node->set_operator(OP); return node; } ////////////////////////////////////////// ////////////////OPERATOR////////////////// ////////////////////////////////////////// int VisualScriptSelect::get_output_sequence_port_count() const { return 0; } bool VisualScriptSelect::has_input_sequence_port() const { return false; } int VisualScriptSelect::get_input_value_port_count() const { return 3; } int VisualScriptSelect::get_output_value_port_count() const { return 1; } String VisualScriptSelect::get_output_sequence_port_text(int p_port) const { return String(); } PropertyInfo VisualScriptSelect::get_input_value_port_info(int p_idx) const { if (p_idx == 0) { return PropertyInfo(Variant::BOOL, "cond"); } else if (p_idx == 1) { return PropertyInfo(typed, "a"); } else { return PropertyInfo(typed, "b"); } } PropertyInfo VisualScriptSelect::get_output_value_port_info(int p_idx) const { return PropertyInfo(typed, "out"); } String VisualScriptSelect::get_caption() const { return RTR("Select"); } String VisualScriptSelect::get_text() const { return RTR("a if cond, else b"); } void VisualScriptSelect::set_typed(Variant::Type p_op) { if (typed == p_op) { return; } typed = p_op; ports_changed_notify(); } Variant::Type VisualScriptSelect::get_typed() const { return typed; } void VisualScriptSelect::_bind_methods() { ClassDB::bind_method(D_METHOD("set_typed", "type"), &VisualScriptSelect::set_typed); ClassDB::bind_method(D_METHOD("get_typed"), &VisualScriptSelect::get_typed); String argt = "Any"; for (int i = 1; i < Variant::VARIANT_MAX; i++) { argt += "," + Variant::get_type_name(Variant::Type(i)); } ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_typed", "get_typed"); } class VisualScriptNodeInstanceSelect : public VisualScriptNodeInstance { public: //virtual int get_working_memory_size() const override { return 0; } virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { bool cond = *p_inputs[0]; if (cond) { *p_outputs[0] = *p_inputs[1]; } else { *p_outputs[0] = *p_inputs[2]; } return 0; } }; VisualScriptNodeInstance *VisualScriptSelect::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceSelect *instance = memnew(VisualScriptNodeInstanceSelect); return instance; } VisualScriptSelect::VisualScriptSelect() { typed = Variant::NIL; } ////////////////////////////////////////// ////////////////VARIABLE GET////////////////// ////////////////////////////////////////// int VisualScriptVariableGet::get_output_sequence_port_count() const { return 0; } bool VisualScriptVariableGet::has_input_sequence_port() const { return false; } int VisualScriptVariableGet::get_input_value_port_count() const { return 0; } int VisualScriptVariableGet::get_output_value_port_count() const { return 1; } String VisualScriptVariableGet::get_output_sequence_port_text(int p_port) const { return String(); } PropertyInfo VisualScriptVariableGet::get_input_value_port_info(int p_idx) const { return PropertyInfo(); } PropertyInfo VisualScriptVariableGet::get_output_value_port_info(int p_idx) const { PropertyInfo pinfo; pinfo.name = "value"; if (get_visual_script().is_valid() && get_visual_script()->has_variable(variable)) { PropertyInfo vinfo = get_visual_script()->get_variable_info(variable); pinfo.type = vinfo.type; pinfo.hint = vinfo.hint; pinfo.hint_string = vinfo.hint_string; } return pinfo; } String VisualScriptVariableGet::get_caption() const { return vformat(RTR("Get %s"), variable); } void VisualScriptVariableGet::set_variable(StringName p_variable) { if (variable == p_variable) { return; } variable = p_variable; ports_changed_notify(); } StringName VisualScriptVariableGet::get_variable() const { return variable; } void VisualScriptVariableGet::_validate_property(PropertyInfo &property) const { if (property.name == "var_name" && get_visual_script().is_valid()) { Ref vs = get_visual_script(); List vars; vs->get_variable_list(&vars); String vhint; for (const StringName &E : vars) { if (!vhint.is_empty()) { vhint += ","; } vhint += E.operator String(); } property.hint = PROPERTY_HINT_ENUM; property.hint_string = vhint; } } void VisualScriptVariableGet::_bind_methods() { ClassDB::bind_method(D_METHOD("set_variable", "name"), &VisualScriptVariableGet::set_variable); ClassDB::bind_method(D_METHOD("get_variable"), &VisualScriptVariableGet::get_variable); ADD_PROPERTY(PropertyInfo(Variant::STRING, "var_name"), "set_variable", "get_variable"); } class VisualScriptNodeInstanceVariableGet : public VisualScriptNodeInstance { public: VisualScriptVariableGet *node = nullptr; VisualScriptInstance *instance = nullptr; StringName variable; virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (!instance->get_variable(variable, p_outputs[0])) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = RTR("VariableGet not found in script:") + " '" + String(variable) + "'"; return 0; } return 0; } }; VisualScriptNodeInstance *VisualScriptVariableGet::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceVariableGet *instance = memnew(VisualScriptNodeInstanceVariableGet); instance->node = this; instance->instance = p_instance; instance->variable = variable; return instance; } VisualScriptVariableGet::VisualScriptVariableGet() { } ////////////////////////////////////////// ////////////////VARIABLE SET////////////////// ////////////////////////////////////////// int VisualScriptVariableSet::get_output_sequence_port_count() const { return 1; } bool VisualScriptVariableSet::has_input_sequence_port() const { return true; } int VisualScriptVariableSet::get_input_value_port_count() const { return 1; } int VisualScriptVariableSet::get_output_value_port_count() const { return 0; } String VisualScriptVariableSet::get_output_sequence_port_text(int p_port) const { return String(); } PropertyInfo VisualScriptVariableSet::get_input_value_port_info(int p_idx) const { PropertyInfo pinfo; pinfo.name = "set"; if (get_visual_script().is_valid() && get_visual_script()->has_variable(variable)) { PropertyInfo vinfo = get_visual_script()->get_variable_info(variable); pinfo.type = vinfo.type; pinfo.hint = vinfo.hint; pinfo.hint_string = vinfo.hint_string; } return pinfo; } PropertyInfo VisualScriptVariableSet::get_output_value_port_info(int p_idx) const { return PropertyInfo(); } String VisualScriptVariableSet::get_caption() const { return vformat(RTR("Set %s"), variable); } void VisualScriptVariableSet::set_variable(StringName p_variable) { if (variable == p_variable) { return; } variable = p_variable; ports_changed_notify(); } StringName VisualScriptVariableSet::get_variable() const { return variable; } void VisualScriptVariableSet::_validate_property(PropertyInfo &property) const { if (property.name == "var_name" && get_visual_script().is_valid()) { Ref vs = get_visual_script(); List vars; vs->get_variable_list(&vars); String vhint; for (const StringName &E : vars) { if (!vhint.is_empty()) { vhint += ","; } vhint += E.operator String(); } property.hint = PROPERTY_HINT_ENUM; property.hint_string = vhint; } } void VisualScriptVariableSet::_bind_methods() { ClassDB::bind_method(D_METHOD("set_variable", "name"), &VisualScriptVariableSet::set_variable); ClassDB::bind_method(D_METHOD("get_variable"), &VisualScriptVariableSet::get_variable); ADD_PROPERTY(PropertyInfo(Variant::STRING, "var_name"), "set_variable", "get_variable"); } class VisualScriptNodeInstanceVariableSet : public VisualScriptNodeInstance { public: VisualScriptVariableSet *node = nullptr; VisualScriptInstance *instance = nullptr; StringName variable; //virtual int get_working_memory_size() const override { return 0; } virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (!instance->set_variable(variable, *p_inputs[0])) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = RTR("VariableSet not found in script:") + " '" + String(variable) + "'"; } return 0; } }; VisualScriptNodeInstance *VisualScriptVariableSet::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceVariableSet *instance = memnew(VisualScriptNodeInstanceVariableSet); instance->node = this; instance->instance = p_instance; instance->variable = variable; return instance; } VisualScriptVariableSet::VisualScriptVariableSet() { } ////////////////////////////////////////// ////////////////CONSTANT////////////////// ////////////////////////////////////////// int VisualScriptConstant::get_output_sequence_port_count() const { return 0; } bool VisualScriptConstant::has_input_sequence_port() const { return false; } int VisualScriptConstant::get_input_value_port_count() const { return 0; } int VisualScriptConstant::get_output_value_port_count() const { return 1; } String VisualScriptConstant::get_output_sequence_port_text(int p_port) const { return String(); } PropertyInfo VisualScriptConstant::get_input_value_port_info(int p_idx) const { return PropertyInfo(); } PropertyInfo VisualScriptConstant::get_output_value_port_info(int p_idx) const { PropertyInfo pinfo; pinfo.name = String(value); pinfo.type = type; return pinfo; } String VisualScriptConstant::get_caption() const { return RTR("Constant"); } void VisualScriptConstant::set_constant_type(Variant::Type p_type) { if (type == p_type) { return; } type = p_type; Callable::CallError ce; Variant::construct(type, value, nullptr, 0, ce); ports_changed_notify(); notify_property_list_changed(); } Variant::Type VisualScriptConstant::get_constant_type() const { return type; } void VisualScriptConstant::set_constant_value(Variant p_value) { if (value == p_value) { return; } value = p_value; ports_changed_notify(); } Variant VisualScriptConstant::get_constant_value() const { return value; } void VisualScriptConstant::_validate_property(PropertyInfo &property) const { if (property.name == "value") { property.type = type; if (type == Variant::NIL) { property.usage = PROPERTY_USAGE_NONE; //do not save if nil } } } void VisualScriptConstant::_bind_methods() { ClassDB::bind_method(D_METHOD("set_constant_type", "type"), &VisualScriptConstant::set_constant_type); ClassDB::bind_method(D_METHOD("get_constant_type"), &VisualScriptConstant::get_constant_type); ClassDB::bind_method(D_METHOD("set_constant_value", "value"), &VisualScriptConstant::set_constant_value); ClassDB::bind_method(D_METHOD("get_constant_value"), &VisualScriptConstant::get_constant_value); String argt = "Null"; for (int i = 1; i < Variant::VARIANT_MAX; i++) { argt += "," + Variant::get_type_name(Variant::Type(i)); } ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_constant_type", "get_constant_type"); ADD_PROPERTY(PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT | PROPERTY_USAGE_DEFAULT), "set_constant_value", "get_constant_value"); } class VisualScriptNodeInstanceConstant : public VisualScriptNodeInstance { public: Variant constant; //virtual int get_working_memory_size() const override { return 0; } virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = constant; return 0; } }; VisualScriptNodeInstance *VisualScriptConstant::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceConstant *instance = memnew(VisualScriptNodeInstanceConstant); instance->constant = value; return instance; } VisualScriptConstant::VisualScriptConstant() { type = Variant::NIL; } ////////////////////////////////////////// ////////////////PRELOAD////////////////// ////////////////////////////////////////// int VisualScriptPreload::get_output_sequence_port_count() const { return 0; } bool VisualScriptPreload::has_input_sequence_port() const { return false; } int VisualScriptPreload::get_input_value_port_count() const { return 0; } int VisualScriptPreload::get_output_value_port_count() const { return 1; } String VisualScriptPreload::get_output_sequence_port_text(int p_port) const { return String(); } PropertyInfo VisualScriptPreload::get_input_value_port_info(int p_idx) const { return PropertyInfo(); } PropertyInfo VisualScriptPreload::get_output_value_port_info(int p_idx) const { PropertyInfo pinfo; pinfo.type = Variant::OBJECT; if (preload.is_valid()) { pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE; pinfo.hint_string = preload->get_class(); if (preload->get_path().is_resource_file()) { pinfo.name = preload->get_path(); } else if (!preload->get_name().is_empty()) { pinfo.name = preload->get_name(); } else { pinfo.name = preload->get_class(); } } else { pinfo.name = ""; } return pinfo; } String VisualScriptPreload::get_caption() const { return RTR("Preload"); } void VisualScriptPreload::set_preload(const Ref &p_preload) { if (preload == p_preload) { return; } preload = p_preload; ports_changed_notify(); } Ref VisualScriptPreload::get_preload() const { return preload; } void VisualScriptPreload::_bind_methods() { ClassDB::bind_method(D_METHOD("set_preload", "resource"), &VisualScriptPreload::set_preload); ClassDB::bind_method(D_METHOD("get_preload"), &VisualScriptPreload::get_preload); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), "set_preload", "get_preload"); } class VisualScriptNodeInstancePreload : public VisualScriptNodeInstance { public: Ref preload; //virtual int get_working_memory_size() const override { return 0; } virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = preload; return 0; } }; VisualScriptNodeInstance *VisualScriptPreload::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstancePreload *instance = memnew(VisualScriptNodeInstancePreload); instance->preload = preload; return instance; } VisualScriptPreload::VisualScriptPreload() { } ////////////////////////////////////////// ////////////////INDEX//////////////////// ////////////////////////////////////////// int VisualScriptIndexGet::get_output_sequence_port_count() const { return 0; } bool VisualScriptIndexGet::has_input_sequence_port() const { return false; } int VisualScriptIndexGet::get_input_value_port_count() const { return 2; } int VisualScriptIndexGet::get_output_value_port_count() const { return 1; } String VisualScriptIndexGet::get_output_sequence_port_text(int p_port) const { return String(); } PropertyInfo VisualScriptIndexGet::get_input_value_port_info(int p_idx) const { if (p_idx == 0) { return PropertyInfo(Variant::NIL, "base"); } else { return PropertyInfo(Variant::NIL, "index"); } } PropertyInfo VisualScriptIndexGet::get_output_value_port_info(int p_idx) const { return PropertyInfo(); } String VisualScriptIndexGet::get_caption() const { return RTR("Get Index"); } class VisualScriptNodeInstanceIndexGet : public VisualScriptNodeInstance { public: //virtual int get_working_memory_size() const override { return 0; } virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { bool valid; *p_outputs[0] = p_inputs[0]->get(*p_inputs[1], &valid); if (!valid) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = "Invalid get: " + p_inputs[0]->get_construct_string(); } return 0; } }; VisualScriptNodeInstance *VisualScriptIndexGet::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceIndexGet *instance = memnew(VisualScriptNodeInstanceIndexGet); return instance; } VisualScriptIndexGet::VisualScriptIndexGet() { } ////////////////////////////////////////// ////////////////INDEXSET////////////////// ////////////////////////////////////////// int VisualScriptIndexSet::get_output_sequence_port_count() const { return 1; } bool VisualScriptIndexSet::has_input_sequence_port() const { return true; } int VisualScriptIndexSet::get_input_value_port_count() const { return 3; } int VisualScriptIndexSet::get_output_value_port_count() const { return 0; } String VisualScriptIndexSet::get_output_sequence_port_text(int p_port) const { return String(); } PropertyInfo VisualScriptIndexSet::get_input_value_port_info(int p_idx) const { if (p_idx == 0) { return PropertyInfo(Variant::NIL, "base"); } else if (p_idx == 1) { return PropertyInfo(Variant::NIL, "index"); } else { return PropertyInfo(Variant::NIL, "value"); } } PropertyInfo VisualScriptIndexSet::get_output_value_port_info(int p_idx) const { return PropertyInfo(); } String VisualScriptIndexSet::get_caption() const { return RTR("Set Index"); } class VisualScriptNodeInstanceIndexSet : public VisualScriptNodeInstance { public: //virtual int get_working_memory_size() const override { return 0; } virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { bool valid; ((Variant *)p_inputs[0])->set(*p_inputs[1], *p_inputs[2], &valid); if (!valid) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = "Invalid set: " + p_inputs[1]->get_construct_string(); } return 0; } }; VisualScriptNodeInstance *VisualScriptIndexSet::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceIndexSet *instance = memnew(VisualScriptNodeInstanceIndexSet); return instance; } VisualScriptIndexSet::VisualScriptIndexSet() { } ////////////////////////////////////////// ////////////////GLOBALCONSTANT/////////// ////////////////////////////////////////// int VisualScriptGlobalConstant::get_output_sequence_port_count() const { return 0; } bool VisualScriptGlobalConstant::has_input_sequence_port() const { return false; } int VisualScriptGlobalConstant::get_input_value_port_count() const { return 0; } int VisualScriptGlobalConstant::get_output_value_port_count() const { return 1; } String VisualScriptGlobalConstant::get_output_sequence_port_text(int p_port) const { return String(); } PropertyInfo VisualScriptGlobalConstant::get_input_value_port_info(int p_idx) const { return PropertyInfo(); } PropertyInfo VisualScriptGlobalConstant::get_output_value_port_info(int p_idx) const { String name = CoreConstants::get_global_constant_name(index); return PropertyInfo(Variant::INT, name); } String VisualScriptGlobalConstant::get_caption() const { return RTR("Global Constant"); } void VisualScriptGlobalConstant::set_global_constant(int p_which) { index = p_which; notify_property_list_changed(); ports_changed_notify(); } int VisualScriptGlobalConstant::get_global_constant() { return index; } class VisualScriptNodeInstanceGlobalConstant : public VisualScriptNodeInstance { public: int index = 0; virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = CoreConstants::get_global_constant_value(index); return 0; } }; VisualScriptNodeInstance *VisualScriptGlobalConstant::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceGlobalConstant *instance = memnew(VisualScriptNodeInstanceGlobalConstant); instance->index = index; return instance; } void VisualScriptGlobalConstant::_bind_methods() { ClassDB::bind_method(D_METHOD("set_global_constant", "index"), &VisualScriptGlobalConstant::set_global_constant); ClassDB::bind_method(D_METHOD("get_global_constant"), &VisualScriptGlobalConstant::get_global_constant); String cc; for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) { if (i > 0) { cc += ","; } cc += CoreConstants::get_global_constant_name(i); } ADD_PROPERTY(PropertyInfo(Variant::INT, "constant", PROPERTY_HINT_ENUM, cc), "set_global_constant", "get_global_constant"); } VisualScriptGlobalConstant::VisualScriptGlobalConstant() { index = 0; } ////////////////////////////////////////// ////////////////CLASSCONSTANT/////////// ////////////////////////////////////////// int VisualScriptClassConstant::get_output_sequence_port_count() const { return 0; } bool VisualScriptClassConstant::has_input_sequence_port() const { return false; } int VisualScriptClassConstant::get_input_value_port_count() const { return 0; } int VisualScriptClassConstant::get_output_value_port_count() const { return 1; } String VisualScriptClassConstant::get_output_sequence_port_text(int p_port) const { return String(); } PropertyInfo VisualScriptClassConstant::get_input_value_port_info(int p_idx) const { return PropertyInfo(); } PropertyInfo VisualScriptClassConstant::get_output_value_port_info(int p_idx) const { if (name == "") { return PropertyInfo(Variant::INT, String(base_type)); } else { return PropertyInfo(Variant::INT, String(base_type) + "." + String(name)); } } String VisualScriptClassConstant::get_caption() const { return RTR("Class Constant"); } void VisualScriptClassConstant::set_class_constant(const StringName &p_which) { name = p_which; notify_property_list_changed(); ports_changed_notify(); } StringName VisualScriptClassConstant::get_class_constant() { return name; } void VisualScriptClassConstant::set_base_type(const StringName &p_which) { base_type = p_which; List constants; ClassDB::get_integer_constant_list(base_type, &constants, true); if (constants.size() > 0) { bool found_name = false; for (const String &E : constants) { if (E == name) { found_name = true; break; } } if (!found_name) { name = constants[0]; } } else { name = ""; } notify_property_list_changed(); ports_changed_notify(); } StringName VisualScriptClassConstant::get_base_type() { return base_type; } class VisualScriptNodeInstanceClassConstant : public VisualScriptNodeInstance { public: int value = 0; bool valid = false; virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (!valid) { r_error_str = "Invalid constant name, pick a valid class constant."; r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; } *p_outputs[0] = value; return 0; } }; VisualScriptNodeInstance *VisualScriptClassConstant::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceClassConstant *instance = memnew(VisualScriptNodeInstanceClassConstant); instance->value = ClassDB::get_integer_constant(base_type, name, &instance->valid); return instance; } void VisualScriptClassConstant::_validate_property(PropertyInfo &property) const { if (property.name == "constant") { List constants; ClassDB::get_integer_constant_list(base_type, &constants, true); property.hint_string = ""; for (const String &E : constants) { if (!property.hint_string.is_empty()) { property.hint_string += ","; } property.hint_string += E; } } } void VisualScriptClassConstant::_bind_methods() { ClassDB::bind_method(D_METHOD("set_class_constant", "name"), &VisualScriptClassConstant::set_class_constant); ClassDB::bind_method(D_METHOD("get_class_constant"), &VisualScriptClassConstant::get_class_constant); ClassDB::bind_method(D_METHOD("set_base_type", "name"), &VisualScriptClassConstant::set_base_type); ClassDB::bind_method(D_METHOD("get_base_type"), &VisualScriptClassConstant::get_base_type); ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "constant", PROPERTY_HINT_ENUM, ""), "set_class_constant", "get_class_constant"); } VisualScriptClassConstant::VisualScriptClassConstant() { base_type = "Object"; } ////////////////////////////////////////// ////////////////BASICTYPECONSTANT/////////// ////////////////////////////////////////// int VisualScriptBasicTypeConstant::get_output_sequence_port_count() const { return 0; } bool VisualScriptBasicTypeConstant::has_input_sequence_port() const { return false; } int VisualScriptBasicTypeConstant::get_input_value_port_count() const { return 0; } int VisualScriptBasicTypeConstant::get_output_value_port_count() const { return 1; } String VisualScriptBasicTypeConstant::get_output_sequence_port_text(int p_port) const { return String(); } PropertyInfo VisualScriptBasicTypeConstant::get_input_value_port_info(int p_idx) const { return PropertyInfo(); } PropertyInfo VisualScriptBasicTypeConstant::get_output_value_port_info(int p_idx) const { return PropertyInfo(type, "value"); } String VisualScriptBasicTypeConstant::get_caption() const { return RTR("Basic Constant"); } String VisualScriptBasicTypeConstant::get_text() const { if (name == "") { return Variant::get_type_name(type); } else { return Variant::get_type_name(type) + "." + String(name); } } void VisualScriptBasicTypeConstant::set_basic_type_constant(const StringName &p_which) { name = p_which; notify_property_list_changed(); ports_changed_notify(); } StringName VisualScriptBasicTypeConstant::get_basic_type_constant() const { return name; } void VisualScriptBasicTypeConstant::set_basic_type(Variant::Type p_which) { type = p_which; List constants; Variant::get_constants_for_type(type, &constants); if (constants.size() > 0) { bool found_name = false; for (const StringName &E : constants) { if (E == name) { found_name = true; break; } } if (!found_name) { name = constants[0]; } } else { name = ""; } notify_property_list_changed(); ports_changed_notify(); } Variant::Type VisualScriptBasicTypeConstant::get_basic_type() const { return type; } class VisualScriptNodeInstanceBasicTypeConstant : public VisualScriptNodeInstance { public: Variant value; bool valid = false; virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (!valid) { r_error_str = "Invalid constant name, pick a valid basic type constant."; r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; } *p_outputs[0] = value; return 0; } }; VisualScriptNodeInstance *VisualScriptBasicTypeConstant::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceBasicTypeConstant *instance = memnew(VisualScriptNodeInstanceBasicTypeConstant); instance->value = Variant::get_constant_value(type, name, &instance->valid); return instance; } void VisualScriptBasicTypeConstant::_validate_property(PropertyInfo &property) const { if (property.name == "constant") { List constants; Variant::get_constants_for_type(type, &constants); if (constants.size() == 0) { property.usage = PROPERTY_USAGE_NONE; return; } property.hint_string = ""; for (const StringName &E : constants) { if (!property.hint_string.is_empty()) { property.hint_string += ","; } property.hint_string += String(E); } } } void VisualScriptBasicTypeConstant::_bind_methods() { ClassDB::bind_method(D_METHOD("set_basic_type", "name"), &VisualScriptBasicTypeConstant::set_basic_type); ClassDB::bind_method(D_METHOD("get_basic_type"), &VisualScriptBasicTypeConstant::get_basic_type); ClassDB::bind_method(D_METHOD("set_basic_type_constant", "name"), &VisualScriptBasicTypeConstant::set_basic_type_constant); ClassDB::bind_method(D_METHOD("get_basic_type_constant"), &VisualScriptBasicTypeConstant::get_basic_type_constant); String argt = "Null"; for (int i = 1; i < Variant::VARIANT_MAX; i++) { argt += "," + Variant::get_type_name(Variant::Type(i)); } ADD_PROPERTY(PropertyInfo(Variant::INT, "basic_type", PROPERTY_HINT_ENUM, argt), "set_basic_type", "get_basic_type"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "constant", PROPERTY_HINT_ENUM, ""), "set_basic_type_constant", "get_basic_type_constant"); } VisualScriptBasicTypeConstant::VisualScriptBasicTypeConstant() { type = Variant::NIL; } ////////////////////////////////////////// ////////////////MATHCONSTANT/////////// ////////////////////////////////////////// const char *VisualScriptMathConstant::const_name[MATH_CONSTANT_MAX] = { "One", "PI", "PI/2", "TAU", "E", "Sqrt2", "INF", "NAN" }; double VisualScriptMathConstant::const_value[MATH_CONSTANT_MAX] = { 1.0, Math_PI, Math_PI * 0.5, Math_TAU, 2.71828182845904523536, Math::sqrt(2.0), INFINITY, NAN }; int VisualScriptMathConstant::get_output_sequence_port_count() const { return 0; } bool VisualScriptMathConstant::has_input_sequence_port() const { return false; } int VisualScriptMathConstant::get_input_value_port_count() const { return 0; } int VisualScriptMathConstant::get_output_value_port_count() const { return 1; } String VisualScriptMathConstant::get_output_sequence_port_text(int p_port) const { return String(); } PropertyInfo VisualScriptMathConstant::get_input_value_port_info(int p_idx) const { return PropertyInfo(); } PropertyInfo VisualScriptMathConstant::get_output_value_port_info(int p_idx) const { return PropertyInfo(Variant::FLOAT, const_name[constant]); } String VisualScriptMathConstant::get_caption() const { return RTR("Math Constant"); } void VisualScriptMathConstant::set_math_constant(MathConstant p_which) { constant = p_which; notify_property_list_changed(); ports_changed_notify(); } VisualScriptMathConstant::MathConstant VisualScriptMathConstant::get_math_constant() { return constant; } class VisualScriptNodeInstanceMathConstant : public VisualScriptNodeInstance { public: float value = 0.0f; virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = value; return 0; } }; VisualScriptNodeInstance *VisualScriptMathConstant::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceMathConstant *instance = memnew(VisualScriptNodeInstanceMathConstant); instance->value = const_value[constant]; return instance; } void VisualScriptMathConstant::_bind_methods() { ClassDB::bind_method(D_METHOD("set_math_constant", "which"), &VisualScriptMathConstant::set_math_constant); ClassDB::bind_method(D_METHOD("get_math_constant"), &VisualScriptMathConstant::get_math_constant); String cc; for (int i = 0; i < MATH_CONSTANT_MAX; i++) { if (i > 0) { cc += ","; } cc += const_name[i]; } ADD_PROPERTY(PropertyInfo(Variant::INT, "constant", PROPERTY_HINT_ENUM, cc), "set_math_constant", "get_math_constant"); BIND_ENUM_CONSTANT(MATH_CONSTANT_ONE); BIND_ENUM_CONSTANT(MATH_CONSTANT_PI); BIND_ENUM_CONSTANT(MATH_CONSTANT_HALF_PI); BIND_ENUM_CONSTANT(MATH_CONSTANT_TAU); BIND_ENUM_CONSTANT(MATH_CONSTANT_E); BIND_ENUM_CONSTANT(MATH_CONSTANT_SQRT2); BIND_ENUM_CONSTANT(MATH_CONSTANT_INF); BIND_ENUM_CONSTANT(MATH_CONSTANT_NAN); BIND_ENUM_CONSTANT(MATH_CONSTANT_MAX); } VisualScriptMathConstant::VisualScriptMathConstant() { constant = MATH_CONSTANT_ONE; } ////////////////////////////////////////// ////////////////ENGINESINGLETON/////////// ////////////////////////////////////////// int VisualScriptEngineSingleton::get_output_sequence_port_count() const { return 0; } bool VisualScriptEngineSingleton::has_input_sequence_port() const { return false; } int VisualScriptEngineSingleton::get_input_value_port_count() const { return 0; } int VisualScriptEngineSingleton::get_output_value_port_count() const { return 1; } String VisualScriptEngineSingleton::get_output_sequence_port_text(int p_port) const { return String(); } PropertyInfo VisualScriptEngineSingleton::get_input_value_port_info(int p_idx) const { return PropertyInfo(); } PropertyInfo VisualScriptEngineSingleton::get_output_value_port_info(int p_idx) const { return PropertyInfo(Variant::OBJECT, singleton); } String VisualScriptEngineSingleton::get_caption() const { return RTR("Get Engine Singleton"); } void VisualScriptEngineSingleton::set_singleton(const String &p_string) { singleton = p_string; notify_property_list_changed(); ports_changed_notify(); } String VisualScriptEngineSingleton::get_singleton() { return singleton; } class VisualScriptNodeInstanceEngineSingleton : public VisualScriptNodeInstance { public: Object *singleton = nullptr; //virtual int get_working_memory_size() const override { return 0; } virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = singleton; return 0; } }; VisualScriptNodeInstance *VisualScriptEngineSingleton::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceEngineSingleton *instance = memnew(VisualScriptNodeInstanceEngineSingleton); instance->singleton = Engine::get_singleton()->get_singleton_object(singleton); return instance; } VisualScriptEngineSingleton::TypeGuess VisualScriptEngineSingleton::guess_output_type(TypeGuess *p_inputs, int p_output) const { Object *obj = Engine::get_singleton()->get_singleton_object(singleton); TypeGuess tg; tg.type = Variant::OBJECT; if (obj) { tg.gdclass = obj->get_class(); tg.script = obj->get_script(); } return tg; } void VisualScriptEngineSingleton::_validate_property(PropertyInfo &property) const { String cc; List singletons; Engine::get_singleton()->get_singletons(&singletons); for (const Engine::Singleton &E : singletons) { if (E.name == "VS" || E.name == "PS" || E.name == "PS2D" || E.name == "AS" || E.name == "TS" || E.name == "SS" || E.name == "SS2D") { continue; //skip these, too simple named } if (!cc.is_empty()) { cc += ","; } cc += E.name; } property.hint = PROPERTY_HINT_ENUM; property.hint_string = cc; } void VisualScriptEngineSingleton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_singleton", "name"), &VisualScriptEngineSingleton::set_singleton); ClassDB::bind_method(D_METHOD("get_singleton"), &VisualScriptEngineSingleton::get_singleton); ADD_PROPERTY(PropertyInfo(Variant::STRING, "constant"), "set_singleton", "get_singleton"); } VisualScriptEngineSingleton::VisualScriptEngineSingleton() { singleton = String(); } ////////////////////////////////////////// ////////////////GETNODE/////////// ////////////////////////////////////////// int VisualScriptSceneNode::get_output_sequence_port_count() const { return 0; } bool VisualScriptSceneNode::has_input_sequence_port() const { return false; } int VisualScriptSceneNode::get_input_value_port_count() const { return 0; } int VisualScriptSceneNode::get_output_value_port_count() const { return 1; } String VisualScriptSceneNode::get_output_sequence_port_text(int p_port) const { return String(); } PropertyInfo VisualScriptSceneNode::get_input_value_port_info(int p_idx) const { return PropertyInfo(); } PropertyInfo VisualScriptSceneNode::get_output_value_port_info(int p_idx) const { return PropertyInfo(Variant::OBJECT, path.simplified()); } String VisualScriptSceneNode::get_caption() const { return RTR("Get Scene Node"); } void VisualScriptSceneNode::set_node_path(const NodePath &p_path) { path = p_path; notify_property_list_changed(); ports_changed_notify(); } NodePath VisualScriptSceneNode::get_node_path() { return path; } class VisualScriptNodeInstanceSceneNode : public VisualScriptNodeInstance { public: VisualScriptSceneNode *node = nullptr; VisualScriptInstance *instance = nullptr; NodePath path; //virtual int get_working_memory_size() const override { return 0; } virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { Node *node = Object::cast_to(instance->get_owner_ptr()); if (!node) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = "Base object is not a Node!"; return 0; } Node *another = node->get_node(path); if (!another) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = "Path does not lead Node!"; return 0; } *p_outputs[0] = another; return 0; } }; VisualScriptNodeInstance *VisualScriptSceneNode::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceSceneNode *instance = memnew(VisualScriptNodeInstanceSceneNode); instance->node = this; instance->instance = p_instance; instance->path = path; return instance; } #ifdef TOOLS_ENABLED static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref