From 5e8c71f9637548e34ef4fc9a5698c768ff679f96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Qui=C3=B1ones?= Date: Fri, 3 Jan 2025 12:11:35 -0300 Subject: [PATCH] Fix types relationships The types relationship (previously named cast_relationships) tell which type can be used in the context of another type. For example, integers and floats are exchangeable. And in particular, all other types can be used in boolean context: `if not Color.BLACK:` is allowed in GDScript as Color.BLACK is falsey. Same for the empty string, zero number, etc. This fixes a bug where an integer or float value block was allowed to be snapped into a string slot. This removes outdated custom casting code that has been abandoned. https://github.com/endlessm/godot-block-coding/issues/351 --- addons/block_code/block_code_plugin.gd | 3 - addons/block_code/drag_manager/drag.gd | 4 +- addons/block_code/types/types.gd | 147 ++----------------------- 3 files changed, 9 insertions(+), 145 deletions(-) diff --git a/addons/block_code/block_code_plugin.gd b/addons/block_code/block_code_plugin.gd index ff960f1c..759a9881 100644 --- a/addons/block_code/block_code_plugin.gd +++ b/addons/block_code/block_code_plugin.gd @@ -3,7 +3,6 @@ extends EditorPlugin const MainPanelScene := preload("res://addons/block_code/ui/main_panel.tscn") const MainPanel = preload("res://addons/block_code/ui/main_panel.gd") -const Types = preload("res://addons/block_code/types/types.gd") const TxUtils := preload("res://addons/block_code/translation/utils.gd") const ScriptWindow := preload("res://addons/block_code/ui/script_window/script_window.tscn") @@ -39,8 +38,6 @@ func _init(): func _enter_tree(): - Types.init_cast_graph() - editor_inspector = EditorInterface.get_inspector() main_panel = MainPanelScene.instantiate() diff --git a/addons/block_code/drag_manager/drag.gd b/addons/block_code/drag_manager/drag.gd index 102b38c0..ce0a03d4 100644 --- a/addons/block_code/drag_manager/drag.gd +++ b/addons/block_code/drag_manager/drag.gd @@ -128,8 +128,8 @@ func _snaps_to(node: Node) -> bool: if _block.definition.type != _snap_point.block_type: return false - if _block.definition.type == Types.BlockType.VALUE and not Types.can_cast(_block.definition.variant_type, _snap_point.variant_type): - # We only snap Value blocks to snaps that can cast to same variant: + if _block.definition.type == Types.BlockType.VALUE and not Types.has_relationship(_block.definition.variant_type, _snap_point.variant_type): + # We only snap Value blocks to snaps if their types have a relationship: return false # Check if any parent node is this node diff --git a/addons/block_code/types/types.gd b/addons/block_code/types/types.gd index e1768560..12a0875a 100644 --- a/addons/block_code/types/types.gd +++ b/addons/block_code/types/types.gd @@ -36,147 +36,14 @@ const STRING_TO_VARIANT_TYPE: Dictionary = { "STRING_NAME": TYPE_STRING_NAME, } -const cast_relationships = [ - [TYPE_INT, TYPE_FLOAT, "float(%s)"], - [TYPE_FLOAT, TYPE_INT, "int(%s)"], - [TYPE_INT, TYPE_STRING, "str(%s)"], - [TYPE_FLOAT, TYPE_STRING, "str(%s)"], - [TYPE_COLOR, TYPE_STRING, "str(%s)"], - [TYPE_VECTOR2, TYPE_STRING, "str(%s)"], - [TYPE_VECTOR2, TYPE_BOOL, "%s"], - [TYPE_VECTOR3, TYPE_STRING, "str(%s)"], - [TYPE_VECTOR3, TYPE_BOOL, "%s"], -] - -# Directed graph, edges are CastGraphEdge -static var cast_graph: Dictionary - - -class CastGraphEdge: - var to: Variant.Type - var cast_format: String - - func _init(p_to: Variant.Type, p_cast_format: String): - to = p_to - cast_format = p_cast_format - - -static func init_cast_graph(): - cast_graph = {} - - for rel in cast_relationships: - if not cast_graph.has(rel[0]): - cast_graph[rel[0]] = [] - - if not cast_graph.has(rel[1]): - cast_graph[rel[1]] = [] - - var edges: Array = cast_graph[rel[0]] - - edges.append(CastGraphEdge.new(rel[1], rel[2])) - - -# Graph recursive utils -static var prev: Dictionary -static var dist: Dictionary -const INT_MAX: int = 1000000000 - - -static func dijkstra(source: Variant.Type): - prev = {} - dist = {} - - var queue := PriorityQueue.new() - - dist[source] = 0 - queue.push(source, 0) - - for v in cast_graph.keys(): - if v != source: - dist[v] = INT_MAX - prev[v] = null - queue.push(v, INT_MAX) - - while not queue.is_empty(): - var u = queue.pop() - - if !cast_graph.has(u): - continue - - for edge in cast_graph[u]: - var v = edge.to - var alt = dist[u] + 1 - if alt < dist[v]: - dist[v] = alt - prev[v] = CastGraphEdge.new(u, edge.cast_format) - queue.update_priority(v, alt) +const types_relationships = { + TYPE_INT: [TYPE_FLOAT], + TYPE_FLOAT: [TYPE_INT], + TYPE_BOOL: [TYPE_STRING, TYPE_INT, TYPE_FLOAT, TYPE_VECTOR2, TYPE_VECTOR3, TYPE_COLOR, TYPE_NODE_PATH, TYPE_OBJECT, TYPE_NIL, TYPE_STRING_NAME], +} -static func can_cast(type: Variant.Type, parent_type: Variant.Type) -> bool: +static func has_relationship(type: Variant.Type, parent_type: Variant.Type) -> bool: if type == parent_type: return true - - if cast_graph.has(type) and cast_graph.has(parent_type): - dijkstra(type) - return dist[parent_type] < INT_MAX - return false - - -static func cast(val: String, type: Variant.Type, parent_type: Variant.Type): - if type == parent_type: - return val - - if cast_graph.has(type) and cast_graph.has(parent_type): - dijkstra(type) - if dist[parent_type] < INT_MAX: - var prev_edge = prev[parent_type] - var cast_string = "%s" - while prev_edge: - cast_string %= prev_edge.cast_format - if prev.has(prev_edge.to): - prev_edge = prev[prev_edge.to] - else: - prev_edge = null - - return cast_string % val - - return null - - -# TODO: replace with max heap -class PriorityQueue: - var data: Array = [] - - func _init(): - data = [] - - func push(element, priority): - data.append([element, priority]) - _sort() - - func _sort(): - data.sort_custom(func(a, b): a[1] < b[1]) - - func pop(): - if data.size() > 0: - return data.pop_front()[0] - return null - - func peek(): - if data.size() > 0: - return data[0][0] - return null - - func is_empty(): - return data.size() == 0 - - func update_priority(element, priority): - var found_pair = null - for pair in data: - if pair[0] == element: - found_pair = pair - break - - if found_pair: - found_pair[1] = priority - _sort() + return type in types_relationships.get(parent_type, [])