commit
29ca79bd68
8 changed files with 203 additions and 104 deletions
|
@ -867,17 +867,26 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
|
||||||
|
|
||||||
script->reload(p_soft_reload);
|
script->reload(p_soft_reload);
|
||||||
script->update_exports();
|
script->update_exports();
|
||||||
|
|
||||||
|
if (!script->valid) {
|
||||||
|
script->pending_reload_instances.clear();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
const StringName &class_namespace = script->tied_class_namespace_for_reload;
|
const StringName &class_namespace = script->tied_class_namespace_for_reload;
|
||||||
const StringName &class_name = script->tied_class_name_for_reload;
|
const StringName &class_name = script->tied_class_name_for_reload;
|
||||||
GDMonoAssembly *project_assembly = gdmono->get_project_assembly();
|
GDMonoAssembly *project_assembly = gdmono->get_project_assembly();
|
||||||
GDMonoAssembly *tools_assembly = gdmono->get_tools_assembly();
|
|
||||||
|
|
||||||
// Search in project and tools assemblies first as those are the most likely to have the class
|
// Search in project and tools assemblies first as those are the most likely to have the class
|
||||||
GDMonoClass *script_class = (project_assembly ? project_assembly->get_class(class_namespace, class_name) : NULL);
|
GDMonoClass *script_class = (project_assembly ? project_assembly->get_class(class_namespace, class_name) : NULL);
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
if (!script_class) {
|
if (!script_class) {
|
||||||
|
GDMonoAssembly *tools_assembly = gdmono->get_tools_assembly();
|
||||||
script_class = (tools_assembly ? tools_assembly->get_class(class_namespace, class_name) : NULL);
|
script_class = (tools_assembly ? tools_assembly->get_class(class_namespace, class_name) : NULL);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!script_class) {
|
if (!script_class) {
|
||||||
script_class = gdmono->get_class(class_namespace, class_name);
|
script_class = gdmono->get_class(class_namespace, class_name);
|
||||||
}
|
}
|
||||||
|
@ -897,12 +906,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
|
||||||
|
|
||||||
GDMonoClass *native = GDMonoUtils::get_class_native_base(script_class);
|
GDMonoClass *native = GDMonoUtils::get_class_native_base(script_class);
|
||||||
|
|
||||||
Ref<CSharpScript> new_script = CSharpScript::create_for_managed_type(script_class, native);
|
CSharpScript::initialize_for_managed_type(script, script_class, native);
|
||||||
CRASH_COND(new_script.is_null());
|
|
||||||
|
|
||||||
new_script->pending_reload_instances = script->pending_reload_instances;
|
|
||||||
new_script->pending_reload_state = script->pending_reload_state;
|
|
||||||
script = new_script;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String native_name = NATIVE_GDMONOCLASS_NAME(script->native);
|
String native_name = NATIVE_GDMONOCLASS_NAME(script->native);
|
||||||
|
@ -953,7 +957,6 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
|
||||||
CRASH_COND(si != NULL);
|
CRASH_COND(si != NULL);
|
||||||
#endif
|
#endif
|
||||||
// Re-create script instance
|
// Re-create script instance
|
||||||
|
|
||||||
obj->set_script(script.get_ref_ptr()); // will create the script instance as well
|
obj->set_script(script.get_ref_ptr()); // will create the script instance as well
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1203,7 +1206,9 @@ CSharpLanguage::CSharpLanguage() {
|
||||||
|
|
||||||
scripts_metadata_invalidated = true;
|
scripts_metadata_invalidated = true;
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
godotsharp_editor = NULL;
|
godotsharp_editor = NULL;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
CSharpLanguage::~CSharpLanguage() {
|
CSharpLanguage::~CSharpLanguage() {
|
||||||
|
@ -2144,7 +2149,6 @@ void CSharpScript::_update_exports_values(Map<StringName, Variant> &values, List
|
||||||
propnames.push_back(E->get());
|
propnames.push_back(E->get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void CSharpScript::_update_member_info_no_exports() {
|
void CSharpScript::_update_member_info_no_exports() {
|
||||||
|
|
||||||
|
@ -2191,6 +2195,7 @@ void CSharpScript::_update_member_info_no_exports() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool CSharpScript::_update_exports() {
|
bool CSharpScript::_update_exports() {
|
||||||
|
|
||||||
|
@ -2673,35 +2678,46 @@ void CSharpScript::_bind_methods() {
|
||||||
|
|
||||||
Ref<CSharpScript> CSharpScript::create_for_managed_type(GDMonoClass *p_class, GDMonoClass *p_native) {
|
Ref<CSharpScript> CSharpScript::create_for_managed_type(GDMonoClass *p_class, GDMonoClass *p_native) {
|
||||||
|
|
||||||
// This method should not fail
|
// This method should not fail, only assertions allowed
|
||||||
|
|
||||||
CRASH_COND(p_class == NULL);
|
CRASH_COND(p_class == NULL);
|
||||||
|
|
||||||
// TODO OPTIMIZE: Cache the 'CSharpScript' associated with this 'p_class' instead of allocating a new one every time
|
// TODO OPTIMIZE: Cache the 'CSharpScript' associated with this 'p_class' instead of allocating a new one every time
|
||||||
Ref<CSharpScript> script = memnew(CSharpScript);
|
Ref<CSharpScript> script = memnew(CSharpScript);
|
||||||
|
|
||||||
script->name = p_class->get_name();
|
initialize_for_managed_type(script, p_class, p_native);
|
||||||
script->script_class = p_class;
|
|
||||||
script->native = p_native;
|
|
||||||
|
|
||||||
CRASH_COND(script->native == NULL);
|
return script;
|
||||||
|
}
|
||||||
|
|
||||||
GDMonoClass *base = script->script_class->get_parent_class();
|
void CSharpScript::initialize_for_managed_type(Ref<CSharpScript> p_script, GDMonoClass *p_class, GDMonoClass *p_native) {
|
||||||
|
|
||||||
if (base != script->native)
|
// This method should not fail, only assertions allowed
|
||||||
script->base = base;
|
|
||||||
|
|
||||||
script->valid = true;
|
CRASH_COND(p_class == NULL);
|
||||||
script->tool = script->script_class->has_attribute(CACHED_CLASS(ToolAttribute));
|
|
||||||
|
|
||||||
if (!script->tool) {
|
p_script->name = p_class->get_name();
|
||||||
GDMonoClass *nesting_class = script->script_class->get_nesting_class();
|
p_script->script_class = p_class;
|
||||||
script->tool = nesting_class && nesting_class->has_attribute(CACHED_CLASS(ToolAttribute));
|
p_script->native = p_native;
|
||||||
|
|
||||||
|
CRASH_COND(p_script->native == NULL);
|
||||||
|
|
||||||
|
GDMonoClass *base = p_script->script_class->get_parent_class();
|
||||||
|
|
||||||
|
if (base != p_script->native)
|
||||||
|
p_script->base = base;
|
||||||
|
|
||||||
|
p_script->valid = true;
|
||||||
|
p_script->tool = p_script->script_class->has_attribute(CACHED_CLASS(ToolAttribute));
|
||||||
|
|
||||||
|
if (!p_script->tool) {
|
||||||
|
GDMonoClass *nesting_class = p_script->script_class->get_nesting_class();
|
||||||
|
p_script->tool = nesting_class && nesting_class->has_attribute(CACHED_CLASS(ToolAttribute));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TOOLS_ENABLED
|
#if TOOLS_ENABLED
|
||||||
if (!script->tool) {
|
if (!p_script->tool) {
|
||||||
script->tool = script->script_class->get_assembly() == GDMono::get_singleton()->get_tools_assembly();
|
p_script->tool = p_script->script_class->get_assembly() == GDMono::get_singleton()->get_tools_assembly();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -2710,10 +2726,10 @@ Ref<CSharpScript> CSharpScript::create_for_managed_type(GDMonoClass *p_class, GD
|
||||||
// Native base methods must be fetched before the current class.
|
// Native base methods must be fetched before the current class.
|
||||||
// Not needed if the script class itself is a native class.
|
// Not needed if the script class itself is a native class.
|
||||||
|
|
||||||
if (script->script_class != script->native) {
|
if (p_script->script_class != p_script->native) {
|
||||||
GDMonoClass *native_top = script->native;
|
GDMonoClass *native_top = p_script->native;
|
||||||
while (native_top) {
|
while (native_top) {
|
||||||
native_top->fetch_methods_with_godot_api_checks(script->native);
|
native_top->fetch_methods_with_godot_api_checks(p_script->native);
|
||||||
|
|
||||||
if (native_top == CACHED_CLASS(GodotObject))
|
if (native_top == CACHED_CLASS(GodotObject))
|
||||||
break;
|
break;
|
||||||
|
@ -2723,19 +2739,19 @@ Ref<CSharpScript> CSharpScript::create_for_managed_type(GDMonoClass *p_class, GD
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
script->script_class->fetch_methods_with_godot_api_checks(script->native);
|
p_script->script_class->fetch_methods_with_godot_api_checks(p_script->native);
|
||||||
|
|
||||||
// Need to fetch method from base classes as well
|
// Need to fetch method from base classes as well
|
||||||
GDMonoClass *top = script->script_class;
|
GDMonoClass *top = p_script->script_class;
|
||||||
while (top && top != script->native) {
|
while (top && top != p_script->native) {
|
||||||
top->fetch_methods_with_godot_api_checks(script->native);
|
top->fetch_methods_with_godot_api_checks(p_script->native);
|
||||||
top = top->get_parent_class();
|
top = top->get_parent_class();
|
||||||
}
|
}
|
||||||
|
|
||||||
script->load_script_signals(script->script_class, script->native);
|
p_script->load_script_signals(p_script->script_class, p_script->native);
|
||||||
script->_update_member_info_no_exports();
|
#ifdef TOOLS_ENABLED
|
||||||
|
p_script->_update_member_info_no_exports();
|
||||||
return script;
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSharpScript::can_instance() const {
|
bool CSharpScript::can_instance() const {
|
||||||
|
|
|
@ -121,6 +121,7 @@ class CSharpScript : public Script {
|
||||||
bool placeholder_fallback_enabled;
|
bool placeholder_fallback_enabled;
|
||||||
bool exports_invalidated;
|
bool exports_invalidated;
|
||||||
void _update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames);
|
void _update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames);
|
||||||
|
void _update_member_info_no_exports();
|
||||||
virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder);
|
virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -131,7 +132,6 @@ class CSharpScript : public Script {
|
||||||
void load_script_signals(GDMonoClass *p_class, GDMonoClass *p_native_class);
|
void load_script_signals(GDMonoClass *p_class, GDMonoClass *p_native_class);
|
||||||
bool _get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Vector<Argument> ¶ms);
|
bool _get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Vector<Argument> ¶ms);
|
||||||
|
|
||||||
void _update_member_info_no_exports();
|
|
||||||
bool _update_exports();
|
bool _update_exports();
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
bool _get_member_export(IMonoClassMember *p_member, bool p_inspect_export, PropertyInfo &r_prop_info, bool &r_exported);
|
bool _get_member_export(IMonoClassMember *p_member, bool p_inspect_export, PropertyInfo &r_prop_info, bool &r_exported);
|
||||||
|
@ -144,6 +144,7 @@ class CSharpScript : public Script {
|
||||||
// Do not use unless you know what you are doing
|
// Do not use unless you know what you are doing
|
||||||
friend void GDMonoInternals::tie_managed_to_unmanaged(MonoObject *, Object *);
|
friend void GDMonoInternals::tie_managed_to_unmanaged(MonoObject *, Object *);
|
||||||
static Ref<CSharpScript> create_for_managed_type(GDMonoClass *p_class, GDMonoClass *p_native);
|
static Ref<CSharpScript> create_for_managed_type(GDMonoClass *p_class, GDMonoClass *p_native);
|
||||||
|
static void initialize_for_managed_type(Ref<CSharpScript> p_script, GDMonoClass *p_class, GDMonoClass *p_native);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
@ -354,7 +355,9 @@ public:
|
||||||
|
|
||||||
_FORCE_INLINE_ static CSharpLanguage *get_singleton() { return singleton; }
|
_FORCE_INLINE_ static CSharpLanguage *get_singleton() { return singleton; }
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
_FORCE_INLINE_ EditorPlugin *get_godotsharp_editor() const { return godotsharp_editor; }
|
_FORCE_INLINE_ EditorPlugin *get_godotsharp_editor() const { return godotsharp_editor; }
|
||||||
|
#endif
|
||||||
|
|
||||||
static void release_script_gchandle(Ref<MonoGCHandle> &p_gchandle);
|
static void release_script_gchandle(Ref<MonoGCHandle> &p_gchandle);
|
||||||
static void release_script_gchandle(MonoObject *p_expected_obj, Ref<MonoGCHandle> &p_gchandle);
|
static void release_script_gchandle(MonoObject *p_expected_obj, Ref<MonoGCHandle> &p_gchandle);
|
||||||
|
|
|
@ -58,7 +58,7 @@ namespace GodotTools
|
||||||
{
|
{
|
||||||
var oldFileDict = (Dictionary) oldFileVar;
|
var oldFileDict = (Dictionary) oldFileVar;
|
||||||
|
|
||||||
if (ulong.TryParse((string) oldFileDict["modified_time"], out ulong storedModifiedTime))
|
if (ulong.TryParse(oldFileDict["modified_time"] as string, out ulong storedModifiedTime))
|
||||||
{
|
{
|
||||||
if (storedModifiedTime == modifiedTime)
|
if (storedModifiedTime == modifiedTime)
|
||||||
{
|
{
|
||||||
|
|
|
@ -875,14 +875,14 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir, Vect
|
||||||
da->make_dir("Core");
|
da->make_dir("Core");
|
||||||
da->make_dir("ObjectType");
|
da->make_dir("ObjectType");
|
||||||
|
|
||||||
String core_dir = path_join(p_proj_dir, "Core");
|
String core_dir = path::join(p_proj_dir, "Core");
|
||||||
String obj_type_dir = path_join(p_proj_dir, "ObjectType");
|
String obj_type_dir = path::join(p_proj_dir, "ObjectType");
|
||||||
|
|
||||||
// Generate source file for global scope constants and enums
|
// Generate source file for global scope constants and enums
|
||||||
{
|
{
|
||||||
StringBuilder constants_source;
|
StringBuilder constants_source;
|
||||||
_generate_global_constants(constants_source);
|
_generate_global_constants(constants_source);
|
||||||
String output_file = path_join(core_dir, BINDINGS_GLOBAL_SCOPE_CLASS "_constants.cs");
|
String output_file = path::join(core_dir, BINDINGS_GLOBAL_SCOPE_CLASS "_constants.cs");
|
||||||
Error save_err = _save_file(output_file, constants_source);
|
Error save_err = _save_file(output_file, constants_source);
|
||||||
if (save_err != OK)
|
if (save_err != OK)
|
||||||
return save_err;
|
return save_err;
|
||||||
|
@ -896,7 +896,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir, Vect
|
||||||
if (itype.api_type == ClassDB::API_EDITOR)
|
if (itype.api_type == ClassDB::API_EDITOR)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
String output_file = path_join(obj_type_dir, itype.proxy_name + ".cs");
|
String output_file = path::join(obj_type_dir, itype.proxy_name + ".cs");
|
||||||
Error err = _generate_cs_type(itype, output_file);
|
Error err = _generate_cs_type(itype, output_file);
|
||||||
|
|
||||||
if (err == ERR_SKIP)
|
if (err == ERR_SKIP)
|
||||||
|
@ -917,7 +917,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir, Vect
|
||||||
const String &file_name = E->key();
|
const String &file_name = E->key();
|
||||||
const GodotCsCompressedFile &file_data = E->value();
|
const GodotCsCompressedFile &file_data = E->value();
|
||||||
|
|
||||||
String output_file = path_join(core_dir, file_name);
|
String output_file = path::join(core_dir, file_name);
|
||||||
|
|
||||||
Vector<uint8_t> data;
|
Vector<uint8_t> data;
|
||||||
data.resize(file_data.uncompressed_size);
|
data.resize(file_data.uncompressed_size);
|
||||||
|
@ -971,7 +971,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir, Vect
|
||||||
|
|
||||||
cs_icalls_content.append(INDENT1 CLOSE_BLOCK CLOSE_BLOCK);
|
cs_icalls_content.append(INDENT1 CLOSE_BLOCK CLOSE_BLOCK);
|
||||||
|
|
||||||
String internal_methods_file = path_join(core_dir, BINDINGS_CLASS_NATIVECALLS ".cs");
|
String internal_methods_file = path::join(core_dir, BINDINGS_CLASS_NATIVECALLS ".cs");
|
||||||
|
|
||||||
Error err = _save_file(internal_methods_file, cs_icalls_content);
|
Error err = _save_file(internal_methods_file, cs_icalls_content);
|
||||||
if (err != OK)
|
if (err != OK)
|
||||||
|
@ -996,8 +996,8 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir, Ve
|
||||||
da->make_dir("Core");
|
da->make_dir("Core");
|
||||||
da->make_dir("ObjectType");
|
da->make_dir("ObjectType");
|
||||||
|
|
||||||
String core_dir = path_join(p_proj_dir, "Core");
|
String core_dir = path::join(p_proj_dir, "Core");
|
||||||
String obj_type_dir = path_join(p_proj_dir, "ObjectType");
|
String obj_type_dir = path::join(p_proj_dir, "ObjectType");
|
||||||
|
|
||||||
for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) {
|
for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) {
|
||||||
const TypeInterface &itype = E.get();
|
const TypeInterface &itype = E.get();
|
||||||
|
@ -1005,7 +1005,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir, Ve
|
||||||
if (itype.api_type != ClassDB::API_EDITOR)
|
if (itype.api_type != ClassDB::API_EDITOR)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
String output_file = path_join(obj_type_dir, itype.proxy_name + ".cs");
|
String output_file = path::join(obj_type_dir, itype.proxy_name + ".cs");
|
||||||
Error err = _generate_cs_type(itype, output_file);
|
Error err = _generate_cs_type(itype, output_file);
|
||||||
|
|
||||||
if (err == ERR_SKIP)
|
if (err == ERR_SKIP)
|
||||||
|
@ -1051,7 +1051,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir, Ve
|
||||||
|
|
||||||
cs_icalls_content.append(INDENT1 CLOSE_BLOCK CLOSE_BLOCK);
|
cs_icalls_content.append(INDENT1 CLOSE_BLOCK CLOSE_BLOCK);
|
||||||
|
|
||||||
String internal_methods_file = path_join(core_dir, BINDINGS_CLASS_NATIVECALLS_EDITOR ".cs");
|
String internal_methods_file = path::join(core_dir, BINDINGS_CLASS_NATIVECALLS_EDITOR ".cs");
|
||||||
|
|
||||||
Error err = _save_file(internal_methods_file, cs_icalls_content);
|
Error err = _save_file(internal_methods_file, cs_icalls_content);
|
||||||
if (err != OK)
|
if (err != OK)
|
||||||
|
@ -1064,7 +1064,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir, Ve
|
||||||
|
|
||||||
Error BindingsGenerator::generate_cs_api(const String &p_output_dir) {
|
Error BindingsGenerator::generate_cs_api(const String &p_output_dir) {
|
||||||
|
|
||||||
String output_dir = DirAccess::get_full_path(p_output_dir, DirAccess::ACCESS_FILESYSTEM);
|
String output_dir = path::abspath(path::realpath(p_output_dir));
|
||||||
|
|
||||||
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||||
ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
|
ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
|
||||||
|
@ -1862,7 +1862,7 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
|
||||||
|
|
||||||
output.append("\n#endif // MONO_GLUE_ENABLED\n");
|
output.append("\n#endif // MONO_GLUE_ENABLED\n");
|
||||||
|
|
||||||
Error save_err = _save_file(path_join(p_output_dir, "mono_glue.gen.cpp"), output);
|
Error save_err = _save_file(path::join(p_output_dir, "mono_glue.gen.cpp"), output);
|
||||||
if (save_err != OK)
|
if (save_err != OK)
|
||||||
return save_err;
|
return save_err;
|
||||||
|
|
||||||
|
@ -2192,7 +2192,7 @@ void BindingsGenerator::_populate_object_type_interfaces() {
|
||||||
|
|
||||||
itype.base_name = ClassDB::get_parent_class(type_cname);
|
itype.base_name = ClassDB::get_parent_class(type_cname);
|
||||||
itype.is_singleton = Engine::get_singleton()->has_singleton(itype.proxy_name);
|
itype.is_singleton = Engine::get_singleton()->has_singleton(itype.proxy_name);
|
||||||
itype.is_instantiable = ClassDB::can_instance(type_cname) && !itype.is_singleton;
|
itype.is_instantiable = class_info->creation_func && !itype.is_singleton;
|
||||||
itype.is_reference = ClassDB::is_parent_class(type_cname, name_cache.type_Reference);
|
itype.is_reference = ClassDB::is_parent_class(type_cname, name_cache.type_Reference);
|
||||||
itype.memory_own = itype.is_reference;
|
itype.memory_own = itype.is_reference;
|
||||||
|
|
||||||
|
|
|
@ -219,7 +219,18 @@ MonoBoolean godot_icall_DynamicGodotObject_SetMember(Object *p_ptr, MonoString *
|
||||||
}
|
}
|
||||||
|
|
||||||
MonoString *godot_icall_Object_ToString(Object *p_ptr) {
|
MonoString *godot_icall_Object_ToString(Object *p_ptr) {
|
||||||
return GDMonoMarshal::mono_string_from_godot(Variant(p_ptr).operator String());
|
#ifdef DEBUG_ENABLED
|
||||||
|
// Cannot happen in C#; would get an ObjectDisposedException instead.
|
||||||
|
CRASH_COND(p_ptr == NULL);
|
||||||
|
|
||||||
|
if (ScriptDebugger::get_singleton() && !Object::cast_to<Reference>(p_ptr)) { // Only if debugging!
|
||||||
|
// Cannot happen either in C#; the handle is nullified when the object is destroyed
|
||||||
|
CRASH_COND(!ObjectDB::instance_validate(p_ptr));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
String result = "[" + p_ptr->get_class() + ":" + itos(p_ptr->get_instance_id()) + "]";
|
||||||
|
return GDMonoMarshal::mono_string_from_godot(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void godot_register_object_icalls() {
|
void godot_register_object_icalls() {
|
||||||
|
|
|
@ -241,9 +241,9 @@ void GDMono::initialize() {
|
||||||
locations.push_back("/usr/local/var/homebrew/linked/mono/");
|
locations.push_back("/usr/local/var/homebrew/linked/mono/");
|
||||||
|
|
||||||
for (int i = 0; i < locations.size(); i++) {
|
for (int i = 0; i < locations.size(); i++) {
|
||||||
String hint_assembly_rootdir = path_join(locations[i], "lib");
|
String hint_assembly_rootdir = path::join(locations[i], "lib");
|
||||||
String hint_mscorlib_path = path_join(hint_assembly_rootdir, "mono", "4.5", "mscorlib.dll");
|
String hint_mscorlib_path = path::join(hint_assembly_rootdir, "mono", "4.5", "mscorlib.dll");
|
||||||
String hint_config_dir = path_join(locations[i], "etc");
|
String hint_config_dir = path::join(locations[i], "etc");
|
||||||
|
|
||||||
if (FileAccess::exists(hint_mscorlib_path) && DirAccess::exists(hint_config_dir)) {
|
if (FileAccess::exists(hint_mscorlib_path) && DirAccess::exists(hint_config_dir)) {
|
||||||
assembly_rootdir = hint_assembly_rootdir;
|
assembly_rootdir = hint_assembly_rootdir;
|
||||||
|
@ -564,6 +564,7 @@ bool GDMono::_load_corlib_assembly() {
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
static bool copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name, APIAssembly::Type p_api_type) {
|
static bool copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name, APIAssembly::Type p_api_type) {
|
||||||
|
|
||||||
// Create destination directory if needed
|
// Create destination directory if needed
|
||||||
|
@ -607,6 +608,7 @@ static bool copy_api_assembly(const String &p_src_dir, const String &p_dst_dir,
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool GDMono::_load_core_api_assembly() {
|
bool GDMono::_load_core_api_assembly() {
|
||||||
|
|
||||||
|
|
|
@ -36,16 +36,21 @@
|
||||||
#include "core/project_settings.h"
|
#include "core/project_settings.h"
|
||||||
|
|
||||||
#ifdef WINDOWS_ENABLED
|
#ifdef WINDOWS_ENABLED
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
#define ENV_PATH_SEP ";"
|
#define ENV_PATH_SEP ";"
|
||||||
#else
|
#else
|
||||||
#define ENV_PATH_SEP ":"
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define ENV_PATH_SEP ":"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
String path_which(const String &p_name) {
|
namespace path {
|
||||||
|
|
||||||
|
String find_executable(const String &p_name) {
|
||||||
#ifdef WINDOWS_ENABLED
|
#ifdef WINDOWS_ENABLED
|
||||||
Vector<String> exts = OS::get_singleton()->get_environment("PATHEXT").split(ENV_PATH_SEP, false);
|
Vector<String> exts = OS::get_singleton()->get_environment("PATHEXT").split(ENV_PATH_SEP, false);
|
||||||
#endif
|
#endif
|
||||||
|
@ -55,7 +60,7 @@ String path_which(const String &p_name) {
|
||||||
return String();
|
return String();
|
||||||
|
|
||||||
for (int i = 0; i < env_path.size(); i++) {
|
for (int i = 0; i < env_path.size(); i++) {
|
||||||
String p = path_join(env_path[i], p_name);
|
String p = path::join(env_path[i], p_name);
|
||||||
|
|
||||||
#ifdef WINDOWS_ENABLED
|
#ifdef WINDOWS_ENABLED
|
||||||
for (int j = 0; j < exts.size(); j++) {
|
for (int j = 0; j < exts.size(); j++) {
|
||||||
|
@ -73,42 +78,96 @@ String path_which(const String &p_name) {
|
||||||
return String();
|
return String();
|
||||||
}
|
}
|
||||||
|
|
||||||
void fix_path(const String &p_path, String &r_out) {
|
String cwd() {
|
||||||
r_out = p_path.replace("\\", "/");
|
|
||||||
|
|
||||||
while (true) { // in case of using 2 or more slash
|
|
||||||
String compare = r_out.replace("//", "/");
|
|
||||||
if (r_out == compare)
|
|
||||||
break;
|
|
||||||
else
|
|
||||||
r_out = compare;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool rel_path_to_abs(const String &p_existing_path, String &r_abs_path) {
|
|
||||||
#ifdef WINDOWS_ENABLED
|
#ifdef WINDOWS_ENABLED
|
||||||
CharType ret[_MAX_PATH];
|
const DWORD expected_size = ::GetCurrentDirectoryW(0, NULL);
|
||||||
if (::_wfullpath(ret, p_existing_path.c_str(), _MAX_PATH)) {
|
|
||||||
String abspath = String(ret).replace("\\", "/");
|
String buffer;
|
||||||
int pos = abspath.find(":/");
|
buffer.resize((int)expected_size);
|
||||||
if (pos != -1) {
|
if (::GetCurrentDirectoryW(expected_size, buffer.ptrw()) == 0)
|
||||||
r_abs_path = abspath.substr(pos - 1, abspath.length());
|
return ".";
|
||||||
} else {
|
|
||||||
r_abs_path = abspath;
|
return buffer.simplify_path();
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
char *resolved_path = ::realpath(p_existing_path.utf8().get_data(), NULL);
|
char buffer[PATH_MAX];
|
||||||
if (resolved_path) {
|
if (::getcwd(buffer, sizeof(buffer)) == NULL)
|
||||||
String retstr;
|
return ".";
|
||||||
bool success = !retstr.parse_utf8(resolved_path);
|
|
||||||
::free(resolved_path);
|
String result;
|
||||||
if (success) {
|
if (result.parse_utf8(buffer))
|
||||||
r_abs_path = retstr;
|
return ".";
|
||||||
return true;
|
|
||||||
}
|
return result.simplify_path();
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String abspath(const String &p_path) {
|
||||||
|
if (p_path.is_abs_path()) {
|
||||||
|
return p_path.simplify_path();
|
||||||
|
} else {
|
||||||
|
return path::join(path::cwd(), p_path).simplify_path();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String realpath(const String &p_path) {
|
||||||
|
#ifdef WINDOWS_ENABLED
|
||||||
|
// Open file without read/write access
|
||||||
|
HANDLE hFile = ::CreateFileW(p_path.c_str(), 0,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||||
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
|
||||||
|
if (hFile == INVALID_HANDLE_VALUE)
|
||||||
|
return p_path;
|
||||||
|
|
||||||
|
const DWORD expected_size = ::GetFinalPathNameByHandleW(hFile, NULL, 0, FILE_NAME_NORMALIZED);
|
||||||
|
|
||||||
|
if (expected_size == 0) {
|
||||||
|
::CloseHandle(hFile);
|
||||||
|
return p_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
String buffer;
|
||||||
|
buffer.resize((int)expected_size);
|
||||||
|
::GetFinalPathNameByHandleW(hFile, buffer.ptrw(), expected_size, FILE_NAME_NORMALIZED);
|
||||||
|
|
||||||
|
::CloseHandle(hFile);
|
||||||
|
return buffer.simplify_path();
|
||||||
|
#elif UNIX_ENABLED
|
||||||
|
char *resolved_path = ::realpath(p_path.utf8().get_data(), NULL);
|
||||||
|
|
||||||
|
if (!resolved_path)
|
||||||
|
return p_path;
|
||||||
|
|
||||||
|
String result;
|
||||||
|
bool parse_ok = result.parse_utf8(resolved_path);
|
||||||
|
::free(resolved_path);
|
||||||
|
|
||||||
|
if (parse_ok)
|
||||||
|
return p_path;
|
||||||
|
|
||||||
|
return result.simplify_path();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
String join(const String &p_a, const String &p_b) {
|
||||||
|
if (p_a.empty())
|
||||||
|
return p_b;
|
||||||
|
|
||||||
|
const CharType a_last = p_a[p_a.length() - 1];
|
||||||
|
if ((a_last == '/' || a_last == '\\') ||
|
||||||
|
(p_b.size() > 0 && (p_b[0] == '/' || p_b[0] == '\\'))) {
|
||||||
|
return p_a + p_b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p_a + "/" + p_b;
|
||||||
|
}
|
||||||
|
|
||||||
|
String join(const String &p_a, const String &p_b, const String &p_c) {
|
||||||
|
return path::join(path::join(p_a, p_b), p_c);
|
||||||
|
}
|
||||||
|
|
||||||
|
String join(const String &p_a, const String &p_b, const String &p_c, const String &p_d) {
|
||||||
|
return path::join(path::join(path::join(p_a, p_b), p_c), p_d);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace path
|
||||||
|
|
|
@ -31,24 +31,32 @@
|
||||||
#ifndef PATH_UTILS_H
|
#ifndef PATH_UTILS_H
|
||||||
#define PATH_UTILS_H
|
#define PATH_UTILS_H
|
||||||
|
|
||||||
|
#include "core/string_builder.h"
|
||||||
#include "core/ustring.h"
|
#include "core/ustring.h"
|
||||||
|
|
||||||
_FORCE_INLINE_ String path_join(const String &e1, const String &e2) {
|
namespace path {
|
||||||
return e1.plus_file(e2);
|
|
||||||
}
|
|
||||||
|
|
||||||
_FORCE_INLINE_ String path_join(const String &e1, const String &e2, const String &e3) {
|
String join(const String &p_a, const String &p_b);
|
||||||
return e1.plus_file(e2).plus_file(e3);
|
String join(const String &p_a, const String &p_b, const String &p_c);
|
||||||
}
|
String join(const String &p_a, const String &p_b, const String &p_c, const String &p_d);
|
||||||
|
|
||||||
_FORCE_INLINE_ String path_join(const String &e1, const String &e2, const String &e3, const String &e4) {
|
String find_executable(const String &p_name);
|
||||||
return e1.plus_file(e2).plus_file(e3).plus_file(e4);
|
|
||||||
}
|
|
||||||
|
|
||||||
String path_which(const String &p_name);
|
/// Returns a normalized absolute path to the current working directory
|
||||||
|
String cwd();
|
||||||
|
|
||||||
void fix_path(const String &p_path, String &r_out);
|
/**
|
||||||
|
* Obtains a normalized absolute path to p_path. Symbolic links are
|
||||||
|
* not resolved. The path p_path might not exist in the file system.
|
||||||
|
*/
|
||||||
|
String abspath(const String &p_path);
|
||||||
|
|
||||||
bool rel_path_to_abs(const String &p_existing_path, String &r_abs_path);
|
/**
|
||||||
|
* Obtains a normalized path to p_path with symbolic links resolved.
|
||||||
|
* The resulting path might be either a relative or an absolute path.
|
||||||
|
*/
|
||||||
|
String realpath(const String &p_path);
|
||||||
|
|
||||||
|
} // namespace path
|
||||||
|
|
||||||
#endif // PATH_UTILS_H
|
#endif // PATH_UTILS_H
|
||||||
|
|
Loading…
Reference in a new issue