Skip to content

Fix types relationships #352

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
3 changes: 0 additions & 3 deletions addons/block_code/block_code_plugin.gd
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down Expand Up @@ -39,8 +38,6 @@ func _init():


func _enter_tree():
Types.init_cast_graph()

editor_inspector = EditorInterface.get_inspector()

main_panel = MainPanelScene.instantiate()
Expand Down
4 changes: 2 additions & 2 deletions addons/block_code/drag_manager/drag.gd
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
147 changes: 7 additions & 140 deletions addons/block_code/types/types.gd
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this looks much cleaner, although I found casting to a boolean works in if statements or converting through a boolean block, but not for directly setting a boolean variable (Parser Error: Value of type "String" cannot be assigned to a variable of type "bool".) but that situation is unlikely due to it's unique shape. I also think that boolean to integer could be added in the future, similar to #267 (true => 1, false => 0).

Copy link
Contributor Author

@manuq manuq Jan 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this looks much cleaner, although I found casting to a boolean works in if statements or converting through a boolean block, but not for directly setting a boolean variable (Parser Error: Value of type "String" cannot be assigned to a variable of type "bool".) but that situation is unlikely due to it's unique shape. I also think that boolean to integer could be added in the future, similar to #267 (true => 1, false => 0).

Oh right, good catch. The assignment is a problem. The issue was there before. For example:
Captura desde 2025-01-06 11-59-05

Which gives: Parser Error: Value of type "Vector2" cannot be assigned to a variable of type "bool".

This PR makes it a bit worse, allowing for more value blocks to be snapped in boolean setters.

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, [])
Loading