Skip to content

Commit

Permalink
Merge pull request #316 from endlessm/T35649-fix-drag-drop-obj-property
Browse files Browse the repository at this point in the history
BlockScriptSerialization: Re-generate block definition for object property blocks
  • Loading branch information
starnight authored Nov 20, 2024
2 parents b71d679 + 5c3358d commit 3cfcf76
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 57 deletions.
14 changes: 13 additions & 1 deletion addons/block_code/block_code_node/block_code.gd
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ extends Node

const TxUtils := preload("res://addons/block_code/translation/utils.gd")

@export var block_script: BlockScriptSerialization = null
@export var block_script: BlockScriptSerialization = null:
set = _set_block_script


func _init():
Expand Down Expand Up @@ -37,6 +38,17 @@ func _enter_tree():
block_script = new_block_script


func _set_block_script(value):
if value == null:
# Wipe out the bidirectional link between this block code node and the
# block script
if block_script:
block_script.block_code_node = null
else:
value.block_code_node = self
block_script = value


func _update_parent_script():
if Engine.is_editor_hint():
push_error("Updating the parent script must happen in game.")
Expand Down
55 changes: 41 additions & 14 deletions addons/block_code/code_generation/blocks_catalog.gd
Original file line number Diff line number Diff line change
Expand Up @@ -253,25 +253,52 @@ static func add_custom_blocks(
static func get_variable_block_definitions(variables: Array[VariableDefinition]) -> Array[BlockDefinition]:
var block_definitions: Array[BlockDefinition] = []
for variable: VariableDefinition in variables:
var type_string: String = Types.VARIANT_TYPE_TO_STRING[variable.var_type]
var block_def: BlockDefinition

# Getter
var block_def = BlockDefinition.new()
block_def.name = "get_var_%s" % variable.var_name
block_def.category = "Variables"
block_def.type = Types.BlockType.VALUE
block_def.variant_type = variable.var_type
block_def.display_template = variable.var_name
block_def.code_template = variable.var_name
block_def = get_variable_getter_block_definition(variable)
block_definitions.append(block_def)

# Setter
block_def = BlockDefinition.new()
block_def.name = "set_var_%s" % variable.var_name
block_def.category = "Variables"
block_def.type = Types.BlockType.STATEMENT
block_def.display_template = "Set %s to {value: %s}" % [variable.var_name, type_string]
block_def.code_template = "%s = {value}" % [variable.var_name]
block_def = get_variable_setter_block_definition(variable)
block_definitions.append(block_def)

return block_definitions


static func get_variable_getter_block_definition(variable: VariableDefinition) -> BlockDefinition:
var block_def := BlockDefinition.new()

block_def.name = "get_var_%s" % variable.var_name
block_def.category = "Variables"
block_def.type = Types.BlockType.VALUE
block_def.variant_type = variable.var_type
block_def.display_template = variable.var_name
block_def.code_template = variable.var_name

return block_def


static func get_variable_setter_block_definition(variable: VariableDefinition) -> BlockDefinition:
var type_string: String = Types.VARIANT_TYPE_TO_STRING[variable.var_type]
var block_def := BlockDefinition.new()

block_def.name = "set_var_%s" % variable.var_name
block_def.category = "Variables"
block_def.type = Types.BlockType.STATEMENT
block_def.display_template = "Set %s to {value: %s}" % [variable.var_name, type_string]
block_def.code_template = "%s = {value}" % variable.var_name

return block_def


static func get_property_getter_block_definition(variable: VariableDefinition) -> BlockDefinition:
var block_def := get_variable_getter_block_definition(variable)
block_def.description = "The %s property" % variable.var_name
return block_def


static func get_property_setter_block_definition(variable: VariableDefinition) -> BlockDefinition:
var block_def := get_variable_setter_block_definition(variable)
block_def.description = "Set the %s property" % variable.var_name
return block_def
69 changes: 59 additions & 10 deletions addons/block_code/serialization/block_script_serialization.gd
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ const SCENE_PER_TYPE = {
@export var generated_script: String
@export var version: int

var block_code_node: BlockCode

var _available_blocks: Array[BlockDefinition]
var _categories: Array[BlockCategory]

Expand Down Expand Up @@ -81,22 +83,26 @@ func instantiate_block_by_name(block_name: String) -> Block:

func get_block_definition(block_name: String) -> BlockDefinition:
var split := block_name.split(":", true, 1)
var block_definition: BlockDefinition

if len(split) > 1:
return _get_parameter_block_definition(split[0], split[1])

var block_definition = _get_base_block_definition(block_name)
block_definition = _get_base_block_definition(block_name)
if block_definition != null:
return block_definition

if block_definition == null:
# FIXME: This is a workaround for old-style output block references.
# These were generated ahead of time using a block name that has
# a "_" before the parameter name. Now, these parameter blocks
# are generated on demand for any block name containing a ":".
# Please remove this fallback when it is no longer necessary.
split = block_name.rsplit("_", true, 1)
return _get_parameter_block_definition(split[0], split[1])
block_definition = _get_obj_property_block_definition(block_name)
if block_definition != null:
return block_definition

return block_definition
# FIXME: This is a workaround for old-style output block references.
# These were generated ahead of time using a block name that has
# a "_" before the parameter name. Now, these parameter blocks
# are generated on demand for any block name containing a ":".
# Please remove this fallback when it is no longer necessary.
split = block_name.rsplit("_", true, 1)
return _get_parameter_block_definition(split[0], split[1])


func _get_base_block_definition(block_name: String) -> BlockDefinition:
Expand Down Expand Up @@ -133,6 +139,49 @@ func _get_parameter_block_definition(block_name: String, parameter_name: String)
return block_definition


func _get_obj_property_block_definition(block_name: String) -> BlockDefinition:
var block_definition: BlockDefinition
var variable: VariableDefinition
var property_name: String
var is_getter = true

if block_name.begins_with("get_var_"):
property_name = block_name.get_slice("get_var_", 1)
elif block_name.begins_with("set_var_"):
property_name = block_name.get_slice("set_var_", 1)
is_getter = false
else:
return null

# Getter block needs the property's variant type information by visiting the
# block_code_node's parent node because the type is not saved as a key of
# the resource in the scene file
var property_info := _get_parent_node_property_info(property_name)
if not property_info.has("type"):
return null

if is_getter:
variable = VariableDefinition.new(property_name, property_info["type"])
block_definition = BlocksCatalog.get_property_getter_block_definition(variable)
else:
variable = VariableDefinition.new(property_name, property_info["type"])
block_definition = BlocksCatalog.get_property_setter_block_definition(variable)

return block_definition


func _get_parent_node_property_info(property_name: String) -> Dictionary:
if not block_code_node:
return {}

var properties := block_code_node.get_parent().get_property_list()
for property in properties:
if property["name"] == property_name:
return property

return {}


func _update_block_definitions():
_available_blocks.clear()
_available_blocks.append_array(_get_inherited_block_definitions())
Expand Down
44 changes: 12 additions & 32 deletions addons/block_code/ui/block_canvas/block_canvas.gd
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ extends MarginContainer

const ASTList = preload("res://addons/block_code/code_generation/ast_list.gd")
const BlockAST = preload("res://addons/block_code/code_generation/block_ast.gd")
const BlocksCatalog = preload("res://addons/block_code/code_generation/blocks_catalog.gd")
const BlockCodePlugin = preload("res://addons/block_code/block_code_plugin.gd")
const BlockDefinition = preload("res://addons/block_code/code_generation/block_definition.gd")
const BlockTreeUtil = preload("res://addons/block_code/ui/block_tree_util.gd")
const DragManager = preload("res://addons/block_code/drag_manager/drag_manager.gd")
const ScriptGenerator = preload("res://addons/block_code/code_generation/script_generator.gd")
const Types = preload("res://addons/block_code/types/types.gd")
const Util = preload("res://addons/block_code/ui/util.gd")
const VariableDefinition = preload("res://addons/block_code/code_generation/variable_definition.gd")

const EXTEND_MARGIN: float = 800
const BLOCK_AUTO_PLACE_MARGIN: Vector2 = Vector2(25, 8)
Expand Down Expand Up @@ -79,8 +81,10 @@ func _can_drop_data(at_position: Vector2, data: Variant) -> bool:
if typeof(data) != TYPE_DICTIONARY:
return false

# Allow dropping property block
# Allow dropping property block of the block code node's parent node
if data.get("type", "") == "obj_property":
if data["object"] != _context.parent_node:
return false
return true

var nodes: Array = data.get("nodes", [])
Expand Down Expand Up @@ -124,44 +128,20 @@ func _drop_node(at_position: Vector2, data: Variant) -> void:


func _drop_obj_property(at_position: Vector2, data: Variant) -> void:
var object_name = str(data["object"]).get_slice(":", 0)
var property_name = data["property"]
var property_value = data["value"]
var is_getter = !_modifier_ctrl

# Prepare a Variable block to set / get the property's value according to
# the modifier KEY_CTRL pressing.
var variable := VariableDefinition.new(property_name, typeof(property_value))
var block_definition: BlockDefinition
var property_type = typeof(property_value)
if _modifier_ctrl:
var type_string: String = Types.VARIANT_TYPE_TO_STRING[property_type]
block_definition = (
BlockDefinition
. new(
&"%s_set_%s" % [object_name, property_name],
object_name,
"Set the %s property" % property_name,
"Variables",
Types.BlockType.STATEMENT,
property_type,
"set %s to {value: %s}" % [property_name.capitalize().to_lower(), type_string],
"%s = {value}" % property_name,
{"value": property_value},
)
)

if is_getter:
block_definition = BlocksCatalog.get_property_getter_block_definition(variable)
else:
block_definition = (
BlockDefinition
. new(
&"%s_get_%s" % [object_name, property_name],
object_name,
"The %s property" % property_name,
"Variables",
Types.BlockType.VALUE,
property_type,
"%s" % property_name.capitalize().to_lower(),
"%s" % property_name,
)
)
block_definition = BlocksCatalog.get_property_setter_block_definition(variable)
block_definition.defaults = {"value": property_value}

var block = _context.block_script.instantiate_block(block_definition)
add_block(block, at_position)
Expand Down

0 comments on commit 3cfcf76

Please sign in to comment.