2017-10-02 23:24:00 +02:00
/*************************************************************************/
/* csharp_script.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
2019-01-01 12:53:14 +01:00
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
2017-10-02 23:24:00 +02: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-05 00:50:27 +01:00
2017-10-02 23:24:00 +02:00
# ifndef CSHARP_SCRIPT_H
# define CSHARP_SCRIPT_H
2018-09-11 18:13:45 +02:00
# include "core/io/resource_loader.h"
# include "core/io/resource_saver.h"
# include "core/script_language.h"
# include "core/self_list.h"
2017-10-02 23:24:00 +02:00
# include "mono_gc_handle.h"
# include "mono_gd/gd_mono.h"
# include "mono_gd/gd_mono_header.h"
# include "mono_gd/gd_mono_internals.h"
class CSharpScript ;
class CSharpInstance ;
class CSharpLanguage ;
# ifdef NO_SAFE_CAST
template < typename TScriptInstance , typename TScriptLanguage >
TScriptInstance * cast_script_instance ( ScriptInstance * p_inst ) {
2018-09-12 02:41:54 +02:00
if ( ! p_inst )
return NULL ;
2017-10-02 23:24:00 +02:00
return p_inst - > get_language ( ) = = TScriptLanguage : : get_singleton ( ) ? static_cast < TScriptInstance * > ( p_inst ) : NULL ;
}
# else
template < typename TScriptInstance , typename TScriptLanguage >
TScriptInstance * cast_script_instance ( ScriptInstance * p_inst ) {
return dynamic_cast < TScriptInstance * > ( p_inst ) ;
}
# endif
# define CAST_CSHARP_INSTANCE(m_inst) (cast_script_instance<CSharpInstance, CSharpLanguage>(m_inst))
class CSharpScript : public Script {
GDCLASS ( CSharpScript , Script )
friend class CSharpInstance ;
friend class CSharpLanguage ;
2018-10-22 19:27:41 +02:00
friend struct CSharpScriptDepSort ;
2017-10-02 23:24:00 +02:00
bool tool ;
bool valid ;
bool builtin ;
GDMonoClass * base ;
GDMonoClass * native ;
GDMonoClass * script_class ;
Ref < CSharpScript > base_cache ; // TODO what's this for?
Set < Object * > instances ;
2019-01-22 18:33:36 +01:00
# ifdef GD_MONO_HOT_RELOAD
2018-11-30 20:43:06 +01:00
struct StateBackup {
// TODO
// Replace with buffer containing the serialized state of managed scripts.
// Keep variant state backup to use only with script instance placeholders.
List < Pair < StringName , Variant > > properties ;
} ;
2019-01-22 18:33:36 +01:00
Set < ObjectID > pending_reload_instances ;
Map < ObjectID , StateBackup > pending_reload_state ;
2018-11-30 20:43:06 +01:00
# endif
2017-10-02 23:24:00 +02:00
String source ;
StringName name ;
SelfList < CSharpScript > script_list ;
2018-01-18 23:27:43 +01:00
struct Argument {
String name ;
Variant : : Type type ;
} ;
2018-02-18 22:47:43 +01:00
Map < StringName , Vector < Argument > > _signals ;
bool signals_invalidated ;
2017-10-02 23:24:00 +02:00
# ifdef TOOLS_ENABLED
List < PropertyInfo > exported_members_cache ; // members_cache
Map < StringName , Variant > exported_members_defval_cache ; // member_default_values_cache
Set < PlaceHolderScriptInstance * > placeholders ;
bool source_changed_cache ;
2019-01-10 00:26:00 +01:00
bool placeholder_fallback_enabled ;
2017-10-02 23:24:00 +02:00
bool exports_invalidated ;
void _update_exports_values ( Map < StringName , Variant > & values , List < PropertyInfo > & propnames ) ;
virtual void _placeholder_erased ( PlaceHolderScriptInstance * p_placeholder ) ;
# endif
Map < StringName , PropertyInfo > member_info ;
void _clear ( ) ;
2018-07-01 03:14:40 +02:00
void load_script_signals ( GDMonoClass * p_class , GDMonoClass * p_native_class ) ;
2018-01-18 23:27:43 +01:00
bool _get_signal ( GDMonoClass * p_class , GDMonoClass * p_delegate , Vector < Argument > & params ) ;
2018-01-18 18:17:29 +01:00
2017-10-02 23:24:00 +02:00
bool _update_exports ( ) ;
2018-01-27 18:44:04 +01:00
# ifdef TOOLS_ENABLED
2019-01-29 00:02:35 +01:00
bool _get_member_export ( GDMonoClass * p_class , IMonoClassMember * p_member , PropertyInfo & r_prop_info , bool & r_exported ) ;
2018-01-27 18:44:04 +01:00
# endif
2018-01-04 21:05:46 +01:00
2017-10-02 23:24:00 +02:00
CSharpInstance * _create_instance ( const Variant * * p_args , int p_argcount , Object * p_owner , bool p_isref , Variant : : CallError & r_error ) ;
Variant _new ( const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) ;
// Do not use unless you know what you are doing
friend void GDMonoInternals : : tie_managed_to_unmanaged ( MonoObject * , Object * ) ;
2019-02-04 20:39:02 +01:00
static Ref < CSharpScript > create_for_managed_type ( GDMonoClass * p_class , GDMonoClass * p_native ) ;
2017-10-02 23:24:00 +02:00
protected :
static void _bind_methods ( ) ;
Variant call ( const StringName & p_method , const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) ;
virtual void _resource_path_changed ( ) ;
2017-10-30 22:17:20 +01:00
bool _get ( const StringName & p_name , Variant & r_ret ) const ;
bool _set ( const StringName & p_name , const Variant & p_value ) ;
void _get_property_list ( List < PropertyInfo > * p_properties ) const ;
2017-10-02 23:24:00 +02:00
public :
virtual bool can_instance ( ) const ;
virtual StringName get_instance_base_type ( ) const ;
virtual ScriptInstance * instance_create ( Object * p_this ) ;
2018-07-29 22:40:09 +02:00
virtual PlaceHolderScriptInstance * placeholder_instance_create ( Object * p_this ) ;
2017-10-02 23:24:00 +02:00
virtual bool instance_has ( const Object * p_this ) const ;
virtual bool has_source_code ( ) const ;
virtual String get_source_code ( ) const ;
virtual void set_source_code ( const String & p_code ) ;
virtual Error reload ( bool p_keep_state = false ) ;
2018-01-18 23:27:43 +01:00
virtual bool has_script_signal ( const StringName & p_signal ) const ;
virtual void get_script_signal_list ( List < MethodInfo > * r_signals ) const ;
2017-10-02 23:24:00 +02:00
/* TODO */ virtual bool get_property_default_value ( const StringName & p_property , Variant & r_value ) const ;
virtual void get_script_property_list ( List < PropertyInfo > * p_list ) const ;
virtual void update_exports ( ) ;
virtual bool is_tool ( ) const { return tool ; }
2018-11-30 21:45:44 +01:00
virtual bool is_valid ( ) const { return valid ; }
2018-11-27 23:55:37 +01:00
2017-10-02 23:24:00 +02:00
virtual Ref < Script > get_base_script ( ) const ;
virtual ScriptLanguage * get_language ( ) const ;
2018-11-01 16:35:16 +01:00
virtual void get_script_method_list ( List < MethodInfo > * p_list ) const ;
2017-10-02 23:24:00 +02:00
bool has_method ( const StringName & p_method ) const ;
2018-11-01 16:35:16 +01:00
MethodInfo get_method_info ( const StringName & p_method ) const ;
2017-10-02 23:24:00 +02:00
virtual int get_member_line ( const StringName & p_member ) const ;
2019-01-10 00:26:00 +01:00
# ifdef TOOLS_ENABLED
virtual bool is_placeholder_fallback_enabled ( ) const { return placeholder_fallback_enabled ; }
# endif
2017-10-02 23:24:00 +02:00
Error load_source_code ( const String & p_path ) ;
StringName get_script_name ( ) const ;
CSharpScript ( ) ;
~ CSharpScript ( ) ;
} ;
class CSharpInstance : public ScriptInstance {
friend class CSharpScript ;
friend class CSharpLanguage ;
2018-09-12 02:41:54 +02:00
2017-10-02 23:24:00 +02:00
Object * owner ;
bool base_ref ;
bool ref_dying ;
2018-09-12 02:41:54 +02:00
bool unsafe_referenced ;
2018-11-30 20:43:06 +01:00
bool predelete_notified ;
2018-12-01 02:23:55 +01:00
bool destructing_script_instance ;
2018-09-12 02:41:54 +02:00
Ref < CSharpScript > script ;
Ref < MonoGCHandle > gchandle ;
2017-10-02 23:24:00 +02:00
2018-09-12 02:41:54 +02:00
bool _reference_owner_unsafe ( ) ;
2019-02-03 06:35:22 +01:00
/*
* If true is returned , the caller must memdelete the script instance ' s owner .
*/
2018-09-12 02:41:54 +02:00
bool _unreference_owner_unsafe ( ) ;
2019-02-03 06:35:22 +01:00
/*
* If NULL is returned , the caller must destroy the script instance by removing it from its owner .
*/
2018-09-12 02:41:54 +02:00
MonoObject * _internal_new_managed ( ) ;
2017-10-02 23:24:00 +02:00
// Do not use unless you know what you are doing
friend void GDMonoInternals : : tie_managed_to_unmanaged ( MonoObject * , Object * ) ;
static CSharpInstance * create_for_managed_type ( Object * p_owner , CSharpScript * p_script , const Ref < MonoGCHandle > & p_gchandle ) ;
2017-12-31 22:37:57 +01:00
void _call_multilevel ( MonoObject * p_mono_object , const StringName & p_method , const Variant * * p_args , int p_argcount ) ;
2019-01-29 00:02:35 +01:00
MultiplayerAPI : : RPCMode _member_get_rpc_mode ( IMonoClassMember * p_member ) const ;
2018-01-04 21:05:46 +01:00
2017-10-02 23:24:00 +02:00
public :
MonoObject * get_mono_object ( ) const ;
2018-12-01 02:23:55 +01:00
_FORCE_INLINE_ bool is_destructing_script_instance ( ) { return destructing_script_instance ; }
2019-02-03 06:35:22 +01:00
virtual Object * get_owner ( ) ;
2017-10-02 23:24:00 +02:00
virtual bool set ( const StringName & p_name , const Variant & p_value ) ;
virtual bool get ( const StringName & p_name , Variant & r_ret ) const ;
virtual void get_property_list ( List < PropertyInfo > * p_properties ) const ;
virtual Variant : : Type get_property_type ( const StringName & p_name , bool * r_is_valid ) const ;
/* TODO */ virtual void get_method_list ( List < MethodInfo > * p_list ) const { }
virtual bool has_method ( const StringName & p_method ) const ;
virtual Variant call ( const StringName & p_method , const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) ;
virtual void call_multilevel ( const StringName & p_method , const Variant * * p_args , int p_argcount ) ;
virtual void call_multilevel_reversed ( const StringName & p_method , const Variant * * p_args , int p_argcount ) ;
2018-09-12 21:08:18 +02:00
void mono_object_disposed ( MonoObject * p_obj ) ;
2019-02-03 06:35:22 +01:00
/*
* If ' r_delete_owner ' is set to true , the caller must memdelete the script instance ' s owner . Otherwise , if
* ' r_remove_script_instance ' is set to true , the caller must destroy the script instance by removing it from its owner .
*/
void mono_object_disposed_baseref ( MonoObject * p_obj , bool p_is_finalizer , bool & r_delete_owner , bool & r_remove_script_instance ) ;
2017-10-02 23:24:00 +02:00
2017-12-31 22:37:57 +01:00
virtual void refcount_incremented ( ) ;
virtual bool refcount_decremented ( ) ;
2017-10-02 23:24:00 +02:00
2018-05-13 07:07:56 +02:00
virtual MultiplayerAPI : : RPCMode get_rpc_mode ( const StringName & p_method ) const ;
virtual MultiplayerAPI : : RPCMode get_rset_mode ( const StringName & p_variable ) const ;
2017-10-02 23:24:00 +02:00
virtual void notification ( int p_notification ) ;
2018-09-12 02:41:54 +02:00
void _call_notification ( int p_notification ) ;
2017-10-02 23:24:00 +02:00
virtual Ref < Script > get_script ( ) const ;
virtual ScriptLanguage * get_language ( ) ;
CSharpInstance ( ) ;
~ CSharpInstance ( ) ;
} ;
2018-09-12 02:41:54 +02:00
struct CSharpScriptBinding {
2019-02-03 06:35:22 +01:00
bool inited ;
2018-09-12 02:41:54 +02:00
StringName type_name ;
GDMonoClass * wrapper_class ;
Ref < MonoGCHandle > gchandle ;
} ;
2017-10-02 23:24:00 +02:00
class CSharpLanguage : public ScriptLanguage {
friend class CSharpScript ;
friend class CSharpInstance ;
static CSharpLanguage * singleton ;
2017-12-31 22:37:57 +01:00
bool finalizing ;
2017-10-02 23:24:00 +02:00
GDMono * gdmono ;
SelfList < CSharpScript > : : List script_list ;
2018-11-30 20:43:06 +01:00
Mutex * script_instances_mutex ;
Mutex * script_gchandle_release_mutex ;
Mutex * language_bind_mutex ;
2017-10-02 23:24:00 +02:00
2018-09-12 02:41:54 +02:00
Map < Object * , CSharpScriptBinding > script_bindings ;
2017-10-02 23:24:00 +02:00
struct StringNameCache {
2017-10-16 03:54:23 +02:00
StringName _signal_callback ;
2017-10-02 23:24:00 +02:00
StringName _set ;
StringName _get ;
StringName _notification ;
2017-10-30 22:17:20 +01:00
StringName _script_source ;
2017-10-02 23:24:00 +02:00
StringName dotctor ; // .ctor
StringNameCache ( ) ;
} ;
int lang_idx ;
2018-10-22 19:43:19 +02:00
Dictionary scripts_metadata ;
2017-10-02 23:24:00 +02:00
public :
2017-10-30 22:17:20 +01:00
StringNameCache string_names ;
2019-02-04 20:39:02 +01:00
Mutex * get_language_bind_mutex ( ) { return language_bind_mutex ; }
2017-10-02 23:24:00 +02:00
_FORCE_INLINE_ int get_language_index ( ) { return lang_idx ; }
void set_language_index ( int p_idx ) ;
2017-10-16 03:54:23 +02:00
_FORCE_INLINE_ const StringNameCache & get_string_names ( ) { return string_names ; }
2017-10-02 23:24:00 +02:00
_FORCE_INLINE_ static CSharpLanguage * get_singleton ( ) { return singleton ; }
2018-09-12 02:41:54 +02:00
static void release_script_gchandle ( Ref < MonoGCHandle > & p_gchandle ) ;
static void release_script_gchandle ( MonoObject * p_pinned_expected_obj , Ref < MonoGCHandle > & p_gchandle ) ;
2017-10-02 23:24:00 +02:00
bool debug_break ( const String & p_error , bool p_allow_continue = true ) ;
bool debug_break_parse ( const String & p_file , int p_line , const String & p_error ) ;
2019-01-22 18:33:36 +01:00
# ifdef GD_MONO_HOT_RELOAD
2018-11-30 20:43:06 +01:00
bool is_assembly_reloading_needed ( ) ;
void reload_assemblies ( bool p_soft_reload ) ;
2017-10-02 23:24:00 +02:00
# endif
2018-10-22 19:43:19 +02:00
void project_assembly_loaded ( ) ;
_FORCE_INLINE_ const Dictionary & get_scripts_metadata ( ) { return scripts_metadata ; }
2017-10-02 23:24:00 +02:00
virtual String get_name ( ) const ;
/* LANGUAGE FUNCTIONS */
virtual String get_type ( ) const ;
virtual String get_extension ( ) const ;
virtual Error execute_file ( const String & p_path ) ;
virtual void init ( ) ;
virtual void finish ( ) ;
/* EDITOR FUNCTIONS */
virtual void get_reserved_words ( List < String > * p_words ) const ;
virtual void get_comment_delimiters ( List < String > * p_delimiters ) const ;
virtual void get_string_delimiters ( List < String > * p_delimiters ) const ;
virtual Ref < Script > get_template ( const String & p_class_name , const String & p_base_class_name ) const ;
2017-10-30 22:17:20 +01:00
virtual bool is_using_templates ( ) ;
virtual void make_template ( const String & p_class_name , const String & p_base_class_name , Ref < Script > & p_script ) ;
2018-07-01 18:17:40 +02:00
/* TODO */ virtual bool 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 = NULL , Set < int > * r_safe_lines = NULL ) const { return true ; }
2018-03-09 23:34:32 +01:00
virtual String validate_path ( const String & p_path ) const ;
2017-10-02 23:24:00 +02:00
virtual Script * create_script ( ) const ;
virtual bool has_named_classes ( ) const ;
2017-10-24 01:54:47 +02:00
virtual bool supports_builtin_mode ( ) const ;
2017-10-02 23:24:00 +02:00
/* TODO? */ virtual int find_function ( const String & p_function , const String & p_code ) const { return - 1 ; }
virtual String make_function ( const String & p_class , const String & p_name , const PoolStringArray & p_args ) const ;
/* TODO? */ Error complete_code ( const String & p_code , const String & p_base_path , Object * p_owner , List < String > * r_options , String & r_call_hint ) { return ERR_UNAVAILABLE ; }
2017-10-30 22:17:20 +01:00
virtual String _get_indentation ( ) const ;
2017-10-02 23:24:00 +02:00
/* TODO? */ virtual void auto_indent_code ( String & p_code , int p_from_line , int p_to_line ) const { }
/* TODO */ virtual void add_global_constant ( const StringName & p_variable , const Variant & p_value ) { }
/* DEBUGGER FUNCTIONS */
/* TODO */ virtual String debug_get_error ( ) const { return " " ; }
/* TODO */ virtual int debug_get_stack_level_count ( ) const { return 1 ; }
/* TODO */ virtual int debug_get_stack_level_line ( int p_level ) const { return 1 ; }
/* TODO */ virtual String debug_get_stack_level_function ( int p_level ) const { return " " ; }
/* TODO */ virtual String debug_get_stack_level_source ( int p_level ) const { return " " ; }
/* TODO */ virtual void debug_get_stack_level_locals ( int p_level , List < String > * p_locals , List < Variant > * p_values , int p_max_subitems , int p_max_depth ) { }
/* TODO */ virtual void debug_get_stack_level_members ( int p_level , List < String > * p_members , List < Variant > * p_values , int p_max_subitems , int p_max_depth ) { }
/* TODO */ virtual void debug_get_globals ( List < String > * p_locals , List < Variant > * p_values , int p_max_subitems , int p_max_depth ) { }
/* TODO */ virtual String debug_parse_stack_level_expression ( int p_level , const String & p_expression , int p_max_subitems , int p_max_depth ) { return " " ; }
2018-01-09 17:19:03 +01:00
virtual Vector < StackInfo > debug_get_current_stack_info ( ) ;
2017-10-02 23:24:00 +02:00
/* PROFILING FUNCTIONS */
/* TODO */ virtual void profiling_start ( ) { }
/* TODO */ virtual void profiling_stop ( ) { }
/* TODO */ virtual int profiling_get_accumulated_data ( ProfilingInfo * p_info_arr , int p_info_max ) { return 0 ; }
/* TODO */ virtual int profiling_get_frame_data ( ProfilingInfo * p_info_arr , int p_info_max ) { return 0 ; }
virtual void frame ( ) ;
/* TODO? */ virtual void get_public_functions ( List < MethodInfo > * p_functions ) const { }
/* TODO? */ virtual void get_public_constants ( List < Pair < String , Variant > > * p_constants ) const { }
virtual void reload_all_scripts ( ) ;
virtual void reload_tool_script ( const Ref < Script > & p_script , bool p_soft_reload ) ;
/* LOADER FUNCTIONS */
virtual void get_recognized_extensions ( List < String > * p_extensions ) const ;
# ifdef TOOLS_ENABLED
virtual Error open_in_external_editor ( const Ref < Script > & p_script , int p_line , int p_col ) ;
virtual bool overrides_external_editor ( ) ;
# endif
/* THREAD ATTACHING */
virtual void thread_enter ( ) ;
virtual void thread_exit ( ) ;
// Don't use these. I'm watching you
virtual void * alloc_instance_binding_data ( Object * p_object ) ;
virtual void free_instance_binding_data ( void * p_data ) ;
2018-02-22 15:34:08 +01:00
virtual void refcount_incremented_instance_binding ( Object * p_object ) ;
virtual bool refcount_decremented_instance_binding ( Object * p_object ) ;
2017-10-02 23:24:00 +02:00
2019-02-04 20:39:02 +01:00
Map < Object * , CSharpScriptBinding > : : Element * insert_script_binding ( Object * p_object , const CSharpScriptBinding & p_script_binding ) ;
2019-02-03 06:35:22 +01:00
bool setup_csharp_script_binding ( CSharpScriptBinding & r_script_binding , Object * p_object ) ;
2018-01-27 18:44:04 +01:00
# ifdef DEBUG_ENABLED
2018-01-09 17:19:03 +01:00
Vector < StackInfo > stack_trace_get_info ( MonoObject * p_stack_trace ) ;
2018-01-27 18:44:04 +01:00
# endif
2018-01-09 17:19:03 +01:00
2017-10-02 23:24:00 +02:00
CSharpLanguage ( ) ;
~ CSharpLanguage ( ) ;
} ;
class ResourceFormatLoaderCSharpScript : public ResourceFormatLoader {
2018-06-11 02:59:53 +02:00
GDCLASS ( ResourceFormatLoaderCSharpScript , ResourceFormatLoader )
2017-10-02 23:24:00 +02:00
public :
virtual RES load ( const String & p_path , const String & p_original_path = " " , Error * r_error = NULL ) ;
virtual void get_recognized_extensions ( List < String > * p_extensions ) const ;
virtual bool handles_type ( const String & p_type ) const ;
virtual String get_resource_type ( const String & p_path ) const ;
} ;
class ResourceFormatSaverCSharpScript : public ResourceFormatSaver {
2018-06-11 02:59:53 +02:00
GDCLASS ( ResourceFormatSaverCSharpScript , ResourceFormatSaver )
2017-10-02 23:24:00 +02:00
public :
virtual Error save ( const String & p_path , const RES & p_resource , uint32_t p_flags = 0 ) ;
virtual void get_recognized_extensions ( const RES & p_resource , List < String > * p_extensions ) const ;
virtual bool recognize ( const RES & p_resource ) const ;
} ;
# endif // CSHARP_SCRIPT_H