fix: implement varargs for ESC commands. 'custom' makes use of this #592

This commit is contained in:
Duncan Brown
2022-05-02 16:50:57 -04:00
committed by GitHub
parent ba5be04565
commit 738ce0debc
5 changed files with 53 additions and 27 deletions

View File

@@ -1,16 +1,17 @@
# `custom object node func_name [params]` # `custom object node func_name [params...]`
# #
# #
# Executes the specified Godot function. This function must be in a script # Executes the specified Godot function. This function must be in a script
# attached to a child node of a registered `ESCitem`. # attached to a child node of a registered `ESCItem`.
# #
# **Parameters** # **Parameters**
# #
# - *object*: Global ID of the target `ESCItem` # - *object*: Global ID of the target `ESCItem`
# - *node*: Name of the child node of the target `ESCItem` # - *node*: Name of the child node of the target `ESCItem`
# - *func_name*: Name of the function to be called # - *func_name*: Name of the function to be called
# - params: Any arguments to be passed to the function (array and object parameters are not supported). Multiple # - params: Any arguments to be passed to the function (array and object parameters are not supported).
# parameters can be passed by using comma-separated values inside a string # Multiple parameters can be passed by simply passing them in as additional arguments separated by
# spaces, e.g. `custom the_object the_node the_function arg1 arg2 arg3`
# #
# @ESC # @ESC
extends ESCBaseCommand extends ESCBaseCommand
@@ -22,7 +23,9 @@ func configure() -> ESCCommandArgumentDescriptor:
return ESCCommandArgumentDescriptor.new( return ESCCommandArgumentDescriptor.new(
3, 3,
[TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_ARRAY], [TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_ARRAY],
[null, null, null, []] [null, null, null, []],
[true],
true
) )

View File

@@ -42,14 +42,14 @@ func _init(command_string):
).strip_edges() ).strip_edges()
) )
for parameter in parsed_parameters.split(" "): for parameter in parsed_parameters.split(" "):
if parameter.begins_with('"') and parameter.ends_with('"'): if len(parameter) > 1 and parameter.begins_with('"') and parameter.ends_with('"'):
parameters.append( parameters.append(
parameter parameter
) )
elif ":" in parameter and '"' in parameter: elif ":" in parameter and '"' in parameter:
quote_open = true quote_open = true
parameter_values.append(parameter) parameter_values.append(parameter)
elif parameter.begins_with('"'): elif not quote_open and parameter.begins_with('"'):
quote_open = true quote_open = true
parameter_values.append(parameter) parameter_values.append(parameter)
elif parameter.ends_with('"'): elif parameter.ends_with('"'):

View File

@@ -30,24 +30,30 @@ var defaults: Array = []
# Whether to strip quotes on specific arguments # Whether to strip quotes on specific arguments
var strip_quotes: Array = [] var strip_quotes: Array = []
# Whether the final argument is a series of varargs
var has_varargs: bool = false
# Initialize the descriptor # Initialize the descriptor
func _init( func _init(
p_min_args: int = 0, p_min_args: int = 0,
p_types: Array = [], p_types: Array = [],
p_defaults: Array = [], p_defaults: Array = [],
p_strip_quotes: Array = [true] p_strip_quotes: Array = [true],
p_has_varargs: bool = false
): ):
max_args = p_types.size() max_args = p_types.size()
min_args = p_min_args min_args = p_min_args
types = p_types types = p_types
defaults = p_defaults defaults = p_defaults
strip_quotes = p_strip_quotes strip_quotes = p_strip_quotes
has_varargs = p_has_varargs
# Combine the default argument values with the given arguments # Combine the default argument values with the given arguments
func prepare_arguments(arguments: Array) -> Array: func prepare_arguments(arguments: Array) -> Array:
var complete_arguments = defaults var complete_arguments = defaults
var varargs = []
for index in range(arguments.size()): for index in range(arguments.size()):
# If we have too many arguments passed in, complete_arguments won't # If we have too many arguments passed in, complete_arguments won't
@@ -55,22 +61,32 @@ func prepare_arguments(arguments: Array) -> Array:
# to avoid duplicating validation code, just grow complete_arguments # to avoid duplicating validation code, just grow complete_arguments
# since the arguments won't be used anyway. # since the arguments won't be used anyway.
if index >= complete_arguments.size(): if index >= complete_arguments.size():
complete_arguments.append(arguments[index]) if has_varargs:
continue varargs.append(arguments[index])
else:
complete_arguments[index] = escoria.utils.get_typed_value( complete_arguments.append(arguments[index])
arguments[index], elif index == complete_arguments.size() - 1 and has_varargs:
types[index] # Varargs are a special case and need to be gathered and added at
) # the end as an array, untyped and unchecked. They should also only
var strip = strip_quotes[0] # appear at the very end of a command's argument list.
if strip_quotes.size() == complete_arguments.size(): varargs.append(arguments[index])
strip = strip_quotes[index] else:
complete_arguments[index] = escoria.utils.get_typed_value(
if strip and typeof(complete_arguments[index]) == TYPE_STRING: arguments[index],
complete_arguments[index] = complete_arguments[index].replace( types[index]
'"',
''
) )
var strip = strip_quotes[0]
if strip_quotes.size() == complete_arguments.size():
strip = strip_quotes[index]
if strip and typeof(complete_arguments[index]) == TYPE_STRING:
complete_arguments[index] = complete_arguments[index].replace(
'"',
''
)
if has_varargs:
complete_arguments[complete_arguments.size() - 1] = varargs
return complete_arguments return complete_arguments
@@ -91,7 +107,7 @@ func validate(command: String, arguments: Array) -> bool:
] ]
) )
if arguments.size() > self.max_args: if arguments.size() > self.max_args and not has_varargs:
escoria.logger.report_errors( escoria.logger.report_errors(
"ESCCommandArgumentDescriptor:validate()", "ESCCommandArgumentDescriptor:validate()",
[ [
@@ -104,6 +120,11 @@ func validate(command: String, arguments: Array) -> bool:
if arguments[index] == null: if arguments[index] == null:
# No type checking for null values # No type checking for null values
continue continue
if has_varargs and index == arguments.size() - 1:
# If we have varargs at the end, do not validate them.
continue
var correct = false var correct = false
var types_index = index var types_index = index
if types_index > types.size(): if types_index > types.size():

View File

@@ -75,7 +75,8 @@ func set_scene(p_scene: Node) -> void:
# #
# - p_scene: The scene currently being initialized by set_scene. # - p_scene: The scene currently being initialized by set_scene.
func finish_current_scene_init(p_scene: Node) -> void: func finish_current_scene_init(p_scene: Node) -> void:
move_child(p_scene, 0) if is_a_parent_of(p_scene):
move_child(p_scene, 0)
current_scene = p_scene current_scene = p_scene

View File

@@ -2,6 +2,7 @@
:setup :setup
custom r3_r_exit door_enabler enable_door a b c 1 2 345
# If the room hasn't been visited previously, open the bridge and break the button # If the room hasn't been visited previously, open the bridge and break the button
> [!room3_visited] > [!room3_visited]
@@ -21,7 +22,7 @@
# We use a custom function to enable the collision polygon on the door # We use a custom function to enable the collision polygon on the door
# to enable it to work as a door once the bridge is closed. # to enable it to work as a door once the bridge is closed.
# You'll find the script in room3/Hotspots/r_door/door_enabler # You'll find the script in room3/Hotspots/r_door/door_enabler
custom r3_r_exit door_enabler enable_door custom r3_r_exit door_enabler enable_door
> [eq ESC_LAST_SCENE room2] > [eq ESC_LAST_SCENE room2]
teleport player r3_l_exit teleport player r3_l_exit
@@ -67,4 +68,4 @@
# This is for when you close the bridge then go back to room 2 # This is for when you close the bridge then go back to room 2
# Set the bridge closed # Set the bridge closed
set_global r3_bridge_closed true set_global r3_bridge_closed true