Files
godot-visual-script/visual_script_yield_nodes.cpp
K. S. Ernest (iFire) Lee 9a4df15d3e Codebase Enhancements and Performance Improvements
We've made several updates to improve our codebase and application performance.

- Clang format was applied for better readability and consistency, aiding other developers in understanding and contributing to the code.
- We resolved issues that were causing visual script compilation failure. The visual script now compiles successfully, ensuring application functionality.
- Broken sections within the codebase were fixed, improving overall stability.
- Built-in functions from the visual script were removed to simplify the code and enhance readability.
- Generic search performance was improved to provide faster results, enhancing user experience.
- Missing flow nodes were added to the Visual Script, ensuring all necessary components are present for correct functioning.

In an effort to streamline the codebase:

- `VisualScriptComment` class and related code were removed, reducing complexity and improving maintainability.
- Error messages were optimized for quicker feedback when errors occur.
- Licenses were updated to reflect recent changes, ensuring legal compliance and project transparency.
- The `get_global_name()` override in `visual_script.h` was fixed, and `TYPE_BUILTIN_FUNC` in `visual_script_expression.h` was removed, improving code functionality.
- Search logic was refactored to avoid double searching, enhancing performance.
- Documentation was updated to reflect recent changes, providing accurate information to users and developers.
- Property selection logic in `VisualScriptPropertySelector` was refactored for easier understanding and modification.
- Code was refactored to avoid variable shadowing, improving readability and reducing potential errors.
- `.clang-format` and `.clang-tidy` configuration files were added to ensure consistent code styling.

To make the code more robust and easier to understand:

- Variable names were corrected for clarity, and error handling in `visual_script_expression.cpp` was improved.
- Function and variable names were refactored for better readability and maintainability.
- Member editing logic in `VisualScriptEditor` was simplified.
- Name variables were updated to be unique, avoiding potential conflicts and errors.
- The `VisualScriptSubCall` class was refactored for simplicity and ease of understanding.

For macOS workflow:

- It was updated to use the latest version and correct path for installing Vulkan SDK, enabling the application to leverage the latest features and improvements from the Vulkan SDK.
- Mac Vulkan SDK was installed to support Vulkan-based functionalities.

Lastly, we made necessary changes to pass CI/CD tests, ensuring the code quality and stability of the application.
2023-08-19 09:42:23 -07:00

635 lines
18 KiB
C++

/**************************************************************************/
/* visual_script_yield_nodes.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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_yield_nodes.h"
#include "core/os/os.h"
#include "scene/main/node.h"
#include "scene/main/scene_tree.h"
#include "visual_script_nodes.h"
//////////////////////////////////////////
////////////////YIELD///////////
//////////////////////////////////////////
int VisualScriptYield::get_output_sequence_port_count() const { return 1; }
bool VisualScriptYield::has_input_sequence_port() const { return true; }
int VisualScriptYield::get_input_value_port_count() const { return 0; }
int VisualScriptYield::get_output_value_port_count() const { return 0; }
String VisualScriptYield::get_output_sequence_port_text(int p_port) const {
return String();
}
PropertyInfo VisualScriptYield::get_input_value_port_info(int p_idx) const {
return PropertyInfo();
}
PropertyInfo VisualScriptYield::get_output_value_port_info(int p_idx) const {
return PropertyInfo();
}
String VisualScriptYield::get_caption() const {
return yield_mode == YIELD_RETURN ? RTR("Yield") : RTR("Wait");
}
String VisualScriptYield::get_text() const {
switch (yield_mode) {
case YIELD_RETURN:
return "";
break;
case YIELD_FRAME:
return RTR("Next Frame");
break;
case YIELD_PHYSICS_FRAME:
return RTR("Next Physics Frame");
break;
case YIELD_WAIT:
return vformat(RTR("%s sec(s)"), rtos(wait_time));
break;
}
return String();
}
class VisualScriptNodeInstanceYield : public VisualScriptNodeInstance {
public:
VisualScriptYield::YieldMode mode;
double wait_time = 0.0;
virtual int get_working_memory_size() const override {
return 1;
} // yield needs at least 1
// virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
// virtual bool get_output_port_unsequenced(int p_idx,Variant*
// r_value,Variant* p_working_mem,String &r_error) const { return 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 (p_start_mode == START_MODE_RESUME_YIELD) {
return 0; // resuming yield
} else {
// yield
SceneTree *tree =
Object::cast_to<SceneTree>(OS::get_singleton()->get_main_loop());
if (!tree) {
r_error_str = "Main Loop is not SceneTree";
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
return 0;
}
Ref<VisualScriptFunctionState> state;
state.instantiate();
int ret = STEP_YIELD_BIT;
switch (mode) {
case VisualScriptYield::YIELD_RETURN:
ret = STEP_EXIT_FUNCTION_BIT;
break; // return the yield
case VisualScriptYield::YIELD_FRAME:
state->connect_to_signal(tree, "process_frame", Array());
break;
case VisualScriptYield::YIELD_PHYSICS_FRAME:
state->connect_to_signal(tree, "physics_frame", Array());
break;
case VisualScriptYield::YIELD_WAIT:
state->connect_to_signal(tree->create_timer(wait_time).ptr(), "timeout",
Array());
break;
}
*p_working_mem = state;
return ret;
}
}
};
VisualScriptNodeInstance *
VisualScriptYield::instantiate(VisualScriptInstance *p_instance) {
VisualScriptNodeInstanceYield *instance =
memnew(VisualScriptNodeInstanceYield);
// instance->instance=p_instance;
instance->mode = yield_mode;
instance->wait_time = wait_time;
return instance;
}
void VisualScriptYield::set_yield_mode(YieldMode p_mode) {
if (yield_mode == p_mode) {
return;
}
yield_mode = p_mode;
ports_changed_notify();
notify_property_list_changed();
}
VisualScriptYield::YieldMode VisualScriptYield::get_yield_mode() {
return yield_mode;
}
void VisualScriptYield::set_wait_time(double p_time) {
if (wait_time == p_time) {
return;
}
wait_time = p_time;
ports_changed_notify();
}
double VisualScriptYield::get_wait_time() { return wait_time; }
void VisualScriptYield::_validate_property(PropertyInfo &p_property) const {
if (p_property.name == "wait_time") {
if (yield_mode != YIELD_WAIT) {
p_property.usage = PROPERTY_USAGE_NONE;
}
}
}
void VisualScriptYield::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_yield_mode", "mode"),
&VisualScriptYield::set_yield_mode);
ClassDB::bind_method(D_METHOD("get_yield_mode"),
&VisualScriptYield::get_yield_mode);
ClassDB::bind_method(D_METHOD("set_wait_time", "sec"),
&VisualScriptYield::set_wait_time);
ClassDB::bind_method(D_METHOD("get_wait_time"),
&VisualScriptYield::get_wait_time);
ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM,
"Frame,Physics Frame,Time",
PROPERTY_USAGE_NO_EDITOR),
"set_yield_mode", "get_yield_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wait_time"), "set_wait_time",
"get_wait_time");
BIND_ENUM_CONSTANT(YIELD_FRAME);
BIND_ENUM_CONSTANT(YIELD_PHYSICS_FRAME);
BIND_ENUM_CONSTANT(YIELD_WAIT);
}
VisualScriptYield::VisualScriptYield() {
yield_mode = YIELD_FRAME;
wait_time = 1;
}
template <VisualScriptYield::YieldMode MODE>
static Ref<VisualScriptNode> create_yield_node(const String &p_name) {
Ref<VisualScriptYield> node;
node.instantiate();
node->set_yield_mode(MODE);
return node;
}
///////////////////////////////////////////////////
////////////////YIELD SIGNAL//////////////////////
//////////////////////////////////////////////////
int VisualScriptYieldSignal::get_output_sequence_port_count() const {
return 1;
}
bool VisualScriptYieldSignal::has_input_sequence_port() const { return true; }
#ifdef TOOLS_ENABLED
static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node,
const Ref<Script> &script) {
if (p_edited_scene != p_current_node &&
p_current_node->get_owner() != p_edited_scene) {
return nullptr;
}
Ref<Script> scr = p_current_node->get_script();
if (scr.is_valid() && scr == script) {
return p_current_node;
}
for (int i = 0; i < p_current_node->get_child_count(); i++) {
Node *n =
_find_script_node(p_edited_scene, p_current_node->get_child(i), script);
if (n) {
return n;
}
}
return nullptr;
}
#endif
Node *VisualScriptYieldSignal::_get_base_node() const {
#ifdef TOOLS_ENABLED
Ref<Script> yield_script = get_visual_script();
if (!yield_script.is_valid()) {
return nullptr;
}
MainLoop *main_loop = OS::get_singleton()->get_main_loop();
SceneTree *scene_tree = Object::cast_to<SceneTree>(main_loop);
if (!scene_tree) {
return nullptr;
}
Node *edited_scene = scene_tree->get_edited_scene_root();
if (!edited_scene) {
return nullptr;
}
Node *script_node = _find_script_node(edited_scene, edited_scene, yield_script);
if (!script_node) {
return nullptr;
}
if (!script_node->has_node(base_path)) {
return nullptr;
}
Node *path_to = script_node->get_node(base_path);
return path_to;
#else
return nullptr;
#endif
}
StringName VisualScriptYieldSignal::_get_base_type() const {
if (call_mode == CALL_MODE_SELF && get_visual_script().is_valid()) {
return get_visual_script()->get_instance_base_type();
} else if (call_mode == CALL_MODE_NODE_PATH &&
get_visual_script().is_valid()) {
Node *path = _get_base_node();
if (path) {
return path->get_class();
}
}
return base_type;
}
int VisualScriptYieldSignal::get_input_value_port_count() const {
if (call_mode == CALL_MODE_INSTANCE) {
return 1;
} else {
return 0;
}
}
int VisualScriptYieldSignal::get_output_value_port_count() const {
MethodInfo sr;
if (!ClassDB::get_signal(_get_base_type(), signal, &sr)) {
return 0;
}
return sr.arguments.size();
}
String
VisualScriptYieldSignal::get_output_sequence_port_text(int p_port) const {
return String();
}
PropertyInfo
VisualScriptYieldSignal::get_input_value_port_info(int p_idx) const {
if (call_mode == CALL_MODE_INSTANCE) {
return PropertyInfo(Variant::OBJECT, "instance");
} else {
return PropertyInfo();
}
}
PropertyInfo
VisualScriptYieldSignal::get_output_value_port_info(int p_idx) const {
MethodInfo sr;
if (!ClassDB::get_signal(_get_base_type(), signal, &sr)) {
return PropertyInfo(); // no signal
}
ERR_FAIL_INDEX_V(p_idx, sr.arguments.size(), PropertyInfo());
return sr.arguments[p_idx];
}
String VisualScriptYieldSignal::get_caption() const {
switch (call_mode) {
case CALL_MODE_SELF: {
return RTR("WaitSignal");
} break;
case CALL_MODE_NODE_PATH: {
return RTR("WaitNodeSignal");
} break;
case CALL_MODE_INSTANCE: {
return RTR("WaitInstanceSignal");
} break;
}
return String();
}
String VisualScriptYieldSignal::get_text() const {
if (call_mode == CALL_MODE_SELF) {
return " " + String(signal) + "()";
} else {
return " " + _get_base_type() + "." + String(signal) + "()";
}
}
void VisualScriptYieldSignal::set_base_type(const StringName &p_type) {
if (base_type == p_type) {
return;
}
base_type = p_type;
notify_property_list_changed();
ports_changed_notify();
}
StringName VisualScriptYieldSignal::get_base_type() const { return base_type; }
void VisualScriptYieldSignal::set_signal(const StringName &p_type) {
if (signal == p_type) {
return;
}
signal = p_type;
notify_property_list_changed();
ports_changed_notify();
}
StringName VisualScriptYieldSignal::get_signal() const { return signal; }
void VisualScriptYieldSignal::set_base_path(const NodePath &p_type) {
if (base_path == p_type) {
return;
}
base_path = p_type;
notify_property_list_changed();
ports_changed_notify();
}
NodePath VisualScriptYieldSignal::get_base_path() const { return base_path; }
void VisualScriptYieldSignal::set_call_mode(CallMode p_mode) {
if (call_mode == p_mode) {
return;
}
call_mode = p_mode;
notify_property_list_changed();
ports_changed_notify();
}
VisualScriptYieldSignal::CallMode
VisualScriptYieldSignal::get_call_mode() const {
return call_mode;
}
void VisualScriptYieldSignal::_validate_property(
PropertyInfo &p_property) const {
if (p_property.name == "base_type") {
if (call_mode != CALL_MODE_INSTANCE) {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
if (p_property.name == "node_path") {
if (call_mode != CALL_MODE_NODE_PATH) {
p_property.usage = PROPERTY_USAGE_NONE;
} else {
Node *bnode = _get_base_node();
if (bnode) {
p_property.hint_string = bnode->get_path(); // convert to long string
}
}
}
if (p_property.name == "signal") {
p_property.hint = PROPERTY_HINT_ENUM;
List<MethodInfo> methods;
ClassDB::get_signal_list(_get_base_type(), &methods);
List<String> mstring;
for (const MethodInfo &E : methods) {
if (E.name.begins_with("_")) {
continue;
}
mstring.push_back(E.name.get_slice(":", 0));
}
mstring.sort();
String ml;
for (const String &E : mstring) {
if (!ml.is_empty()) {
ml += ",";
}
ml += E;
}
p_property.hint_string = ml;
}
}
void VisualScriptYieldSignal::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_base_type", "base_type"),
&VisualScriptYieldSignal::set_base_type);
ClassDB::bind_method(D_METHOD("get_base_type"),
&VisualScriptYieldSignal::get_base_type);
ClassDB::bind_method(D_METHOD("set_signal", "signal"),
&VisualScriptYieldSignal::set_signal);
ClassDB::bind_method(D_METHOD("get_signal"),
&VisualScriptYieldSignal::get_signal);
ClassDB::bind_method(D_METHOD("set_call_mode", "mode"),
&VisualScriptYieldSignal::set_call_mode);
ClassDB::bind_method(D_METHOD("get_call_mode"),
&VisualScriptYieldSignal::get_call_mode);
ClassDB::bind_method(D_METHOD("set_base_path", "base_path"),
&VisualScriptYieldSignal::set_base_path);
ClassDB::bind_method(D_METHOD("get_base_path"),
&VisualScriptYieldSignal::get_base_path);
String bt;
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
if (i > 0) {
bt += ",";
}
bt += Variant::get_type_name(Variant::Type(i));
}
ADD_PROPERTY(PropertyInfo(Variant::INT, "call_mode", PROPERTY_HINT_ENUM,
"Self,Node Path,Instance"),
"set_call_mode", "get_call_mode");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type",
PROPERTY_HINT_TYPE_STRING, "Object"),
"set_base_type", "get_base_type");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path",
PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),
"set_base_path", "get_base_path");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "signal"), "set_signal",
"get_signal");
BIND_ENUM_CONSTANT(CALL_MODE_SELF);
BIND_ENUM_CONSTANT(CALL_MODE_NODE_PATH);
BIND_ENUM_CONSTANT(CALL_MODE_INSTANCE);
}
class VisualScriptNodeInstanceYieldSignal : public VisualScriptNodeInstance {
public:
VisualScriptYieldSignal::CallMode call_mode;
NodePath node_path;
int output_args = 0;
StringName signal;
VisualScriptYieldSignal *node = nullptr;
VisualScriptInstance *instance = nullptr;
virtual int get_working_memory_size() const override { return 1; }
// virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
// virtual bool get_output_port_unsequenced(int p_idx,Variant*
// r_value,Variant* p_working_mem,String &r_error) const { return true; }
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 (p_start_mode == START_MODE_RESUME_YIELD) {
return 0; // resuming yield
} else {
// yield
Object *object = nullptr;
switch (call_mode) {
case VisualScriptYieldSignal::CALL_MODE_SELF: {
object = instance->get_owner_ptr();
} break;
case VisualScriptYieldSignal::CALL_MODE_NODE_PATH: {
Node *yield_node = Object::cast_to<Node>(instance->get_owner_ptr());
if (!yield_node) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
r_error_str = "Base object is not a Node!";
return 0;
}
Node *another = yield_node->get_node(node_path);
if (!another) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
r_error_str = "Path does not lead Node!";
return 0;
}
object = another;
} break;
case VisualScriptYieldSignal::CALL_MODE_INSTANCE: {
object = *p_inputs[0];
if (!object) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
r_error_str = "Supplied instance input is null.";
return 0;
}
} break;
}
Ref<VisualScriptFunctionState> state;
state.instantiate();
state->connect_to_signal(object, signal, Array());
*p_working_mem = state;
return STEP_YIELD_BIT;
}
}
};
VisualScriptNodeInstance *
VisualScriptYieldSignal::instantiate(VisualScriptInstance *p_instance) {
VisualScriptNodeInstanceYieldSignal *instance =
memnew(VisualScriptNodeInstanceYieldSignal);
instance->node = this;
instance->instance = p_instance;
instance->signal = signal;
instance->call_mode = call_mode;
instance->node_path = base_path;
instance->output_args = get_output_value_port_count();
return instance;
}
VisualScriptYieldSignal::VisualScriptYieldSignal() {
call_mode = CALL_MODE_SELF;
base_type = "Object";
}
template <VisualScriptYieldSignal::CallMode cmode>
static Ref<VisualScriptNode> create_yield_signal_node(const String &p_name) {
Ref<VisualScriptYieldSignal> node;
node.instantiate();
node->set_call_mode(cmode);
return node;
}
void register_visual_script_yield_nodes() {
VisualScriptLanguage::singleton->add_register_func(
"functions/wait/wait_frame",
create_yield_node<VisualScriptYield::YIELD_FRAME>);
VisualScriptLanguage::singleton->add_register_func(
"functions/wait/wait_physics_frame",
create_yield_node<VisualScriptYield::YIELD_PHYSICS_FRAME>);
VisualScriptLanguage::singleton->add_register_func(
"functions/wait/wait_time",
create_yield_node<VisualScriptYield::YIELD_WAIT>);
VisualScriptLanguage::singleton->add_register_func(
"functions/yield", create_yield_node<VisualScriptYield::YIELD_RETURN>);
VisualScriptLanguage::singleton->add_register_func(
"functions/yield_signal", create_node_generic<VisualScriptYieldSignal>);
}