Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmake/scripts/generate_godot_extension_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ def get_operator_name(op_type):
elif op_type == "unary+":
return "Unary+"
elif op_type == "%":
return "Module"
return "Modulo"
elif op_type == "**":
return "Power"
elif op_type == "<<":
Expand Down
166 changes: 83 additions & 83 deletions src/api/extension_db.cpp

Large diffs are not rendered by default.

16 changes: 14 additions & 2 deletions src/common/property_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,24 @@ namespace PropertyUtils
/// Checks whether the property represents an enum.
/// @param p_property the property to check
/// @return true if the property is an enumeration, false otherwise
_FORCE_INLINE_ bool is_enum(const PropertyInfo& p_property) { return p_property.hint == PROPERTY_HINT_ENUM || p_property.usage & PROPERTY_USAGE_CLASS_IS_ENUM; }
_FORCE_INLINE_ bool is_enum(const PropertyInfo& p_property)
{
if (p_property.type != Variant::INT)
return false;

return p_property.hint == PROPERTY_HINT_ENUM || p_property.usage & PROPERTY_USAGE_CLASS_IS_ENUM;
}

/// Checks whether the property is a bitfield.
/// @param p_property the property to check
/// @return true if the property is a bitfield, false otherwise
_FORCE_INLINE_ bool is_bitfield(const PropertyInfo& p_property) { return p_property.hint == PROPERTY_HINT_FLAGS || p_property.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD; }
_FORCE_INLINE_ bool is_bitfield(const PropertyInfo& p_property)
{
if (p_property.type != Variant::INT)
return false;

return p_property.hint == PROPERTY_HINT_FLAGS || p_property.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD;
}

/// Checks whether the property is a class enum.
/// @param p_property the property to check
Expand Down
1 change: 1 addition & 0 deletions src/common/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ void OrchestratorSettings::_register_settings()
_settings.emplace_back(BOOL_SETTING("ui/graph/show_overlay_action_tooltips", true));
_settings.emplace_back(COLOR_NO_ALPHA_SETTING("ui/graph/knot_selected_color", Color(0.68f, 0.44f, 0.09f)));

_settings.emplace_back(SENUM_SETTING("ui/nodes/connection_hotzone_scale", "100%,150%,200%", "100%"));
_settings.emplace_back(BOOL_SETTING("ui/nodes/show_type_icons", true));
_settings.emplace_back(BOOL_SETTING("ui/nodes/resizable_by_default", false));
_settings.emplace_back(BOOL_SETTING("ui/nodes/highlight_selected_connections", false));
Expand Down
9 changes: 9 additions & 0 deletions src/editor/actions/introspector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1016,9 +1016,18 @@ Vector<Ref<OrchestratorEditorIntrospector::Action>> OrchestratorEditorIntrospect
{ "right_type_name", info.right_type_name },
{ "return_type", info.return_type } });

PackedStringArray keywords = Array::make(info.name, info.code, info.left_type_name, info.right_type_name);
if (info.op == VariantOperators::OP_MODULE)
{
keywords.push_back("mod");
keywords.push_back("modulus");
}

actions.push_back(_script_node_builder<OScriptNodeOperator>(operator_category, operator_name, data)
.inputs(Vector({ info.left_type, info.right_type }))
.outputs(Vector({ info.return_type }))
.keywords(keywords)
.no_capitalize(true)
.build());
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/editor/component_panels/variables_panel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ void OrchestratorScriptVariablesComponentPanel::_create_variable_item(TreeItem*
{
int32_t index = item->get_button_count(0);
item->add_button(0, SceneUtils::get_editor_icon("GuiVisibilityVisible"), 3);
item->set_button_tooltip_text(0, index, "Variable is exported and visible outside the orchestration.");
item->set_button_tooltip_text(0, index, "Variable is exported and can be modified in the inspector.");
item->set_button_disabled(0, index, false);
}
else if (p_variable->is_constant())
Expand All @@ -87,7 +87,7 @@ void OrchestratorScriptVariablesComponentPanel::_create_variable_item(TreeItem*
}
else
{
String tooltip = "Variable is private and not exported.";
String tooltip = "Variable is not exported and only visible to scripts.";
if (!p_variable->is_exportable())
tooltip += "\nType cannot be exported.";

Expand Down
62 changes: 62 additions & 0 deletions src/editor/graph/graph_edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,22 @@ void OrchestratorGraphEdit::_drop_data_variable(const String& p_name, const Vect
spawn_node(options);
}

bool OrchestratorGraphEdit::_is_in_port_hotzone(const Vector2& p_pos, const Vector2& p_mouse_pos, const Vector2i& p_port_size, bool p_left)
{
const int32_t port_hotzone_outer_extent = get_theme_constant("port_hotzone_outer_extent");
const int32_t port_hotzone_inner_extent = get_theme_constant("port_hotzone_inner_extent");

const String hotzone_percent = ORCHESTRATOR_GET("ui/nodes/connection_hotzone_scale", "100%");
const Vector2i port_size = p_port_size * (hotzone_percent.replace("%", "").to_float() / 100.0);

const Rect2 hotzone = Rect2(
p_pos.x - (p_left ? port_hotzone_outer_extent : port_hotzone_inner_extent),
p_pos.y - port_size.height / 2.0,
port_hotzone_inner_extent + port_hotzone_outer_extent,
port_size.height);

return hotzone.has_point(p_mouse_pos);
}

void OrchestratorGraphEdit::_gui_input(const Ref<InputEvent>& p_event)
{
Expand Down Expand Up @@ -1295,6 +1311,46 @@ PackedVector2Array OrchestratorGraphEdit::_get_connection_line(const Vector2& p_
return curve_points;
}

bool OrchestratorGraphEdit::_is_in_input_hotzone(Object* p_in_node, int32_t p_in_port, const Vector2& p_mouse_position)
{
GraphNode* node = cast_to<GraphNode>(p_in_node);
if (!node)
return false;

const Ref<Texture2D> icon = node->get_slot_custom_icon_left(p_in_port);
if (!icon.is_valid())
return false;

Vector2i port_size = Vector2i(icon->get_width(), icon->get_height());
int slot_index = node->get_input_port_slot(p_in_port);
Control* child = cast_to<Control>(node->get_child(slot_index, false));
port_size.height = MAX(port_size.height, child ? child->get_size().y : 0);

const float zoom = get_zoom();
const Vector2 pos = node->get_input_port_position(p_in_port) * zoom + node->get_position();
return _is_in_port_hotzone(pos / zoom, p_mouse_position, port_size, true);
}

bool OrchestratorGraphEdit::_is_in_output_hotzone(Object* p_in_node, int32_t p_in_port, const Vector2& p_mouse_position)
{
GraphNode* node = cast_to<GraphNode>(p_in_node);
if (!node)
return false;

const Ref<Texture2D> icon = node->get_slot_custom_icon_right(p_in_port);
if (!icon.is_valid())
return false;

Vector2i port_size = Vector2i(icon->get_width(), icon->get_height());
int slot_index = node->get_output_port_slot(p_in_port);
Control* child = cast_to<Control>(node->get_child(slot_index, false));
port_size.height = MAX(port_size.height, child ? child->get_size().y : 0);

const float zoom = get_zoom();
const Vector2 pos = node->get_output_port_position(p_in_port) * zoom + node->get_position();
return _is_in_port_hotzone(pos / zoom, p_mouse_position, port_size, false);
}

bool OrchestratorGraphEdit::_get_connection_for_points(const Vector2& p_from_position,
const Vector2& p_to_position,
OScriptConnection& r_connection) const
Expand Down Expand Up @@ -1622,6 +1678,7 @@ void OrchestratorGraphEdit::_connect_with_menu(PinHandle p_handle, const Vector2
menu->set_show_filter_option(false);
menu->set_start_collapsed(true);
menu->connect("action_selected", callable_mp_this(_on_action_menu_selection));
menu->connect("canceled", callable_mp_this(_on_action_menu_canceled));

Ref<OrchestratorEditorActionFilterEngine> filter_engine;
filter_engine.instantiate();
Expand Down Expand Up @@ -1854,6 +1911,11 @@ void OrchestratorGraphEdit::_on_action_menu_selection(const Ref<OrchestratorEdit
}
}

void OrchestratorGraphEdit::_on_action_menu_canceled()
{
_drag_from_pin.reset();
}

void OrchestratorGraphEdit::_on_connection_drag_ended()
{
for_each_graph_node([](OrchestratorGraphNode* node) {
Expand Down
7 changes: 7 additions & 0 deletions src/editor/graph/graph_edit.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ class OrchestratorGraphEdit : public GraphEdit
void _drop_data_function(const Dictionary& p_function, const Vector2& p_at_position, bool p_as_callable);
void _drop_data_variable(const String& p_name, const Vector2& p_at_position, bool p_validated, bool p_setter);

bool _is_in_port_hotzone(const Vector2& p_pos, const Vector2& p_mouse_pos, const Vector2i& p_port_size, bool p_left);

public:
// The OrchestratorGraphEdit maintains a static clipboard so that data can be shared across different graph
// instances easily in the tab view, and so these methods are called by the MainView during the
Expand Down Expand Up @@ -257,6 +259,8 @@ class OrchestratorGraphEdit : public GraphEdit
void _drop_data(const Vector2& p_position, const Variant& p_data) override;
bool _is_node_hover_valid(const StringName& p_from, int p_from_port, const StringName& p_to, int p_to_port) override;
PackedVector2Array _get_connection_line(const Vector2& p_from_position, const Vector2& p_to_position) const override;
bool _is_in_input_hotzone(Object* p_in_node, int32_t p_in_port, const Vector2& p_mouse_position) override;
bool _is_in_output_hotzone(Object* p_in_node, int32_t p_in_port, const Vector2& p_mouse_position) override;
//~ End GraphEdit overrides

/// Spawn a node in the graph
Expand Down Expand Up @@ -396,6 +400,9 @@ class OrchestratorGraphEdit : public GraphEdit
/// @param p_action the action definition
void _on_action_menu_selection(const Ref<OrchestratorEditorActionDefinition>& p_action);

/// Handles when the action menu is closed without a selection
void _on_action_menu_canceled();

/// Connection drag started
/// @param p_from the source node
/// @param p_from_port source node port
Expand Down
6 changes: 5 additions & 1 deletion src/editor/graph/graph_node_pin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,11 @@ bool is_numeric(Variant::Type p_type)

bool OrchestratorGraphNodePin::can_accept(OrchestratorGraphNodePin* p_pin)
{
return _pin->can_accept(p_pin->_pin);
ERR_FAIL_NULL_V(p_pin, false);

const OrchestratorGraphNodePin* source = _pin->is_output() ? this : p_pin;
const OrchestratorGraphNodePin* target = _pin->is_output() ? p_pin : this;
return target->_pin->can_accept(source->_pin);
}

void OrchestratorGraphNodePin::link(OrchestratorGraphNodePin* p_pin)
Expand Down
6 changes: 1 addition & 5 deletions src/editor/graph/nodes/graph_node_default.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,11 +249,7 @@ Vector<OrchestratorGraphNodePin*> OrchestratorGraphNodeDefault::get_eligible_aut

if (!pin->is_execution() && !p_pin->is_execution())
{
const Variant::Type lhs_type = pin->get_property_info().type;
const Variant::Type rhs_type = p_pin->get_property_info().type;
const bool lhs_variant = PropertyUtils::is_variant(pin->get_property_info());
const bool rhs_variant = PropertyUtils::is_variant(p_pin->get_property_info());
if (lhs_type != rhs_type && !lhs_variant && !rhs_variant)
if (!p_pin->can_accept(pin))
continue;
}

Expand Down
34 changes: 21 additions & 13 deletions src/script/node_pin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -490,24 +490,32 @@ bool OScriptNodePin::can_accept(const Ref<OScriptNodePin>& p_pin) const
// Types match
if (_property.type == p_pin->get_type())
{
const String target_class = _property.class_name;
const String source_class = p_pin->get_property_info().class_name;
if (!target_class.is_empty() && !source_class.is_empty())
// Certain properties specify more than one class type separated by commas.
// For example, CanvasItem materials which can be ShaderMaterial,CanvasItemMaterial
const PackedStringArray source_classes = p_pin->get_property_info().class_name.split(",");
const PackedStringArray target_classes = _property.class_name.split(",");
if (!target_classes.is_empty() && !source_classes.is_empty())
{
// Check inheritance of global classes
if (ScriptServer::is_global_class(source_class) && ScriptServer::is_parent_class(source_class, target_class))
return true;

// Either must be the same or the target must be a super type of the source
// The equality check is to handle enum classes that aren't registered as "classes" in Godot terms
if (ClassDB::is_parent_class(source_class, target_class) || target_class == source_class)
return true;
for (const String& source_class : source_classes)
{
for (const String& target_class : target_classes)
{
// Check inheritance of global classes
if (ScriptServer::is_global_class(source_class) && ScriptServer::is_parent_class(source_class, target_class))
return true;

// Either must be the same or the target must be a super type of the source
// The equality check is to handle enum classes that aren't registered as "classes" in Godot terms
if (ClassDB::is_parent_class(source_class, target_class) || target_class == source_class)
return true;
}
}

return false;
}
else if (target_class.is_empty() && !source_class.is_empty())
else if (_property.class_name.is_empty() && !source_classes.is_empty())
{
// If the source is a derived object type of the target, thats fine
// If the source is a derived object type of the target, that's fine
if (_property.type == Variant::OBJECT)
return true;

Expand Down
9 changes: 8 additions & 1 deletion src/script/nodes/properties/property.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,12 @@ bool OScriptNodeProperty::_get_class_property(const String& p_class_name, const
return false;
}

bool OScriptNodeProperty::_is_same_or_parent(const String& p_target_class) const
{
return _orchestration->get_base_type() == p_target_class
|| ClassDB::is_parent_class(_orchestration->get_base_type(), p_target_class);
}

void OScriptNodeProperty::_upgrade(uint32_t p_version, uint32_t p_current_version)
{
if (p_version == 1 && p_current_version >= 2)
Expand Down Expand Up @@ -306,7 +312,8 @@ void OScriptNodeProperty::validate_node_during_build(BuildLog& p_log) const
const Ref<OScriptNodePin> target = find_pin("target", PD_Input);
if (!target->has_any_connections())
{
p_log.error(this, "Requires a connection.");
if (!_is_same_or_parent(target->get_target_class()))
p_log.error(this, "Requires a connection.");
}
// todo: Temporarily disabled as lookups are not always reliable, and validation errors are mistakenly thrown
// else
Expand Down
5 changes: 5 additions & 0 deletions src/script/nodes/properties/property.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ class OScriptNodeProperty : public OScriptNode
/// @return true if found, false otherwise
bool _get_class_property(const String& p_class_name, const String& p_name, PropertyInfo& r_property);

/// Check whether the specified target class is the same or the parent of the orchestration
/// @param p_target_class the class to check
/// @return true if its the same or a parent type
bool _is_same_or_parent(const String& p_target_class) const;

//~ Begin OScriptNode Interface
void _upgrade(uint32_t p_version, uint32_t p_current_version) override;
//~ End OScriptNode Interface
Expand Down
17 changes: 16 additions & 1 deletion src/script/nodes/properties/property_get.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class OScriptNodePropertyGetInstance : public OScriptNodeInstance
String _target_class;
PropertyInfo _property;
NodePath _node_path;
bool _enforce_self = false;

Node* _get_node_path_target(OScriptExecutionContext& p_context)
{
Expand All @@ -53,7 +54,10 @@ class OScriptNodePropertyGetInstance : public OScriptNodeInstance

case OScriptNodeProperty::CALL_INSTANCE:
{
Variant instance = p_context.get_input(0);
Variant instance = _enforce_self
? Variant(p_context.get_owner())
: p_context.get_input(0);

if (instance.get_type() == Variant::OBJECT)
{
Object* obj = Object::cast_to<Object>(instance);
Expand Down Expand Up @@ -127,6 +131,17 @@ OScriptNodeInstance* OScriptNodePropertyGet::instantiate()
OScriptNodePropertyGetInstance* i = memnew(OScriptNodePropertyGetInstance);
i->_node = this;
i->_call_mode = _call_mode;

if (_call_mode == CALL_INSTANCE)
{
const Ref<OScriptNodePin> target = find_pin("target", PD_Input);
if (target.is_valid() && !target->has_any_connections())
{
if (_is_same_or_parent(target->get_target_class()))
i->_enforce_self = true;
}
}

i->_target_class = _base_type;
i->_property = _property;
i->_node_path = _node_path;
Expand Down
Loading
Loading