void add_item(const String &p_project_path, const String &p_item_type, const String &p_include) { _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN) GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectUtils"); Variant project_path = p_project_path; Variant item_type = p_item_type; Variant include = p_include; const Variant *args[3] = { &project_path, &item_type, &include }; MonoException *exc = NULL; klass->get_method("AddItemToProjectChecked", 3)->invoke(NULL, args, &exc); if (exc) { GDMonoUtils::debug_print_unhandled_exception(exc); ERR_FAIL(); } }
String generate_core_api_project(const String &p_dir, const Vector<String> &p_files) { _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN) GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectGenerator"); Variant dir = p_dir; Variant compile_items = p_files; const Variant *args[2] = { &dir, &compile_items }; MonoException *exc = NULL; MonoObject *ret = klass->get_method("GenCoreApiProject", 2)->invoke(NULL, args, &exc); if (exc) { GDMonoUtils::debug_print_unhandled_exception(exc); ERR_FAIL_V(String()); } return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : String(); }
String generate_game_project(const String &p_dir, const String &p_name, const Vector<String> &p_files) { _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN) GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectGenerator"); Variant dir = p_dir; Variant name = p_name; Variant compile_items = p_files; const Variant *args[3] = { &dir, &name, &compile_items }; MonoObject *ex = NULL; MonoObject *ret = klass->get_method("GenGameProject", 3)->invoke(NULL, args, &ex); if (ex) { mono_print_unhandled_exception(ex); ERR_FAIL_V(String()); } return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : ""; }
void GodotSharpBuilds::BuildProcess::start(bool p_blocking) { _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN) exit_code = -1; String logs_dir = GodotSharpDirs::get_build_logs_dir().plus_file(build_info.solution.md5_text() + "_" + build_info.configuration); if (build_tab) { build_tab->on_build_start(); } else { build_tab = memnew(MonoBuildTab(build_info, logs_dir)); MonoBottomPanel::get_singleton()->add_build_tab(build_tab); } if (p_blocking) { // Required in order to update the build tasks list Main::iteration(); } if (!exited) { exited = true; String message = "Tried to start build process, but it is already running"; build_tab->on_build_exec_failed(message); ERR_EXPLAIN(message); ERR_FAIL(); } exited = false; // Remove old issues file String issues_file = "msbuild_issues.csv"; DirAccessRef d = DirAccess::create_for_path(logs_dir); if (d->file_exists(issues_file)) { Error err = d->remove(issues_file); if (err != OK) { exited = true; String file_path = ProjectSettings::get_singleton()->localize_path(logs_dir).plus_file(issues_file); String message = "Cannot remove issues file: " + file_path; build_tab->on_build_exec_failed(message); ERR_EXPLAIN(message); ERR_FAIL(); } } GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Build", "BuildInstance"); MonoObject *mono_object = mono_object_new(mono_domain_get(), klass->get_raw()); // Construct Variant solution = build_info.solution; Variant config = build_info.configuration; const Variant *ctor_args[2] = { &solution, &config }; MonoObject *ex = NULL; GDMonoMethod *ctor = klass->get_method(".ctor", 2); ctor->invoke(mono_object, ctor_args, &ex); if (ex) { exited = true; String message = "The build constructor threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(ex); build_tab->on_build_exec_failed(message); ERR_EXPLAIN(message); ERR_FAIL(); } // Call Build Variant logger_assembly = OS::get_singleton()->get_executable_path().get_base_dir().plus_file(EDITOR_TOOLS_ASSEMBLY_NAME) + ".dll"; Variant logger_output_dir = logs_dir; Variant custom_props = build_info.custom_props; const Variant *args[3] = { &logger_assembly, &logger_output_dir, &custom_props }; ex = NULL; GDMonoMethod *build_method = klass->get_method(p_blocking ? "Build" : "BuildAsync", 3); build_method->invoke(mono_object, args, &ex); if (ex) { exited = true; String message = "The build method threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(ex); build_tab->on_build_exec_failed(message); ERR_EXPLAIN(message); ERR_FAIL(); } // Build returned if (p_blocking) { exited = true; exit_code = klass->get_field("exitCode")->get_int_value(mono_object); if (exit_code != 0 && OS::get_singleton()->is_stdout_verbose()) OS::get_singleton()->print(String("MSBuild finished with exit code " + itos(exit_code) + "\n").utf8()); build_tab->on_build_exit(exit_code == 0 ? MonoBuildTab::RESULT_SUCCESS : MonoBuildTab::RESULT_ERROR); } else { build_instance = MonoGCHandle::create_strong(mono_object); exited = false; } }
void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base) { CRASH_COND(!CACHED_CLASS(GodotObject)->is_assignable_from(this)); if (methods_fetched) return; void *iter = NULL; MonoMethod *raw_method = NULL; while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != NULL) { StringName name = mono_method_get_name(raw_method); // get_method implicitly fetches methods and adds them to this->methods GDMonoMethod *method = get_method(raw_method, name); ERR_CONTINUE(!method); if (method->get_name() != name) { #ifdef DEBUG_ENABLED String fullname = method->get_ret_type_full_name() + " " + name + "(" + method->get_signature_desc(true) + ")"; WARN_PRINTS("Method `" + fullname + "` is hidden by Godot API method. Should be `" + method->get_full_name_no_class() + "`. In class `" + namespace_name + "." + class_name + "`."); #endif continue; } #ifdef DEBUG_ENABLED // For debug builds, we also fetched from native base classes as well before if this is not a native base class. // This allows us to warn the user here if he is using snake_case by mistake. if (p_native_base != this) { GDMonoClass *native_top = p_native_base; while (native_top) { GDMonoMethod *m = native_top->get_method(name, method->get_parameters_count()); if (m && m->get_name() != name) { // found String fullname = m->get_ret_type_full_name() + " " + name + "(" + m->get_signature_desc(true) + ")"; WARN_PRINTS("Method `" + fullname + "` should be `" + m->get_full_name_no_class() + "`. In class `" + namespace_name + "." + class_name + "`."); break; } if (native_top == CACHED_CLASS(GodotObject)) break; native_top = native_top->get_parent_class(); } } #endif uint32_t flags = mono_method_get_flags(method->mono_method, NULL); if (!(flags & MONO_METHOD_ATTR_VIRTUAL)) continue; // Virtual method of Godot Object derived type, let's try to find GodotMethod attribute GDMonoClass *top = p_native_base; while (top) { GDMonoMethod *base_method = top->get_method(name, method->get_parameters_count()); if (base_method && base_method->has_attribute(CACHED_CLASS(GodotMethodAttribute))) { // Found base method with GodotMethod attribute. // We get the original API method name from this attribute. // This name must point to the virtual method. MonoObject *attr = base_method->get_attribute(CACHED_CLASS(GodotMethodAttribute)); StringName godot_method_name = CACHED_FIELD(GodotMethodAttribute, methodName)->get_string_value(attr); #ifdef DEBUG_ENABLED CRASH_COND(godot_method_name == StringName()); #endif MethodKey key = MethodKey(godot_method_name, method->get_parameters_count()); GDMonoMethod **existing_method = methods.getptr(key); if (existing_method) memdelete(*existing_method); // Must delete old one methods.set(key, method); break; } if (top == CACHED_CLASS(GodotObject)) break; top = top->get_parent_class(); } } methods_fetched = true; }