2014-02-09 22:10:30 -03:00
/**************************************************************************/
/* script_language.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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-05 00:50:27 +01:00
2014-02-09 22:10:30 -03:00
# include "script_language.h"
2018-09-11 18:13:45 +02:00
2020-11-07 19:33:38 -03:00
# include "core/config/project_settings.h"
2020-02-27 03:30:20 +01:00
# include "core/debugger/engine_debugger.h"
# include "core/debugger/script_debugger.h"
2024-03-07 20:19:05 +01:00
# include "core/io/resource_loader.h"
2020-05-12 17:01:17 +02:00
2020-02-12 11:51:50 +01:00
# include <stdint.h>
2014-02-09 22:10:30 -03:00
ScriptLanguage * ScriptServer : : _languages [ MAX_LANGUAGES ] ;
int ScriptServer : : _language_count = 0 ;
2023-11-09 12:29:47 +01:00
bool ScriptServer : : languages_ready = false ;
Mutex ScriptServer : : languages_mutex ;
2014-02-09 22:10:30 -03:00
bool ScriptServer : : scripting_enabled = true ;
2016-06-13 10:58:32 -03:00
bool ScriptServer : : reload_scripts_on_save = false ;
2020-04-02 01:20:12 +02:00
ScriptEditRequestFunction ScriptServer : : edit_request_func = nullptr ;
2014-02-09 22:10:30 -03:00
void Script : : _notification ( int p_what ) {
2022-02-16 00:52:32 +01:00
switch ( p_what ) {
case NOTIFICATION_POSTINITIALIZE : {
if ( EngineDebugger : : is_active ( ) ) {
2024-04-16 20:01:53 -04:00
callable_mp ( this , & Script : : _set_debugger_break_language ) . call_deferred ( ) ;
2022-02-16 00:52:32 +01:00
}
} break ;
2014-02-09 22:10:30 -03:00
}
}
2019-08-01 14:13:40 -05:00
Variant Script : : _get_property_default_value ( const StringName & p_property ) {
Variant ret ;
get_property_default_value ( p_property , ret ) ;
return ret ;
}
2022-08-05 20:35:08 +02:00
TypedArray < Dictionary > Script : : _get_script_property_list ( ) {
TypedArray < Dictionary > ret ;
2019-08-01 14:13:40 -05:00
List < PropertyInfo > list ;
get_script_property_list ( & list ) ;
2021-07-24 15:46:25 +02:00
for ( const PropertyInfo & E : list ) {
2021-07-15 23:45:57 -04:00
ret . append ( E . operator Dictionary ( ) ) ;
2019-08-01 14:13:40 -05:00
}
return ret ;
}
2022-08-05 20:35:08 +02:00
TypedArray < Dictionary > Script : : _get_script_method_list ( ) {
TypedArray < Dictionary > ret ;
2019-08-01 14:13:40 -05:00
List < MethodInfo > list ;
get_script_method_list ( & list ) ;
2021-07-24 15:46:25 +02:00
for ( const MethodInfo & E : list ) {
2021-07-15 23:45:57 -04:00
ret . append ( E . operator Dictionary ( ) ) ;
2019-08-01 14:13:40 -05:00
}
return ret ;
}
2022-08-05 20:35:08 +02:00
TypedArray < Dictionary > Script : : _get_script_signal_list ( ) {
TypedArray < Dictionary > ret ;
2019-08-01 14:13:40 -05:00
List < MethodInfo > list ;
get_script_signal_list ( & list ) ;
2021-07-24 15:46:25 +02:00
for ( const MethodInfo & E : list ) {
2021-07-15 23:45:57 -04:00
ret . append ( E . operator Dictionary ( ) ) ;
2019-08-01 14:13:40 -05:00
}
return ret ;
}
Dictionary Script : : _get_script_constant_map ( ) {
Dictionary ret ;
2022-05-13 15:04:37 +02:00
HashMap < StringName , Variant > map ;
2019-08-01 14:13:40 -05:00
get_constants ( & map ) ;
2021-08-09 14:13:42 -06:00
for ( const KeyValue < StringName , Variant > & E : map ) {
ret [ E . key ] = E . value ;
2019-08-01 14:13:40 -05:00
}
return ret ;
}
2024-04-16 20:01:53 -04:00
void Script : : _set_debugger_break_language ( ) {
if ( EngineDebugger : : is_active ( ) ) {
EngineDebugger : : get_script_debugger ( ) - > set_break_language ( get_language ( ) ) ;
}
}
2024-01-28 15:16:09 +01:00
int Script : : get_script_method_argument_count ( const StringName & p_method , bool * r_is_valid ) const {
MethodInfo mi = get_method_info ( p_method ) ;
if ( mi = = MethodInfo ( ) ) {
if ( r_is_valid ) {
* r_is_valid = false ;
}
return 0 ;
}
if ( r_is_valid ) {
* r_is_valid = true ;
}
return mi . arguments . size ( ) ;
}
2022-07-31 11:07:48 +03:00
# ifdef TOOLS_ENABLED
PropertyInfo Script : : get_class_category ( ) const {
String path = get_path ( ) ;
2022-09-29 12:53:28 +03:00
String scr_name ;
2022-07-31 11:07:48 +03:00
if ( is_built_in ( ) ) {
if ( get_name ( ) . is_empty ( ) ) {
2022-09-29 12:53:28 +03:00
scr_name = TTR ( " Built-in script " ) ;
2022-07-31 11:07:48 +03:00
} else {
2022-09-29 12:53:28 +03:00
scr_name = vformat ( " %s (%s) " , get_name ( ) , TTR ( " Built-in " ) ) ;
2022-07-31 11:07:48 +03:00
}
} else {
if ( get_name ( ) . is_empty ( ) ) {
2022-09-29 12:53:28 +03:00
scr_name = path . get_file ( ) ;
2022-07-31 11:07:48 +03:00
} else {
2022-09-29 12:53:28 +03:00
scr_name = get_name ( ) ;
2022-07-31 11:07:48 +03:00
}
}
2022-09-29 12:53:28 +03:00
return PropertyInfo ( Variant : : NIL , scr_name , PROPERTY_HINT_NONE , path , PROPERTY_USAGE_CATEGORY ) ;
2022-07-31 11:07:48 +03:00
}
# endif // TOOLS_ENABLED
2014-02-09 22:10:30 -03:00
void Script : : _bind_methods ( ) {
2021-06-17 16:03:09 -06:00
ClassDB : : bind_method ( D_METHOD ( " can_instantiate " ) , & Script : : can_instantiate ) ;
2017-02-13 12:47:24 +01:00
//ClassDB::bind_method(D_METHOD("instance_create","base_object"),&Script::instance_create);
ClassDB : : bind_method ( D_METHOD ( " instance_has " , " base_object " ) , & Script : : instance_has ) ;
ClassDB : : bind_method ( D_METHOD ( " has_source_code " ) , & Script : : has_source_code ) ;
ClassDB : : bind_method ( D_METHOD ( " get_source_code " ) , & Script : : get_source_code ) ;
ClassDB : : bind_method ( D_METHOD ( " set_source_code " , " source " ) , & Script : : set_source_code ) ;
ClassDB : : bind_method ( D_METHOD ( " reload " , " keep_state " ) , & Script : : reload , DEFVAL ( false ) ) ;
2017-12-19 06:55:55 -06:00
ClassDB : : bind_method ( D_METHOD ( " get_base_script " ) , & Script : : get_base_script ) ;
ClassDB : : bind_method ( D_METHOD ( " get_instance_base_type " ) , & Script : : get_instance_base_type ) ;
2017-08-29 14:33:27 -03:00
2023-12-18 14:56:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_global_name " ) , & Script : : get_global_name ) ;
2017-08-29 14:33:27 -03:00
ClassDB : : bind_method ( D_METHOD ( " has_script_signal " , " signal_name " ) , & Script : : has_script_signal ) ;
2019-08-01 14:13:40 -05:00
ClassDB : : bind_method ( D_METHOD ( " get_script_property_list " ) , & Script : : _get_script_property_list ) ;
ClassDB : : bind_method ( D_METHOD ( " get_script_method_list " ) , & Script : : _get_script_method_list ) ;
ClassDB : : bind_method ( D_METHOD ( " get_script_signal_list " ) , & Script : : _get_script_signal_list ) ;
ClassDB : : bind_method ( D_METHOD ( " get_script_constant_map " ) , & Script : : _get_script_constant_map ) ;
2019-09-24 11:44:48 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_property_default_value " , " property " ) , & Script : : _get_property_default_value ) ;
2019-08-01 14:13:40 -05:00
2017-08-29 14:33:27 -03:00
ClassDB : : bind_method ( D_METHOD ( " is_tool " ) , & Script : : is_tool ) ;
2023-05-23 09:25:34 -07:00
ClassDB : : bind_method ( D_METHOD ( " is_abstract " ) , & Script : : is_abstract ) ;
2018-01-12 00:35:12 +02:00
2021-06-17 19:10:18 -04:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " source_code " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NONE ) , " set_source_code " , " get_source_code " ) ;
2014-02-09 22:10:30 -03:00
}
2024-03-07 20:19:05 +01:00
void Script : : reload_from_file ( ) {
# ifdef TOOLS_ENABLED
// Replicates how the ScriptEditor reloads script resources, which generally handles it.
// However, when scripts are to be reloaded but aren't open in the internal editor, we go through here instead.
const Ref < Script > rel = ResourceLoader : : load ( ResourceLoader : : path_remap ( get_path ( ) ) , get_class ( ) , ResourceFormatLoader : : CACHE_MODE_IGNORE ) ;
if ( rel . is_null ( ) ) {
return ;
}
set_source_code ( rel - > get_source_code ( ) ) ;
set_last_modified_time ( rel - > get_last_modified_time ( ) ) ;
reload ( ) ;
# else
Resource : : reload_from_file ( ) ;
# endif
}
2014-02-09 22:10:30 -03:00
void ScriptServer : : set_scripting_enabled ( bool p_enabled ) {
scripting_enabled = p_enabled ;
}
bool ScriptServer : : is_scripting_enabled ( ) {
return scripting_enabled ;
}
ScriptLanguage * ScriptServer : : get_language ( int p_idx ) {
2023-11-09 12:29:47 +01:00
MutexLock lock ( languages_mutex ) ;
2020-04-02 01:20:12 +02:00
ERR_FAIL_INDEX_V ( p_idx , _language_count , nullptr ) ;
2014-02-09 22:10:30 -03:00
return _languages [ p_idx ] ;
}
2024-01-26 13:03:32 +01:00
ScriptLanguage * ScriptServer : : get_language_for_extension ( const String & p_extension ) {
MutexLock lock ( languages_mutex ) ;
for ( int i = 0 ; i < _language_count ; i + + ) {
if ( _languages [ i ] & & _languages [ i ] - > get_extension ( ) = = p_extension ) {
return _languages [ i ] ;
}
}
return nullptr ;
}
2022-10-09 22:03:59 +02:00
Error ScriptServer : : register_language ( ScriptLanguage * p_language ) {
2023-11-09 12:29:47 +01:00
MutexLock lock ( languages_mutex ) ;
2022-10-09 22:03:59 +02:00
ERR_FAIL_NULL_V ( p_language , ERR_INVALID_PARAMETER ) ;
ERR_FAIL_COND_V_MSG ( _language_count > = MAX_LANGUAGES , ERR_UNAVAILABLE , " Script languages limit has been reach, cannot register more. " ) ;
for ( int i = 0 ; i < _language_count ; i + + ) {
const ScriptLanguage * other_language = _languages [ i ] ;
ERR_FAIL_COND_V_MSG ( other_language - > get_extension ( ) = = p_language - > get_extension ( ) , ERR_ALREADY_EXISTS , " A script language with extension ' " + p_language - > get_extension ( ) + " ' is already registered. " ) ;
ERR_FAIL_COND_V_MSG ( other_language - > get_name ( ) = = p_language - > get_name ( ) , ERR_ALREADY_EXISTS , " A script language with name ' " + p_language - > get_name ( ) + " ' is already registered. " ) ;
ERR_FAIL_COND_V_MSG ( other_language - > get_type ( ) = = p_language - > get_type ( ) , ERR_ALREADY_EXISTS , " A script language with type ' " + p_language - > get_type ( ) + " ' is already registered. " ) ;
}
2014-02-09 22:10:30 -03:00
_languages [ _language_count + + ] = p_language ;
2022-10-09 22:03:59 +02:00
return OK ;
2014-02-09 22:10:30 -03:00
}
2022-10-09 22:03:59 +02:00
Error ScriptServer : : unregister_language ( const ScriptLanguage * p_language ) {
2023-11-09 12:29:47 +01:00
MutexLock lock ( languages_mutex ) ;
2016-06-26 10:53:34 -03:00
for ( int i = 0 ; i < _language_count ; i + + ) {
if ( _languages [ i ] = = p_language ) {
_language_count - - ;
if ( i < _language_count ) {
SWAP ( _languages [ i ] , _languages [ _language_count ] ) ;
}
2022-10-09 22:03:59 +02:00
return OK ;
2016-06-26 10:53:34 -03:00
}
}
2022-10-09 22:03:59 +02:00
return ERR_DOES_NOT_EXIST ;
2016-06-26 10:53:34 -03:00
}
2014-11-13 00:53:12 -03:00
void ScriptServer : : init_languages ( ) {
2022-10-18 16:43:37 +02:00
{ // Load global classes.
2018-07-15 19:29:00 -03:00
global_classes_clear ( ) ;
2022-12-25 15:08:32 +01:00
# ifndef DISABLE_DEPRECATED
2018-07-15 19:29:00 -03:00
if ( ProjectSettings : : get_singleton ( ) - > has_setting ( " _global_script_classes " ) ) {
2022-10-18 16:43:37 +02:00
Array script_classes = GLOBAL_GET ( " _global_script_classes " ) ;
2018-07-15 19:29:00 -03:00
2023-12-24 13:44:21 +01:00
for ( const Variant & script_class : script_classes ) {
Dictionary c = script_class ;
2020-08-25 13:01:55 +02:00
if ( ! c . has ( " class " ) | | ! c . has ( " language " ) | | ! c . has ( " path " ) | | ! c . has ( " base " ) ) {
2018-07-15 19:29:00 -03:00
continue ;
2020-05-14 16:41:43 +02:00
}
2018-07-15 19:29:00 -03:00
add_global_class ( c [ " class " ] , c [ " base " ] , c [ " language " ] , c [ " path " ] ) ;
}
2022-12-25 15:08:32 +01:00
ProjectSettings : : get_singleton ( ) - > clear ( " _global_script_classes " ) ;
}
# endif
Array script_classes = ProjectSettings : : get_singleton ( ) - > get_global_class_list ( ) ;
2023-12-24 13:44:21 +01:00
for ( const Variant & script_class : script_classes ) {
Dictionary c = script_class ;
2022-12-25 15:08:32 +01:00
if ( ! c . has ( " class " ) | | ! c . has ( " language " ) | | ! c . has ( " path " ) | | ! c . has ( " base " ) ) {
continue ;
}
add_global_class ( c [ " class " ] , c [ " base " ] , c [ " language " ] , c [ " path " ] ) ;
2018-07-15 19:29:00 -03:00
}
}
2023-11-13 16:06:48 +01:00
HashSet < ScriptLanguage * > langs_to_init ;
2023-11-09 12:29:47 +01:00
{
MutexLock lock ( languages_mutex ) ;
for ( int i = 0 ; i < _language_count ; i + + ) {
2023-11-13 16:06:48 +01:00
if ( _languages [ i ] ) {
langs_to_init . insert ( _languages [ i ] ) ;
}
2023-11-09 12:29:47 +01:00
}
2023-11-13 16:06:48 +01:00
}
2023-11-09 12:29:47 +01:00
2023-11-13 16:06:48 +01:00
for ( ScriptLanguage * E : langs_to_init ) {
E - > init ( ) ;
}
{
MutexLock lock ( languages_mutex ) ;
2023-11-09 12:29:47 +01:00
languages_ready = true ;
2014-11-13 00:53:12 -03:00
}
}
2017-07-22 16:11:04 -03:00
void ScriptServer : : finish_languages ( ) {
2023-11-13 16:06:48 +01:00
HashSet < ScriptLanguage * > langs_to_finish ;
2023-11-09 12:29:47 +01:00
2023-11-13 16:06:48 +01:00
{
MutexLock lock ( languages_mutex ) ;
for ( int i = 0 ; i < _language_count ; i + + ) {
if ( _languages [ i ] ) {
langs_to_finish . insert ( _languages [ i ] ) ;
}
}
2017-07-22 16:11:04 -03:00
}
2023-11-09 12:29:47 +01:00
2023-11-13 16:06:48 +01:00
for ( ScriptLanguage * E : langs_to_finish ) {
E - > finish ( ) ;
}
{
MutexLock lock ( languages_mutex ) ;
languages_ready = false ;
}
global_classes_clear ( ) ;
2023-11-09 12:29:47 +01:00
}
bool ScriptServer : : are_languages_initialized ( ) {
MutexLock lock ( languages_mutex ) ;
return languages_ready ;
2017-07-22 16:11:04 -03:00
}
2016-06-13 10:58:32 -03:00
void ScriptServer : : set_reload_scripts_on_save ( bool p_enable ) {
reload_scripts_on_save = p_enable ;
}
bool ScriptServer : : is_reload_scripts_on_save_enabled ( ) {
return reload_scripts_on_save ;
}
2016-06-25 10:40:33 -03:00
void ScriptServer : : thread_enter ( ) {
2023-11-09 12:29:47 +01:00
MutexLock lock ( languages_mutex ) ;
if ( ! languages_ready ) {
2023-04-29 13:54:52 -04:00
return ;
}
2016-06-25 10:40:33 -03:00
for ( int i = 0 ; i < _language_count ; i + + ) {
_languages [ i ] - > thread_enter ( ) ;
}
}
void ScriptServer : : thread_exit ( ) {
2023-11-09 12:29:47 +01:00
MutexLock lock ( languages_mutex ) ;
if ( ! languages_ready ) {
2023-04-29 13:54:52 -04:00
return ;
}
2016-06-25 10:40:33 -03:00
for ( int i = 0 ; i < _language_count ; i + + ) {
_languages [ i ] - > thread_exit ( ) ;
}
}
2018-07-15 19:29:00 -03:00
HashMap < StringName , ScriptServer : : GlobalScriptClass > ScriptServer : : global_classes ;
2023-01-19 16:47:01 +01:00
HashMap < StringName , Vector < StringName > > ScriptServer : : inheriters_cache ;
bool ScriptServer : : inheriters_cache_dirty = true ;
2018-07-15 19:29:00 -03:00
void ScriptServer : : global_classes_clear ( ) {
global_classes . clear ( ) ;
2023-01-19 16:47:01 +01:00
inheriters_cache . clear ( ) ;
2018-07-15 19:29:00 -03:00
}
void ScriptServer : : add_global_class ( const StringName & p_class , const StringName & p_base , const StringName & p_language , const String & p_path ) {
2019-10-07 12:05:39 +02:00
ERR_FAIL_COND_MSG ( p_class = = p_base | | ( global_classes . has ( p_base ) & & get_global_class_native_base ( p_base ) = = p_class ) , " Cyclic inheritance in script class. " ) ;
2024-03-06 12:14:21 -05:00
GlobalScriptClass * existing = global_classes . getptr ( p_class ) ;
if ( existing ) {
// Update an existing class (only set dirty if something changed).
if ( existing - > base ! = p_base | | existing - > path ! = p_path | | existing - > language ! = p_language ) {
existing - > base = p_base ;
existing - > path = p_path ;
existing - > language = p_language ;
inheriters_cache_dirty = true ;
}
} else {
// Add new class.
GlobalScriptClass g ;
g . language = p_language ;
g . path = p_path ;
g . base = p_base ;
global_classes [ p_class ] = g ;
inheriters_cache_dirty = true ;
}
2018-07-15 19:29:00 -03:00
}
2020-05-14 14:29:06 +02:00
2018-07-15 19:29:00 -03:00
void ScriptServer : : remove_global_class ( const StringName & p_class ) {
global_classes . erase ( p_class ) ;
2023-01-19 16:47:01 +01:00
inheriters_cache_dirty = true ;
}
void ScriptServer : : get_inheriters_list ( const StringName & p_base_type , List < StringName > * r_classes ) {
if ( inheriters_cache_dirty ) {
inheriters_cache . clear ( ) ;
for ( const KeyValue < StringName , GlobalScriptClass > & K : global_classes ) {
if ( ! inheriters_cache . has ( K . value . base ) ) {
inheriters_cache [ K . value . base ] = Vector < StringName > ( ) ;
}
inheriters_cache [ K . value . base ] . push_back ( K . key ) ;
}
for ( KeyValue < StringName , Vector < StringName > > & K : inheriters_cache ) {
K . value . sort_custom < StringName : : AlphCompare > ( ) ;
}
inheriters_cache_dirty = false ;
}
if ( ! inheriters_cache . has ( p_base_type ) ) {
return ;
}
const Vector < StringName > & v = inheriters_cache [ p_base_type ] ;
for ( int i = 0 ; i < v . size ( ) ; i + + ) {
r_classes - > push_back ( v [ i ] ) ;
}
2018-07-15 19:29:00 -03:00
}
2020-05-14 14:29:06 +02:00
2023-01-18 17:32:28 +01:00
void ScriptServer : : remove_global_class_by_path ( const String & p_path ) {
for ( const KeyValue < StringName , GlobalScriptClass > & kv : global_classes ) {
if ( kv . value . path = = p_path ) {
global_classes . erase ( kv . key ) ;
2023-01-19 16:47:01 +01:00
inheriters_cache_dirty = true ;
2023-01-18 17:32:28 +01:00
return ;
}
}
}
2018-07-15 19:29:00 -03:00
bool ScriptServer : : is_global_class ( const StringName & p_class ) {
return global_classes . has ( p_class ) ;
}
2020-05-14 14:29:06 +02:00
2018-07-15 19:29:00 -03:00
StringName ScriptServer : : get_global_class_language ( const StringName & p_class ) {
ERR_FAIL_COND_V ( ! global_classes . has ( p_class ) , StringName ( ) ) ;
return global_classes [ p_class ] . language ;
}
2020-05-14 14:29:06 +02:00
2018-07-15 19:29:00 -03:00
String ScriptServer : : get_global_class_path ( const String & p_class ) {
ERR_FAIL_COND_V ( ! global_classes . has ( p_class ) , String ( ) ) ;
return global_classes [ p_class ] . path ;
}
StringName ScriptServer : : get_global_class_base ( const String & p_class ) {
ERR_FAIL_COND_V ( ! global_classes . has ( p_class ) , String ( ) ) ;
return global_classes [ p_class ] . base ;
}
2020-05-14 14:29:06 +02:00
2019-03-09 00:47:27 -03:00
StringName ScriptServer : : get_global_class_native_base ( const String & p_class ) {
ERR_FAIL_COND_V ( ! global_classes . has ( p_class ) , String ( ) ) ;
String base = global_classes [ p_class ] . base ;
while ( global_classes . has ( base ) ) {
base = global_classes [ base ] . base ;
}
return base ;
}
2020-05-14 14:29:06 +02:00
2018-07-15 19:29:00 -03:00
void ScriptServer : : get_global_class_list ( List < StringName > * r_global_classes ) {
List < StringName > classes ;
2022-05-08 10:09:19 +02:00
for ( const KeyValue < StringName , GlobalScriptClass > & E : global_classes ) {
classes . push_back ( E . key ) ;
2018-07-15 19:29:00 -03:00
}
classes . sort_custom < StringName : : AlphCompare > ( ) ;
2021-07-24 15:46:25 +02:00
for ( const StringName & E : classes ) {
2021-07-15 23:45:57 -04:00
r_global_classes - > push_back ( E ) ;
2018-07-15 19:29:00 -03:00
}
}
2020-05-14 14:29:06 +02:00
2018-07-15 19:29:00 -03:00
void ScriptServer : : save_global_classes ( ) {
2022-12-25 15:08:32 +01:00
Dictionary class_icons ;
Array script_classes = ProjectSettings : : get_singleton ( ) - > get_global_class_list ( ) ;
2023-12-24 13:44:21 +01:00
for ( const Variant & script_class : script_classes ) {
Dictionary d = script_class ;
2022-12-25 15:08:32 +01:00
if ( ! d . has ( " name " ) | | ! d . has ( " icon " ) ) {
continue ;
}
class_icons [ d [ " name " ] ] = d [ " icon " ] ;
}
2018-07-15 19:29:00 -03:00
List < StringName > gc ;
get_global_class_list ( & gc ) ;
Array gcarr ;
2021-07-24 15:46:25 +02:00
for ( const StringName & E : gc ) {
2018-07-15 19:29:00 -03:00
Dictionary d ;
2021-07-15 23:45:57 -04:00
d [ " class " ] = E ;
d [ " language " ] = global_classes [ E ] . language ;
d [ " path " ] = global_classes [ E ] . path ;
d [ " base " ] = global_classes [ E ] . base ;
2022-12-25 15:08:32 +01:00
d [ " icon " ] = class_icons . get ( E , " " ) ;
2018-07-15 19:29:00 -03:00
gcarr . push_back ( d ) ;
}
2022-12-25 15:08:32 +01:00
ProjectSettings : : get_singleton ( ) - > store_global_class_list ( gcarr ) ;
2018-07-15 19:29:00 -03:00
}
2023-01-31 10:52:43 +01:00
String ScriptServer : : get_global_class_cache_file_path ( ) {
return ProjectSettings : : get_singleton ( ) - > get_global_class_list_path ( ) ;
}
2018-07-15 19:29:00 -03:00
////////////////////
2022-06-27 13:10:04 -07:00
2020-04-02 01:20:12 +02:00
ScriptCodeCompletionCache * ScriptCodeCompletionCache : : singleton = nullptr ;
2015-06-26 01:14:31 -03:00
ScriptCodeCompletionCache : : ScriptCodeCompletionCache ( ) {
singleton = this ;
}
2020-04-01 20:07:43 +01:00
void ScriptLanguage : : get_core_type_words ( List < String > * p_core_type_words ) const {
p_core_type_words - > push_back ( " String " ) ;
p_core_type_words - > push_back ( " Vector2 " ) ;
p_core_type_words - > push_back ( " Vector2i " ) ;
p_core_type_words - > push_back ( " Rect2 " ) ;
p_core_type_words - > push_back ( " Rect2i " ) ;
p_core_type_words - > push_back ( " Vector3 " ) ;
p_core_type_words - > push_back ( " Vector3i " ) ;
p_core_type_words - > push_back ( " Transform2D " ) ;
2022-07-20 01:11:13 +02:00
p_core_type_words - > push_back ( " Vector4 " ) ;
p_core_type_words - > push_back ( " Vector4i " ) ;
2020-04-01 20:07:43 +01:00
p_core_type_words - > push_back ( " Plane " ) ;
2021-06-15 23:04:50 +10:00
p_core_type_words - > push_back ( " Quaternion " ) ;
2020-04-01 20:07:43 +01:00
p_core_type_words - > push_back ( " AABB " ) ;
p_core_type_words - > push_back ( " Basis " ) ;
2021-06-15 23:04:50 +10:00
p_core_type_words - > push_back ( " Transform3D " ) ;
2022-07-20 01:11:13 +02:00
p_core_type_words - > push_back ( " Projection " ) ;
2020-04-01 20:07:43 +01:00
p_core_type_words - > push_back ( " Color " ) ;
p_core_type_words - > push_back ( " StringName " ) ;
p_core_type_words - > push_back ( " NodePath " ) ;
p_core_type_words - > push_back ( " RID " ) ;
p_core_type_words - > push_back ( " Callable " ) ;
p_core_type_words - > push_back ( " Signal " ) ;
p_core_type_words - > push_back ( " Dictionary " ) ;
p_core_type_words - > push_back ( " Array " ) ;
p_core_type_words - > push_back ( " PackedByteArray " ) ;
p_core_type_words - > push_back ( " PackedInt32Array " ) ;
p_core_type_words - > push_back ( " PackedInt64Array " ) ;
p_core_type_words - > push_back ( " PackedFloat32Array " ) ;
p_core_type_words - > push_back ( " PackedFloat64Array " ) ;
p_core_type_words - > push_back ( " PackedStringArray " ) ;
p_core_type_words - > push_back ( " PackedVector2Array " ) ;
p_core_type_words - > push_back ( " PackedVector3Array " ) ;
p_core_type_words - > push_back ( " PackedColorArray " ) ;
2024-04-08 07:51:34 -07:00
p_core_type_words - > push_back ( " PackedVector4Array " ) ;
2020-04-01 20:07:43 +01:00
}
2014-02-09 22:10:30 -03:00
void ScriptLanguage : : frame ( ) {
}
2023-05-23 05:12:34 +02:00
TypedArray < int > ScriptLanguage : : CodeCompletionOption : : get_option_characteristics ( const String & p_base ) {
// Return characacteristics of the match found by order of importance.
// Matches will be ranked by a lexicographical order on the vector returned by this function.
// The lower values indicate better matches and that they should go before in the order of appearance.
if ( last_matches = = matches ) {
return charac ;
}
charac . clear ( ) ;
// Ensure base is not empty and at the same time that matches is not empty too.
if ( p_base . length ( ) = = 0 ) {
last_matches = matches ;
charac . push_back ( location ) ;
return charac ;
}
charac . push_back ( matches . size ( ) ) ;
charac . push_back ( ( matches [ 0 ] . first = = 0 ) ? 0 : 1 ) ;
const char32_t * target_char = & p_base [ 0 ] ;
int bad_case = 0 ;
for ( const Pair < int , int > & match_segment : matches ) {
const char32_t * string_to_complete_char = & display [ match_segment . first ] ;
for ( int j = 0 ; j < match_segment . second ; j + + , string_to_complete_char + + , target_char + + ) {
if ( * string_to_complete_char ! = * target_char ) {
bad_case + + ;
}
}
}
charac . push_back ( bad_case ) ;
2023-09-04 17:08:14 +02:00
charac . push_back ( location ) ;
2023-05-23 05:12:34 +02:00
charac . push_back ( matches [ 0 ] . first ) ;
last_matches = matches ;
return charac ;
}
void ScriptLanguage : : CodeCompletionOption : : clear_characteristics ( ) {
charac = TypedArray < int > ( ) ;
}
TypedArray < int > ScriptLanguage : : CodeCompletionOption : : get_option_cached_characteristics ( ) const {
// Only returns the cached value and warns if it was not updated since the last change of matches.
if ( last_matches ! = matches ) {
WARN_PRINT ( " Characteristics are not up to date. " ) ;
}
return charac ;
}
2023-06-11 18:23:48 +02:00
void ScriptLanguage : : _bind_methods ( ) {
BIND_ENUM_CONSTANT ( SCRIPT_NAME_CASING_AUTO ) ;
BIND_ENUM_CONSTANT ( SCRIPT_NAME_CASING_PASCAL_CASE ) ;
BIND_ENUM_CONSTANT ( SCRIPT_NAME_CASING_SNAKE_CASE ) ;
BIND_ENUM_CONSTANT ( SCRIPT_NAME_CASING_KEBAB_CASE ) ;
}
2014-02-09 22:10:30 -03:00
bool PlaceHolderScriptInstance : : set ( const StringName & p_name , const Variant & p_value ) {
2020-05-14 16:41:43 +02:00
if ( script - > is_placeholder_fallback_enabled ( ) ) {
2018-07-29 22:40:09 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
2018-07-29 22:40:09 +02:00
2014-02-09 22:10:30 -03:00
if ( values . has ( p_name ) ) {
2017-08-06 09:32:52 -03:00
Variant defval ;
if ( script - > get_property_default_value ( p_name , defval ) ) {
2022-11-06 23:21:43 -05:00
// The evaluate function ensures that a NIL variant is equal to e.g. an empty Resource.
// Simply doing defval == p_value does not do this.
if ( Variant : : evaluate ( Variant : : OP_EQUAL , defval , p_value ) ) {
2017-08-06 09:32:52 -03:00
values . erase ( p_name ) ;
return true ;
}
}
2014-02-09 22:10:30 -03:00
values [ p_name ] = p_value ;
return true ;
2017-08-06 09:32:52 -03:00
} else {
Variant defval ;
if ( script - > get_property_default_value ( p_name , defval ) ) {
2022-11-06 23:21:43 -05:00
if ( Variant : : evaluate ( Variant : : OP_NOT_EQUAL , defval , p_value ) ) {
2017-08-06 09:32:52 -03:00
values [ p_name ] = p_value ;
}
return true ;
}
2014-02-09 22:10:30 -03:00
}
return false ;
}
2020-05-14 14:29:06 +02:00
2014-02-09 22:10:30 -03:00
bool PlaceHolderScriptInstance : : get ( const StringName & p_name , Variant & r_ret ) const {
if ( values . has ( p_name ) ) {
r_ret = values [ p_name ] ;
return true ;
}
2017-08-06 09:32:52 -03:00
2019-03-05 23:19:02 +02:00
if ( constants . has ( p_name ) ) {
r_ret = constants [ p_name ] ;
return true ;
}
2019-01-10 00:26:00 +01:00
if ( ! script - > is_placeholder_fallback_enabled ( ) ) {
2018-07-29 22:40:09 +02:00
Variant defval ;
if ( script - > get_property_default_value ( p_name , defval ) ) {
r_ret = defval ;
return true ;
}
2017-08-06 09:32:52 -03:00
}
2018-07-29 22:40:09 +02:00
2014-02-09 22:10:30 -03:00
return false ;
}
void PlaceHolderScriptInstance : : get_property_list ( List < PropertyInfo > * p_properties ) const {
2019-01-10 00:26:00 +01:00
if ( script - > is_placeholder_fallback_enabled ( ) ) {
2021-07-15 23:45:57 -04:00
for ( const PropertyInfo & E : properties ) {
p_properties - > push_back ( E ) ;
2018-07-29 22:40:09 +02:00
}
} else {
2021-07-15 23:45:57 -04:00
for ( const PropertyInfo & E : properties ) {
PropertyInfo pinfo = E ;
p_properties - > push_back ( E ) ;
2017-08-06 09:32:52 -03:00
}
2014-02-09 22:10:30 -03:00
}
}
2015-12-05 14:18:22 -03:00
Variant : : Type PlaceHolderScriptInstance : : get_property_type ( const StringName & p_name , bool * r_is_valid ) const {
if ( values . has ( p_name ) ) {
2020-05-14 16:41:43 +02:00
if ( r_is_valid ) {
2015-12-05 14:18:22 -03:00
* r_is_valid = true ;
2020-05-14 16:41:43 +02:00
}
2015-12-05 14:18:22 -03:00
return values [ p_name ] . get_type ( ) ;
}
2019-03-05 23:19:02 +02:00
if ( constants . has ( p_name ) ) {
2020-05-14 16:41:43 +02:00
if ( r_is_valid ) {
2019-03-05 23:19:02 +02:00
* r_is_valid = true ;
2020-05-14 16:41:43 +02:00
}
2019-03-05 23:19:02 +02:00
return constants [ p_name ] . get_type ( ) ;
}
2020-05-14 16:41:43 +02:00
if ( r_is_valid ) {
2015-12-05 14:18:22 -03:00
* r_is_valid = false ;
2020-05-14 16:41:43 +02:00
}
2015-12-05 14:18:22 -03:00
return Variant : : NIL ;
}
2018-06-30 19:58:37 -03:00
void PlaceHolderScriptInstance : : get_method_list ( List < MethodInfo > * p_list ) const {
2020-05-14 16:41:43 +02:00
if ( script - > is_placeholder_fallback_enabled ( ) ) {
2018-07-29 22:40:09 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2018-07-29 22:40:09 +02:00
2018-06-30 19:58:37 -03:00
if ( script . is_valid ( ) ) {
script - > get_script_method_list ( p_list ) ;
}
}
2020-05-14 14:29:06 +02:00
2018-06-30 19:58:37 -03:00
bool PlaceHolderScriptInstance : : has_method ( const StringName & p_method ) const {
2020-05-14 16:41:43 +02:00
if ( script - > is_placeholder_fallback_enabled ( ) ) {
2018-07-29 22:40:09 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
2018-07-29 22:40:09 +02:00
2018-06-30 19:58:37 -03:00
if ( script . is_valid ( ) ) {
2024-06-22 08:05:46 +02:00
Ref < Script > scr = script ;
while ( scr . is_valid ( ) ) {
if ( scr - > has_method ( p_method ) ) {
return true ;
}
scr = scr - > get_base_script ( ) ;
}
2018-06-30 19:58:37 -03:00
}
return false ;
}
2022-05-13 15:04:37 +02:00
void PlaceHolderScriptInstance : : update ( const List < PropertyInfo > & p_properties , const HashMap < StringName , Variant > & p_values ) {
2022-05-19 17:00:06 +02:00
HashSet < StringName > new_values ;
2021-07-15 23:45:57 -04:00
for ( const PropertyInfo & E : p_properties ) {
2023-11-28 20:50:10 +01:00
if ( E . usage & ( PROPERTY_USAGE_GROUP | PROPERTY_USAGE_SUBGROUP | PROPERTY_USAGE_CATEGORY ) ) {
continue ;
}
2021-07-15 23:45:57 -04:00
StringName n = E . name ;
2014-02-09 22:10:30 -03:00
new_values . insert ( n ) ;
2021-07-15 23:45:57 -04:00
if ( ! values . has ( n ) | | values [ n ] . get_type ( ) ! = E . type ) {
2020-05-14 16:41:43 +02:00
if ( p_values . has ( n ) ) {
2014-02-09 22:10:30 -03:00
values [ n ] = p_values [ n ] ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
}
}
properties = p_properties ;
List < StringName > to_remove ;
2022-05-13 15:04:37 +02:00
for ( KeyValue < StringName , Variant > & E : values ) {
if ( ! new_values . has ( E . key ) ) {
to_remove . push_back ( E . key ) ;
2020-05-14 16:41:43 +02:00
}
2017-08-06 09:32:52 -03:00
Variant defval ;
2022-05-13 15:04:37 +02:00
if ( script - > get_property_default_value ( E . key , defval ) ) {
2017-08-06 09:32:52 -03:00
//remove because it's the same as the default value
2022-05-13 15:04:37 +02:00
if ( defval = = E . value ) {
to_remove . push_back ( E . key ) ;
2017-08-06 09:32:52 -03:00
}
}
2014-02-09 22:10:30 -03:00
}
while ( to_remove . size ( ) ) {
values . erase ( to_remove . front ( ) - > get ( ) ) ;
to_remove . pop_front ( ) ;
}
2014-09-22 00:50:48 -03:00
if ( owner & & owner - > get_script_instance ( ) = = this ) {
2021-02-10 17:18:45 -03:00
owner - > notify_property_list_changed ( ) ;
2014-09-22 00:50:48 -03:00
}
2014-02-09 22:10:30 -03:00
//change notify
2019-03-05 23:19:02 +02:00
constants . clear ( ) ;
script - > get_constants ( & constants ) ;
2014-02-09 22:10:30 -03:00
}
2018-07-29 22:40:09 +02:00
void PlaceHolderScriptInstance : : property_set_fallback ( const StringName & p_name , const Variant & p_value , bool * r_valid ) {
2019-01-10 00:26:00 +01:00
if ( script - > is_placeholder_fallback_enabled ( ) ) {
2022-05-13 15:04:37 +02:00
HashMap < StringName , Variant > : : Iterator E = values . find ( p_name ) ;
2018-07-29 22:40:09 +02:00
if ( E ) {
2022-05-13 15:04:37 +02:00
E - > value = p_value ;
2018-07-29 22:40:09 +02:00
} else {
values . insert ( p_name , p_value ) ;
}
bool found = false ;
2021-07-15 23:45:57 -04:00
for ( const PropertyInfo & F : properties ) {
if ( F . name = = p_name ) {
2018-07-29 22:40:09 +02:00
found = true ;
break ;
}
}
if ( ! found ) {
2024-03-04 22:23:00 +01:00
PropertyHint hint = PROPERTY_HINT_NONE ;
const Object * obj = p_value . get_validated_object ( ) ;
if ( obj & & obj - > is_class ( " Node " ) ) {
hint = PROPERTY_HINT_NODE_TYPE ;
}
properties . push_back ( PropertyInfo ( p_value . get_type ( ) , p_name , hint , " " , PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_SCRIPT_VARIABLE ) ) ;
2018-07-29 22:40:09 +02:00
}
}
2020-05-14 16:41:43 +02:00
if ( r_valid ) {
2018-07-29 22:40:09 +02:00
* r_valid = false ; // Cannot change the value in either case
2020-05-14 16:41:43 +02:00
}
2018-07-29 22:40:09 +02:00
}
Variant PlaceHolderScriptInstance : : property_get_fallback ( const StringName & p_name , bool * r_valid ) {
2019-01-10 00:26:00 +01:00
if ( script - > is_placeholder_fallback_enabled ( ) ) {
2022-05-13 15:04:37 +02:00
HashMap < StringName , Variant > : : ConstIterator E = values . find ( p_name ) ;
2018-07-29 22:40:09 +02:00
if ( E ) {
2020-05-14 16:41:43 +02:00
if ( r_valid ) {
2018-07-29 22:40:09 +02:00
* r_valid = true ;
2020-05-14 16:41:43 +02:00
}
2022-05-13 15:04:37 +02:00
return E - > value ;
2018-07-29 22:40:09 +02:00
}
2019-03-05 23:19:02 +02:00
E = constants . find ( p_name ) ;
if ( E ) {
2020-05-14 16:41:43 +02:00
if ( r_valid ) {
2019-03-05 23:19:02 +02:00
* r_valid = true ;
2020-05-14 16:41:43 +02:00
}
2022-05-13 15:04:37 +02:00
return E - > value ;
2019-03-05 23:19:02 +02:00
}
2018-07-29 22:40:09 +02:00
}
2020-05-14 16:41:43 +02:00
if ( r_valid ) {
2018-07-29 22:40:09 +02:00
* r_valid = false ;
2020-05-14 16:41:43 +02:00
}
2018-07-29 22:40:09 +02:00
return Variant ( ) ;
}
2017-12-06 21:36:34 +01:00
PlaceHolderScriptInstance : : PlaceHolderScriptInstance ( ScriptLanguage * p_language , Ref < Script > p_script , Object * p_owner ) :
owner ( p_owner ) ,
language ( p_language ) ,
2019-01-10 00:26:00 +01:00
script ( p_script ) {
2014-02-09 22:10:30 -03:00
}
PlaceHolderScriptInstance : : ~ PlaceHolderScriptInstance ( ) {
if ( script . is_valid ( ) ) {
script - > _placeholder_erased ( this ) ;
}
}