2017-03-05 14:47:28 +00:00
/*************************************************************************/
/* visual_script.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 12:16:55 +00:00
/* https://godotengine.org */
2017-03-05 14:47:28 +00:00
/*************************************************************************/
2021-01-01 19:13:46 +00:00
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
2017-03-05 14:47:28 +00:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
2018-01-04 23:50:27 +00:00
2016-08-02 22:11:05 +00:00
# include "visual_script.h"
2017-03-05 14:47:28 +00:00
2020-11-07 22:33:38 +00:00
# include "core/config/project_settings.h"
2019-04-10 05:07:40 +00:00
# include "core/core_string_names.h"
2018-09-11 16:13:45 +00:00
# include "core/os/os.h"
2017-03-05 15:44:50 +00:00
# include "scene/main/node.h"
# include "visual_script_nodes.h"
2016-08-06 22:00:54 +00:00
2020-06-17 15:39:25 +00:00
// Used by editor, this is not really saved.
2016-08-06 22:00:54 +00:00
void VisualScriptNode : : set_breakpoint ( bool p_breakpoint ) {
2017-03-05 15:44:50 +00:00
breakpoint = p_breakpoint ;
2016-08-06 22:00:54 +00:00
}
bool VisualScriptNode : : is_breakpoint ( ) const {
return breakpoint ;
}
2018-09-29 19:50:04 +00:00
void VisualScriptNode : : ports_changed_notify ( ) {
2016-08-04 01:06:39 +00:00
emit_signal ( " ports_changed " ) ;
}
2017-03-05 15:44:50 +00:00
void VisualScriptNode : : set_default_input_value ( int p_port , const Variant & p_value ) {
ERR_FAIL_INDEX ( p_port , default_input_values . size ( ) ) ;
2016-08-04 01:06:39 +00:00
2017-03-05 15:44:50 +00:00
default_input_values [ p_port ] = p_value ;
2016-08-31 15:49:45 +00:00
# ifdef TOOLS_ENABLED
2020-06-17 15:39:25 +00:00
if ( script_used . is_valid ( ) ) {
script_used - > set_edited ( true ) ;
2016-08-31 15:49:45 +00:00
}
# endif
2016-08-04 01:06:39 +00:00
}
Variant VisualScriptNode : : get_default_input_value ( int p_port ) const {
2017-03-05 15:44:50 +00:00
ERR_FAIL_INDEX_V ( p_port , default_input_values . size ( ) , Variant ( ) ) ;
2016-08-04 01:06:39 +00:00
return default_input_values [ p_port ] ;
}
void VisualScriptNode : : _set_default_input_values ( Array p_values ) {
2017-03-05 15:44:50 +00:00
default_input_values = p_values ;
2016-08-04 01:06:39 +00:00
}
2016-08-25 20:45:20 +00:00
void VisualScriptNode : : validate_input_default_values ( ) {
2019-03-04 18:41:50 +00:00
default_input_values . resize ( MAX ( default_input_values . size ( ) , get_input_value_port_count ( ) ) ) ; //let it grow as big as possible, we don't want to lose values on resize
2016-08-04 01:06:39 +00:00
2020-06-17 15:39:25 +00:00
// Actually validate on save.
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < get_input_value_port_count ( ) ; i + + ) {
2016-08-04 01:06:39 +00:00
Variant : : Type expected = get_input_value_port_info ( i ) . type ;
2017-03-05 15:44:50 +00:00
if ( expected = = Variant : : NIL | | expected = = default_input_values [ i ] . get_type ( ) ) {
2016-08-25 20:45:20 +00:00
continue ;
2017-03-05 15:44:50 +00:00
} else {
2020-06-17 15:39:25 +00:00
// Not the same, reconvert.
2020-02-19 19:27:19 +00:00
Callable : : CallError ce ;
2016-08-25 20:45:20 +00:00
Variant existing = default_input_values [ i ] ;
2017-03-05 15:44:50 +00:00
const Variant * existingp = & existing ;
2020-11-09 03:19:09 +00:00
Variant : : construct ( expected , default_input_values [ i ] , & existingp , 1 , ce ) ;
2020-02-19 19:27:19 +00:00
if ( ce . error ! = Callable : : CallError : : CALL_OK ) {
2016-08-25 20:45:20 +00:00
//could not convert? force..
2020-11-09 03:19:09 +00:00
Variant : : construct ( expected , default_input_values [ i ] , nullptr , 0 , ce ) ;
2016-08-04 01:06:39 +00:00
}
}
}
2016-08-25 20:45:20 +00:00
}
Array VisualScriptNode : : _get_default_input_values ( ) const {
2020-06-17 15:39:25 +00:00
// Validate on save, since on load there is little info about this.
2019-03-04 18:41:50 +00:00
Array values = default_input_values ;
values . resize ( get_input_value_port_count ( ) ) ;
2016-08-25 20:45:20 +00:00
2019-03-04 18:41:50 +00:00
return values ;
2016-08-04 01:06:39 +00:00
}
2018-04-29 23:28:31 +00:00
String VisualScriptNode : : get_text ( ) const {
return " " ;
}
2016-08-02 22:11:05 +00:00
void VisualScriptNode : : _bind_methods ( ) {
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_visual_script " ) , & VisualScriptNode : : get_visual_script ) ;
ClassDB : : bind_method ( D_METHOD ( " set_default_input_value " , " port_idx " , " value " ) , & VisualScriptNode : : set_default_input_value ) ;
ClassDB : : bind_method ( D_METHOD ( " get_default_input_value " , " port_idx " ) , & VisualScriptNode : : get_default_input_value ) ;
2017-09-28 10:07:20 +00:00
ClassDB : : bind_method ( D_METHOD ( " ports_changed_notify " ) , & VisualScriptNode : : ports_changed_notify ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " _set_default_input_values " , " values " ) , & VisualScriptNode : : _set_default_input_values ) ;
ClassDB : : bind_method ( D_METHOD ( " _get_default_input_values " ) , & VisualScriptNode : : _get_default_input_values ) ;
2016-08-04 01:06:39 +00:00
2018-01-11 22:35:12 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : ARRAY , " _default_input_values " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL ) , " _set_default_input_values " , " _get_default_input_values " ) ;
2016-08-02 22:11:05 +00:00
ADD_SIGNAL ( MethodInfo ( " ports_changed " ) ) ;
}
2017-03-05 15:44:50 +00:00
VisualScriptNode : : TypeGuess VisualScriptNode : : guess_output_type ( TypeGuess * p_inputs , int p_output ) const {
2020-06-17 15:39:25 +00:00
ERR_FAIL_COND_V ( get_output_value_port_count ( ) < = p_output , TypeGuess ( ) ) ;
2016-08-31 02:44:14 +00:00
PropertyInfo pinfo = get_output_value_port_info ( p_output ) ;
TypeGuess tg ;
2017-03-05 15:44:50 +00:00
tg . type = pinfo . type ;
if ( pinfo . hint = = PROPERTY_HINT_RESOURCE_TYPE ) {
2017-07-01 00:30:17 +00:00
tg . gdclass = pinfo . hint_string ;
2016-08-31 02:44:14 +00:00
}
return tg ;
}
2016-08-02 22:11:05 +00:00
Ref < VisualScript > VisualScriptNode : : get_visual_script ( ) const {
2020-06-17 15:39:25 +00:00
return script_used ;
2016-08-02 22:11:05 +00:00
}
2016-08-06 22:00:54 +00:00
VisualScriptNode : : VisualScriptNode ( ) {
}
2016-08-02 22:11:05 +00:00
////////////////
/////////////////////
2016-08-06 01:46:45 +00:00
VisualScriptNodeInstance : : VisualScriptNodeInstance ( ) {
}
2016-08-02 22:11:05 +00:00
VisualScriptNodeInstance : : ~ VisualScriptNodeInstance ( ) {
2016-08-06 01:46:45 +00:00
if ( sequence_outputs ) {
2016-08-31 02:44:14 +00:00
memdelete_arr ( sequence_outputs ) ;
2016-08-06 01:46:45 +00:00
}
if ( input_ports ) {
2016-08-31 02:44:14 +00:00
memdelete_arr ( input_ports ) ;
2016-08-06 01:46:45 +00:00
}
if ( output_ports ) {
2016-08-31 02:44:14 +00:00
memdelete_arr ( output_ports ) ;
2016-08-06 01:46:45 +00:00
}
2016-08-02 22:11:05 +00:00
}
2020-06-17 15:39:25 +00:00
void VisualScript : : add_function ( const StringName & p_name , int p_func_node_id ) {
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( instances . size ( ) ) ;
2016-08-02 22:11:05 +00:00
ERR_FAIL_COND ( ! String ( p_name ) . is_valid_identifier ( ) ) ;
ERR_FAIL_COND ( functions . has ( p_name ) ) ;
2020-06-17 15:39:25 +00:00
ERR_FAIL_COND ( variables . has ( p_name ) ) ;
ERR_FAIL_COND ( custom_signals . has ( p_name ) ) ;
2016-08-02 22:11:05 +00:00
2017-03-05 15:44:50 +00:00
functions [ p_name ] = Function ( ) ;
2020-06-17 15:39:25 +00:00
functions [ p_name ] . func_id = p_func_node_id ;
2016-08-02 22:11:05 +00:00
}
2017-03-05 15:44:50 +00:00
bool VisualScript : : has_function ( const StringName & p_name ) const {
2016-08-02 22:11:05 +00:00
return functions . has ( p_name ) ;
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
void VisualScript : : remove_function ( const StringName & p_name ) {
ERR_FAIL_COND ( instances . size ( ) ) ;
2016-08-02 22:11:05 +00:00
ERR_FAIL_COND ( ! functions . has ( p_name ) ) ;
2020-06-17 15:39:25 +00:00
// Let the editor handle the node removal.
2016-08-02 22:11:05 +00:00
functions . erase ( p_name ) ;
}
2017-03-05 15:44:50 +00:00
void VisualScript : : rename_function ( const StringName & p_name , const StringName & p_new_name ) {
ERR_FAIL_COND ( instances . size ( ) ) ;
2016-08-02 22:11:05 +00:00
ERR_FAIL_COND ( ! functions . has ( p_name ) ) ;
2020-05-14 14:41:43 +00:00
if ( p_new_name = = p_name ) {
2016-08-02 22:11:05 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2016-08-02 22:11:05 +00:00
ERR_FAIL_COND ( ! String ( p_new_name ) . is_valid_identifier ( ) ) ;
ERR_FAIL_COND ( functions . has ( p_new_name ) ) ;
ERR_FAIL_COND ( variables . has ( p_new_name ) ) ;
ERR_FAIL_COND ( custom_signals . has ( p_new_name ) ) ;
2017-03-05 15:44:50 +00:00
functions [ p_new_name ] = functions [ p_name ] ;
2016-08-02 22:11:05 +00:00
functions . erase ( p_name ) ;
}
2020-06-17 15:39:25 +00:00
void VisualScript : : set_scroll ( const Vector2 & p_scroll ) {
scroll = p_scroll ;
2016-08-06 22:00:54 +00:00
}
2020-06-17 15:39:25 +00:00
Vector2 VisualScript : : get_scroll ( ) const {
return scroll ;
2016-08-06 22:00:54 +00:00
}
2016-08-02 22:11:05 +00:00
void VisualScript : : get_function_list ( List < StringName > * r_functions ) const {
2020-06-17 15:39:25 +00:00
functions . get_key_list ( r_functions ) ;
// r_functions->sort_custom<StringName::AlphCompare>(); // Don't force sorting.
2016-08-02 22:11:05 +00:00
}
2017-03-05 15:44:50 +00:00
int VisualScript : : get_function_node_id ( const StringName & p_name ) const {
ERR_FAIL_COND_V ( ! functions . has ( p_name ) , - 1 ) ;
2016-08-02 22:11:05 +00:00
2020-06-17 15:39:25 +00:00
return functions [ p_name ] . func_id ;
2016-08-02 22:11:05 +00:00
}
void VisualScript : : _node_ports_changed ( int p_id ) {
2020-06-17 15:39:25 +00:00
Ref < VisualScriptNode > vsn = nodes [ p_id ] . node ;
2016-08-02 22:11:05 +00:00
2019-05-02 12:29:07 +00:00
vsn - > validate_input_default_values ( ) ;
2016-08-25 20:45:20 +00:00
2020-06-17 15:39:25 +00:00
// Must revalidate all the functions.
2016-08-02 22:11:05 +00:00
{
List < SequenceConnection > to_remove ;
2020-06-17 15:39:25 +00:00
for ( Set < SequenceConnection > : : Element * E = sequence_connections . front ( ) ; E ; E = E - > next ( ) ) {
2017-03-05 15:44:50 +00:00
if ( E - > get ( ) . from_node = = p_id & & E - > get ( ) . from_output > = vsn - > get_output_sequence_port_count ( ) ) {
2016-08-02 22:11:05 +00:00
to_remove . push_back ( E - > get ( ) ) ;
}
2017-03-05 15:44:50 +00:00
if ( E - > get ( ) . to_node = = p_id & & ! vsn - > has_input_sequence_port ( ) ) {
2016-08-02 22:11:05 +00:00
to_remove . push_back ( E - > get ( ) ) ;
}
}
2017-03-05 15:44:50 +00:00
while ( to_remove . size ( ) ) {
2020-06-17 15:39:25 +00:00
sequence_connections . erase ( to_remove . front ( ) - > get ( ) ) ;
2016-08-02 22:11:05 +00:00
to_remove . pop_front ( ) ;
}
}
{
List < DataConnection > to_remove ;
2020-06-17 15:39:25 +00:00
for ( Set < DataConnection > : : Element * E = data_connections . front ( ) ; E ; E = E - > next ( ) ) {
2017-03-05 15:44:50 +00:00
if ( E - > get ( ) . from_node = = p_id & & E - > get ( ) . from_port > = vsn - > get_output_value_port_count ( ) ) {
2016-08-02 22:11:05 +00:00
to_remove . push_back ( E - > get ( ) ) ;
}
2017-03-05 15:44:50 +00:00
if ( E - > get ( ) . to_node = = p_id & & E - > get ( ) . to_port > = vsn - > get_input_value_port_count ( ) ) {
2016-08-02 22:11:05 +00:00
to_remove . push_back ( E - > get ( ) ) ;
}
}
2017-03-05 15:44:50 +00:00
while ( to_remove . size ( ) ) {
2020-06-17 15:39:25 +00:00
data_connections . erase ( to_remove . front ( ) - > get ( ) ) ;
2016-08-02 22:11:05 +00:00
to_remove . pop_front ( ) ;
}
}
2016-08-15 07:54:02 +00:00
# ifdef TOOLS_ENABLED
2020-06-17 15:39:25 +00:00
set_edited ( true ) ; // Something changed, let's set as edited.
emit_signal ( " node_ports_changed " , p_id ) ;
2016-08-15 07:54:02 +00:00
# endif
2016-08-02 22:11:05 +00:00
}
2020-06-17 15:39:25 +00:00
void VisualScript : : add_node ( int p_id , const Ref < VisualScriptNode > & p_node , const Point2 & p_pos ) {
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( instances . size ( ) ) ;
2020-06-17 15:39:25 +00:00
ERR_FAIL_COND ( nodes . has ( p_id ) ) ; // ID can exist only one in script.
2016-08-02 22:11:05 +00:00
2020-06-17 15:39:25 +00:00
NodeData nd ;
2017-03-05 15:44:50 +00:00
nd . node = p_node ;
nd . pos = p_pos ;
2016-08-02 22:11:05 +00:00
Ref < VisualScriptNode > vsn = p_node ;
2020-02-21 17:28:45 +00:00
vsn - > connect ( " ports_changed " , callable_mp ( this , & VisualScript : : _node_ports_changed ) , varray ( p_id ) ) ;
2020-06-17 15:39:25 +00:00
vsn - > script_used = Ref < VisualScript > ( this ) ;
vsn - > validate_input_default_values ( ) ; // Validate when fully loaded.
2016-08-02 22:11:05 +00:00
2020-06-17 15:39:25 +00:00
nodes [ p_id ] = nd ;
2016-08-02 22:11:05 +00:00
}
2020-06-17 15:39:25 +00:00
void VisualScript : : remove_node ( int p_id ) {
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( instances . size ( ) ) ;
2020-06-17 15:39:25 +00:00
ERR_FAIL_COND ( ! nodes . has ( p_id ) ) ;
2016-08-02 22:11:05 +00:00
{
List < SequenceConnection > to_remove ;
2020-06-17 15:39:25 +00:00
for ( Set < SequenceConnection > : : Element * E = sequence_connections . front ( ) ; E ; E = E - > next ( ) ) {
2017-03-05 15:44:50 +00:00
if ( E - > get ( ) . from_node = = p_id | | E - > get ( ) . to_node = = p_id ) {
2016-08-02 22:11:05 +00:00
to_remove . push_back ( E - > get ( ) ) ;
}
}
2017-03-05 15:44:50 +00:00
while ( to_remove . size ( ) ) {
2020-06-17 15:39:25 +00:00
sequence_connections . erase ( to_remove . front ( ) - > get ( ) ) ;
2016-08-02 22:11:05 +00:00
to_remove . pop_front ( ) ;
}
}
{
List < DataConnection > to_remove ;
2020-06-17 15:39:25 +00:00
for ( Set < DataConnection > : : Element * E = data_connections . front ( ) ; E ; E = E - > next ( ) ) {
2017-03-05 15:44:50 +00:00
if ( E - > get ( ) . from_node = = p_id | | E - > get ( ) . to_node = = p_id ) {
2016-08-02 22:11:05 +00:00
to_remove . push_back ( E - > get ( ) ) ;
}
}
2017-03-05 15:44:50 +00:00
while ( to_remove . size ( ) ) {
2020-06-17 15:39:25 +00:00
data_connections . erase ( to_remove . front ( ) - > get ( ) ) ;
2016-08-02 22:11:05 +00:00
to_remove . pop_front ( ) ;
}
}
2020-06-17 15:39:25 +00:00
nodes [ p_id ] . node - > disconnect ( " ports_changed " , callable_mp ( this , & VisualScript : : _node_ports_changed ) ) ;
nodes [ p_id ] . node - > script_used . unref ( ) ;
2016-08-02 22:11:05 +00:00
2020-06-17 15:39:25 +00:00
nodes . erase ( p_id ) ;
2016-08-02 22:11:05 +00:00
}
2020-06-17 15:39:25 +00:00
bool VisualScript : : has_node ( int p_id ) const {
return nodes . has ( p_id ) ;
2016-08-06 22:00:54 +00:00
}
2016-08-02 22:11:05 +00:00
2020-06-17 15:39:25 +00:00
Ref < VisualScriptNode > VisualScript : : get_node ( int p_id ) const {
ERR_FAIL_COND_V ( ! nodes . has ( p_id ) , Ref < VisualScriptNode > ( ) ) ;
2016-08-02 22:11:05 +00:00
2020-06-17 15:39:25 +00:00
return nodes [ p_id ] . node ;
2016-08-02 22:11:05 +00:00
}
2020-06-17 15:39:25 +00:00
void VisualScript : : set_node_position ( int p_id , const Point2 & p_pos ) {
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( instances . size ( ) ) ;
2020-06-17 15:39:25 +00:00
ERR_FAIL_COND ( ! nodes . has ( p_id ) ) ;
nodes [ p_id ] . pos = p_pos ;
2016-08-02 22:11:05 +00:00
}
2020-06-17 15:39:25 +00:00
Point2 VisualScript : : get_node_position ( int p_id ) const {
ERR_FAIL_COND_V ( ! nodes . has ( p_id ) , Point2 ( ) ) ;
return nodes [ p_id ] . pos ;
2016-08-02 22:11:05 +00:00
}
2020-06-17 15:39:25 +00:00
void VisualScript : : get_node_list ( List < int > * r_nodes ) const {
nodes . get_key_list ( r_nodes ) ;
2016-08-02 22:11:05 +00:00
}
2020-06-17 15:39:25 +00:00
void VisualScript : : sequence_connect ( int p_from_node , int p_from_output , int p_to_node ) {
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( instances . size ( ) ) ;
2016-08-02 22:11:05 +00:00
SequenceConnection sc ;
2017-03-05 15:44:50 +00:00
sc . from_node = p_from_node ;
sc . from_output = p_from_output ;
sc . to_node = p_to_node ;
2020-06-17 15:39:25 +00:00
ERR_FAIL_COND ( sequence_connections . has ( sc ) ) ;
2016-08-02 22:11:05 +00:00
2020-06-17 15:39:25 +00:00
sequence_connections . insert ( sc ) ;
2016-08-02 22:11:05 +00:00
}
2020-06-17 15:39:25 +00:00
void VisualScript : : sequence_disconnect ( int p_from_node , int p_from_output , int p_to_node ) {
2016-08-02 22:11:05 +00:00
SequenceConnection sc ;
2017-03-05 15:44:50 +00:00
sc . from_node = p_from_node ;
sc . from_output = p_from_output ;
sc . to_node = p_to_node ;
2020-06-17 15:39:25 +00:00
ERR_FAIL_COND ( ! sequence_connections . has ( sc ) ) ;
2016-08-02 22:11:05 +00:00
2020-06-17 15:39:25 +00:00
sequence_connections . erase ( sc ) ;
2016-08-02 22:11:05 +00:00
}
2020-06-17 15:39:25 +00:00
bool VisualScript : : has_sequence_connection ( int p_from_node , int p_from_output , int p_to_node ) const {
2016-08-02 22:11:05 +00:00
SequenceConnection sc ;
2017-03-05 15:44:50 +00:00
sc . from_node = p_from_node ;
sc . from_output = p_from_output ;
sc . to_node = p_to_node ;
2016-08-02 22:11:05 +00:00
2020-06-17 15:39:25 +00:00
return sequence_connections . has ( sc ) ;
2016-08-02 22:11:05 +00:00
}
2020-06-17 15:39:25 +00:00
void VisualScript : : get_sequence_connection_list ( List < SequenceConnection > * r_connection ) const {
for ( const Set < SequenceConnection > : : Element * E = sequence_connections . front ( ) ; E ; E = E - > next ( ) ) {
2016-08-02 22:11:05 +00:00
r_connection - > push_back ( E - > get ( ) ) ;
}
}
2020-06-17 15:39:25 +00:00
void VisualScript : : data_connect ( int p_from_node , int p_from_port , int p_to_node , int p_to_port ) {
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( instances . size ( ) ) ;
2016-08-02 22:11:05 +00:00
DataConnection dc ;
2017-03-05 15:44:50 +00:00
dc . from_node = p_from_node ;
dc . from_port = p_from_port ;
dc . to_node = p_to_node ;
dc . to_port = p_to_port ;
2016-08-02 22:11:05 +00:00
2020-06-17 15:39:25 +00:00
ERR_FAIL_COND ( data_connections . has ( dc ) ) ;
2016-08-02 22:11:05 +00:00
2020-06-17 15:39:25 +00:00
data_connections . insert ( dc ) ;
2016-08-02 22:11:05 +00:00
}
2020-06-17 15:39:25 +00:00
void VisualScript : : data_disconnect ( int p_from_node , int p_from_port , int p_to_node , int p_to_port ) {
2016-08-02 22:11:05 +00:00
DataConnection dc ;
2017-03-05 15:44:50 +00:00
dc . from_node = p_from_node ;
dc . from_port = p_from_port ;
dc . to_node = p_to_node ;
dc . to_port = p_to_port ;
2016-08-02 22:11:05 +00:00
2020-06-17 15:39:25 +00:00
ERR_FAIL_COND ( ! data_connections . has ( dc ) ) ;
2016-08-02 22:11:05 +00:00
2020-06-17 15:39:25 +00:00
data_connections . erase ( dc ) ;
2016-08-02 22:11:05 +00:00
}
2020-06-17 15:39:25 +00:00
bool VisualScript : : has_data_connection ( int p_from_node , int p_from_port , int p_to_node , int p_to_port ) const {
2016-08-02 22:11:05 +00:00
DataConnection dc ;
2017-03-05 15:44:50 +00:00
dc . from_node = p_from_node ;
dc . from_port = p_from_port ;
dc . to_node = p_to_node ;
dc . to_port = p_to_port ;
2016-08-02 22:11:05 +00:00
2020-06-17 15:39:25 +00:00
return data_connections . has ( dc ) ;
2016-08-02 22:11:05 +00:00
}
2020-06-17 15:39:25 +00:00
bool VisualScript : : is_input_value_port_connected ( int p_node , int p_port ) const {
for ( const Set < DataConnection > : : Element * E = data_connections . front ( ) ; E ; E = E - > next ( ) ) {
2020-05-14 14:41:43 +00:00
if ( E - > get ( ) . to_node = = p_node & & E - > get ( ) . to_port = = p_port ) {
2016-08-04 01:06:39 +00:00
return true ;
2020-05-14 14:41:43 +00:00
}
2016-08-04 01:06:39 +00:00
}
return false ;
}
2020-06-17 15:39:25 +00:00
bool VisualScript : : get_input_value_port_connection_source ( int p_node , int p_port , int * r_node , int * r_port ) const {
for ( const Set < DataConnection > : : Element * E = data_connections . front ( ) ; E ; E = E - > next ( ) ) {
2017-03-05 15:44:50 +00:00
if ( E - > get ( ) . to_node = = p_node & & E - > get ( ) . to_port = = p_port ) {
* r_node = E - > get ( ) . from_node ;
* r_port = E - > get ( ) . from_port ;
2016-09-03 17:58:23 +00:00
return true ;
}
}
return false ;
}
2020-06-17 15:39:25 +00:00
void VisualScript : : get_data_connection_list ( List < DataConnection > * r_connection ) const {
for ( const Set < DataConnection > : : Element * E = data_connections . front ( ) ; E ; E = E - > next ( ) ) {
2016-08-02 22:11:05 +00:00
r_connection - > push_back ( E - > get ( ) ) ;
}
}
2019-07-26 20:00:23 +00:00
void VisualScript : : set_tool_enabled ( bool p_enabled ) {
is_tool_script = p_enabled ;
}
2017-03-05 15:44:50 +00:00
void VisualScript : : add_variable ( const StringName & p_name , const Variant & p_default_value , bool p_export ) {
ERR_FAIL_COND ( instances . size ( ) ) ;
2016-08-02 22:11:05 +00:00
ERR_FAIL_COND ( ! String ( p_name ) . is_valid_identifier ( ) ) ;
ERR_FAIL_COND ( variables . has ( p_name ) ) ;
Variable v ;
2017-03-05 15:44:50 +00:00
v . default_value = p_default_value ;
v . info . type = p_default_value . get_type ( ) ;
v . info . name = p_name ;
v . info . hint = PROPERTY_HINT_NONE ;
v . _export = p_export ;
2016-08-02 22:11:05 +00:00
2017-03-05 15:44:50 +00:00
variables [ p_name ] = v ;
2016-08-06 01:46:45 +00:00
# ifdef TOOLS_ENABLED
_update_placeholders ( ) ;
# endif
2016-08-02 22:11:05 +00:00
}
2017-03-05 15:44:50 +00:00
bool VisualScript : : has_variable ( const StringName & p_name ) const {
2016-08-02 22:11:05 +00:00
return variables . has ( p_name ) ;
}
2017-03-05 15:44:50 +00:00
void VisualScript : : remove_variable ( const StringName & p_name ) {
2016-08-02 22:11:05 +00:00
ERR_FAIL_COND ( ! variables . has ( p_name ) ) ;
variables . erase ( p_name ) ;
2016-08-06 01:46:45 +00:00
# ifdef TOOLS_ENABLED
_update_placeholders ( ) ;
# endif
2016-08-02 22:11:05 +00:00
}
2017-03-05 15:44:50 +00:00
void VisualScript : : set_variable_default_value ( const StringName & p_name , const Variant & p_value ) {
2016-08-02 22:11:05 +00:00
ERR_FAIL_COND ( ! variables . has ( p_name ) ) ;
2017-03-05 15:44:50 +00:00
variables [ p_name ] . default_value = p_value ;
2016-08-02 22:11:05 +00:00
2016-08-06 01:46:45 +00:00
# ifdef TOOLS_ENABLED
_update_placeholders ( ) ;
# endif
2016-08-02 22:11:05 +00:00
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
Variant VisualScript : : get_variable_default_value ( const StringName & p_name ) const {
ERR_FAIL_COND_V ( ! variables . has ( p_name ) , Variant ( ) ) ;
2016-08-02 22:11:05 +00:00
return variables [ p_name ] . default_value ;
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
void VisualScript : : set_variable_info ( const StringName & p_name , const PropertyInfo & p_info ) {
ERR_FAIL_COND ( instances . size ( ) ) ;
2016-08-02 22:11:05 +00:00
ERR_FAIL_COND ( ! variables . has ( p_name ) ) ;
2017-03-05 15:44:50 +00:00
variables [ p_name ] . info = p_info ;
variables [ p_name ] . info . name = p_name ;
2016-08-02 22:11:05 +00:00
2016-08-06 01:46:45 +00:00
# ifdef TOOLS_ENABLED
_update_placeholders ( ) ;
# endif
2016-08-02 22:11:05 +00:00
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
PropertyInfo VisualScript : : get_variable_info ( const StringName & p_name ) const {
ERR_FAIL_COND_V ( ! variables . has ( p_name ) , PropertyInfo ( ) ) ;
2016-08-02 22:11:05 +00:00
return variables [ p_name ] . info ;
}
2017-03-05 15:44:50 +00:00
void VisualScript : : set_variable_export ( const StringName & p_name , bool p_export ) {
2016-08-31 02:44:14 +00:00
ERR_FAIL_COND ( ! variables . has ( p_name ) ) ;
2017-03-05 15:44:50 +00:00
variables [ p_name ] . _export = p_export ;
2017-07-01 00:30:17 +00:00
# ifdef TOOLS_ENABLED
_update_placeholders ( ) ;
# endif
2016-08-31 02:44:14 +00:00
}
2017-03-05 15:44:50 +00:00
bool VisualScript : : get_variable_export ( const StringName & p_name ) const {
ERR_FAIL_COND_V ( ! variables . has ( p_name ) , false ) ;
2016-08-31 02:44:14 +00:00
return variables [ p_name ] . _export ;
}
2017-03-05 15:44:50 +00:00
void VisualScript : : _set_variable_info ( const StringName & p_name , const Dictionary & p_info ) {
2016-08-02 22:11:05 +00:00
PropertyInfo pinfo ;
2020-05-14 14:41:43 +00:00
if ( p_info . has ( " type " ) ) {
2017-03-05 15:44:50 +00:00
pinfo . type = Variant : : Type ( int ( p_info [ " type " ] ) ) ;
2020-05-14 14:41:43 +00:00
}
if ( p_info . has ( " name " ) ) {
2017-03-05 15:44:50 +00:00
pinfo . name = p_info [ " name " ] ;
2020-05-14 14:41:43 +00:00
}
if ( p_info . has ( " hint " ) ) {
2017-03-05 15:44:50 +00:00
pinfo . hint = PropertyHint ( int ( p_info [ " hint " ] ) ) ;
2020-05-14 14:41:43 +00:00
}
if ( p_info . has ( " hint_string " ) ) {
2017-03-05 15:44:50 +00:00
pinfo . hint_string = p_info [ " hint_string " ] ;
2020-05-14 14:41:43 +00:00
}
if ( p_info . has ( " usage " ) ) {
2017-03-05 15:44:50 +00:00
pinfo . usage = p_info [ " usage " ] ;
2020-05-14 14:41:43 +00:00
}
2016-08-02 22:11:05 +00:00
2017-03-05 15:44:50 +00:00
set_variable_info ( p_name , pinfo ) ;
2016-08-02 22:11:05 +00:00
}
2017-03-05 15:44:50 +00:00
Dictionary VisualScript : : _get_variable_info ( const StringName & p_name ) const {
PropertyInfo pinfo = get_variable_info ( p_name ) ;
2016-08-02 22:11:05 +00:00
Dictionary d ;
2017-03-05 15:44:50 +00:00
d [ " type " ] = pinfo . type ;
d [ " name " ] = pinfo . name ;
d [ " hint " ] = pinfo . hint ;
d [ " hint_string " ] = pinfo . hint_string ;
d [ " usage " ] = pinfo . usage ;
2016-08-02 22:11:05 +00:00
return d ;
}
2017-03-05 15:44:50 +00:00
void VisualScript : : get_variable_list ( List < StringName > * r_variables ) const {
2020-06-17 15:39:25 +00:00
variables . get_key_list ( r_variables ) ;
// r_variables->sort_custom<StringName::AlphCompare>(); // Don't force it.
2016-08-02 22:11:05 +00:00
}
2017-03-05 15:44:50 +00:00
void VisualScript : : set_instance_base_type ( const StringName & p_type ) {
ERR_FAIL_COND ( instances . size ( ) ) ;
base_type = p_type ;
2016-08-02 22:11:05 +00:00
}
2017-03-05 15:44:50 +00:00
void VisualScript : : rename_variable ( const StringName & p_name , const StringName & p_new_name ) {
ERR_FAIL_COND ( instances . size ( ) ) ;
2016-08-02 22:11:05 +00:00
ERR_FAIL_COND ( ! variables . has ( p_name ) ) ;
2020-05-14 14:41:43 +00:00
if ( p_new_name = = p_name ) {
2016-08-02 22:11:05 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2016-08-02 22:11:05 +00:00
ERR_FAIL_COND ( ! String ( p_new_name ) . is_valid_identifier ( ) ) ;
ERR_FAIL_COND ( functions . has ( p_new_name ) ) ;
ERR_FAIL_COND ( variables . has ( p_new_name ) ) ;
ERR_FAIL_COND ( custom_signals . has ( p_new_name ) ) ;
2017-03-05 15:44:50 +00:00
variables [ p_new_name ] = variables [ p_name ] ;
2016-08-02 22:11:05 +00:00
variables . erase ( p_name ) ;
2020-06-17 15:39:25 +00:00
List < int > ids ;
get_node_list ( & ids ) ;
for ( List < int > : : Element * E = ids . front ( ) ; E ; E = E - > next ( ) ) {
Ref < VisualScriptVariableGet > nodeget = get_node ( E - > get ( ) ) ;
if ( nodeget . is_valid ( ) ) {
if ( nodeget - > get_variable ( ) = = p_name ) {
nodeget - > set_variable ( p_new_name ) ;
}
} else {
Ref < VisualScriptVariableSet > nodeset = get_node ( E - > get ( ) ) ;
if ( nodeset . is_valid ( ) ) {
if ( nodeset - > get_variable ( ) = = p_name ) {
nodeset - > set_variable ( p_new_name ) ;
2020-04-03 09:35:26 +00:00
}
}
}
}
2016-08-02 22:11:05 +00:00
}
2017-03-05 15:44:50 +00:00
void VisualScript : : add_custom_signal ( const StringName & p_name ) {
ERR_FAIL_COND ( instances . size ( ) ) ;
2016-08-02 22:11:05 +00:00
ERR_FAIL_COND ( ! String ( p_name ) . is_valid_identifier ( ) ) ;
ERR_FAIL_COND ( custom_signals . has ( p_name ) ) ;
2017-03-05 15:44:50 +00:00
custom_signals [ p_name ] = Vector < Argument > ( ) ;
2016-08-02 22:11:05 +00:00
}
2017-03-05 15:44:50 +00:00
bool VisualScript : : has_custom_signal ( const StringName & p_name ) const {
2016-08-02 22:11:05 +00:00
return custom_signals . has ( p_name ) ;
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
void VisualScript : : custom_signal_add_argument ( const StringName & p_func , Variant : : Type p_type , const String & p_name , int p_index ) {
ERR_FAIL_COND ( instances . size ( ) ) ;
2016-08-02 22:11:05 +00:00
ERR_FAIL_COND ( ! custom_signals . has ( p_func ) ) ;
Argument arg ;
2017-03-05 15:44:50 +00:00
arg . type = p_type ;
arg . name = p_name ;
2020-05-14 14:41:43 +00:00
if ( p_index < 0 ) {
2016-08-02 22:11:05 +00:00
custom_signals [ p_func ] . push_back ( arg ) ;
2020-05-14 14:41:43 +00:00
} else {
2017-03-05 15:44:50 +00:00
custom_signals [ p_func ] . insert ( 0 , arg ) ;
2020-05-14 14:41:43 +00:00
}
2016-08-02 22:11:05 +00:00
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
void VisualScript : : custom_signal_set_argument_type ( const StringName & p_func , int p_argidx , Variant : : Type p_type ) {
ERR_FAIL_COND ( instances . size ( ) ) ;
2016-08-02 22:11:05 +00:00
ERR_FAIL_COND ( ! custom_signals . has ( p_func ) ) ;
2017-03-05 15:44:50 +00:00
ERR_FAIL_INDEX ( p_argidx , custom_signals [ p_func ] . size ( ) ) ;
2018-07-25 01:11:03 +00:00
custom_signals [ p_func ] . write [ p_argidx ] . type = p_type ;
2016-08-02 22:11:05 +00:00
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
Variant : : Type VisualScript : : custom_signal_get_argument_type ( const StringName & p_func , int p_argidx ) const {
ERR_FAIL_COND_V ( ! custom_signals . has ( p_func ) , Variant : : NIL ) ;
ERR_FAIL_INDEX_V ( p_argidx , custom_signals [ p_func ] . size ( ) , Variant : : NIL ) ;
2016-08-02 22:11:05 +00:00
return custom_signals [ p_func ] [ p_argidx ] . type ;
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
void VisualScript : : custom_signal_set_argument_name ( const StringName & p_func , int p_argidx , const String & p_name ) {
ERR_FAIL_COND ( instances . size ( ) ) ;
2016-08-02 22:11:05 +00:00
ERR_FAIL_COND ( ! custom_signals . has ( p_func ) ) ;
2017-03-05 15:44:50 +00:00
ERR_FAIL_INDEX ( p_argidx , custom_signals [ p_func ] . size ( ) ) ;
2018-07-25 01:11:03 +00:00
custom_signals [ p_func ] . write [ p_argidx ] . name = p_name ;
2016-08-02 22:11:05 +00:00
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
String VisualScript : : custom_signal_get_argument_name ( const StringName & p_func , int p_argidx ) const {
ERR_FAIL_COND_V ( ! custom_signals . has ( p_func ) , String ( ) ) ;
ERR_FAIL_INDEX_V ( p_argidx , custom_signals [ p_func ] . size ( ) , String ( ) ) ;
2016-08-02 22:11:05 +00:00
return custom_signals [ p_func ] [ p_argidx ] . name ;
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
void VisualScript : : custom_signal_remove_argument ( const StringName & p_func , int p_argidx ) {
ERR_FAIL_COND ( instances . size ( ) ) ;
2016-08-02 22:11:05 +00:00
ERR_FAIL_COND ( ! custom_signals . has ( p_func ) ) ;
2017-03-05 15:44:50 +00:00
ERR_FAIL_INDEX ( p_argidx , custom_signals [ p_func ] . size ( ) ) ;
2016-08-02 22:11:05 +00:00
custom_signals [ p_func ] . remove ( p_argidx ) ;
}
2017-03-05 15:44:50 +00:00
int VisualScript : : custom_signal_get_argument_count ( const StringName & p_func ) const {
ERR_FAIL_COND_V ( ! custom_signals . has ( p_func ) , 0 ) ;
2016-08-02 22:11:05 +00:00
return custom_signals [ p_func ] . size ( ) ;
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
void VisualScript : : custom_signal_swap_argument ( const StringName & p_func , int p_argidx , int p_with_argidx ) {
ERR_FAIL_COND ( instances . size ( ) ) ;
2016-08-02 22:11:05 +00:00
ERR_FAIL_COND ( ! custom_signals . has ( p_func ) ) ;
2017-03-05 15:44:50 +00:00
ERR_FAIL_INDEX ( p_argidx , custom_signals [ p_func ] . size ( ) ) ;
ERR_FAIL_INDEX ( p_with_argidx , custom_signals [ p_func ] . size ( ) ) ;
2016-08-02 22:11:05 +00:00
2018-07-25 01:11:03 +00:00
SWAP ( custom_signals [ p_func ] . write [ p_argidx ] , custom_signals [ p_func ] . write [ p_with_argidx ] ) ;
2016-08-02 22:11:05 +00:00
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
void VisualScript : : remove_custom_signal ( const StringName & p_name ) {
ERR_FAIL_COND ( instances . size ( ) ) ;
2016-08-02 22:11:05 +00:00
ERR_FAIL_COND ( ! custom_signals . has ( p_name ) ) ;
custom_signals . erase ( p_name ) ;
}
2017-03-05 15:44:50 +00:00
void VisualScript : : rename_custom_signal ( const StringName & p_name , const StringName & p_new_name ) {
ERR_FAIL_COND ( instances . size ( ) ) ;
2016-08-02 22:11:05 +00:00
ERR_FAIL_COND ( ! custom_signals . has ( p_name ) ) ;
2020-05-14 14:41:43 +00:00
if ( p_new_name = = p_name ) {
2016-08-02 22:11:05 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2016-08-02 22:11:05 +00:00
ERR_FAIL_COND ( ! String ( p_new_name ) . is_valid_identifier ( ) ) ;
ERR_FAIL_COND ( functions . has ( p_new_name ) ) ;
ERR_FAIL_COND ( variables . has ( p_new_name ) ) ;
ERR_FAIL_COND ( custom_signals . has ( p_new_name ) ) ;
2017-03-05 15:44:50 +00:00
custom_signals [ p_new_name ] = custom_signals [ p_name ] ;
2016-08-02 22:11:05 +00:00
custom_signals . erase ( p_name ) ;
}
void VisualScript : : get_custom_signal_list ( List < StringName > * r_custom_signals ) const {
2020-03-17 06:33:00 +00:00
for ( const Map < StringName , Vector < Argument > > : : Element * E = custom_signals . front ( ) ; E ; E = E - > next ( ) ) {
2016-08-02 22:11:05 +00:00
r_custom_signals - > push_back ( E - > key ( ) ) ;
}
r_custom_signals - > sort_custom < StringName : : AlphCompare > ( ) ;
}
int VisualScript : : get_available_id ( ) const {
2020-06-17 15:39:25 +00:00
// This is infinitely increasing,
// so one might want to implement a better solution,
// if the there is a case for huge number of nodes to be added to visual script.
List < int > nds ;
nodes . get_key_list ( & nds ) ;
int max = - 1 ;
for ( const List < int > : : Element * E = nds . front ( ) ; E ; E = E - > next ( ) ) {
if ( E - > get ( ) > max ) {
max = E - > get ( ) ;
2020-05-14 14:41:43 +00:00
}
2016-08-02 22:11:05 +00:00
}
2020-06-17 15:39:25 +00:00
return ( max + 1 ) ;
2016-08-02 22:11:05 +00:00
}
/////////////////////////////////
bool VisualScript : : can_instance ( ) const {
2020-06-17 15:39:25 +00:00
return true ; // ScriptServer::is_scripting_enabled();
2016-08-02 22:11:05 +00:00
}
StringName VisualScript : : get_instance_base_type ( ) const {
return base_type ;
}
2016-08-25 20:45:20 +00:00
Ref < Script > VisualScript : : get_base_script ( ) const {
2020-06-17 15:39:25 +00:00
return Ref < Script > ( ) ; // No inheritance in visual script.
2016-08-25 20:45:20 +00:00
}
2016-08-06 01:46:45 +00:00
# ifdef TOOLS_ENABLED
void VisualScript : : _placeholder_erased ( PlaceHolderScriptInstance * p_placeholder ) {
placeholders . erase ( p_placeholder ) ;
}
void VisualScript : : _update_placeholders ( ) {
2020-05-14 14:41:43 +00:00
if ( placeholders . size ( ) = = 0 ) {
2020-06-17 15:39:25 +00:00
return ; // No bother if no placeholders.
2020-05-14 14:41:43 +00:00
}
2016-08-06 01:46:45 +00:00
List < PropertyInfo > pinfo ;
2017-03-05 15:44:50 +00:00
Map < StringName , Variant > values ;
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
List < StringName > keys ;
variables . get_key_list ( & keys ) ;
for ( List < StringName > : : Element * E = keys . front ( ) ; E ; E = E - > next ( ) ) {
if ( ! variables [ E - > get ( ) ] . _export ) {
2016-08-31 20:58:51 +00:00
continue ;
2020-05-14 14:41:43 +00:00
}
2016-08-31 20:58:51 +00:00
2020-06-17 15:39:25 +00:00
PropertyInfo p = variables [ E - > get ( ) ] . info ;
p . name = String ( E - > get ( ) ) ;
2016-08-06 01:46:45 +00:00
pinfo . push_back ( p ) ;
2020-06-17 15:39:25 +00:00
values [ p . name ] = variables [ E - > get ( ) ] . default_value ;
2016-08-06 01:46:45 +00:00
}
2017-03-05 15:44:50 +00:00
for ( Set < PlaceHolderScriptInstance * > : : Element * E = placeholders . front ( ) ; E ; E = E - > next ( ) ) {
E - > get ( ) - > update ( pinfo , values ) ;
2016-08-06 01:46:45 +00:00
}
}
# endif
2017-03-05 15:44:50 +00:00
ScriptInstance * VisualScript : : instance_create ( Object * p_this ) {
2016-08-06 01:46:45 +00:00
# ifdef TOOLS_ENABLED
2019-07-26 20:00:23 +00:00
if ( ! ScriptServer : : is_scripting_enabled ( ) & & ! is_tool_script ) {
2017-03-05 15:44:50 +00:00
PlaceHolderScriptInstance * sins = memnew ( PlaceHolderScriptInstance ( VisualScriptLanguage : : singleton , Ref < Script > ( ( Script * ) this ) , p_this ) ) ;
2016-08-06 01:46:45 +00:00
placeholders . insert ( sins ) ;
List < PropertyInfo > pinfo ;
2017-03-05 15:44:50 +00:00
Map < StringName , Variant > values ;
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
List < StringName > keys ;
variables . get_key_list ( & keys ) ;
for ( const List < StringName > : : Element * E = keys . front ( ) ; E ; E = E - > next ( ) ) {
2021-04-05 12:09:59 +00:00
if ( ! variables [ E - > get ( ) ] . _export ) {
2016-08-31 20:58:51 +00:00
continue ;
2021-04-05 12:09:59 +00:00
}
2016-08-31 20:58:51 +00:00
2020-06-17 15:39:25 +00:00
PropertyInfo p = variables [ E - > get ( ) ] . info ;
p . name = String ( E - > get ( ) ) ;
2016-08-06 01:46:45 +00:00
pinfo . push_back ( p ) ;
2020-06-17 15:39:25 +00:00
values [ p . name ] = variables [ E - > get ( ) ] . default_value ;
2016-08-06 01:46:45 +00:00
}
2017-03-05 15:44:50 +00:00
sins - > update ( pinfo , values ) ;
2016-08-06 01:46:45 +00:00
return sins ;
}
# endif
2017-03-05 15:44:50 +00:00
VisualScriptInstance * instance = memnew ( VisualScriptInstance ) ;
instance - > create ( Ref < VisualScript > ( this ) , p_this ) ;
2016-08-06 01:46:45 +00:00
2020-02-26 10:28:13 +00:00
{
MutexLock lock ( VisualScriptLanguage : : singleton - > lock ) ;
2016-08-06 01:46:45 +00:00
2020-02-26 10:28:13 +00:00
instances [ p_this ] = instance ;
}
2016-08-06 01:46:45 +00:00
return instance ;
2016-08-02 22:11:05 +00:00
}
bool VisualScript : : instance_has ( const Object * p_this ) const {
2017-03-05 15:44:50 +00:00
return instances . has ( ( Object * ) p_this ) ;
2016-08-02 22:11:05 +00:00
}
bool VisualScript : : has_source_code ( ) const {
return false ;
}
String VisualScript : : get_source_code ( ) const {
return String ( ) ;
}
2017-03-05 15:44:50 +00:00
void VisualScript : : set_source_code ( const String & p_code ) {
2016-08-02 22:11:05 +00:00
}
Error VisualScript : : reload ( bool p_keep_state ) {
return OK ;
}
bool VisualScript : : is_tool ( ) const {
2019-07-26 20:00:23 +00:00
return is_tool_script ;
2016-08-02 22:11:05 +00:00
}
2018-11-27 22:55:37 +00:00
bool VisualScript : : is_valid ( ) const {
2020-06-17 15:39:25 +00:00
return true ; // Always valid.
2018-11-27 22:55:37 +00:00
}
2016-08-02 22:11:05 +00:00
ScriptLanguage * VisualScript : : get_language ( ) const {
return VisualScriptLanguage : : singleton ;
}
2017-03-05 15:44:50 +00:00
bool VisualScript : : has_script_signal ( const StringName & p_signal ) const {
2016-08-06 01:46:45 +00:00
return custom_signals . has ( p_signal ) ;
2016-08-02 22:11:05 +00:00
}
void VisualScript : : get_script_signal_list ( List < MethodInfo > * r_signals ) const {
2020-03-17 06:33:00 +00:00
for ( const Map < StringName , Vector < Argument > > : : Element * E = custom_signals . front ( ) ; E ; E = E - > next ( ) ) {
2016-08-06 01:46:45 +00:00
MethodInfo mi ;
2017-03-05 15:44:50 +00:00
mi . name = E - > key ( ) ;
for ( int i = 0 ; i < E - > get ( ) . size ( ) ; i + + ) {
2016-08-06 01:46:45 +00:00
PropertyInfo arg ;
2017-03-05 15:44:50 +00:00
arg . type = E - > get ( ) [ i ] . type ;
arg . name = E - > get ( ) [ i ] . name ;
2016-08-06 01:46:45 +00:00
mi . arguments . push_back ( arg ) ;
}
r_signals - > push_back ( mi ) ;
}
2016-08-02 22:11:05 +00:00
}
2017-03-05 15:44:50 +00:00
bool VisualScript : : get_property_default_value ( const StringName & p_property , Variant & r_value ) const {
2020-05-14 14:41:43 +00:00
if ( ! variables . has ( p_property ) ) {
2016-08-06 01:46:45 +00:00
return false ;
2020-05-14 14:41:43 +00:00
}
2016-08-06 01:46:45 +00:00
2017-03-05 15:44:50 +00:00
r_value = variables [ p_property ] . default_value ;
2016-08-06 01:46:45 +00:00
return true ;
2016-08-02 22:11:05 +00:00
}
2020-05-14 12:29:06 +00:00
2016-08-19 19:48:08 +00:00
void VisualScript : : get_script_method_list ( List < MethodInfo > * p_list ) const {
2020-06-17 15:39:25 +00:00
List < StringName > funcs ;
functions . get_key_list ( & funcs ) ;
for ( List < StringName > : : Element * E = funcs . front ( ) ; E ; E = E - > next ( ) ) {
2016-08-02 22:11:05 +00:00
MethodInfo mi ;
2020-06-17 15:39:25 +00:00
mi . name = E - > get ( ) ;
if ( functions [ E - > get ( ) ] . func_id > = 0 ) {
Ref < VisualScriptFunction > func = nodes [ functions [ E - > get ( ) ] . func_id ] . node ;
2016-08-02 22:11:05 +00:00
if ( func . is_valid ( ) ) {
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < func - > get_argument_count ( ) ; i + + ) {
2016-08-02 22:11:05 +00:00
PropertyInfo arg ;
2017-03-05 15:44:50 +00:00
arg . name = func - > get_argument_name ( i ) ;
arg . type = func - > get_argument_type ( i ) ;
2016-08-02 22:11:05 +00:00
mi . arguments . push_back ( arg ) ;
}
2019-09-13 19:14:12 +00:00
p_list - > push_back ( mi ) ;
2016-08-02 22:11:05 +00:00
}
}
}
}
2017-03-05 15:44:50 +00:00
bool VisualScript : : has_method ( const StringName & p_method ) const {
2016-08-08 04:21:22 +00:00
return functions . has ( p_method ) ;
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
MethodInfo VisualScript : : get_method_info ( const StringName & p_method ) const {
2020-06-17 15:39:25 +00:00
const Function funct = functions [ p_method ] ;
if ( funct . func_id = = - 1 ) {
2016-08-08 04:21:22 +00:00
return MethodInfo ( ) ;
2020-05-14 14:41:43 +00:00
}
2016-08-08 04:21:22 +00:00
MethodInfo mi ;
2020-06-17 15:39:25 +00:00
mi . name = p_method ;
if ( funct . func_id > = 0 ) {
Ref < VisualScriptFunction > func = nodes [ funct . func_id ] . node ;
2016-08-08 04:21:22 +00:00
if ( func . is_valid ( ) ) {
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < func - > get_argument_count ( ) ; i + + ) {
2016-08-08 04:21:22 +00:00
PropertyInfo arg ;
2017-03-05 15:44:50 +00:00
arg . name = func - > get_argument_name ( i ) ;
arg . type = func - > get_argument_type ( i ) ;
2016-08-08 04:21:22 +00:00
mi . arguments . push_back ( arg ) ;
}
2017-08-08 16:14:36 +00:00
if ( ! func - > is_sequenced ( ) ) {
mi . flags | = METHOD_FLAG_CONST ;
}
2016-08-08 04:21:22 +00:00
}
}
return mi ;
}
2016-08-23 22:29:07 +00:00
void VisualScript : : get_script_property_list ( List < PropertyInfo > * p_list ) const {
List < StringName > vars ;
get_variable_list ( & vars ) ;
2017-03-05 15:44:50 +00:00
for ( List < StringName > : : Element * E = vars . front ( ) ; E ; E = E - > next ( ) ) {
2017-07-01 00:30:17 +00:00
//if (!variables[E->get()]._export)
// continue;
PropertyInfo pi = variables [ E - > get ( ) ] . info ;
pi . usage | = PROPERTY_USAGE_SCRIPT_VARIABLE ;
p_list - > push_back ( pi ) ;
2016-08-23 22:29:07 +00:00
}
}
2017-04-15 17:48:10 +00:00
int VisualScript : : get_member_line ( const StringName & p_member ) const {
2020-06-17 15:39:25 +00:00
return functions [ p_member ] . func_id ; // will be -1 if not found
2017-04-15 17:48:10 +00:00
}
2016-09-05 21:50:30 +00:00
# ifdef TOOLS_ENABLED
2016-08-31 20:58:51 +00:00
bool VisualScript : : are_subnodes_edited ( ) const {
2020-06-17 15:39:25 +00:00
List < int > keys ;
nodes . get_key_list ( & keys ) ;
for ( const List < int > : : Element * F = keys . front ( ) ; F ; F = F - > next ( ) ) {
if ( nodes [ F - > get ( ) ] . node - > is_edited ( ) ) {
return true ;
2016-08-31 20:58:51 +00:00
}
}
return false ;
}
2016-09-05 21:50:30 +00:00
# endif
2016-08-08 04:21:22 +00:00
2021-05-26 12:07:57 +00:00
const Vector < MultiplayerAPI : : RPCConfig > VisualScript : : get_rpc_methods ( ) const {
2020-02-12 10:51:50 +00:00
return rpc_functions ;
}
2017-03-05 15:44:50 +00:00
void VisualScript : : _set_data ( const Dictionary & p_data ) {
2016-08-02 22:11:05 +00:00
Dictionary d = p_data ;
2020-05-14 14:41:43 +00:00
if ( d . has ( " base_type " ) ) {
2017-03-05 15:44:50 +00:00
base_type = d [ " base_type " ] ;
2020-05-14 14:41:43 +00:00
}
2016-08-02 22:11:05 +00:00
variables . clear ( ) ;
2017-03-05 15:44:50 +00:00
Array vars = d [ " variables " ] ;
for ( int i = 0 ; i < vars . size ( ) ; i + + ) {
Dictionary v = vars [ i ] ;
2016-08-06 01:46:45 +00:00
StringName name = v [ " name " ] ;
add_variable ( name ) ;
2017-03-05 15:44:50 +00:00
_set_variable_info ( name , v ) ;
set_variable_default_value ( name , v [ " default_value " ] ) ;
set_variable_export ( name , v . has ( " export " ) & & bool ( v [ " export " ] ) ) ;
2016-08-02 22:11:05 +00:00
}
custom_signals . clear ( ) ;
2017-03-05 15:44:50 +00:00
Array sigs = d [ " signals " ] ;
for ( int i = 0 ; i < sigs . size ( ) ; i + + ) {
Dictionary cs = sigs [ i ] ;
2016-08-02 22:11:05 +00:00
add_custom_signal ( cs [ " name " ] ) ;
2017-03-05 15:44:50 +00:00
Array args = cs [ " arguments " ] ;
for ( int j = 0 ; j < args . size ( ) ; j + = 2 ) {
custom_signal_add_argument ( cs [ " name " ] , Variant : : Type ( int ( args [ j + 1 ] ) ) , args [ j ] ) ;
2016-08-02 22:11:05 +00:00
}
}
2017-03-05 15:44:50 +00:00
Array funcs = d [ " functions " ] ;
2016-08-02 22:11:05 +00:00
functions . clear ( ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < funcs . size ( ) ; i + + ) {
Dictionary func = funcs [ i ] ;
2020-06-17 15:39:25 +00:00
add_function ( func [ " name " ] , func [ " function_id " ] ) ;
}
{
Array nodes = d [ " nodes " ] ;
for ( int i = 0 ; i < nodes . size ( ) ; i + = 3 ) {
add_node ( nodes [ i ] , nodes [ i + 2 ] , nodes [ i + 1 ] ) ;
2019-09-13 19:14:12 +00:00
}
2016-08-02 22:11:05 +00:00
2020-06-17 15:39:25 +00:00
Array sequence_connections = d [ " sequence_connections " ] ;
2017-03-05 15:44:50 +00:00
for ( int j = 0 ; j < sequence_connections . size ( ) ; j + = 3 ) {
2020-06-17 15:39:25 +00:00
sequence_connect ( sequence_connections [ j + 0 ] , sequence_connections [ j + 1 ] , sequence_connections [ j + 2 ] ) ;
2016-08-02 22:11:05 +00:00
}
2020-06-17 15:39:25 +00:00
Array data_connections = d [ " data_connections " ] ;
2017-03-05 15:44:50 +00:00
for ( int j = 0 ; j < data_connections . size ( ) ; j + = 4 ) {
2020-06-17 15:39:25 +00:00
data_connect ( data_connections [ j + 0 ] , data_connections [ j + 1 ] , data_connections [ j + 2 ] , data_connections [ j + 3 ] ) ;
2016-08-02 22:11:05 +00:00
}
}
2020-06-17 15:39:25 +00:00
is_tool_script = d [ " is_tool_script " ] ;
scroll = d [ " scroll " ] ;
2019-07-26 20:00:23 +00:00
2020-06-17 15:39:25 +00:00
// Takes all the rpc methods.
2020-02-12 10:51:50 +00:00
rpc_functions . clear ( ) ;
2020-06-17 15:39:25 +00:00
List < StringName > fns ;
functions . get_key_list ( & fns ) ;
for ( const List < StringName > : : Element * E = fns . front ( ) ; E ; E = E - > next ( ) ) {
if ( functions [ E - > get ( ) ] . func_id > = 0 & & nodes . has ( functions [ E - > get ( ) ] . func_id ) ) {
Ref < VisualScriptFunction > vsf = nodes [ functions [ E - > get ( ) ] . func_id ] . node ;
2020-02-12 10:51:50 +00:00
if ( vsf . is_valid ( ) ) {
if ( vsf - > get_rpc_mode ( ) ! = MultiplayerAPI : : RPC_MODE_DISABLED ) {
2021-05-26 12:07:57 +00:00
MultiplayerAPI : : RPCConfig nd ;
2020-06-17 15:39:25 +00:00
nd . name = E - > get ( ) ;
2021-05-26 12:07:57 +00:00
nd . rpc_mode = vsf - > get_rpc_mode ( ) ;
nd . transfer_mode = NetworkedMultiplayerPeer : : TRANSFER_MODE_RELIABLE ; // TODO
2020-02-12 10:51:50 +00:00
if ( rpc_functions . find ( nd ) = = - 1 ) {
rpc_functions . push_back ( nd ) ;
}
}
}
}
}
// Sort so we are 100% that they are always the same.
2021-05-26 12:07:57 +00:00
rpc_functions . sort_custom < MultiplayerAPI : : SortRPCConfig > ( ) ;
2016-08-02 22:11:05 +00:00
}
2017-03-05 15:44:50 +00:00
Dictionary VisualScript : : _get_data ( ) const {
2016-08-02 22:11:05 +00:00
Dictionary d ;
2017-03-05 15:44:50 +00:00
d [ " base_type " ] = base_type ;
2020-06-17 15:39:25 +00:00
2016-08-02 22:11:05 +00:00
Array vars ;
2020-06-17 15:39:25 +00:00
List < StringName > var_names ;
variables . get_key_list ( & var_names ) ;
for ( const List < StringName > : : Element * E = var_names . front ( ) ; E ; E = E - > next ( ) ) {
Dictionary var = _get_variable_info ( E - > get ( ) ) ;
var [ " name " ] = E - > get ( ) ; // Make sure it's the right one.
var [ " default_value " ] = variables [ E - > get ( ) ] . default_value ;
var [ " export " ] = variables [ E - > get ( ) ] . _export ;
2016-08-02 22:11:05 +00:00
vars . push_back ( var ) ;
}
2017-03-05 15:44:50 +00:00
d [ " variables " ] = vars ;
2016-08-02 22:11:05 +00:00
Array sigs ;
2020-03-17 06:33:00 +00:00
for ( const Map < StringName , Vector < Argument > > : : Element * E = custom_signals . front ( ) ; E ; E = E - > next ( ) ) {
2016-08-02 22:11:05 +00:00
Dictionary cs ;
2017-03-05 15:44:50 +00:00
cs [ " name " ] = E - > key ( ) ;
2016-08-02 22:11:05 +00:00
Array args ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < E - > get ( ) . size ( ) ; i + + ) {
2016-08-02 22:11:05 +00:00
args . push_back ( E - > get ( ) [ i ] . name ) ;
args . push_back ( E - > get ( ) [ i ] . type ) ;
}
2017-03-05 15:44:50 +00:00
cs [ " arguments " ] = args ;
2016-08-02 22:11:05 +00:00
sigs . push_back ( cs ) ;
}
2017-03-05 15:44:50 +00:00
d [ " signals " ] = sigs ;
2016-08-02 22:11:05 +00:00
Array funcs ;
2020-06-17 15:39:25 +00:00
List < StringName > func_names ;
functions . get_key_list ( & func_names ) ;
for ( const List < StringName > : : Element * E = func_names . front ( ) ; E ; E = E - > next ( ) ) {
2016-08-02 22:11:05 +00:00
Dictionary func ;
2020-06-17 15:39:25 +00:00
func [ " name " ] = E - > get ( ) ;
func [ " function_id " ] = functions [ E - > get ( ) ] . func_id ;
funcs . push_back ( func ) ;
}
d [ " functions " ] = funcs ;
2016-08-02 22:11:05 +00:00
2020-06-17 15:39:25 +00:00
Array nds ;
List < int > node_ids ;
nodes . get_key_list ( & node_ids ) ;
for ( const List < int > : : Element * F = node_ids . front ( ) ; F ; F = F - > next ( ) ) {
nds . push_back ( F - > get ( ) ) ;
nds . push_back ( nodes [ F - > get ( ) ] . pos ) ;
nds . push_back ( nodes [ F - > get ( ) ] . node ) ;
}
d [ " nodes " ] = nds ;
2016-08-02 22:11:05 +00:00
2020-06-17 15:39:25 +00:00
Array seqconns ;
for ( const Set < SequenceConnection > : : Element * F = sequence_connections . front ( ) ; F ; F = F - > next ( ) ) {
seqconns . push_back ( F - > get ( ) . from_node ) ;
seqconns . push_back ( F - > get ( ) . from_output ) ;
seqconns . push_back ( F - > get ( ) . to_node ) ;
}
d [ " sequence_connections " ] = seqconns ;
2016-08-02 22:11:05 +00:00
2020-06-17 15:39:25 +00:00
Array dataconns ;
for ( const Set < DataConnection > : : Element * F = data_connections . front ( ) ; F ; F = F - > next ( ) ) {
dataconns . push_back ( F - > get ( ) . from_node ) ;
dataconns . push_back ( F - > get ( ) . from_port ) ;
dataconns . push_back ( F - > get ( ) . to_node ) ;
dataconns . push_back ( F - > get ( ) . to_port ) ;
2016-08-02 22:11:05 +00:00
}
2020-06-17 15:39:25 +00:00
d [ " data_connections " ] = dataconns ;
2016-08-02 22:11:05 +00:00
2019-07-26 20:00:23 +00:00
d [ " is_tool_script " ] = is_tool_script ;
2020-06-17 15:39:25 +00:00
d [ " scroll " ] = scroll ;
2019-07-26 20:00:23 +00:00
2016-08-02 22:11:05 +00:00
return d ;
}
void VisualScript : : _bind_methods ( ) {
2021-01-04 16:12:55 +00:00
ClassDB : : bind_method ( D_METHOD ( " add_function " , " name " , " func_node_id " ) , & VisualScript : : add_function ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " has_function " , " name " ) , & VisualScript : : has_function ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_function " , " name " ) , & VisualScript : : remove_function ) ;
ClassDB : : bind_method ( D_METHOD ( " rename_function " , " name " , " new_name " ) , & VisualScript : : rename_function ) ;
2020-06-17 15:39:25 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_scroll " , " ofs " ) , & VisualScript : : set_scroll ) ;
ClassDB : : bind_method ( D_METHOD ( " get_scroll " ) , & VisualScript : : get_scroll ) ;
2017-03-05 15:44:50 +00:00
2020-06-17 15:39:25 +00:00
ClassDB : : bind_method ( D_METHOD ( " add_node " , " id " , " node " , " position " ) , & VisualScript : : add_node , DEFVAL ( Point2 ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_node " , " id " ) , & VisualScript : : remove_node ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_function_node_id " , " name " ) , & VisualScript : : get_function_node_id ) ;
2020-06-17 15:39:25 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_node " , " id " ) , & VisualScript : : get_node ) ;
ClassDB : : bind_method ( D_METHOD ( " has_node " , " id " ) , & VisualScript : : has_node ) ;
ClassDB : : bind_method ( D_METHOD ( " set_node_position " , " id " , " position " ) , & VisualScript : : set_node_position ) ;
ClassDB : : bind_method ( D_METHOD ( " get_node_position " , " id " ) , & VisualScript : : get_node_position ) ;
2017-03-05 15:44:50 +00:00
2020-06-17 15:39:25 +00:00
ClassDB : : bind_method ( D_METHOD ( " sequence_connect " , " from_node " , " from_output " , " to_node " ) , & VisualScript : : sequence_connect ) ;
ClassDB : : bind_method ( D_METHOD ( " sequence_disconnect " , " from_node " , " from_output " , " to_node " ) , & VisualScript : : sequence_disconnect ) ;
ClassDB : : bind_method ( D_METHOD ( " has_sequence_connection " , " from_node " , " from_output " , " to_node " ) , & VisualScript : : has_sequence_connection ) ;
2017-03-05 15:44:50 +00:00
2020-06-17 15:39:25 +00:00
ClassDB : : bind_method ( D_METHOD ( " data_connect " , " from_node " , " from_port " , " to_node " , " to_port " ) , & VisualScript : : data_connect ) ;
ClassDB : : bind_method ( D_METHOD ( " data_disconnect " , " from_node " , " from_port " , " to_node " , " to_port " ) , & VisualScript : : data_disconnect ) ;
ClassDB : : bind_method ( D_METHOD ( " has_data_connection " , " from_node " , " from_port " , " to_node " , " to_port " ) , & VisualScript : : has_data_connection ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " add_variable " , " name " , " default_value " , " export " ) , & VisualScript : : add_variable , DEFVAL ( Variant ( ) ) , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " has_variable " , " name " ) , & VisualScript : : has_variable ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_variable " , " name " ) , & VisualScript : : remove_variable ) ;
ClassDB : : bind_method ( D_METHOD ( " set_variable_default_value " , " name " , " value " ) , & VisualScript : : set_variable_default_value ) ;
ClassDB : : bind_method ( D_METHOD ( " get_variable_default_value " , " name " ) , & VisualScript : : get_variable_default_value ) ;
ClassDB : : bind_method ( D_METHOD ( " set_variable_info " , " name " , " value " ) , & VisualScript : : _set_variable_info ) ;
ClassDB : : bind_method ( D_METHOD ( " get_variable_info " , " name " ) , & VisualScript : : _get_variable_info ) ;
ClassDB : : bind_method ( D_METHOD ( " set_variable_export " , " name " , " enable " ) , & VisualScript : : set_variable_export ) ;
ClassDB : : bind_method ( D_METHOD ( " get_variable_export " , " name " ) , & VisualScript : : get_variable_export ) ;
ClassDB : : bind_method ( D_METHOD ( " rename_variable " , " name " , " new_name " ) , & VisualScript : : rename_variable ) ;
ClassDB : : bind_method ( D_METHOD ( " add_custom_signal " , " name " ) , & VisualScript : : add_custom_signal ) ;
ClassDB : : bind_method ( D_METHOD ( " has_custom_signal " , " name " ) , & VisualScript : : has_custom_signal ) ;
ClassDB : : bind_method ( D_METHOD ( " custom_signal_add_argument " , " name " , " type " , " argname " , " index " ) , & VisualScript : : custom_signal_add_argument , DEFVAL ( - 1 ) ) ;
ClassDB : : bind_method ( D_METHOD ( " custom_signal_set_argument_type " , " name " , " argidx " , " type " ) , & VisualScript : : custom_signal_set_argument_type ) ;
ClassDB : : bind_method ( D_METHOD ( " custom_signal_get_argument_type " , " name " , " argidx " ) , & VisualScript : : custom_signal_get_argument_type ) ;
ClassDB : : bind_method ( D_METHOD ( " custom_signal_set_argument_name " , " name " , " argidx " , " argname " ) , & VisualScript : : custom_signal_set_argument_name ) ;
ClassDB : : bind_method ( D_METHOD ( " custom_signal_get_argument_name " , " name " , " argidx " ) , & VisualScript : : custom_signal_get_argument_name ) ;
2017-07-22 10:11:42 +00:00
ClassDB : : bind_method ( D_METHOD ( " custom_signal_remove_argument " , " name " , " argidx " ) , & VisualScript : : custom_signal_remove_argument ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " custom_signal_get_argument_count " , " name " ) , & VisualScript : : custom_signal_get_argument_count ) ;
ClassDB : : bind_method ( D_METHOD ( " custom_signal_swap_argument " , " name " , " argidx " , " withidx " ) , & VisualScript : : custom_signal_swap_argument ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_custom_signal " , " name " ) , & VisualScript : : remove_custom_signal ) ;
ClassDB : : bind_method ( D_METHOD ( " rename_custom_signal " , " name " , " new_name " ) , & VisualScript : : rename_custom_signal ) ;
2017-02-13 11:47:24 +00:00
//ClassDB::bind_method(D_METHOD("set_variable_info","name","info"),&VScript::set_variable_info);
//ClassDB::bind_method(D_METHOD("get_variable_info","name"),&VScript::set_variable_info);
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_instance_base_type " , " type " ) , & VisualScript : : set_instance_base_type ) ;
2017-02-13 11:47:24 +00:00
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " _set_data " , " data " ) , & VisualScript : : _set_data ) ;
ClassDB : : bind_method ( D_METHOD ( " _get_data " ) , & VisualScript : : _get_data ) ;
2016-08-02 22:11:05 +00:00
2018-01-11 22:35:12 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : DICTIONARY , " data " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL ) , " _set_data " , " _get_data " ) ;
2016-08-02 22:11:05 +00:00
2020-06-17 15:39:25 +00:00
ADD_SIGNAL ( MethodInfo ( " node_ports_changed " , PropertyInfo ( Variant : : INT , " id " ) ) ) ;
2016-08-02 22:11:05 +00:00
}
VisualScript : : VisualScript ( ) {
2017-03-05 15:44:50 +00:00
base_type = " Object " ;
2019-11-01 15:16:31 +00:00
is_tool_script = false ;
2016-08-02 22:11:05 +00:00
}
2020-04-20 22:06:00 +00:00
bool VisualScript : : inherits_script ( const Ref < Script > & p_script ) const {
2020-06-17 15:39:25 +00:00
return this = = p_script . ptr ( ) ; // There is no inheritance in visual scripts, so this is enough.
2019-09-13 19:14:12 +00:00
}
2020-06-17 15:39:25 +00:00
Set < int > VisualScript : : get_output_sequence_ports_connected ( int from_node ) {
2018-05-13 03:34:35 +00:00
List < VisualScript : : SequenceConnection > * sc = memnew ( List < VisualScript : : SequenceConnection > ) ;
2020-06-17 15:39:25 +00:00
get_sequence_connection_list ( sc ) ;
2018-05-13 03:34:35 +00:00
Set < int > connected ;
for ( List < VisualScript : : SequenceConnection > : : Element * E = sc - > front ( ) ; E ; E = E - > next ( ) ) {
if ( E - > get ( ) . from_node = = from_node ) {
connected . insert ( E - > get ( ) . from_output ) ;
}
}
memdelete ( sc ) ;
return connected ;
}
2016-08-02 22:11:05 +00:00
VisualScript : : ~ VisualScript ( ) {
2020-06-17 15:39:25 +00:00
// Remove all nodes and stuff that hold data refs.
List < int > nds ;
nodes . get_key_list ( & nds ) ;
for ( const List < int > : : Element * E = nds . front ( ) ; E ; E = E - > next ( ) ) {
remove_node ( E - > get ( ) ) ;
2016-08-02 22:11:05 +00:00
}
}
////////////////////////////////////////////
2017-03-05 15:44:50 +00:00
bool VisualScriptInstance : : set ( const StringName & p_name , const Variant & p_value ) {
Map < StringName , Variant > : : Element * E = variables . find ( p_name ) ;
2020-05-14 14:41:43 +00:00
if ( ! E ) {
2016-09-04 13:38:41 +00:00
return false ;
2020-05-14 14:41:43 +00:00
}
2016-08-06 01:46:45 +00:00
2017-03-05 15:44:50 +00:00
E - > get ( ) = p_value ;
2016-08-06 01:46:45 +00:00
return true ;
}
2017-03-05 15:44:50 +00:00
bool VisualScriptInstance : : get ( const StringName & p_name , Variant & r_ret ) const {
const Map < StringName , Variant > : : Element * E = variables . find ( p_name ) ;
2020-05-14 14:41:43 +00:00
if ( ! E ) {
2016-08-06 01:46:45 +00:00
return false ;
2020-05-14 14:41:43 +00:00
}
2016-08-06 01:46:45 +00:00
2017-03-05 15:44:50 +00:00
r_ret = E - > get ( ) ;
2016-09-06 22:12:28 +00:00
return true ;
2016-08-06 01:46:45 +00:00
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
void VisualScriptInstance : : get_property_list ( List < PropertyInfo > * p_properties ) const {
2020-06-17 15:39:25 +00:00
List < StringName > vars ;
script - > variables . get_key_list ( & vars ) ;
for ( const List < StringName > : : Element * E = vars . front ( ) ; E ; E = E - > next ( ) ) {
if ( ! script - > variables [ E - > get ( ) ] . _export ) {
2016-08-31 02:44:14 +00:00
continue ;
2020-05-14 14:41:43 +00:00
}
2020-06-17 15:39:25 +00:00
PropertyInfo p = script - > variables [ E - > get ( ) ] . info ;
p . name = String ( E - > get ( ) ) ;
2017-07-01 00:30:17 +00:00
p . usage | = PROPERTY_USAGE_SCRIPT_VARIABLE ;
2016-08-06 01:46:45 +00:00
p_properties - > push_back ( p ) ;
}
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
Variant : : Type VisualScriptInstance : : get_property_type ( const StringName & p_name , bool * r_is_valid ) const {
2020-06-17 15:39:25 +00:00
if ( ! script - > variables . has ( p_name ) ) {
2020-05-14 14:41:43 +00:00
if ( r_is_valid ) {
2017-03-05 15:44:50 +00:00
* r_is_valid = false ;
2020-05-14 14:41:43 +00:00
}
2016-08-06 01:46:45 +00:00
ERR_FAIL_V ( Variant : : NIL ) ;
}
2020-05-14 14:41:43 +00:00
if ( r_is_valid ) {
2017-03-05 15:44:50 +00:00
* r_is_valid = true ;
2020-05-14 14:41:43 +00:00
}
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
return script - > variables [ p_name ] . info . type ;
2016-08-06 01:46:45 +00:00
}
2017-03-05 15:44:50 +00:00
void VisualScriptInstance : : get_method_list ( List < MethodInfo > * p_list ) const {
2020-06-17 15:39:25 +00:00
List < StringName > fns ;
script - > functions . get_key_list ( & fns ) ;
for ( const List < StringName > : : Element * E = fns . front ( ) ; E ; E = E - > next ( ) ) {
2016-08-06 01:46:45 +00:00
MethodInfo mi ;
2020-06-17 15:39:25 +00:00
mi . name = E - > get ( ) ;
if ( script - > functions [ E - > get ( ) ] . func_id > = 0 & & script - > nodes . has ( script - > functions [ E - > get ( ) ] . func_id ) ) {
Ref < VisualScriptFunction > vsf = script - > nodes [ script - > functions [ E - > get ( ) ] . func_id ] . node ;
2016-08-06 01:46:45 +00:00
if ( vsf . is_valid ( ) ) {
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < vsf - > get_argument_count ( ) ; i + + ) {
2016-08-06 01:46:45 +00:00
PropertyInfo arg ;
2017-03-05 15:44:50 +00:00
arg . name = vsf - > get_argument_name ( i ) ;
arg . type = vsf - > get_argument_type ( i ) ;
2016-08-06 01:46:45 +00:00
mi . arguments . push_back ( arg ) ;
}
2020-06-17 15:39:25 +00:00
if ( ! vsf - > is_sequenced ( ) ) { // Assumed constant if not sequenced.
2017-08-08 16:14:36 +00:00
mi . flags | = METHOD_FLAG_CONST ;
}
2016-08-06 01:46:45 +00:00
}
}
p_list - > push_back ( mi ) ;
}
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
bool VisualScriptInstance : : has_method ( const StringName & p_method ) const {
2016-08-06 01:46:45 +00:00
return script - > functions . has ( p_method ) ;
}
2016-08-06 23:13:27 +00:00
//#define VSDEBUG(m_text) print_line(m_text)
# define VSDEBUG(m_text)
2016-08-06 01:46:45 +00:00
2020-02-19 19:27:19 +00:00
void VisualScriptInstance : : _dependency_step ( VisualScriptNodeInstance * node , int p_pass , int * pass_stack , const Variant * * input_args , Variant * * output_args , Variant * variant_stack , Callable : : CallError & r_error , String & error_str , VisualScriptNodeInstance * * r_error_node ) {
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( node - > pass_idx = = - 1 ) ;
2016-08-31 02:44:14 +00:00
2020-05-14 14:41:43 +00:00
if ( pass_stack [ node - > pass_idx ] = = p_pass ) {
2016-08-31 02:44:14 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2016-08-31 02:44:14 +00:00
2017-03-05 15:44:50 +00:00
pass_stack [ node - > pass_idx ] = p_pass ;
2016-08-31 02:44:14 +00:00
2020-12-15 12:04:21 +00:00
if ( ! node - > dependencies . is_empty ( ) ) {
2016-08-31 02:44:14 +00:00
int dc = node - > dependencies . size ( ) ;
2017-11-25 03:07:54 +00:00
VisualScriptNodeInstance * * deps = node - > dependencies . ptrw ( ) ;
2016-08-31 02:44:14 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < dc ; i + + ) {
_dependency_step ( deps [ i ] , p_pass , pass_stack , input_args , output_args , variant_stack , r_error , error_str , r_error_node ) ;
2020-05-14 14:41:43 +00:00
if ( r_error . error ! = Callable : : CallError : : CALL_OK ) {
2016-08-31 02:44:14 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2016-08-31 02:44:14 +00:00
}
}
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < node - > input_port_count ; i + + ) {
2016-08-31 02:44:14 +00:00
int index = node - > input_ports [ i ] & VisualScriptNodeInstance : : INPUT_MASK ;
if ( node - > input_ports [ i ] & VisualScriptNodeInstance : : INPUT_DEFAULT_VALUE_BIT ) {
2020-06-17 15:39:25 +00:00
// Is a default value (unassigned input port).
2017-03-05 15:44:50 +00:00
input_args [ i ] = & default_values [ index ] ;
2016-08-31 02:44:14 +00:00
} else {
2021-03-12 13:35:16 +00:00
// Regular temporary in stack.
2017-03-05 15:44:50 +00:00
input_args [ i ] = & variant_stack [ index ] ;
2016-08-31 02:44:14 +00:00
}
}
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < node - > output_port_count ; i + + ) {
output_args [ i ] = & variant_stack [ node - > output_ports [ i ] ] ;
2016-08-31 02:44:14 +00:00
}
2020-04-01 23:20:12 +00:00
Variant * working_mem = node - > working_mem_idx > = 0 ? & variant_stack [ node - > working_mem_idx ] : ( Variant * ) nullptr ;
2016-08-31 02:44:14 +00:00
2017-03-05 15:44:50 +00:00
node - > step ( input_args , output_args , VisualScriptNodeInstance : : START_MODE_BEGIN_SEQUENCE , working_mem , r_error , error_str ) ;
2020-06-17 15:39:25 +00:00
// Ignore return.
2020-02-19 19:27:19 +00:00
if ( r_error . error ! = Callable : : CallError : : CALL_OK ) {
2017-03-05 15:44:50 +00:00
* r_error_node = node ;
2016-08-31 02:44:14 +00:00
}
}
2020-02-19 19:27:19 +00:00
Variant VisualScriptInstance : : _call_internal ( const StringName & p_method , void * p_stack , int p_stack_size , VisualScriptNodeInstance * p_node , int p_flow_stack_pos , int p_pass , bool p_resuming_yield , Callable : : CallError & r_error ) {
2017-03-05 15:44:50 +00:00
Map < StringName , Function > : : Element * F = functions . find ( p_method ) ;
ERR_FAIL_COND_V ( ! F , Variant ( ) ) ;
Function * f = & F - > get ( ) ;
2016-08-06 01:46:45 +00:00
2021-03-12 13:35:16 +00:00
// This call goes separate, so it can be yielded and suspended.
2017-03-05 15:44:50 +00:00
Variant * variant_stack = ( Variant * ) p_stack ;
bool * sequence_bits = ( bool * ) ( variant_stack + f - > max_stack ) ;
const Variant * * input_args = ( const Variant * * ) ( sequence_bits + f - > node_count ) ;
Variant * * output_args = ( Variant * * ) ( input_args + max_input_args ) ;
2016-08-06 01:46:45 +00:00
int flow_max = f - > flow_stack_size ;
2020-04-01 23:20:12 +00:00
int * flow_stack = flow_max ? ( int * ) ( output_args + max_output_args ) : ( int * ) nullptr ;
int * pass_stack = flow_stack ? ( int * ) ( flow_stack + flow_max ) : ( int * ) nullptr ;
2016-08-06 01:46:45 +00:00
String error_str ;
2017-03-05 15:44:50 +00:00
VisualScriptNodeInstance * node = p_node ;
bool error = false ;
int current_node_id = f - > node ;
2016-08-06 01:46:45 +00:00
Variant return_value ;
2020-04-01 23:20:12 +00:00
Variant * working_mem = nullptr ;
2016-08-07 22:22:33 +00:00
2017-03-05 15:44:50 +00:00
int flow_stack_pos = p_flow_stack_pos ;
2016-08-07 22:22:33 +00:00
2016-08-06 22:00:54 +00:00
# ifdef DEBUG_ENABLED
2020-02-27 02:30:20 +00:00
if ( EngineDebugger : : is_active ( ) ) {
2017-03-05 15:44:50 +00:00
VisualScriptLanguage : : singleton - > enter_function ( this , & p_method , variant_stack , & working_mem , & current_node_id ) ;
2016-08-06 22:00:54 +00:00
}
# endif
2016-08-06 01:46:45 +00:00
2017-03-05 15:44:50 +00:00
while ( true ) {
2020-06-17 15:39:25 +00:00
p_pass + + ; // Increment pass.
2017-03-05 15:44:50 +00:00
current_node_id = node - > get_id ( ) ;
2016-08-06 01:46:45 +00:00
2017-03-05 15:44:50 +00:00
VSDEBUG ( " ==========AT NODE: " + itos ( current_node_id ) + " base: " + node - > get_base_node ( ) - > get_class_name ( ) ) ;
VSDEBUG ( " AT STACK POS: " + itos ( flow_stack_pos ) ) ;
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
// Setup working mem.
2020-04-01 23:20:12 +00:00
working_mem = node - > working_mem_idx > = 0 ? & variant_stack [ node - > working_mem_idx ] : ( Variant * ) nullptr ;
2016-08-06 01:46:45 +00:00
2017-03-05 15:44:50 +00:00
VSDEBUG ( " WORKING MEM: " + itos ( node - > working_mem_idx ) ) ;
2016-08-06 01:46:45 +00:00
2017-03-05 15:44:50 +00:00
if ( current_node_id = = f - > node ) {
2020-06-17 15:39:25 +00:00
// If function node, set up function arguments from beginning of stack.
2016-08-06 01:46:45 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < f - > argument_count ; i + + ) {
input_args [ i ] = & variant_stack [ i ] ;
2016-08-06 01:46:45 +00:00
}
} else {
2020-06-17 15:39:25 +00:00
// Run dependencies first.
2016-08-06 01:46:45 +00:00
2020-12-15 12:04:21 +00:00
if ( ! node - > dependencies . is_empty ( ) ) {
2016-08-31 02:44:14 +00:00
int dc = node - > dependencies . size ( ) ;
2017-11-25 03:07:54 +00:00
VisualScriptNodeInstance * * deps = node - > dependencies . ptrw ( ) ;
2016-08-06 01:46:45 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < dc ; i + + ) {
_dependency_step ( deps [ i ] , p_pass , pass_stack , input_args , output_args , variant_stack , r_error , error_str , & node ) ;
2020-02-19 19:27:19 +00:00
if ( r_error . error ! = Callable : : CallError : : CALL_OK ) {
2017-03-05 15:44:50 +00:00
error = true ;
current_node_id = node - > id ;
2016-08-06 01:46:45 +00:00
break ;
}
2016-08-31 02:44:14 +00:00
}
}
2016-08-06 01:46:45 +00:00
2016-08-31 02:44:14 +00:00
if ( ! error ) {
2020-06-17 15:39:25 +00:00
// Setup input pointers normally.
2017-03-05 15:44:50 +00:00
VSDEBUG ( " INPUT PORTS: " + itos ( node - > input_port_count ) ) ;
2016-08-31 02:44:14 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < node - > input_port_count ; i + + ) {
2016-08-31 02:44:14 +00:00
int index = node - > input_ports [ i ] & VisualScriptNodeInstance : : INPUT_MASK ;
if ( node - > input_ports [ i ] & VisualScriptNodeInstance : : INPUT_DEFAULT_VALUE_BIT ) {
2020-06-17 15:39:25 +00:00
// Is a default value (unassigned input port).
2017-03-05 15:44:50 +00:00
input_args [ i ] = & default_values [ index ] ;
VSDEBUG ( " \t PORT " + itos ( i ) + " DEFAULT VAL " ) ;
2016-08-31 02:44:14 +00:00
} else {
2020-06-17 15:39:25 +00:00
// Regular temporary in stack.
2017-03-05 15:44:50 +00:00
input_args [ i ] = & variant_stack [ index ] ;
VSDEBUG ( " PORT " + itos ( i ) + " AT STACK " + itos ( index ) ) ;
2016-08-31 02:44:14 +00:00
}
2016-08-06 01:46:45 +00:00
}
}
}
2020-05-14 14:41:43 +00:00
if ( error ) {
2016-08-06 01:46:45 +00:00
break ;
2020-05-14 14:41:43 +00:00
}
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
// Setup output pointers.
2016-08-06 01:46:45 +00:00
2017-03-05 15:44:50 +00:00
VSDEBUG ( " OUTPUT PORTS: " + itos ( node - > output_port_count ) ) ;
for ( int i = 0 ; i < node - > output_port_count ; i + + ) {
output_args [ i ] = & variant_stack [ node - > output_ports [ i ] ] ;
VSDEBUG ( " PORT " + itos ( i ) + " AT STACK " + itos ( node - > output_ports [ i ] ) ) ;
2016-08-06 01:46:45 +00:00
}
2020-06-17 15:39:25 +00:00
// Do step.
2016-08-06 01:46:45 +00:00
2016-08-07 22:22:33 +00:00
VisualScriptNodeInstance : : StartMode start_mode ;
{
2017-08-19 14:54:32 +00:00
if ( p_resuming_yield ) {
2017-03-05 15:44:50 +00:00
start_mode = VisualScriptNodeInstance : : START_MODE_RESUME_YIELD ;
2020-06-17 15:39:25 +00:00
p_resuming_yield = false ; // Should resume only the first time.
2017-08-19 14:54:32 +00:00
} else if ( flow_stack & & ( flow_stack [ flow_stack_pos ] & VisualScriptNodeInstance : : FLOW_STACK_PUSHED_BIT ) ) {
2020-06-17 15:39:25 +00:00
// If there is a push bit, it means we are continuing a sequence.
2017-03-05 15:44:50 +00:00
start_mode = VisualScriptNodeInstance : : START_MODE_CONTINUE_SEQUENCE ;
2017-08-19 14:54:32 +00:00
} else {
start_mode = VisualScriptNodeInstance : : START_MODE_BEGIN_SEQUENCE ;
}
2016-08-07 22:22:33 +00:00
}
2016-08-06 22:00:54 +00:00
2017-03-05 15:44:50 +00:00
VSDEBUG ( " STEP - STARTSEQ: " + itos ( start_mode ) ) ;
2016-08-06 01:46:45 +00:00
2017-03-05 15:44:50 +00:00
int ret = node - > step ( input_args , output_args , start_mode , working_mem , r_error , error_str ) ;
2016-08-06 01:46:45 +00:00
2020-02-19 19:27:19 +00:00
if ( r_error . error ! = Callable : : CallError : : CALL_OK ) {
2020-06-17 15:39:25 +00:00
// Use error from step.
2017-03-05 15:44:50 +00:00
error = true ;
2016-08-06 01:46:45 +00:00
break ;
}
2017-03-05 15:44:50 +00:00
if ( ret & VisualScriptNodeInstance : : STEP_YIELD_BIT ) {
2020-06-17 15:39:25 +00:00
// Yielded!
2017-03-05 15:44:50 +00:00
if ( node - > get_working_memory_size ( ) = = 0 ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_METHOD ;
2017-03-05 15:44:50 +00:00
error_str = RTR ( " A node yielded without working memory, please read the docs on how to yield properly! " ) ;
error = true ;
2016-08-07 22:22:33 +00:00
break ;
} else {
Ref < VisualScriptFunctionState > state = * working_mem ;
if ( ! state . is_valid ( ) ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_METHOD ;
2017-03-05 15:44:50 +00:00
error_str = RTR ( " Node yielded, but did not return a function state in the first working memory. " ) ;
error = true ;
2016-08-07 22:22:33 +00:00
break ;
}
2020-06-17 15:39:25 +00:00
// Step 1, capture all state.
2017-08-07 10:17:31 +00:00
state - > instance_id = get_owner_ptr ( ) - > get_instance_id ( ) ;
state - > script_id = get_script ( ) - > get_instance_id ( ) ;
2017-03-05 15:44:50 +00:00
state - > instance = this ;
state - > function = p_method ;
state - > working_mem_index = node - > working_mem_idx ;
state - > variant_stack_size = f - > max_stack ;
state - > node = node ;
state - > flow_stack_pos = flow_stack_pos ;
2016-08-07 22:22:33 +00:00
state - > stack . resize ( p_stack_size ) ;
2017-03-05 15:44:50 +00:00
state - > pass = p_pass ;
2021-04-27 14:19:21 +00:00
memcpy ( state - > stack . ptrw ( ) , p_stack , p_stack_size ) ;
2020-06-17 15:39:25 +00:00
// Step 2, run away, return directly.
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_OK ;
2016-08-07 22:22:33 +00:00
# ifdef DEBUG_ENABLED
2020-06-17 15:39:25 +00:00
// Will re-enter later, so exiting.
2020-02-27 02:30:20 +00:00
if ( EngineDebugger : : is_active ( ) ) {
2016-08-07 22:22:33 +00:00
VisualScriptLanguage : : singleton - > exit_function ( ) ;
}
# endif
return state ;
}
}
2016-08-06 22:00:54 +00:00
# ifdef DEBUG_ENABLED
2020-02-27 02:30:20 +00:00
if ( EngineDebugger : : is_active ( ) ) {
2016-08-06 22:00:54 +00:00
// line
2017-03-05 15:44:50 +00:00
bool do_break = false ;
2016-08-06 22:00:54 +00:00
2020-02-27 02:30:20 +00:00
if ( EngineDebugger : : get_script_debugger ( ) - > get_lines_left ( ) > 0 ) {
2020-05-14 14:41:43 +00:00
if ( EngineDebugger : : get_script_debugger ( ) - > get_depth ( ) < = 0 ) {
2020-02-27 02:30:20 +00:00
EngineDebugger : : get_script_debugger ( ) - > set_lines_left ( EngineDebugger : : get_script_debugger ( ) - > get_lines_left ( ) - 1 ) ;
2020-05-14 14:41:43 +00:00
}
if ( EngineDebugger : : get_script_debugger ( ) - > get_lines_left ( ) < = 0 ) {
2017-03-05 15:44:50 +00:00
do_break = true ;
2020-05-14 14:41:43 +00:00
}
2016-08-06 22:00:54 +00:00
}
2020-05-14 14:41:43 +00:00
if ( EngineDebugger : : get_script_debugger ( ) - > is_breakpoint ( current_node_id , source ) ) {
2017-03-05 15:44:50 +00:00
do_break = true ;
2020-05-14 14:41:43 +00:00
}
2016-08-06 22:00:54 +00:00
if ( do_break ) {
2017-03-05 15:44:50 +00:00
VisualScriptLanguage : : singleton - > debug_break ( " Breakpoint " , true ) ;
2016-08-06 22:00:54 +00:00
}
2020-02-27 02:30:20 +00:00
EngineDebugger : : get_singleton ( ) - > line_poll ( ) ;
2016-08-06 22:00:54 +00:00
}
# endif
2016-08-06 01:46:45 +00:00
int output = ret & VisualScriptNodeInstance : : STEP_MASK ;
2017-03-05 15:44:50 +00:00
VSDEBUG ( " STEP RETURN: " + itos ( ret ) ) ;
2016-08-06 01:46:45 +00:00
if ( ret & VisualScriptNodeInstance : : STEP_EXIT_FUNCTION_BIT ) {
2017-03-05 15:44:50 +00:00
if ( node - > get_working_memory_size ( ) = = 0 ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_METHOD ;
2017-03-05 15:44:50 +00:00
error_str = RTR ( " Return value must be assigned to first element of node working memory! Fix your node please. " ) ;
error = true ;
2016-08-06 01:46:45 +00:00
} else {
2020-06-17 15:39:25 +00:00
// Assign from working memory, first element.
2017-03-05 15:44:50 +00:00
return_value = * working_mem ;
2016-08-06 01:46:45 +00:00
}
2017-03-05 15:44:50 +00:00
VSDEBUG ( " EXITING FUNCTION - VALUE " + String ( return_value ) ) ;
2020-06-17 15:39:25 +00:00
break ; // Exit function requested, bye
2016-08-06 01:46:45 +00:00
}
2020-06-17 15:39:25 +00:00
VisualScriptNodeInstance * next = nullptr ; // Next node.
2016-08-06 01:46:45 +00:00
2017-03-05 15:44:50 +00:00
if ( ( ret = = output | | ret & VisualScriptNodeInstance : : STEP_FLAG_PUSH_STACK_BIT ) & & node - > sequence_output_count ) {
2020-06-17 15:39:25 +00:00
// If no exit bit was set, and has sequence outputs, guess next node.
2019-06-20 14:59:48 +00:00
if ( output > = node - > sequence_output_count ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_METHOD ;
2017-03-05 15:44:50 +00:00
error_str = RTR ( " Node returned an invalid sequence output: " ) + itos ( output ) ;
error = true ;
2016-08-06 01:46:45 +00:00
break ;
}
next = node - > sequence_outputs [ output ] ;
2021-04-29 09:47:24 +00:00
VSDEBUG ( " GOT NEXT NODE - " + ( next ? itos ( next - > get_id ( ) ) : " Null " ) ) ;
2016-08-06 01:46:45 +00:00
}
if ( flow_stack ) {
2020-06-17 15:39:25 +00:00
// Update flow stack pos (may have changed).
2016-08-06 01:46:45 +00:00
flow_stack [ flow_stack_pos ] = current_node_id ;
2020-06-17 15:39:25 +00:00
// Add stack push bit if requested.
2016-08-06 01:46:45 +00:00
if ( ret & VisualScriptNodeInstance : : STEP_FLAG_PUSH_STACK_BIT ) {
flow_stack [ flow_stack_pos ] | = VisualScriptNodeInstance : : FLOW_STACK_PUSHED_BIT ;
2020-06-17 15:39:25 +00:00
sequence_bits [ node - > sequence_index ] = true ; // Remember sequence bit.
2016-08-06 01:46:45 +00:00
VSDEBUG ( " NEXT SEQ - FLAG BIT " ) ;
} else {
2020-06-17 15:39:25 +00:00
sequence_bits [ node - > sequence_index ] = false ; // Forget sequence bit.
2016-08-06 01:46:45 +00:00
VSDEBUG ( " NEXT SEQ - NORMAL " ) ;
}
if ( ret & VisualScriptNodeInstance : : STEP_FLAG_GO_BACK_BIT ) {
2020-06-17 15:39:25 +00:00
// Go back request.
2016-08-06 01:46:45 +00:00
2017-03-05 15:44:50 +00:00
if ( flow_stack_pos > 0 ) {
2016-08-06 01:46:45 +00:00
flow_stack_pos - - ;
2017-03-05 15:44:50 +00:00
node = instances [ flow_stack [ flow_stack_pos ] & VisualScriptNodeInstance : : FLOW_STACK_MASK ] ;
2016-08-06 01:46:45 +00:00
VSDEBUG ( " NEXT IS GO BACK " ) ;
} else {
VSDEBUG ( " NEXT IS GO BACK, BUT NO NEXT SO EXIT " ) ;
2020-06-17 15:39:25 +00:00
break ; // Simply exit without value or error.
2016-08-06 01:46:45 +00:00
}
} else if ( next ) {
if ( sequence_bits [ next - > sequence_index ] ) {
2020-06-17 15:39:25 +00:00
// What happened here is that we are entering a node that is in the middle of doing a sequence (pushed stack) from the front
2016-08-06 01:46:45 +00:00
// because each node has a working memory, we can't really do a sub-sequence
// as a result, the sequence will be restarted and the stack will roll back to find where this node
2020-06-17 15:39:25 +00:00
// started the sequence.
2016-08-06 01:46:45 +00:00
bool found = false ;
2017-03-05 15:44:50 +00:00
for ( int i = flow_stack_pos ; i > = 0 ; i - - ) {
if ( ( flow_stack [ i ] & VisualScriptNodeInstance : : FLOW_STACK_MASK ) = = next - > get_id ( ) ) {
2020-06-17 15:39:25 +00:00
flow_stack_pos = i ; // Roll back and remove bit.
2017-03-05 15:44:50 +00:00
flow_stack [ i ] = next - > get_id ( ) ;
sequence_bits [ next - > sequence_index ] = false ;
found = true ;
2016-08-06 01:46:45 +00:00
}
}
if ( ! found ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_METHOD ;
2017-03-05 15:44:50 +00:00
error_str = RTR ( " Found sequence bit but not the node in the stack, report bug! " ) ;
error = true ;
2016-08-06 01:46:45 +00:00
break ;
}
2017-03-05 15:44:50 +00:00
node = next ;
VSDEBUG ( " RE-ENTERED A LOOP, RETURNED STACK POS TO - " + itos ( flow_stack_pos ) ) ;
2016-08-06 01:46:45 +00:00
} else {
2020-06-17 15:39:25 +00:00
// Check for stack overflow.
2017-03-05 15:44:50 +00:00
if ( flow_stack_pos + 1 > = flow_max ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_METHOD ;
2017-03-05 15:44:50 +00:00
error_str = RTR ( " Stack overflow with stack depth: " ) + itos ( output ) ;
error = true ;
2016-08-06 01:46:45 +00:00
break ;
}
node = next ;
flow_stack_pos + + ;
2017-03-05 15:44:50 +00:00
flow_stack [ flow_stack_pos ] = node - > get_id ( ) ;
2016-08-06 01:46:45 +00:00
VSDEBUG ( " INCREASE FLOW STACK " ) ;
}
} else {
2020-06-17 15:39:25 +00:00
// No next node, try to go back in stack to pushed bit.
2016-08-06 01:46:45 +00:00
bool found = false ;
2017-03-05 15:44:50 +00:00
for ( int i = flow_stack_pos ; i > = 0 ; i - - ) {
VSDEBUG ( " FS " + itos ( i ) + " - " + itos ( flow_stack [ i ] ) ) ;
2016-08-06 01:46:45 +00:00
if ( flow_stack [ i ] & VisualScriptNodeInstance : : FLOW_STACK_PUSHED_BIT ) {
2017-03-05 15:44:50 +00:00
node = instances [ flow_stack [ i ] & VisualScriptNodeInstance : : FLOW_STACK_MASK ] ;
flow_stack_pos = i ;
found = true ;
2016-08-28 23:57:27 +00:00
break ;
2016-08-06 01:46:45 +00:00
}
}
if ( ! found ) {
VSDEBUG ( " NO NEXT NODE, NO GO BACK, EXITING " ) ;
2020-06-17 15:39:25 +00:00
break ; // Done, couldn't find a push stack bit.
2016-08-06 01:46:45 +00:00
}
2017-03-05 15:44:50 +00:00
VSDEBUG ( " NO NEXT NODE, GO BACK TO: " + itos ( flow_stack_pos ) ) ;
2016-08-06 01:46:45 +00:00
}
} else {
2020-06-17 15:39:25 +00:00
node = next ; // Stackless mode, simply assign next node.
2016-08-06 01:46:45 +00:00
}
}
if ( error ) {
2020-06-17 15:39:25 +00:00
// Error
// Function, file, line, error, explanation.
2016-08-06 01:46:45 +00:00
String err_file = script - > get_path ( ) ;
String err_func = p_method ;
2020-06-17 15:39:25 +00:00
int err_line = current_node_id ; // Not a line but it works as one.
2016-08-06 01:46:45 +00:00
2020-02-19 19:27:19 +00:00
if ( node & & ( r_error . error ! = Callable : : CallError : : CALL_ERROR_INVALID_METHOD | | error_str = = String ( ) ) ) {
2017-03-05 15:44:50 +00:00
if ( error_str ! = String ( ) ) {
error_str + = " " ;
2016-09-04 13:34:40 +00:00
}
2020-02-19 19:27:19 +00:00
if ( r_error . error = = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ) {
2017-03-05 15:44:50 +00:00
int errorarg = r_error . argument ;
2020-02-19 19:27:19 +00:00
error_str + = " Cannot convert argument " + itos ( errorarg + 1 ) + " to " + Variant : : get_type_name ( Variant : : Type ( r_error . expected ) ) + " . " ;
} else if ( r_error . error = = Callable : : CallError : : CALL_ERROR_TOO_MANY_ARGUMENTS ) {
2017-03-05 15:44:50 +00:00
error_str + = " Expected " + itos ( r_error . argument ) + " arguments. " ;
2020-02-19 19:27:19 +00:00
} else if ( r_error . error = = Callable : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ) {
2017-03-05 15:44:50 +00:00
error_str + = " Expected " + itos ( r_error . argument ) + " arguments. " ;
2020-02-19 19:27:19 +00:00
} else if ( r_error . error = = Callable : : CallError : : CALL_ERROR_INVALID_METHOD ) {
2017-03-05 15:44:50 +00:00
error_str + = " Invalid Call. " ;
2020-02-19 19:27:19 +00:00
} else if ( r_error . error = = Callable : : CallError : : CALL_ERROR_INSTANCE_IS_NULL ) {
2017-03-05 15:44:50 +00:00
error_str + = " Base Instance is null " ;
2016-08-28 23:57:27 +00:00
}
}
2016-08-06 01:46:45 +00:00
//if (!GDScriptLanguage::get_singleton()->debug_break(err_text,false)) {
2017-03-05 15:44:50 +00:00
// debugger break did not happen
2016-08-06 01:46:45 +00:00
2017-03-05 15:44:50 +00:00
if ( ! VisualScriptLanguage : : singleton - > debug_break ( error_str , false ) ) {
_err_print_error ( err_func . utf8 ( ) . get_data ( ) , err_file . utf8 ( ) . get_data ( ) , err_line , error_str . utf8 ( ) . get_data ( ) , ERR_HANDLER_SCRIPT ) ;
2016-08-06 22:00:54 +00:00
}
2016-08-06 01:46:45 +00:00
//}
} else {
//return_value=
}
2016-08-06 22:00:54 +00:00
# ifdef DEBUG_ENABLED
2020-02-27 02:30:20 +00:00
if ( EngineDebugger : : is_active ( ) ) {
2016-08-06 22:00:54 +00:00
VisualScriptLanguage : : singleton - > exit_function ( ) ;
}
# endif
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
// Clean up variant stack.
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < f - > max_stack ; i + + ) {
2016-08-06 01:46:45 +00:00
variant_stack [ i ] . ~ Variant ( ) ;
}
return return_value ;
}
2020-02-19 19:27:19 +00:00
Variant VisualScriptInstance : : call ( const StringName & p_method , const Variant * * p_args , int p_argcount , Callable : : CallError & r_error ) {
r_error . error = Callable : : CallError : : CALL_OK ; //ok by default
2016-08-07 22:22:33 +00:00
2017-03-05 15:44:50 +00:00
Map < StringName , Function > : : Element * F = functions . find ( p_method ) ;
2016-08-07 22:22:33 +00:00
if ( ! F ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_METHOD ;
2016-08-07 22:22:33 +00:00
return Variant ( ) ;
}
2017-03-05 15:44:50 +00:00
VSDEBUG ( " CALLING: " + String ( p_method ) ) ;
2016-08-07 22:22:33 +00:00
2017-03-05 15:44:50 +00:00
Function * f = & F - > get ( ) ;
2016-08-07 22:22:33 +00:00
2017-03-05 15:44:50 +00:00
int total_stack_size = 0 ;
2016-08-07 22:22:33 +00:00
2017-03-05 15:44:50 +00:00
total_stack_size + = f - > max_stack * sizeof ( Variant ) ; //variants
total_stack_size + = f - > node_count * sizeof ( bool ) ;
total_stack_size + = ( max_input_args + max_output_args ) * sizeof ( Variant * ) ; //arguments
total_stack_size + = f - > flow_stack_size * sizeof ( int ) ; //flow
total_stack_size + = f - > pass_stack_size * sizeof ( int ) ;
2016-08-07 22:22:33 +00:00
2017-03-05 15:44:50 +00:00
VSDEBUG ( " STACK SIZE: " + itos ( total_stack_size ) ) ;
VSDEBUG ( " STACK VARIANTS: : " + itos ( f - > max_stack ) ) ;
VSDEBUG ( " SEQBITS: : " + itos ( f - > node_count ) ) ;
VSDEBUG ( " MAX INPUT: " + itos ( max_input_args ) ) ;
VSDEBUG ( " MAX OUTPUT: " + itos ( max_output_args ) ) ;
VSDEBUG ( " FLOW STACK SIZE: " + itos ( f - > flow_stack_size ) ) ;
VSDEBUG ( " PASS STACK SIZE: " + itos ( f - > pass_stack_size ) ) ;
2016-08-07 22:22:33 +00:00
void * stack = alloca ( total_stack_size ) ;
2017-03-05 15:44:50 +00:00
Variant * variant_stack = ( Variant * ) stack ;
bool * sequence_bits = ( bool * ) ( variant_stack + f - > max_stack ) ;
const Variant * * input_args = ( const Variant * * ) ( sequence_bits + f - > node_count ) ;
Variant * * output_args = ( Variant * * ) ( input_args + max_input_args ) ;
2016-08-07 22:22:33 +00:00
int flow_max = f - > flow_stack_size ;
2020-04-01 23:20:12 +00:00
int * flow_stack = flow_max ? ( int * ) ( output_args + max_output_args ) : ( int * ) nullptr ;
int * pass_stack = flow_stack ? ( int * ) ( flow_stack + flow_max ) : ( int * ) nullptr ;
2016-08-07 22:22:33 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < f - > node_count ; i + + ) {
2020-06-17 15:39:25 +00:00
sequence_bits [ i ] = false ; // All starts as false.
2016-08-07 22:22:33 +00:00
}
2021-04-27 14:19:21 +00:00
memset ( pass_stack , 0 , f - > pass_stack_size * sizeof ( int ) ) ;
2016-08-07 22:22:33 +00:00
2017-03-05 15:44:50 +00:00
Map < int , VisualScriptNodeInstance * > : : Element * E = instances . find ( f - > node ) ;
2016-08-07 22:22:33 +00:00
if ( ! E ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_METHOD ;
2016-08-07 22:22:33 +00:00
2019-08-11 08:49:53 +00:00
ERR_FAIL_V_MSG ( Variant ( ) , " No VisualScriptFunction node in function. " ) ;
2016-08-07 22:22:33 +00:00
}
VisualScriptNodeInstance * node = E - > get ( ) ;
2017-03-05 15:44:50 +00:00
if ( flow_stack ) {
flow_stack [ 0 ] = node - > get_id ( ) ;
2016-08-07 22:22:33 +00:00
}
2017-03-05 15:44:50 +00:00
VSDEBUG ( " ARGUMENTS: " + itos ( f - > argument_count ) = " RECEIVED: " + itos ( p_argcount ) ) ;
2016-08-07 22:22:33 +00:00
2017-03-05 15:44:50 +00:00
if ( p_argcount < f - > argument_count ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
2017-03-05 15:44:50 +00:00
r_error . argument = node - > get_input_port_count ( ) ;
2016-08-07 22:22:33 +00:00
return Variant ( ) ;
}
2017-03-05 15:44:50 +00:00
if ( p_argcount > f - > argument_count ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_TOO_MANY_ARGUMENTS ;
2017-03-05 15:44:50 +00:00
r_error . argument = node - > get_input_port_count ( ) ;
2016-08-07 22:22:33 +00:00
return Variant ( ) ;
}
2020-06-17 15:39:25 +00:00
// Allocate variant stack.
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < f - > max_stack ; i + + ) {
memnew_placement ( & variant_stack [ i ] , Variant ) ;
2016-08-07 22:22:33 +00:00
}
2020-06-17 15:39:25 +00:00
// Allocate function arguments (must be copied for yield to work properly).
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_argcount ; i + + ) {
variant_stack [ i ] = * p_args [ i ] ;
2016-08-07 22:22:33 +00:00
}
2017-03-05 15:44:50 +00:00
return _call_internal ( p_method , stack , total_stack_size , node , 0 , 0 , false , r_error ) ;
2016-08-07 22:22:33 +00:00
}
2017-03-05 15:44:50 +00:00
void VisualScriptInstance : : notification ( int p_notification ) {
2020-06-17 15:39:25 +00:00
// Do nothing as this is called using virtual.
2016-08-06 01:46:45 +00:00
2017-03-05 15:44:50 +00:00
Variant what = p_notification ;
const Variant * whatp = & what ;
2020-02-19 19:27:19 +00:00
Callable : : CallError ce ;
2020-06-17 15:39:25 +00:00
call ( VisualScriptLanguage : : singleton - > notification , & whatp , 1 , ce ) ; // Do as call.
2016-08-06 01:46:45 +00:00
}
2019-04-10 05:07:40 +00:00
String VisualScriptInstance : : to_string ( bool * r_valid ) {
if ( has_method ( CoreStringNames : : get_singleton ( ) - > _to_string ) ) {
2020-02-19 19:27:19 +00:00
Callable : : CallError ce ;
2020-04-01 23:20:12 +00:00
Variant ret = call ( CoreStringNames : : get_singleton ( ) - > _to_string , nullptr , 0 , ce ) ;
2020-02-19 19:27:19 +00:00
if ( ce . error = = Callable : : CallError : : CALL_OK ) {
2019-04-10 05:07:40 +00:00
if ( ret . get_type ( ) ! = Variant : : STRING ) {
2020-05-14 14:41:43 +00:00
if ( r_valid ) {
2019-04-10 05:07:40 +00:00
* r_valid = false ;
2020-05-14 14:41:43 +00:00
}
2019-08-11 08:49:53 +00:00
ERR_FAIL_V_MSG ( String ( ) , " Wrong type for " + CoreStringNames : : get_singleton ( ) - > _to_string + " , must be a String. " ) ;
2019-04-10 05:07:40 +00:00
}
2020-05-14 14:41:43 +00:00
if ( r_valid ) {
2019-04-10 05:07:40 +00:00
* r_valid = true ;
2020-05-14 14:41:43 +00:00
}
2019-04-10 05:07:40 +00:00
return ret . operator String ( ) ;
}
}
2020-05-14 14:41:43 +00:00
if ( r_valid ) {
2019-04-10 05:07:40 +00:00
* r_valid = false ;
2020-05-14 14:41:43 +00:00
}
2019-04-10 05:07:40 +00:00
return String ( ) ;
}
2017-03-05 15:44:50 +00:00
Ref < Script > VisualScriptInstance : : get_script ( ) const {
2016-08-06 01:46:45 +00:00
return script ;
}
2021-05-26 12:07:57 +00:00
const Vector < MultiplayerAPI : : RPCConfig > VisualScriptInstance : : get_rpc_methods ( ) const {
2020-02-12 10:51:50 +00:00
return script - > get_rpc_methods ( ) ;
}
2016-08-19 19:48:08 +00:00
2017-03-05 15:44:50 +00:00
void VisualScriptInstance : : create ( const Ref < VisualScript > & p_script , Object * p_owner ) {
script = p_script ;
owner = p_owner ;
source = p_script - > get_path ( ) ;
2016-08-06 01:46:45 +00:00
max_input_args = 0 ;
max_output_args = 0 ;
2017-08-24 20:58:51 +00:00
if ( Object : : cast_to < Node > ( p_owner ) ) {
2020-06-17 15:39:25 +00:00
// Turn on these if they exist and base is a node.
2017-08-24 20:58:51 +00:00
Node * node = Object : : cast_to < Node > ( p_owner ) ;
2020-05-14 14:41:43 +00:00
if ( p_script - > functions . has ( " _process " ) ) {
2016-08-07 23:08:15 +00:00
node - > set_process ( true ) ;
2020-05-14 14:41:43 +00:00
}
if ( p_script - > functions . has ( " _physics_process " ) ) {
2017-09-30 14:19:07 +00:00
node - > set_physics_process ( true ) ;
2020-05-14 14:41:43 +00:00
}
if ( p_script - > functions . has ( " _input " ) ) {
2016-08-07 23:08:15 +00:00
node - > set_process_input ( true ) ;
2020-05-14 14:41:43 +00:00
}
if ( p_script - > functions . has ( " _unhandled_input " ) ) {
2016-08-07 23:08:15 +00:00
node - > set_process_unhandled_input ( true ) ;
2020-05-14 14:41:43 +00:00
}
if ( p_script - > functions . has ( " _unhandled_key_input " ) ) {
2016-08-07 23:08:15 +00:00
node - > set_process_unhandled_key_input ( true ) ;
2020-05-14 14:41:43 +00:00
}
2016-08-07 23:08:15 +00:00
}
2020-06-17 15:39:25 +00:00
// Setup variables.
{
List < StringName > keys ;
script - > variables . get_key_list ( & keys ) ;
for ( const List < StringName > : : Element * E = keys . front ( ) ; E ; E = E - > next ( ) ) {
variables [ E - > get ( ) ] = script - > variables [ E - > get ( ) ] . default_value ;
2016-08-06 01:46:45 +00:00
}
2020-06-17 15:39:25 +00:00
}
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
// Setup functions from sequence trees.
{
List < StringName > keys ;
script - > functions . get_key_list ( & keys ) ;
for ( const List < StringName > : : Element * E = keys . front ( ) ; E ; E = E - > next ( ) ) {
const VisualScript : : Function vsfn = p_script - > functions [ E - > get ( ) ] ;
Function function ;
function . node = vsfn . func_id ;
function . max_stack = 0 ;
function . flow_stack_size = 0 ;
function . pass_stack_size = 0 ;
function . node_count = 0 ;
Map < StringName , int > local_var_indices ;
if ( function . node < 0 ) {
VisualScriptLanguage : : singleton - > debug_break_parse ( get_script ( ) - > get_path ( ) , 0 , " No start node in function: " + String ( E - > get ( ) ) ) ;
ERR_CONTINUE ( function . node < 0 ) ;
2016-08-06 22:00:54 +00:00
}
2020-06-17 15:39:25 +00:00
{
Ref < VisualScriptFunction > func_node = script - > get_node ( vsfn . func_id ) ;
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
if ( func_node . is_null ( ) ) {
VisualScriptLanguage : : singleton - > debug_break_parse ( get_script ( ) - > get_path ( ) , 0 , " No VisualScriptFunction typed start node in function: " + String ( E - > get ( ) ) ) ;
}
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
ERR_CONTINUE ( ! func_node . is_valid ( ) ) ;
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
function . argument_count = func_node - > get_argument_count ( ) ;
function . max_stack + = function . argument_count ;
function . flow_stack_size = func_node - > is_stack_less ( ) ? 0 : func_node - > get_stack_size ( ) ;
max_input_args = MAX ( max_input_args , function . argument_count ) ;
2016-08-06 01:46:45 +00:00
}
2020-06-17 15:39:25 +00:00
// Function nodes graphs.
Set < VisualScript : : SequenceConnection > seqconns ;
Set < VisualScript : : DataConnection > dataconns ;
Set < int > node_ids ;
node_ids . insert ( function . node ) ;
{
List < int > nd_queue ;
nd_queue . push_back ( function . node ) ;
while ( ! nd_queue . is_empty ( ) ) {
for ( const Set < VisualScript : : SequenceConnection > : : Element * F = script - > sequence_connections . front ( ) ; F ; F = F - > next ( ) ) {
if ( nd_queue . front ( ) - > get ( ) = = F - > get ( ) . from_node & & ! node_ids . has ( F - > get ( ) . to_node ) ) {
nd_queue . push_back ( F - > get ( ) . to_node ) ;
node_ids . insert ( F - > get ( ) . to_node ) ;
}
if ( nd_queue . front ( ) - > get ( ) = = F - > get ( ) . from_node & & ! seqconns . has ( F - > get ( ) ) ) {
seqconns . insert ( F - > get ( ) ) ;
}
}
nd_queue . pop_front ( ) ;
2016-08-06 01:46:45 +00:00
}
2020-06-17 15:39:25 +00:00
HashMap < int , HashMap < int , Pair < int , int > > > dc_lut ; // :: to -> to_port -> (from, from_port)
for ( const Set < VisualScript : : DataConnection > : : Element * F = script - > data_connections . front ( ) ; F ; F = F - > next ( ) ) {
dc_lut [ F - > get ( ) . to_node ] [ F - > get ( ) . to_port ] = Pair < int , int > ( F - > get ( ) . from_node , F - > get ( ) . from_port ) ;
}
for ( const Set < int > : : Element * F = node_ids . front ( ) ; F ; F = F - > next ( ) ) {
nd_queue . push_back ( F - > get ( ) ) ;
}
List < int > dc_keys ;
while ( ! nd_queue . is_empty ( ) ) {
int ky = nd_queue . front ( ) - > get ( ) ;
dc_lut [ ky ] . get_key_list ( & dc_keys ) ;
for ( const List < int > : : Element * F = dc_keys . front ( ) ; F ; F = F - > next ( ) ) {
VisualScript : : DataConnection dc ;
dc . from_node = dc_lut [ ky ] [ F - > get ( ) ] . first ;
dc . from_port = dc_lut [ ky ] [ F - > get ( ) ] . second ;
dc . to_node = ky ;
dc . to_port = F - > get ( ) ;
dataconns . insert ( dc ) ;
nd_queue . push_back ( dc . from_node ) ;
node_ids . insert ( dc . from_node ) ;
}
dc_keys . clear ( ) ; // Necessary as get_key_list does a push_back not a set.
nd_queue . pop_front ( ) ;
2016-08-06 01:46:45 +00:00
}
}
2020-06-17 15:39:25 +00:00
//Multiple passes are required to set up this complex thing..
//First create the nodes.
for ( const Set < int > : : Element * F = node_ids . front ( ) ; F ; F = F - > next ( ) ) {
Ref < VisualScriptNode > node = script - > nodes [ F - > get ( ) ] . node ;
VisualScriptNodeInstance * instance = node - > instance ( this ) ; // Create instance.
ERR_FAIL_COND ( ! instance ) ;
instance - > base = node . ptr ( ) ;
instance - > id = F - > get ( ) ;
instance - > input_port_count = node - > get_input_value_port_count ( ) ;
2021-04-05 12:02:50 +00:00
instance - > input_ports = nullptr ;
2020-06-17 15:39:25 +00:00
instance - > output_port_count = node - > get_output_value_port_count ( ) ;
2021-04-05 12:02:50 +00:00
instance - > output_ports = nullptr ;
2020-06-17 15:39:25 +00:00
instance - > sequence_output_count = node - > get_output_sequence_port_count ( ) ;
instance - > sequence_index = function . node_count + + ;
2021-04-05 12:02:50 +00:00
instance - > sequence_outputs = nullptr ;
2020-06-17 15:39:25 +00:00
instance - > pass_idx = - 1 ;
if ( instance - > input_port_count ) {
instance - > input_ports = memnew_arr ( int , instance - > input_port_count ) ;
for ( int i = 0 ; i < instance - > input_port_count ; i + + ) {
instance - > input_ports [ i ] = - 1 ; // If not assigned, will become default value.
}
}
2016-08-31 02:44:14 +00:00
2020-06-17 15:39:25 +00:00
if ( instance - > output_port_count ) {
instance - > output_ports = memnew_arr ( int , instance - > output_port_count ) ;
for ( int i = 0 ; i < instance - > output_port_count ; i + + ) {
instance - > output_ports [ i ] = - 1 ; // If not assigned, will output to trash.
}
2020-05-14 14:41:43 +00:00
}
2016-08-28 23:57:27 +00:00
2020-06-17 15:39:25 +00:00
if ( instance - > sequence_output_count ) {
instance - > sequence_outputs = memnew_arr ( VisualScriptNodeInstance * , instance - > sequence_output_count ) ;
for ( int i = 0 ; i < instance - > sequence_output_count ; i + + ) {
2021-04-05 12:02:50 +00:00
instance - > sequence_outputs [ i ] = nullptr ; // If it remains null, flow ends here.
2020-06-17 15:39:25 +00:00
}
2016-08-28 23:57:27 +00:00
}
2020-06-17 15:39:25 +00:00
if ( Object : : cast_to < VisualScriptLocalVar > ( node . ptr ( ) ) | | Object : : cast_to < VisualScriptLocalVarSet > ( * node ) ) {
// Working memory is shared only for this node, for the same variables.
Ref < VisualScriptLocalVar > vslv = node ;
2016-08-28 23:57:27 +00:00
2020-06-17 15:39:25 +00:00
StringName var_name ;
2016-08-06 01:46:45 +00:00
2021-04-05 12:09:59 +00:00
if ( Object : : cast_to < VisualScriptLocalVar > ( * node ) ) {
2020-06-17 15:39:25 +00:00
var_name = String ( Object : : cast_to < VisualScriptLocalVar > ( * node ) - > get_var_name ( ) ) . strip_edges ( ) ;
2021-04-05 12:09:59 +00:00
} else {
2020-06-17 15:39:25 +00:00
var_name = String ( Object : : cast_to < VisualScriptLocalVarSet > ( * node ) - > get_var_name ( ) ) . strip_edges ( ) ;
2021-04-05 12:09:59 +00:00
}
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
if ( ! local_var_indices . has ( var_name ) ) {
local_var_indices [ var_name ] = function . max_stack ;
function . max_stack + + ;
}
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
instance - > working_mem_idx = local_var_indices [ var_name ] ;
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
} else if ( instance - > get_working_memory_size ( ) ) {
instance - > working_mem_idx = function . max_stack ;
function . max_stack + = instance - > get_working_memory_size ( ) ;
} else {
instance - > working_mem_idx = - 1 ; //no working mem
}
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
max_input_args = MAX ( max_input_args , instance - > input_port_count ) ;
max_output_args = MAX ( max_output_args , instance - > output_port_count ) ;
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
instances [ F - > get ( ) ] = instance ;
2016-08-06 01:46:45 +00:00
}
2020-06-17 15:39:25 +00:00
function . trash_pos = function . max_stack + + ; // create pos for trash
// Second pass, do data connections.
for ( const Set < VisualScript : : DataConnection > : : Element * F = dataconns . front ( ) ; F ; F = F - > next ( ) ) {
VisualScript : : DataConnection dc = F - > get ( ) ;
ERR_CONTINUE ( ! instances . has ( dc . from_node ) ) ;
VisualScriptNodeInstance * from = instances [ dc . from_node ] ;
ERR_CONTINUE ( ! instances . has ( dc . to_node ) ) ;
VisualScriptNodeInstance * to = instances [ dc . to_node ] ;
ERR_CONTINUE ( dc . from_port > = from - > output_port_count ) ;
ERR_CONTINUE ( dc . to_port > = to - > input_port_count ) ;
if ( from - > output_ports [ dc . from_port ] = = - 1 ) {
int stack_pos = function . max_stack + + ;
from - > output_ports [ dc . from_port ] = stack_pos ;
2016-08-31 02:44:14 +00:00
}
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
if ( from - > get_sequence_output_count ( ) = = 0 & & to - > dependencies . find ( from ) = = - 1 ) {
// If the node we are reading from has no output sequence, we must call step() before reading from it.
if ( from - > pass_idx = = - 1 ) {
from - > pass_idx = function . pass_stack_size ;
function . pass_stack_size + + ;
}
to - > dependencies . push_back ( from ) ;
}
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
to - > input_ports [ dc . to_port ] = from - > output_ports [ dc . from_port ] ; // Read from wherever the stack is.
}
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
// Third pass, do sequence connections.
for ( const Set < VisualScript : : SequenceConnection > : : Element * F = seqconns . front ( ) ; F ; F = F - > next ( ) ) {
VisualScript : : SequenceConnection sc = F - > get ( ) ;
ERR_CONTINUE ( ! instances . has ( sc . from_node ) ) ;
VisualScriptNodeInstance * from = instances [ sc . from_node ] ;
ERR_CONTINUE ( ! instances . has ( sc . to_node ) ) ;
VisualScriptNodeInstance * to = instances [ sc . to_node ] ;
ERR_CONTINUE ( sc . from_output > = from - > sequence_output_count ) ;
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
from - > sequence_outputs [ sc . from_output ] = to ;
}
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
//fourth pass:
// 1) unassigned input ports to default values
// 2) connect unassigned output ports to trash
for ( const Set < int > : : Element * F = node_ids . front ( ) ; F ; F = F - > next ( ) ) {
ERR_CONTINUE ( ! instances . has ( F - > get ( ) ) ) ;
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
Ref < VisualScriptNode > node = script - > nodes [ F - > get ( ) ] . node ;
VisualScriptNodeInstance * instance = instances [ F - > get ( ) ] ;
2016-08-06 01:46:45 +00:00
2020-06-17 15:39:25 +00:00
// Connect to default values.
for ( int i = 0 ; i < instance - > input_port_count ; i + + ) {
if ( instance - > input_ports [ i ] = = - 1 ) {
// Unassigned, connect to default val.
instance - > input_ports [ i ] = default_values . size ( ) | VisualScriptNodeInstance : : INPUT_DEFAULT_VALUE_BIT ;
default_values . push_back ( node - > get_default_input_value ( i ) ) ;
}
2016-08-06 01:46:45 +00:00
}
2020-06-17 15:39:25 +00:00
// Connect to trash.
for ( int i = 0 ; i < instance - > output_port_count ; i + + ) {
if ( instance - > output_ports [ i ] = = - 1 ) {
instance - > output_ports [ i ] = function . trash_pos ; //trash is same for all
}
2016-08-06 01:46:45 +00:00
}
}
2020-06-17 15:39:25 +00:00
functions [ E - > get ( ) ] = function ;
}
2016-08-06 01:46:45 +00:00
}
}
2017-03-05 15:44:50 +00:00
ScriptLanguage * VisualScriptInstance : : get_language ( ) {
2016-08-06 01:46:45 +00:00
return VisualScriptLanguage : : singleton ;
}
VisualScriptInstance : : VisualScriptInstance ( ) {
}
VisualScriptInstance : : ~ VisualScriptInstance ( ) {
2020-02-26 10:28:13 +00:00
{
MutexLock lock ( VisualScriptLanguage : : singleton - > lock ) ;
2016-08-06 01:46:45 +00:00
2020-02-26 10:28:13 +00:00
script - > instances . erase ( owner ) ;
}
2016-08-06 01:46:45 +00:00
2017-03-05 15:44:50 +00:00
for ( Map < int , VisualScriptNodeInstance * > : : Element * E = instances . front ( ) ; E ; E = E - > next ( ) ) {
2016-08-06 01:46:45 +00:00
memdelete ( E - > get ( ) ) ;
}
}
2016-08-07 22:22:33 +00:00
/////////////////////////////////////////////
/////////////////////
2020-02-19 19:27:19 +00:00
Variant VisualScriptFunctionState : : _signal_callback ( const Variant * * p_args , int p_argcount , Callable : : CallError & r_error ) {
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( function = = StringName ( ) , Variant ( ) ) ;
2016-08-07 22:22:33 +00:00
# ifdef DEBUG_ENABLED
2020-02-12 17:24:06 +00:00
ERR_FAIL_COND_V_MSG ( instance_id . is_valid ( ) & & ! ObjectDB : : get_instance ( instance_id ) , Variant ( ) , " Resumed after yield, but class instance is gone. " ) ;
ERR_FAIL_COND_V_MSG ( script_id . is_valid ( ) & & ! ObjectDB : : get_instance ( script_id ) , Variant ( ) , " Resumed after yield, but script is gone. " ) ;
2019-08-11 08:49:53 +00:00
2016-08-07 22:22:33 +00:00
# endif
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_OK ;
2016-08-07 22:22:33 +00:00
Array args ;
2017-03-05 15:44:50 +00:00
if ( p_argcount = = 0 ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
2017-03-05 15:44:50 +00:00
r_error . argument = 1 ;
2016-08-07 22:22:33 +00:00
return Variant ( ) ;
2017-03-05 15:44:50 +00:00
} else if ( p_argcount = = 1 ) {
2016-08-07 22:22:33 +00:00
//noooneee, reserved for me, me and only me.
} else {
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_argcount - 1 ; i + + ) {
2016-08-07 22:22:33 +00:00
args . push_back ( * p_args [ i ] ) ;
}
}
2017-03-05 15:44:50 +00:00
Ref < VisualScriptFunctionState > self = * p_args [ p_argcount - 1 ] ; //hi, I'm myself, needed this to remain alive.
2016-08-07 22:22:33 +00:00
if ( self . is_null ( ) ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
2017-03-05 15:44:50 +00:00
r_error . argument = p_argcount - 1 ;
r_error . expected = Variant : : OBJECT ;
2016-08-07 22:22:33 +00:00
return Variant ( ) ;
}
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_OK ;
2016-08-07 22:22:33 +00:00
2017-03-05 15:44:50 +00:00
Variant * working_mem = ( ( Variant * ) stack . ptr ( ) ) + working_mem_index ;
2016-08-07 22:22:33 +00:00
2020-06-17 15:39:25 +00:00
* working_mem = args ; // Arguments go to working mem.
2016-08-07 22:22:33 +00:00
2017-11-25 03:07:54 +00:00
Variant ret = instance - > _call_internal ( function , stack . ptrw ( ) , stack . size ( ) , node , flow_stack_pos , pass , true , r_error ) ;
2017-03-05 15:44:50 +00:00
function = StringName ( ) ; //invalidate
2016-08-07 22:22:33 +00:00
return ret ;
}
2017-03-05 15:44:50 +00:00
void VisualScriptFunctionState : : connect_to_signal ( Object * p_obj , const String & p_signal , Array p_binds ) {
2021-04-03 10:13:26 +00:00
ERR_FAIL_NULL ( p_obj ) ;
2016-08-07 22:22:33 +00:00
Vector < Variant > binds ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_binds . size ( ) ; i + + ) {
2016-08-07 22:22:33 +00:00
binds . push_back ( p_binds [ i ] ) ;
}
binds . push_back ( Ref < VisualScriptFunctionState > ( this ) ) ; //add myself on the back to avoid dying from unreferencing
2020-12-05 21:01:27 +00:00
p_obj - > connect ( p_signal , Callable ( this , " _signal_callback " ) , binds , CONNECT_ONESHOT ) ;
2016-08-07 22:22:33 +00:00
}
bool VisualScriptFunctionState : : is_valid ( ) const {
2017-03-05 15:44:50 +00:00
return function ! = StringName ( ) ;
2016-08-07 22:22:33 +00:00
}
Variant VisualScriptFunctionState : : resume ( Array p_args ) {
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( function = = StringName ( ) , Variant ( ) ) ;
2016-08-07 22:22:33 +00:00
# ifdef DEBUG_ENABLED
2020-02-12 17:24:06 +00:00
ERR_FAIL_COND_V_MSG ( instance_id . is_valid ( ) & & ! ObjectDB : : get_instance ( instance_id ) , Variant ( ) , " Resumed after yield, but class instance is gone. " ) ;
ERR_FAIL_COND_V_MSG ( script_id . is_valid ( ) & & ! ObjectDB : : get_instance ( script_id ) , Variant ( ) , " Resumed after yield, but script is gone. " ) ;
2019-08-11 08:49:53 +00:00
2016-08-07 22:22:33 +00:00
# endif
2020-02-19 19:27:19 +00:00
Callable : : CallError r_error ;
r_error . error = Callable : : CallError : : CALL_OK ;
2016-08-07 22:22:33 +00:00
2017-03-05 15:44:50 +00:00
Variant * working_mem = ( ( Variant * ) stack . ptr ( ) ) + working_mem_index ;
2016-08-07 22:22:33 +00:00
2020-06-17 15:39:25 +00:00
* working_mem = p_args ; // Arguments go to working mem.
2016-08-07 22:22:33 +00:00
2017-11-25 03:07:54 +00:00
Variant ret = instance - > _call_internal ( function , stack . ptrw ( ) , stack . size ( ) , node , flow_stack_pos , pass , true , r_error ) ;
2017-03-05 15:44:50 +00:00
function = StringName ( ) ; //invalidate
2016-08-07 22:22:33 +00:00
return ret ;
}
void VisualScriptFunctionState : : _bind_methods ( ) {
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " connect_to_signal " , " obj " , " signals " , " args " ) , & VisualScriptFunctionState : : connect_to_signal ) ;
2021-06-14 14:26:17 +00:00
ClassDB : : bind_method ( D_METHOD ( " resume " , " args " ) , & VisualScriptFunctionState : : resume , DEFVAL ( Array ( ) ) ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " is_valid " ) , & VisualScriptFunctionState : : is_valid ) ;
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " _signal_callback " , & VisualScriptFunctionState : : _signal_callback , MethodInfo ( " _signal_callback " ) ) ;
2016-08-07 22:22:33 +00:00
}
VisualScriptFunctionState : : VisualScriptFunctionState ( ) {
}
VisualScriptFunctionState : : ~ VisualScriptFunctionState ( ) {
2017-03-05 15:44:50 +00:00
if ( function ! = StringName ( ) ) {
Variant * s = ( ( Variant * ) stack . ptr ( ) ) ;
for ( int i = 0 ; i < variant_stack_size ; i + + ) {
2016-08-07 22:22:33 +00:00
s [ i ] . ~ Variant ( ) ;
}
}
}
2016-08-06 01:46:45 +00:00
///////////////////////////////////////////////
2016-08-02 22:11:05 +00:00
String VisualScriptLanguage : : get_name ( ) const {
return " VisualScript " ;
}
/* LANGUAGE FUNCTIONS */
void VisualScriptLanguage : : init ( ) {
}
2020-05-14 12:29:06 +00:00
2016-08-02 22:11:05 +00:00
String VisualScriptLanguage : : get_type ( ) const {
return " VisualScript " ;
}
2020-05-14 12:29:06 +00:00
2016-08-02 22:11:05 +00:00
String VisualScriptLanguage : : get_extension ( ) const {
return " vs " ;
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
Error VisualScriptLanguage : : execute_file ( const String & p_path ) {
2016-08-02 22:11:05 +00:00
return OK ;
}
2020-05-14 12:29:06 +00:00
2016-08-02 22:11:05 +00:00
void VisualScriptLanguage : : finish ( ) {
}
/* EDITOR FUNCTIONS */
void VisualScriptLanguage : : get_reserved_words ( List < String > * p_words ) const {
}
2020-05-14 12:29:06 +00:00
2021-04-08 14:12:22 +00:00
bool VisualScriptLanguage : : is_control_flow_keyword ( String p_keyword ) const {
return false ;
}
2016-08-02 22:11:05 +00:00
void VisualScriptLanguage : : get_comment_delimiters ( List < String > * p_delimiters ) const {
}
2020-05-14 12:29:06 +00:00
2016-08-02 22:11:05 +00:00
void VisualScriptLanguage : : get_string_delimiters ( List < String > * p_delimiters ) const {
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
Ref < Script > VisualScriptLanguage : : get_template ( const String & p_class_name , const String & p_base_class_name ) const {
2016-08-06 01:46:45 +00:00
Ref < VisualScript > script ;
script . instance ( ) ;
script - > set_instance_base_type ( p_base_class_name ) ;
return script ;
2016-08-02 22:11:05 +00:00
}
2017-06-13 20:03:08 +00:00
bool VisualScriptLanguage : : is_using_templates ( ) {
return true ;
}
void VisualScriptLanguage : : make_template ( const String & p_class_name , const String & p_base_class_name , Ref < Script > & p_script ) {
Ref < VisualScript > script = p_script ;
script - > set_instance_base_type ( p_base_class_name ) ;
}
2018-07-01 16:17:40 +00:00
bool VisualScriptLanguage : : validate ( const String & p_script , int & r_line_error , int & r_col_error , String & r_test_error , const String & p_path , List < String > * r_functions , List < ScriptLanguage : : Warning > * r_warnings , Set < int > * r_safe_lines ) const {
2016-08-02 22:11:05 +00:00
return false ;
}
2020-05-14 12:29:06 +00:00
2016-08-02 22:11:05 +00:00
Script * VisualScriptLanguage : : create_script ( ) const {
2017-03-05 15:44:50 +00:00
return memnew ( VisualScript ) ;
2016-08-02 22:11:05 +00:00
}
2020-05-14 12:29:06 +00:00
2016-08-02 22:11:05 +00:00
bool VisualScriptLanguage : : has_named_classes ( ) const {
return false ;
}
2020-05-14 12:29:06 +00:00
2017-10-23 23:54:47 +00:00
bool VisualScriptLanguage : : supports_builtin_mode ( ) const {
return true ;
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
int VisualScriptLanguage : : find_function ( const String & p_function , const String & p_code ) const {
2016-08-02 22:11:05 +00:00
return - 1 ;
}
2020-05-14 12:29:06 +00:00
2020-02-17 21:06:54 +00:00
String VisualScriptLanguage : : make_function ( const String & p_class , const String & p_name , const PackedStringArray & p_args ) const {
2016-08-02 22:11:05 +00:00
return String ( ) ;
}
2017-03-05 15:44:50 +00:00
void VisualScriptLanguage : : auto_indent_code ( String & p_code , int p_from_line , int p_to_line ) const {
2016-08-02 22:11:05 +00:00
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
void VisualScriptLanguage : : add_global_constant ( const StringName & p_variable , const Variant & p_value ) {
2016-08-02 22:11:05 +00:00
}
/* DEBUGGER FUNCTIONS */
2017-03-05 15:44:50 +00:00
bool VisualScriptLanguage : : debug_break_parse ( const String & p_file , int p_node , const String & p_error ) {
2020-06-17 15:39:25 +00:00
// Break because of parse error.
2016-08-06 22:00:54 +00:00
2020-02-27 02:30:20 +00:00
if ( EngineDebugger : : is_active ( ) & & Thread : : get_caller_id ( ) = = Thread : : get_main_id ( ) ) {
2017-03-05 15:44:50 +00:00
_debug_parse_err_node = p_node ;
_debug_parse_err_file = p_file ;
_debug_error = p_error ;
2020-02-27 02:30:20 +00:00
EngineDebugger : : get_script_debugger ( ) - > debug ( this , false , true ) ;
2017-03-05 15:44:50 +00:00
return true ;
} else {
return false ;
}
2016-08-06 22:00:54 +00:00
}
2017-03-05 15:44:50 +00:00
bool VisualScriptLanguage : : debug_break ( const String & p_error , bool p_allow_continue ) {
2020-02-27 02:30:20 +00:00
if ( EngineDebugger : : is_active ( ) & & Thread : : get_caller_id ( ) = = Thread : : get_main_id ( ) ) {
2017-03-05 15:44:50 +00:00
_debug_parse_err_node = - 1 ;
_debug_parse_err_file = " " ;
_debug_error = p_error ;
2020-02-27 02:30:20 +00:00
EngineDebugger : : get_script_debugger ( ) - > debug ( this , p_allow_continue , true ) ;
2017-03-05 15:44:50 +00:00
return true ;
} else {
return false ;
}
2016-08-06 22:00:54 +00:00
}
2016-08-02 22:11:05 +00:00
String VisualScriptLanguage : : debug_get_error ( ) const {
2017-03-05 15:44:50 +00:00
return _debug_error ;
2016-08-02 22:11:05 +00:00
}
2016-08-06 22:00:54 +00:00
2016-08-02 22:11:05 +00:00
int VisualScriptLanguage : : debug_get_stack_level_count ( ) const {
2020-05-14 14:41:43 +00:00
if ( _debug_parse_err_node > = 0 ) {
2016-08-06 22:00:54 +00:00
return 1 ;
2020-05-14 14:41:43 +00:00
}
2016-08-06 22:00:54 +00:00
return _debug_call_stack_pos ;
2016-08-02 22:11:05 +00:00
}
2020-05-14 12:29:06 +00:00
2016-08-02 22:11:05 +00:00
int VisualScriptLanguage : : debug_get_stack_level_line ( int p_level ) const {
2020-05-14 14:41:43 +00:00
if ( _debug_parse_err_node > = 0 ) {
2016-08-06 22:00:54 +00:00
return _debug_parse_err_node ;
2020-05-14 14:41:43 +00:00
}
2016-08-06 22:00:54 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_INDEX_V ( p_level , _debug_call_stack_pos , - 1 ) ;
2016-08-06 22:00:54 +00:00
2017-03-05 15:44:50 +00:00
int l = _debug_call_stack_pos - p_level - 1 ;
2016-08-06 22:00:54 +00:00
2017-03-05 15:44:50 +00:00
return * ( _call_stack [ l ] . current_id ) ;
2016-08-02 22:11:05 +00:00
}
2020-05-14 12:29:06 +00:00
2016-08-02 22:11:05 +00:00
String VisualScriptLanguage : : debug_get_stack_level_function ( int p_level ) const {
2020-05-14 14:41:43 +00:00
if ( _debug_parse_err_node > = 0 ) {
2016-08-06 22:00:54 +00:00
return " " ;
2020-05-14 14:41:43 +00:00
}
2016-08-06 22:00:54 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_INDEX_V ( p_level , _debug_call_stack_pos , " " ) ;
int l = _debug_call_stack_pos - p_level - 1 ;
return * _call_stack [ l ] . function ;
2016-08-02 22:11:05 +00:00
}
2020-05-14 12:29:06 +00:00
2016-08-02 22:11:05 +00:00
String VisualScriptLanguage : : debug_get_stack_level_source ( int p_level ) const {
2020-05-14 14:41:43 +00:00
if ( _debug_parse_err_node > = 0 ) {
2016-08-06 22:00:54 +00:00
return _debug_parse_err_file ;
2020-05-14 14:41:43 +00:00
}
2016-08-06 22:00:54 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_INDEX_V ( p_level , _debug_call_stack_pos , " " ) ;
int l = _debug_call_stack_pos - p_level - 1 ;
return _call_stack [ l ] . instance - > get_script_ptr ( ) - > get_path ( ) ;
2016-08-02 22:11:05 +00:00
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
void VisualScriptLanguage : : debug_get_stack_level_locals ( int p_level , List < String > * p_locals , List < Variant > * p_values , int p_max_subitems , int p_max_depth ) {
2020-05-14 14:41:43 +00:00
if ( _debug_parse_err_node > = 0 ) {
2016-08-06 22:00:54 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2016-08-06 22:00:54 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_INDEX ( p_level , _debug_call_stack_pos ) ;
2016-08-06 22:00:54 +00:00
2017-03-05 15:44:50 +00:00
int l = _debug_call_stack_pos - p_level - 1 ;
2016-08-06 22:00:54 +00:00
const StringName * f = _call_stack [ l ] . function ;
ERR_FAIL_COND ( ! _call_stack [ l ] . instance - > functions . has ( * f ) ) ;
2017-01-14 11:26:56 +00:00
//VisualScriptInstance::Function *func = &_call_stack[l].instance->functions[*f];
2016-08-06 22:00:54 +00:00
2017-03-05 15:44:50 +00:00
VisualScriptNodeInstance * node = _call_stack [ l ] . instance - > instances [ * _call_stack [ l ] . current_id ] ;
2016-08-06 22:00:54 +00:00
ERR_FAIL_COND ( ! node ) ;
p_locals - > push_back ( " node_name " ) ;
p_values - > push_back ( node - > get_base_node ( ) - > get_text ( ) ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < node - > input_port_count ; i + + ) {
2016-08-06 22:00:54 +00:00
String name = node - > get_base_node ( ) - > get_input_value_port_info ( i ) . name ;
2017-03-05 15:44:50 +00:00
if ( name = = String ( ) ) {
name = " in_ " + itos ( i ) ;
2016-08-06 22:00:54 +00:00
}
2017-03-05 15:44:50 +00:00
p_locals - > push_back ( " input/ " + name ) ;
2016-08-06 22:00:54 +00:00
//value is trickier
int in_from = node - > input_ports [ i ] ;
2017-03-05 15:44:50 +00:00
int in_value = in_from & VisualScriptNodeInstance : : INPUT_MASK ;
2016-08-06 22:00:54 +00:00
2017-03-05 15:44:50 +00:00
if ( in_from & VisualScriptNodeInstance : : INPUT_DEFAULT_VALUE_BIT ) {
2016-08-06 22:00:54 +00:00
p_values - > push_back ( _call_stack [ l ] . instance - > default_values [ in_value ] ) ;
} else {
2017-03-05 15:44:50 +00:00
p_values - > push_back ( _call_stack [ l ] . stack [ in_value ] ) ;
2016-08-06 22:00:54 +00:00
}
}
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < node - > output_port_count ; i + + ) {
2016-08-06 22:00:54 +00:00
String name = node - > get_base_node ( ) - > get_output_value_port_info ( i ) . name ;
2017-03-05 15:44:50 +00:00
if ( name = = String ( ) ) {
name = " out_ " + itos ( i ) ;
2016-08-06 22:00:54 +00:00
}
2016-08-02 22:11:05 +00:00
2017-03-05 15:44:50 +00:00
p_locals - > push_back ( " output/ " + name ) ;
2016-08-06 22:00:54 +00:00
//value is trickier
int in_from = node - > output_ports [ i ] ;
2017-03-05 15:44:50 +00:00
p_values - > push_back ( _call_stack [ l ] . stack [ in_from ] ) ;
2016-08-06 22:00:54 +00:00
}
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < node - > get_working_memory_size ( ) ; i + + ) {
p_locals - > push_back ( " working_mem/mem_ " + itos ( i ) ) ;
p_values - > push_back ( ( * _call_stack [ l ] . work_mem ) [ i ] ) ;
2016-08-06 22:00:54 +00:00
}
2017-03-05 15:44:50 +00:00
/*
2016-08-06 22:00:54 +00:00
ERR_FAIL_INDEX ( p_level , _debug_call_stack_pos ) ;
VisualFunction * f = _call_stack [ l ] . function ;
List < Pair < StringName , int > > locals ;
f - > debug_get_stack_member_state ( * _call_stack [ l ] . line , & locals ) ;
for ( List < Pair < StringName , int > > : : Element * E = locals . front ( ) ; E ; E = E - > next ( ) ) {
p_locals - > push_back ( E - > get ( ) . first ) ;
p_values - > push_back ( _call_stack [ l ] . stack [ E - > get ( ) . second ] ) ;
}
*/
2016-08-02 22:11:05 +00:00
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
void VisualScriptLanguage : : debug_get_stack_level_members ( int p_level , List < String > * p_members , List < Variant > * p_values , int p_max_subitems , int p_max_depth ) {
2020-05-14 14:41:43 +00:00
if ( _debug_parse_err_node > = 0 ) {
2016-08-06 22:00:54 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2016-08-06 22:00:54 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_INDEX ( p_level , _debug_call_stack_pos ) ;
int l = _debug_call_stack_pos - p_level - 1 ;
2016-08-06 22:00:54 +00:00
Ref < VisualScript > vs = _call_stack [ l ] . instance - > get_script ( ) ;
2020-05-14 14:41:43 +00:00
if ( vs . is_null ( ) ) {
2016-08-06 22:00:54 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2016-08-06 22:00:54 +00:00
List < StringName > vars ;
vs - > get_variable_list ( & vars ) ;
2017-03-05 15:44:50 +00:00
for ( List < StringName > : : Element * E = vars . front ( ) ; E ; E = E - > next ( ) ) {
2016-08-06 22:00:54 +00:00
Variant v ;
2017-03-05 15:44:50 +00:00
if ( _call_stack [ l ] . instance - > get_variable ( E - > get ( ) , & v ) ) {
p_members - > push_back ( " variables/ " + E - > get ( ) ) ;
2016-08-06 22:00:54 +00:00
p_values - > push_back ( v ) ;
}
}
2016-08-02 22:11:05 +00:00
}
2017-03-05 15:44:50 +00:00
void VisualScriptLanguage : : debug_get_globals ( List < String > * p_locals , List < Variant > * p_values , int p_max_subitems , int p_max_depth ) {
2020-06-17 15:39:25 +00:00
// No globals are really reachable in gdscript.
2016-08-02 22:11:05 +00:00
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
String VisualScriptLanguage : : debug_parse_stack_level_expression ( int p_level , const String & p_expression , int p_max_subitems , int p_max_depth ) {
2016-08-06 22:00:54 +00:00
return " " ;
2016-08-02 22:11:05 +00:00
}
void VisualScriptLanguage : : reload_all_scripts ( ) {
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
void VisualScriptLanguage : : reload_tool_script ( const Ref < Script > & p_script , bool p_soft_reload ) {
2016-08-02 22:11:05 +00:00
}
2020-05-14 12:29:06 +00:00
2016-08-02 22:11:05 +00:00
/* LOADER FUNCTIONS */
void VisualScriptLanguage : : get_recognized_extensions ( List < String > * p_extensions ) const {
p_extensions - > push_back ( " vs " ) ;
}
2020-05-14 12:29:06 +00:00
2016-08-02 22:11:05 +00:00
void VisualScriptLanguage : : get_public_functions ( List < MethodInfo > * p_functions ) const {
}
2020-05-14 12:29:06 +00:00
2020-03-17 06:33:00 +00:00
void VisualScriptLanguage : : get_public_constants ( List < Pair < String , Variant > > * p_constants ) const {
2016-08-02 22:11:05 +00:00
}
void VisualScriptLanguage : : profiling_start ( ) {
}
2020-05-14 12:29:06 +00:00
2016-08-02 22:11:05 +00:00
void VisualScriptLanguage : : profiling_stop ( ) {
}
2017-03-05 15:44:50 +00:00
int VisualScriptLanguage : : profiling_get_accumulated_data ( ProfilingInfo * p_info_arr , int p_info_max ) {
2016-08-02 22:11:05 +00:00
return 0 ;
}
2017-03-05 15:44:50 +00:00
int VisualScriptLanguage : : profiling_get_frame_data ( ProfilingInfo * p_info_arr , int p_info_max ) {
2016-08-02 22:11:05 +00:00
return 0 ;
}
2020-04-01 23:20:12 +00:00
VisualScriptLanguage * VisualScriptLanguage : : singleton = nullptr ;
2016-08-02 22:11:05 +00:00
2017-03-05 15:44:50 +00:00
void VisualScriptLanguage : : add_register_func ( const String & p_name , VisualScriptNodeRegisterFunc p_func ) {
2016-08-02 22:11:05 +00:00
ERR_FAIL_COND ( register_funcs . has ( p_name ) ) ;
2017-03-05 15:44:50 +00:00
register_funcs [ p_name ] = p_func ;
2016-08-02 22:11:05 +00:00
}
2017-11-15 15:57:24 +00:00
void VisualScriptLanguage : : remove_register_func ( const String & p_name ) {
ERR_FAIL_COND ( ! register_funcs . has ( p_name ) ) ;
register_funcs . erase ( p_name ) ;
}
2017-03-05 15:44:50 +00:00
Ref < VisualScriptNode > VisualScriptLanguage : : create_node_from_name ( const String & p_name ) {
ERR_FAIL_COND_V ( ! register_funcs . has ( p_name ) , Ref < VisualScriptNode > ( ) ) ;
2016-08-02 22:11:05 +00:00
return register_funcs [ p_name ] ( p_name ) ;
}
void VisualScriptLanguage : : get_registered_node_names ( List < String > * r_names ) {
2017-03-05 15:44:50 +00:00
for ( Map < String , VisualScriptNodeRegisterFunc > : : Element * E = register_funcs . front ( ) ; E ; E = E - > next ( ) ) {
2016-08-02 22:11:05 +00:00
r_names - > push_back ( E - > key ( ) ) ;
}
}
VisualScriptLanguage : : VisualScriptLanguage ( ) {
2017-03-05 15:44:50 +00:00
singleton = this ;
2016-08-06 22:00:54 +00:00
2017-07-18 00:05:38 +00:00
int dmcs = GLOBAL_DEF ( " debug/settings/visual_script/max_call_stack " , 1024 ) ;
2018-10-05 16:43:53 +00:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " debug/settings/visual_script/max_call_stack " , PropertyInfo ( Variant : : INT , " debug/settings/visual_script/max_call_stack " , PROPERTY_HINT_RANGE , " 1024,4096,1,or_greater " ) ) ; //minimum is 1024
2020-02-27 02:30:20 +00:00
if ( EngineDebugger : : is_active ( ) ) {
2020-06-17 15:39:25 +00:00
// Debugging enabled!
2016-08-06 22:00:54 +00:00
_debug_max_call_stack = dmcs ;
2017-03-05 15:44:50 +00:00
_call_stack = memnew_arr ( CallLevel , _debug_max_call_stack + 1 ) ;
2016-08-06 22:00:54 +00:00
} else {
2017-03-05 15:44:50 +00:00
_debug_max_call_stack = 0 ;
2020-04-01 23:20:12 +00:00
_call_stack = nullptr ;
2016-08-06 22:00:54 +00:00
}
2016-08-06 01:46:45 +00:00
}
VisualScriptLanguage : : ~ VisualScriptLanguage ( ) {
2017-03-05 15:44:50 +00:00
if ( _call_stack ) {
2016-08-06 22:00:54 +00:00
memdelete_arr ( _call_stack ) ;
}
2020-04-01 23:20:12 +00:00
singleton = nullptr ;
2016-08-02 22:11:05 +00:00
}