diff options
32 files changed, 720 insertions, 297 deletions
diff --git a/AUTHORS.md b/AUTHORS.md index 9666145582..13a67ce3f5 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -45,9 +45,11 @@ name is available. Bojidar Marinov (bojidar-bg) bruvzg Carl Olsson (not-surt) + Chris Bradfield (cbscribe) Dana Olson (adolson) Daniel J. Ramirez (djrm) Dmitry Koteroff (Krakean) + DualMatrix Emmanuel Leblond (touilleMan) Eric Lasota (elasota) est31 @@ -111,9 +113,9 @@ name is available. Ramesh Ravone (RameshRavone) Ray Koopa (RayKoopa) Rémi Verschelde (akien-mga) + Rhody Lugo (rraallvv) Roberto F. Arroyo (robfram) romulox-x - rraallvv Ruslan Mustakov (endragor) Saniko (sanikoyes) SaracenOne @@ -21,40 +21,43 @@ generous deed immortalized in the next stable release of Godot Engine. ## Mini sponsors + Andrew Dunai Brandon Lamb Christian Uldall Pedersen Christopher Igoe Christoph Woinke GameDev.net Hein-Pieter van Braam + iDev.Network Studios Jamal Alyafei Jay Sistar + Leona Eden Matthieu Huvé Mike King Nathan Warden Neal Gompa (Conan Kudo) Pascal Julien Patrick Aarstad - rottis Ruslan Mustakov Slobodan Milnovic Stephan Lanfermann Stoney Meyerhoeffer + thechris Thomas Mathews VilliHaukka ## Gold donors - 3Dexplorer Asdf cheese65536 K9Kraken - Kris Michael Manuele Finocchiaro Nathanael Beisiegel Officine Pixel S.n.c. + Retro Village Zaven Muradyan + 13MHz Allen Schade Andreas Schüle Austen McRae @@ -62,12 +65,14 @@ generous deed immortalized in the next stable release of Godot Engine. David Gehrig Florian Breisch Gary Oberbrunner + Jay Horton Johannes Wuensch Josep G. Camarasa Joshua Lesperance Krzysztof Dluzniewski Kyle Szklenski Mohammad Taleb + Moonwards Paul LaMotte Ranoller Sergey @@ -91,7 +96,6 @@ generous deed immortalized in the next stable release of Godot Engine. Rami Robert Willes Robin Arys - Rodrigo Loli Ronnie Ashlock ScottMakesGames Thomas Bjarnelöf @@ -102,8 +106,8 @@ generous deed immortalized in the next stable release of Godot Engine. Alessandra Pereyra Alexey Dyadchenko Amanda Haldy - Anthony Ryan Branwen Danielle Zakariasen + Chau Siu Hung Chris Brown Chris Petrich Cody Parker @@ -112,15 +116,16 @@ generous deed immortalized in the next stable release of Godot Engine. E.G. Eric Eric Monson + Ethan Bennis Fidget Sinner flesk G Barnes + Gero GGGames.org Giovanni Solimeno Guilherme Felipe de C. G. da Silva Hasen Judy Heath Hayes - Jay Horton Jeppe Zapp joe513 Juraj Móza @@ -130,10 +135,8 @@ generous deed immortalized in the next stable release of Godot Engine. Markus Wiesner Marvin Nahuel Sacchetti - Neal Barry Nick Nikitin Pablo Cholaky - Patrick Schnorbus Pete Goodwin ray-tracer Ruben Soares Luis @@ -141,10 +144,9 @@ generous deed immortalized in the next stable release of Godot Engine. Sindre Sømme Sofox Stoned Xander - Tim Dalporto Trent McPheron - Wilfrid ARNOLD WytRabbit + Zachariah Gibbons ## Silver donors @@ -177,7 +179,6 @@ generous deed immortalized in the next stable release of Godot Engine. Christian Baune Christian Winter Christopher Schmitt - Chris Wilson Collin Shooltz Daniel Johnson Daniel Kaplan @@ -187,16 +188,14 @@ generous deed immortalized in the next stable release of Godot Engine. David May Disktra Dominik Wetzel - dRez Games Duy Kevin Nguyen Edward Herbert Elias Nykrem Eric Martini Eugenio Hugo Salgüero Jáñez - Extarys Fabian Becker fengjiongmax - Francesco Lisi + Foomf G3Dev sàrl Gerrit Großkopf Gilberto K. Otubo @@ -207,7 +206,6 @@ generous deed immortalized in the next stable release of Godot Engine. ialex32x Jahn Johansen Jaime Ruiz-Borau Vizárraga - Jed Jeff Hungerford Joel Fivat Johan Lindberg @@ -237,7 +235,6 @@ generous deed immortalized in the next stable release of Godot Engine. magodev Manolis Makris Martin Eigel - Martins Odabi Max R.R. Collada Maxwell Mertcan Mermerkaya @@ -256,14 +253,15 @@ generous deed immortalized in the next stable release of Godot Engine. Nicolas SAN AGUSTIN Niko Leopold Noi Sek - Pablo Seibelt Pan Ip Pascal Grüter Pat LaBine Patrick Nafarrete Paul E Hansen + Paul Gieske Paul Mason Paweł Kowal + Phillip Ryals Pierre-Igor Berthet Pietro Vertechi Piotr Kaczmarski @@ -287,9 +285,11 @@ generous deed immortalized in the next stable release of Godot Engine. Tim Tom Larrow Tristan Crawford + Tryggve Sollid Trym Nilsen Tyler Stafos UltyX + Vaiktorg Victor Viktor Ferenczi waka nya diff --git a/core/array.cpp b/core/array.cpp index 9708452850..9f09ddbe15 100644 --- a/core/array.cpp +++ b/core/array.cpp @@ -258,6 +258,7 @@ struct _ArrayVariantSortCustom { Array &Array::sort_custom(Object *p_obj, const StringName &p_function) { ERR_FAIL_NULL_V(p_obj, *this); + ERR_FAIL_COND_V(!p_obj->has_method(p_function), *this); SortArray<Variant, _ArrayVariantSortCustom, true> avs; avs.compare.obj = p_obj; diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp index f202320043..3ae9ff676c 100644 --- a/core/io/image_loader.cpp +++ b/core/io/image_loader.cpp @@ -118,7 +118,6 @@ RES ResourceFormatLoaderImage::load(const String &p_path, const String &p_origin if (r_error) { *r_error = ERR_CANT_OPEN; } - memdelete(f); return RES(); } diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml index 338d01ae5f..10ec15b99d 100644 --- a/doc/classes/Input.xml +++ b/doc/classes/Input.xml @@ -55,6 +55,7 @@ <argument index="0" name="action" type="String"> </argument> <description> + Returns a value between 0 and 1 representing the intensity of the given action. In a joypad, for example, the further away the axis (analog sticks or L2, R2 triggers) is from the dead zone, the closer the value will be to 1. If the action is mapped to a control that has no axis as the keyboard, the value returned will be 0 or 1. </description> </method> <method name="get_connected_joypads"> diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp index 09e50e4aaa..cf8fb08f76 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.cpp +++ b/drivers/coreaudio/audio_driver_coreaudio.cpp @@ -277,7 +277,7 @@ OSStatus AudioDriverCoreAudio::input_callback(void *inRefCon, } } } else { - ERR_PRINT(("AudioUnitRender failed, code: " + itos(result)).utf8().get_data()); + ERR_PRINTS("AudioUnitRender failed, code: " + itos(result)); } ad->unlock(); @@ -289,7 +289,7 @@ void AudioDriverCoreAudio::start() { if (!active) { OSStatus result = AudioOutputUnitStart(audio_unit); if (result != noErr) { - ERR_PRINT(("AudioOutputUnitStart failed, code: " + itos(result)).utf8().get_data()); + ERR_PRINTS("AudioOutputUnitStart failed, code: " + itos(result)); } else { active = true; } @@ -300,7 +300,7 @@ void AudioDriverCoreAudio::stop() { if (active) { OSStatus result = AudioOutputUnitStop(audio_unit); if (result != noErr) { - ERR_PRINT(("AudioOutputUnitStop failed, code: " + itos(result)).utf8().get_data()); + ERR_PRINTS("AudioOutputUnitStop failed, code: " + itos(result)); } else { active = false; } diff --git a/drivers/coremidi/core_midi.cpp b/drivers/coremidi/core_midi.cpp index e8106c4543..2ebbabaa38 100644 --- a/drivers/coremidi/core_midi.cpp +++ b/drivers/coremidi/core_midi.cpp @@ -51,13 +51,13 @@ Error MIDIDriverCoreMidi::open() { OSStatus result = MIDIClientCreate(name, NULL, NULL, &client); CFRelease(name); if (result != noErr) { - ERR_PRINTS("MIDIClientCreate failed: " + String(GetMacOSStatusErrorString(result))); + ERR_PRINTS("MIDIClientCreate failed, code: " + itos(result)); return ERR_CANT_OPEN; } result = MIDIInputPortCreate(client, CFSTR("Godot Input"), MIDIDriverCoreMidi::read, (void *)this, &port_in); if (result != noErr) { - ERR_PRINTS("MIDIInputPortCreate failed: " + String(GetMacOSStatusErrorString(result))); + ERR_PRINTS("MIDIInputPortCreate failed, code: " + itos(result)); return ERR_CANT_OPEN; } @@ -65,7 +65,7 @@ Error MIDIDriverCoreMidi::open() { for (int i = 0; i < sources; i++) { MIDIEndpointRef source = MIDIGetSource(i); - if (source != NULL) { + if (source) { MIDIPortConnectSource(port_in, source, (void *)this); connected_sources.insert(i, source); } diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index eb11aea9cc..c4516c1f17 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -558,6 +558,7 @@ void CreateDialog::_history_selected() { return; search_box->set_text(item->get_text(0).get_slicec(' ', 0)); + favorites->deselect_all(); _update_search(); } @@ -568,6 +569,7 @@ void CreateDialog::_favorite_selected() { return; search_box->set_text(item->get_text(0).get_slicec(' ', 0)); + recent->deselect_all(); _update_search(); } diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 2c69909f23..4d386c1af6 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -1953,7 +1953,7 @@ void FileSystemDock::_get_drag_target_folder(String &target, bool &target_favori } String ltarget = files->get_item_metadata(pos); - target = ltarget.ends_with("/") ? ltarget : path; + target = ltarget.ends_with("/") ? ltarget : path.get_base_dir(); return; } diff --git a/editor/icons/icon_noise_texture.svg b/editor/icons/icon_noise_texture.svg new file mode 100644 index 0000000000..5908c2b2d4 --- /dev/null +++ b/editor/icons/icon_noise_texture.svg @@ -0,0 +1,3 @@ +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> +<path d="m2 1c-0.55228 0-1 0.44772-1 1v12c0 0.55228 0.44772 1 1 1h12c0.55228 0 1-0.44772 1-1v-12c0-0.55228-0.44772-1-1-1zm1 2h10v8h-10zm3 1v2h2v-2zm2 2v2h2v2h2v-6h-2v2zm0 2h-2v-2h-2v4h4z" fill="#e0e0e0" fill-opacity=".99608"/> +</svg> diff --git a/modules/mono/SCsub b/modules/mono/SCsub index 1d5c145027..e4691ee5c8 100644 --- a/modules/mono/SCsub +++ b/modules/mono/SCsub @@ -244,16 +244,13 @@ def mono_build_solution(source, target, env): copyfile(os.path.join(src_dir, asm_file), os.path.join(dst_dir, asm_file)) -output_dir = Dir('#bin').abspath -assemblies_output_dir = Dir(env['mono_assemblies_output_dir']).abspath - -mono_sln_builder = Builder(action=mono_build_solution) -env_mono.Append(BUILDERS={'MonoBuildSolution': mono_sln_builder}) -env_mono.MonoBuildSolution( - os.path.join(assemblies_output_dir, 'GodotSharpTools.dll'), - 'editor/GodotSharpTools/GodotSharpTools.sln' -) - -if os.path.normpath(output_dir) != os.path.normpath(assemblies_output_dir): - rel_assemblies_output_dir = os.path.relpath(assemblies_output_dir, output_dir) - env_mono.Append(CPPDEFINES={'GD_MONO_EDITOR_ASSEMBLIES_DIR': rel_assemblies_output_dir}) +if env['tools']: + output_dir = Dir('#bin').abspath + editor_tools_dir = os.path.join(output_dir, 'GodotSharp', 'Tools') + + mono_sln_builder = Builder(action=mono_build_solution) + env_mono.Append(BUILDERS={'MonoBuildSolution': mono_sln_builder}) + env_mono.MonoBuildSolution( + os.path.join(editor_tools_dir, 'GodotSharpTools.dll'), + 'editor/GodotSharpTools/GodotSharpTools.sln' + ) diff --git a/modules/mono/config.py b/modules/mono/config.py index 01649a972e..8427103ee7 100644 --- a/modules/mono/config.py +++ b/modules/mono/config.py @@ -5,7 +5,7 @@ import sys import subprocess from distutils.version import LooseVersion -from SCons.Script import BoolVariable, Dir, Environment, File, PathVariable, SCons, Variables +from SCons.Script import BoolVariable, Dir, Environment, File, SCons, Variables monoreg = imp.load_source('mono_reg_utils', 'modules/mono/mono_reg_utils.py') @@ -55,30 +55,20 @@ def copy_file(src_dir, dst_dir, name): copyfile(src_path, dst_path) -def custom_path_is_dir_create(key, val, env): - """Validator to check if Path is a directory, creating it if it does not exist. - Similar to PathIsDirCreate, except it uses SCons.Script.Dir() and - SCons.Script.File() in order to support the '#' top level directory token. - """ - # Dir constructor will throw an error if the path points to a file - fsDir = Dir(val) - if not fsDir.exists: - os.makedirs(fsDir.abspath) - - def configure(env): env.use_ptrcall = True env.add_module_version_string('mono') envvars = Variables() envvars.Add(BoolVariable('mono_static', 'Statically link mono', False)) - envvars.Add(PathVariable('mono_assemblies_output_dir', 'Path to the assemblies output directory', '#bin', custom_path_is_dir_create)) + envvars.Add(BoolVariable('copy_mono_root', 'Make a copy of the mono installation directory to bundle with the editor', False)) envvars.Update(env) bits = env['bits'] + tools_enabled = env['tools'] mono_static = env['mono_static'] - assemblies_output_dir = Dir(env['mono_assemblies_output_dir']).abspath + copy_mono_root = env['copy_mono_root'] mono_lib_names = ['mono-2.0-sgen', 'monosgen-2.0'] @@ -151,8 +141,6 @@ def configure(env): raise RuntimeError('Could not find mono shared library in: ' + mono_bin_path) copy_file(mono_bin_path, 'bin', mono_dll_name + '.dll') - - copy_file(os.path.join(mono_lib_path, 'mono', '4.5'), assemblies_output_dir, 'mscorlib.dll') else: sharedlib_ext = '.dylib' if sys.platform == 'darwin' else '.so' @@ -204,16 +192,14 @@ def configure(env): if sys.platform == 'darwin': env.Append(LINKFLAGS=['-Wl,-force_load,' + mono_lib_file]) - elif sys.platform == 'linux' or sys.platform == 'linux2': - env.Append(LINKFLAGS=['-Wl,-whole-archive', mono_lib_file, '-Wl,-no-whole-archive']) else: - raise RuntimeError('mono-static: Not supported on this platform') + env.Append(LINKFLAGS=['-Wl,-whole-archive', mono_lib_file, '-Wl,-no-whole-archive']) else: env.Append(LIBS=[mono_lib]) if sys.platform == 'darwin': env.Append(LIBS=['iconv', 'pthread']) - elif sys.platform == 'linux' or sys.platform == 'linux2': + else: env.Append(LIBS=['m', 'rt', 'dl', 'pthread']) if not mono_static: @@ -223,8 +209,6 @@ def configure(env): raise RuntimeError('Could not find mono shared library in: ' + mono_lib_path) copy_file(mono_lib_path, 'bin', 'lib' + mono_so_name + sharedlib_ext) - - copy_file(os.path.join(mono_lib_path, 'mono', '4.5'), assemblies_output_dir, 'mscorlib.dll') else: assert not mono_static @@ -238,7 +222,6 @@ def configure(env): mono_lib_path = '' mono_so_name = '' - mono_prefix = subprocess.check_output(['pkg-config', 'mono-2', '--variable=prefix']).decode('utf8').strip() tmpenv = Environment() tmpenv.AppendENVPath('PKG_CONFIG_PATH', os.getenv('PKG_CONFIG_PATH')) @@ -255,16 +238,163 @@ def configure(env): raise RuntimeError('Could not find mono shared library in: ' + str(tmpenv['LIBPATH'])) copy_file(mono_lib_path, 'bin', 'lib' + mono_so_name + sharedlib_ext) - copy_file(os.path.join(mono_prefix, 'lib', 'mono', '4.5'), assemblies_output_dir, 'mscorlib.dll') env.Append(LINKFLAGS='-rdynamic') + if not tools_enabled: + if not mono_root: + mono_root = subprocess.check_output(['pkg-config', 'mono-2', '--variable=prefix']).decode('utf8').strip() + + make_template_dir(env, mono_root) + + if copy_mono_root: + if not mono_root: + mono_root = subprocess.check_output(['pkg-config', 'mono-2', '--variable=prefix']).decode('utf8').strip() + + if tools_enabled: + copy_mono_root_files(env, mono_root) + else: + print("Ignoring option: 'copy_mono_root'. Only available for builds with 'tools' enabled.") + + +def make_template_dir(env, mono_root): + from shutil import rmtree + + platform = env['platform'] + target = env['target'] + + template_dir_name = '' + + if platform == 'windows': + template_dir_name = 'data.mono.%s.%s.%s' % (platform, env['bits'], target) + elif platform == 'osx': + template_dir_name = 'data.mono.%s.%s' % (platform, target) + elif platform == 'x11': + template_dir_name = 'data.mono.%s.%s.%s' % (platform, env['bits'], target) + else: + assert False + + output_dir = Dir('#bin').abspath + template_dir = os.path.join(output_dir, template_dir_name) + + template_mono_root_dir = os.path.join(template_dir, 'Mono') + + if os.path.isdir(template_mono_root_dir): + rmtree(template_mono_root_dir) # Clean first + + # Copy etc/mono/ + + template_mono_config_dir = os.path.join(template_mono_root_dir, 'etc', 'mono') + copy_mono_etc_dir(mono_root, template_mono_config_dir, env['platform']) + + # Copy the required shared libraries + + copy_mono_shared_libs(mono_root, template_mono_root_dir, env['platform']) + + +def copy_mono_root_files(env, mono_root): + from glob import glob + from shutil import copy + from shutil import rmtree + + if not mono_root: + raise RuntimeError('Mono installation directory not found') + + output_dir = Dir('#bin').abspath + editor_mono_root_dir = os.path.join(output_dir, 'GodotSharp', 'Mono') + + if os.path.isdir(editor_mono_root_dir): + rmtree(editor_mono_root_dir) # Clean first + + # Copy etc/mono/ + + editor_mono_config_dir = os.path.join(editor_mono_root_dir, 'etc', 'mono') + copy_mono_etc_dir(mono_root, editor_mono_config_dir, env['platform']) + + # Copy the required shared libraries + + copy_mono_shared_libs(mono_root, editor_mono_root_dir, env['platform']) + + # Copy framework assemblies + + mono_framework_dir = os.path.join(mono_root, 'lib', 'mono', '4.5') + mono_framework_facades_dir = os.path.join(mono_framework_dir, 'Facades') + + editor_mono_framework_dir = os.path.join(editor_mono_root_dir, 'lib', 'mono', '4.5') + editor_mono_framework_facades_dir = os.path.join(editor_mono_framework_dir, 'Facades') + + if not os.path.isdir(editor_mono_framework_dir): + os.makedirs(editor_mono_framework_dir) + if not os.path.isdir(editor_mono_framework_facades_dir): + os.makedirs(editor_mono_framework_facades_dir) + + for assembly in glob(os.path.join(mono_framework_dir, '*.dll')): + copy(assembly, editor_mono_framework_dir) + for assembly in glob(os.path.join(mono_framework_facades_dir, '*.dll')): + copy(assembly, editor_mono_framework_facades_dir) + + +def copy_mono_etc_dir(mono_root, target_mono_config_dir, platform): + from distutils.dir_util import copy_tree + from glob import glob + from shutil import copy + + if not os.path.isdir(target_mono_config_dir): + os.makedirs(target_mono_config_dir) + + mono_etc_dir = os.path.join(mono_root, 'etc', 'mono') + if not os.path.isdir(mono_etc_dir): + mono_etc_dir = '' + etc_hint_dirs = [] + if platform != 'windows': + etc_hint_dirs += ['/etc/mono', '/usr/local/etc/mono'] + if 'MONO_CFG_DIR' in os.environ: + etc_hint_dirs += [os.path.join(os.environ['MONO_CFG_DIR'], 'mono')] + for etc_hint_dir in etc_hint_dirs: + if os.path.isdir(etc_hint_dir): + mono_etc_dir = etc_hint_dir + break + if not mono_etc_dir: + raise RuntimeError('Mono installation etc directory not found') + + copy_tree(os.path.join(mono_etc_dir, '2.0'), os.path.join(target_mono_config_dir, '2.0')) + copy_tree(os.path.join(mono_etc_dir, '4.0'), os.path.join(target_mono_config_dir, '4.0')) + copy_tree(os.path.join(mono_etc_dir, '4.5'), os.path.join(target_mono_config_dir, '4.5')) + copy_tree(os.path.join(mono_etc_dir, 'mconfig'), os.path.join(target_mono_config_dir, 'mconfig')) + + for file in glob(os.path.join(mono_etc_dir, '*')): + if os.path.isfile(file): + copy(file, target_mono_config_dir) + + +def copy_mono_shared_libs(mono_root, target_mono_root_dir, platform): + from shutil import copy + + if platform == 'windows': + target_mono_bin_dir = os.path.join(target_mono_root_dir, 'bin') + + if not os.path.isdir(target_mono_bin_dir): + os.makedirs(target_mono_bin_dir) + + copy(os.path.join(mono_root, 'bin', 'MonoPosixHelper.dll'), os.path.join(target_mono_bin_dir, 'MonoPosixHelper.dll')) + else: + target_mono_lib_dir = os.path.join(target_mono_root_dir, 'lib') + + if not os.path.isdir(target_mono_lib_dir): + os.makedirs(target_mono_lib_dir) + + if platform == 'osx': + copy(os.path.join(mono_root, 'lib', 'libMonoPosixHelper.dylib'), os.path.join(target_mono_lib_dir, 'libMonoPosixHelper.dylib')) + elif platform == 'x11': + copy(os.path.join(mono_root, 'lib', 'libmono-btls-shared.so'), os.path.join(target_mono_lib_dir, 'libmono-btls-shared.so')) + copy(os.path.join(mono_root, 'lib', 'libMonoPosixHelper.so'), os.path.join(target_mono_lib_dir, 'libMonoPosixHelper.so')) + def configure_for_mono_version(env, mono_version): if mono_version is None: raise RuntimeError('Mono JIT compiler version not found') print('Found Mono JIT compiler version: ' + str(mono_version)) - if mono_version >= LooseVersion("5.12.0"): + if mono_version >= LooseVersion('5.12.0'): env.Append(CPPFLAGS=['-DHAS_PENDING_EXCEPTIONS']) diff --git a/modules/mono/editor/GodotSharpTools/Editor/GodotSharpExport.cs b/modules/mono/editor/GodotSharpTools/Editor/GodotSharpExport.cs new file mode 100644 index 0000000000..9f0d562ef7 --- /dev/null +++ b/modules/mono/editor/GodotSharpTools/Editor/GodotSharpExport.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.CompilerServices; + +namespace GodotSharpTools.Editor +{ + public static class GodotSharpExport + { + public static void _ExportBegin(string[] features, bool debug, string path, int flags) + { + var featureSet = new HashSet<string>(features); + + if (PlatformHasTemplateDir(featureSet)) + { + string templateDirName = "data.mono"; + + if (featureSet.Contains("Windows")) + { + templateDirName += ".windows"; + templateDirName += featureSet.Contains("64") ? ".64" : ".32"; + } + else if (featureSet.Contains("X11")) + { + templateDirName += ".x11"; + templateDirName += featureSet.Contains("64") ? ".64" : ".32"; + } + else + { + throw new NotSupportedException("Target platform not supported"); + } + + templateDirName += debug ? ".debug" : ".release"; + + string templateDirPath = Path.Combine(GetTemplatesDir(), templateDirName); + + if (!Directory.Exists(templateDirPath)) + throw new FileNotFoundException("Data template directory not found"); + + string outputDir = new FileInfo(path).Directory.FullName; + + string outputDataDir = Path.Combine(outputDir, GetDataDirName()); + + Directory.Delete(outputDataDir, recursive: true); // Clean first + Directory.CreateDirectory(outputDataDir); + + foreach (string dir in Directory.GetDirectories(templateDirPath, "*", SearchOption.AllDirectories)) + { + Directory.CreateDirectory(Path.Combine(outputDataDir, dir.Substring(templateDirPath.Length + 1))); + } + + foreach (string file in Directory.GetFiles(templateDirPath, "*", SearchOption.AllDirectories)) + { + File.Copy(file, Path.Combine(outputDataDir, file.Substring(templateDirPath.Length + 1))); + } + } + } + + public static bool PlatformHasTemplateDir(HashSet<string> featureSet) + { + // OSX export templates are contained in a zip, so we place + // our custom template inside it and let Godot do the rest. + return !featureSet.Contains("OSX"); + } + + [MethodImpl(MethodImplOptions.InternalCall)] + extern static string GetTemplatesDir(); + + [MethodImpl(MethodImplOptions.InternalCall)] + extern static string GetDataDirName(); + } +} diff --git a/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj b/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj index 773e8196f7..fceb732426 100644 --- a/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj +++ b/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj @@ -41,6 +41,7 @@ <Compile Include="Project\ProjectUtils.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Utils\OS.cs" /> + <Compile Include="Editor\GodotSharpExport.cs" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> </Project>
\ No newline at end of file diff --git a/modules/mono/editor/csharp_project.cpp b/modules/mono/editor/csharp_project.cpp index 4764cbe941..6f223b75a3 100644 --- a/modules/mono/editor/csharp_project.cpp +++ b/modules/mono/editor/csharp_project.cpp @@ -51,7 +51,7 @@ String generate_core_api_project(const String &p_dir, const Vector<String> &p_fi MonoObject *ret = klass->get_method("GenCoreApiProject", 2)->invoke(NULL, args, &exc); if (exc) { - GDMonoUtils::debug_unhandled_exception(exc); + GDMonoUtils::debug_print_unhandled_exception(exc); ERR_FAIL_V(String()); } @@ -72,7 +72,7 @@ String generate_editor_api_project(const String &p_dir, const String &p_core_dll MonoObject *ret = klass->get_method("GenEditorApiProject", 3)->invoke(NULL, args, &exc); if (exc) { - GDMonoUtils::debug_unhandled_exception(exc); + GDMonoUtils::debug_print_unhandled_exception(exc); ERR_FAIL_V(String()); } @@ -93,7 +93,7 @@ String generate_game_project(const String &p_dir, const String &p_name, const Ve MonoObject *ret = klass->get_method("GenGameProject", 3)->invoke(NULL, args, &exc); if (exc) { - GDMonoUtils::debug_unhandled_exception(exc); + GDMonoUtils::debug_print_unhandled_exception(exc); ERR_FAIL_V(String()); } @@ -114,7 +114,7 @@ void add_item(const String &p_project_path, const String &p_item_type, const Str klass->get_method("AddItemToProjectChecked", 3)->invoke(NULL, args, &exc); if (exc) { - GDMonoUtils::debug_unhandled_exception(exc); + GDMonoUtils::debug_print_unhandled_exception(exc); ERR_FAIL(); } } diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp index d397814fa7..8fe6e46b60 100644 --- a/modules/mono/editor/godotsharp_builds.cpp +++ b/modules/mono/editor/godotsharp_builds.cpp @@ -249,6 +249,18 @@ bool GodotSharpBuilds::build_api_sln(const String &p_name, const String &p_api_s bool GodotSharpBuilds::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 + if (!DirAccess::exists(p_dst_dir)) { + DirAccess *da = DirAccess::create_for_path(p_dst_dir); + Error err = da->make_dir_recursive(p_dst_dir); + memdelete(da); + + if (err != OK) { + show_build_error_dialog("Failed to create destination directory for the API assemblies. Error: " + itos(err)); + return false; + } + } + String assembly_file = p_assembly_name + ".dll"; String assembly_src = p_src_dir.plus_file(assembly_file); String assembly_dst = p_dst_dir.plus_file(assembly_file); @@ -296,9 +308,9 @@ bool GodotSharpBuilds::make_api_sln(APIAssembly::Type p_api_type) { String api_name = p_api_type == APIAssembly::API_CORE ? API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME; String api_build_config = "Release"; - EditorProgress pr("mono_build_release_" + api_name, "Building " + api_name + " solution...", 4); + EditorProgress pr("mono_build_release_" + api_name, "Building " + api_name + " solution...", 3); - pr.step("Generating " + api_name + " solution"); + pr.step("Generating " + api_name + " solution", 0); String core_api_sln_dir = GodotSharpDirs::get_mono_solutions_dir() .plus_file(_api_folder_name(APIAssembly::API_CORE)) @@ -336,34 +348,19 @@ bool GodotSharpBuilds::make_api_sln(APIAssembly::Type p_api_type) { } } - pr.step("Building " + api_name + " solution"); + pr.step("Building " + api_name + " solution", 1); if (!GodotSharpBuilds::build_api_sln(api_name, api_sln_dir, api_build_config)) return false; - pr.step("Copying " + api_name + " assembly"); - - String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir(); - - // Create assemblies directory if needed - if (!DirAccess::exists(res_assemblies_dir)) { - DirAccess *da = DirAccess::create_for_path(res_assemblies_dir); - Error err = da->make_dir_recursive(res_assemblies_dir); - memdelete(da); - - if (err != OK) { - show_build_error_dialog("Failed to create assemblies directory. Error: " + itos(err)); - return false; - } - } + pr.step("Copying " + api_name + " assembly", 2); // Copy the built assembly to the assemblies directory String api_assembly_dir = api_sln_dir.plus_file("bin").plus_file(api_build_config); + String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir(); if (!GodotSharpBuilds::copy_api_assembly(api_assembly_dir, res_assemblies_dir, api_name, p_api_type)) return false; - pr.step("Done"); - return true; } @@ -372,15 +369,39 @@ bool GodotSharpBuilds::build_project_blocking(const String &p_config) { if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path())) return true; // No solution to build - if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE)) - return false; + String editor_prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir(); + String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir(); - if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR)) - return false; + if (FileAccess::exists(editor_prebuilt_api_dir.plus_file(API_ASSEMBLY_NAME ".dll"))) { + EditorProgress pr("mono_copy_prebuilt_api_assemblies", + "Copying prebuilt " API_ASSEMBLY_NAME " assemblies...", 1); + pr.step("Copying " API_ASSEMBLY_NAME " assembly", 0); - EditorProgress pr("mono_project_debug_build", "Building project solution...", 2); + if (!GodotSharpBuilds::copy_api_assembly(editor_prebuilt_api_dir, res_assemblies_dir, + API_ASSEMBLY_NAME, APIAssembly::API_CORE)) { + return false; + } + } else { + if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE)) + return false; + } - pr.step("Building project solution"); + if (DirAccess::exists(editor_prebuilt_api_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll"))) { + EditorProgress pr("mono_copy_prebuilt_api_assemblies", + "Copying prebuilt " EDITOR_API_ASSEMBLY_NAME " assemblies...", 1); + pr.step("Copying " EDITOR_API_ASSEMBLY_NAME " assembly", 0); + + if (!GodotSharpBuilds::copy_api_assembly(editor_prebuilt_api_dir, res_assemblies_dir, + EDITOR_API_ASSEMBLY_NAME, APIAssembly::API_EDITOR)) { + return false; + } + } else { + if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR)) + return false; + } + + EditorProgress pr("mono_project_debug_build", "Building project solution...", 1); + pr.step("Building project solution", 0); MonoBuildInfo build_info(GodotSharpDirs::get_project_sln_path(), p_config); if (!GodotSharpBuilds::get_singleton()->build(build_info)) { @@ -388,8 +409,6 @@ bool GodotSharpBuilds::build_project_blocking(const String &p_config) { return false; } - pr.step("Done"); - return true; } diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp index 3ee38515bf..fca88a7164 100644 --- a/modules/mono/editor/godotsharp_editor.cpp +++ b/modules/mono/editor/godotsharp_editor.cpp @@ -197,6 +197,7 @@ void GodotSharpEditor::register_internal_calls() { mono_add_internal_call("GodotSharpTools.Utils.OS::GetPlatformName", (void *)godot_icall_Utils_OS_GetPlatformName); GodotSharpBuilds::register_internal_calls(); + GodotSharpExport::register_internal_calls(); } void GodotSharpEditor::show_error_dialog(const String &p_message, const String &p_title) { diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp index cd09e6516a..933ede93dc 100644 --- a/modules/mono/editor/godotsharp_export.cpp +++ b/modules/mono/editor/godotsharp_export.cpp @@ -30,12 +30,37 @@ #include "godotsharp_export.h" +#include "core/version.h" + #include "../csharp_script.h" #include "../godotsharp_defs.h" #include "../godotsharp_dirs.h" +#include "../mono_gd/gd_mono_class.h" +#include "../mono_gd/gd_mono_marshal.h" #include "godotsharp_builds.h" -void GodotSharpExport::_export_file(const String &p_path, const String &p_type, const Set<String> &p_features) { +static MonoString *godot_icall_GodotSharpExport_GetTemplatesDir() { + String current_version = VERSION_FULL_CONFIG; + String templates_dir = EditorSettings::get_singleton()->get_templates_dir().plus_file(current_version); + return GDMonoMarshal::mono_string_from_godot(ProjectSettings::get_singleton()->globalize_path(templates_dir)); +} + +static MonoString *godot_icall_GodotSharpExport_GetDataDirName() { + String appname = ProjectSettings::get_singleton()->get("application/config/name"); + String appname_safe = OS::get_singleton()->get_safe_dir_name(appname); + return GDMonoMarshal::mono_string_from_godot("data_" + appname_safe); +} + +void GodotSharpExport::register_internal_calls() { + static bool registered = false; + ERR_FAIL_COND(registered); + registered = true; + + mono_add_internal_call("GodotSharpTools.Editor.GodotSharpExport::GetTemplatesDir", (void *)godot_icall_GodotSharpExport_GetTemplatesDir); + mono_add_internal_call("GodotSharpTools.Editor.GodotSharpExport::GetDataDirName", (void *)godot_icall_GodotSharpExport_GetDataDirName); +} + +void GodotSharpExport::_export_file(const String &p_path, const String &p_type, const Set<String> &) { if (p_type != CSharpLanguage::get_singleton()->get_type()) return; @@ -56,59 +81,78 @@ void GodotSharpExport::_export_begin(const Set<String> &p_features, bool p_debug // TODO right now there is no way to stop the export process with an error ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized()); - ERR_FAIL_NULL(GDMono::get_singleton()->get_tools_domain()); + ERR_FAIL_NULL(TOOLS_DOMAIN); + ERR_FAIL_NULL(GDMono::get_singleton()->get_editor_tools_assembly()); String build_config = p_debug ? "Debug" : "Release"; ERR_FAIL_COND(!GodotSharpBuilds::build_project_blocking(build_config)); - // Add API assemblies - - String core_api_dll_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(API_ASSEMBLY_NAME ".dll"); - ERR_FAIL_COND(!_add_assembly(core_api_dll_path, core_api_dll_path)); - - String editor_api_dll_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(EDITOR_API_ASSEMBLY_NAME ".dll"); - ERR_FAIL_COND(!_add_assembly(editor_api_dll_path, editor_api_dll_path)); + // Add dependency assemblies - // Add project assembly + Map<String, String> dependencies; String project_dll_name = ProjectSettings::get_singleton()->get("application/config/name"); if (project_dll_name.empty()) { project_dll_name = "UnnamedProject"; } - String project_dll_src_path = GodotSharpDirs::get_res_temp_assemblies_base_dir().plus_file(build_config).plus_file(project_dll_name + ".dll"); - String project_dll_dst_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(project_dll_name + ".dll"); - ERR_FAIL_COND(!_add_assembly(project_dll_src_path, project_dll_dst_path)); - - // Add dependencies - - MonoDomain *prev_domain = mono_domain_get(); - MonoDomain *export_domain = GDMonoUtils::create_domain("GodotEngine.ProjectExportDomain"); + String project_dll_src_dir = GodotSharpDirs::get_res_temp_assemblies_base_dir().plus_file(build_config); + String project_dll_src_path = project_dll_src_dir.plus_file(project_dll_name + ".dll"); + dependencies.insert(project_dll_name, project_dll_src_path); - ERR_FAIL_COND(!export_domain); - ERR_FAIL_COND(!mono_domain_set(export_domain, false)); + { + MonoDomain *export_domain = GDMonoUtils::create_domain("GodotEngine.ProjectExportDomain"); + ERR_FAIL_NULL(export_domain); + _GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(export_domain); - Map<String, String> dependencies; - dependencies.insert("mscorlib", GDMono::get_singleton()->get_corlib_assembly()->get_path()); - - GDMonoAssembly *scripts_assembly = GDMonoAssembly::load_from(project_dll_name, project_dll_src_path, /* refonly: */ true); + _GDMONO_SCOPE_DOMAIN_(export_domain); - ERR_EXPLAIN("Cannot load refonly assembly: " + project_dll_name); - ERR_FAIL_COND(!scripts_assembly); + GDMonoAssembly *scripts_assembly = NULL; + bool load_success = GDMono::get_singleton()->load_assembly_from(project_dll_name, + project_dll_src_dir, &scripts_assembly, /* refonly: */ true); - Error depend_error = _get_assembly_dependencies(scripts_assembly, dependencies); + ERR_EXPLAIN("Cannot load refonly assembly: " + project_dll_name); + ERR_FAIL_COND(!load_success); - GDMono::get_singleton()->finalize_and_unload_domain(export_domain); - mono_domain_set(prev_domain, false); - - ERR_FAIL_COND(depend_error != OK); + Vector<String> search_dirs; + GDMonoAssembly::fill_search_dirs(search_dirs); + Error depend_error = _get_assembly_dependencies(scripts_assembly, search_dirs, dependencies); + ERR_FAIL_COND(depend_error != OK); + } for (Map<String, String>::Element *E = dependencies.front(); E; E = E->next()) { String depend_src_path = E->value(); String depend_dst_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(depend_src_path.get_file()); ERR_FAIL_COND(!_add_assembly(depend_src_path, depend_dst_path)); } + + // Mono specific export template extras (data dir) + + GDMonoClass *export_class = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Editor", "GodotSharpExport"); + ERR_FAIL_NULL(export_class); + GDMonoMethod *export_begin_method = export_class->get_method("_ExportBegin", 4); + ERR_FAIL_NULL(export_begin_method); + + MonoArray *features = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(String), p_features.size()); + int i = 0; + for (const Set<String>::Element *E = p_features.front(); E; E = E->next()) { + MonoString *boxed = GDMonoMarshal::mono_string_from_godot(E->get()); + mono_array_set(features, MonoString *, i, boxed); + i++; + } + + MonoBoolean debug = p_debug; + MonoString *path = GDMonoMarshal::mono_string_from_godot(p_path); + uint32_t flags = p_flags; + void *args[4] = { features, &debug, path, &flags }; + MonoException *exc = NULL; + export_begin_method->invoke_raw(NULL, args, &exc); + + if (exc) { + GDMonoUtils::debug_print_unhandled_exception(exc); + ERR_FAIL(); + } } bool GodotSharpExport::_add_assembly(const String &p_src_path, const String &p_dst_path) { @@ -125,7 +169,7 @@ bool GodotSharpExport::_add_assembly(const String &p_src_path, const String &p_d return true; } -Error GodotSharpExport::_get_assembly_dependencies(GDMonoAssembly *p_assembly, Map<String, String> &r_dependencies) { +Error GodotSharpExport::_get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Map<String, String> &r_dependencies) { MonoImage *image = p_assembly->get_image(); @@ -134,18 +178,48 @@ Error GodotSharpExport::_get_assembly_dependencies(GDMonoAssembly *p_assembly, M mono_assembly_get_assemblyref(image, i, ref_aname); String ref_name = mono_assembly_name_get_name(ref_aname); - if (ref_name == "mscorlib" || r_dependencies.find(ref_name)) + if (r_dependencies.find(ref_name)) continue; GDMonoAssembly *ref_assembly = NULL; - if (!GDMono::get_singleton()->load_assembly(ref_name, ref_aname, &ref_assembly, /* refonly: */ true)) { - ERR_EXPLAIN("Cannot load refonly assembly: " + ref_name); + String path; + bool has_extension = ref_name.ends_with(".dll") || ref_name.ends_with(".exe"); + + for (int i = 0; i < p_search_dirs.size(); i++) { + const String &search_dir = p_search_dirs[i]; + + if (has_extension) { + path = search_dir.plus_file(ref_name); + if (FileAccess::exists(path)) { + GDMono::get_singleton()->load_assembly_from(ref_name.get_basename(), search_dir, ref_aname, &ref_assembly, true); + if (ref_assembly != NULL) + break; + } + } else { + path = search_dir.plus_file(ref_name + ".dll"); + if (FileAccess::exists(path)) { + GDMono::get_singleton()->load_assembly_from(ref_name, search_dir, ref_aname, &ref_assembly, true); + if (ref_assembly != NULL) + break; + } + + path = search_dir.plus_file(ref_name + ".exe"); + if (FileAccess::exists(path)) { + GDMono::get_singleton()->load_assembly_from(ref_name, search_dir, ref_aname, &ref_assembly, true); + if (ref_assembly != NULL) + break; + } + } + } + + if (!ref_assembly) { + ERR_EXPLAIN("Cannot load assembly (refonly): " + ref_name); ERR_FAIL_V(ERR_CANT_RESOLVE); } r_dependencies.insert(ref_name, ref_assembly->get_path()); - Error err = _get_assembly_dependencies(ref_assembly, r_dependencies); + Error err = _get_assembly_dependencies(ref_assembly, p_search_dirs, r_dependencies); if (err != OK) return err; } diff --git a/modules/mono/editor/godotsharp_export.h b/modules/mono/editor/godotsharp_export.h index b38db9660c..f007016578 100644 --- a/modules/mono/editor/godotsharp_export.h +++ b/modules/mono/editor/godotsharp_export.h @@ -43,13 +43,15 @@ class GodotSharpExport : public EditorExportPlugin { bool _add_assembly(const String &p_src_path, const String &p_dst_path); - Error _get_assembly_dependencies(GDMonoAssembly *p_assembly, Map<String, String> &r_dependencies); + Error _get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Map<String, String> &r_dependencies); protected: virtual void _export_file(const String &p_path, const String &p_type, const Set<String> &p_features); virtual void _export_begin(const Set<String> &p_features, bool p_debug, const String &p_path, int p_flags); public: + static void register_internal_calls(); + GodotSharpExport(); ~GodotSharpExport(); }; diff --git a/modules/mono/glue/Managed/Files/Extensions/NodeExtensions.cs b/modules/mono/glue/Managed/Files/Extensions/NodeExtensions.cs index 71534d7782..366d89b1c2 100644 --- a/modules/mono/glue/Managed/Files/Extensions/NodeExtensions.cs +++ b/modules/mono/glue/Managed/Files/Extensions/NodeExtensions.cs @@ -2,42 +2,42 @@ namespace Godot { public partial class Node { - public T GetNode<T>(NodePath path) where T : Godot.Node + public T GetNode<T>(NodePath path) where T : class { - return (T)GetNode(path); + return (T)(object)GetNode(path); } - public T GetNodeOrNull<T>(NodePath path) where T : Godot.Node + public T GetNodeOrNull<T>(NodePath path) where T : class { return GetNode(path) as T; } - public T GetChild<T>(int idx) where T : Godot.Node + public T GetChild<T>(int idx) where T : class { - return (T)GetChild(idx); + return (T)(object)GetChild(idx); } - public T GetChildOrNull<T>(int idx) where T : Godot.Node + public T GetChildOrNull<T>(int idx) where T : class { return GetChild(idx) as T; } - public T GetOwner<T>() where T : Godot.Node + public T GetOwner<T>() where T : class { - return (T)GetOwner(); + return (T)(object)GetOwner(); } - public T GetOwnerOrNull<T>() where T : Godot.Node + public T GetOwnerOrNull<T>() where T : class { return GetOwner() as T; } - public T GetParent<T>() where T : Godot.Node + public T GetParent<T>() where T : class { - return (T)GetParent(); + return (T)(object)GetParent(); } - public T GetParentOrNull<T>() where T : Godot.Node + public T GetParentOrNull<T>() where T : class { return GetParent() as T; } diff --git a/modules/mono/glue/Managed/Files/Extensions/ResourceLoaderExtensions.cs b/modules/mono/glue/Managed/Files/Extensions/ResourceLoaderExtensions.cs index ceecc589e6..684d160b57 100644 --- a/modules/mono/glue/Managed/Files/Extensions/ResourceLoaderExtensions.cs +++ b/modules/mono/glue/Managed/Files/Extensions/ResourceLoaderExtensions.cs @@ -2,9 +2,9 @@ namespace Godot { public static partial class ResourceLoader { - public static T Load<T>(string path) where T : Godot.Resource + public static T Load<T>(string path) where T : class { - return (T) Load(path); + return (T)(object)Load(path); } } } diff --git a/modules/mono/glue/Managed/Files/GD.cs b/modules/mono/glue/Managed/Files/GD.cs index 264be23588..e4818e186c 100644 --- a/modules/mono/glue/Managed/Files/GD.cs +++ b/modules/mono/glue/Managed/Files/GD.cs @@ -65,9 +65,9 @@ namespace Godot return ResourceLoader.Load(path); } - public static T Load<T>(string path) where T : Godot.Resource + public static T Load<T>(string path) where T : class { - return (T) ResourceLoader.Load(path); + return ResourceLoader.Load<T>(path); } public static void Print(params object[] what) diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp index 2570e68f13..d3fb2cb640 100644 --- a/modules/mono/godotsharp_dirs.cpp +++ b/modules/mono/godotsharp_dirs.cpp @@ -30,11 +30,11 @@ #include "godotsharp_dirs.h" +#include "core/os/dir_access.h" #include "core/os/os.h" +#include "core/project_settings.h" #ifdef TOOLS_ENABLED -#include "core/os/dir_access.h" -#include "core/project_settings.h" #include "core/version.h" #include "editor/editor_settings.h" #endif @@ -95,10 +95,18 @@ public: #ifdef TOOLS_ENABLED String mono_solutions_dir; String build_logs_dir; + String sln_filepath; String csproj_filepath; + + String data_mono_bin_dir; + String data_editor_tools_dir; + String data_editor_prebuilt_api_dir; #endif + String data_mono_etc_dir; + String data_mono_lib_dir; + private: _GodotSharpDirs() { res_data_dir = "res://.mono"; @@ -123,10 +131,60 @@ private: name = "UnnamedProject"; } - String base_path = String("res://") + name; + String base_path = ProjectSettings::get_singleton()->globalize_path("res://"); + + sln_filepath = base_path.plus_file(name + ".sln"); + csproj_filepath = base_path.plus_file(name + ".csproj"); +#endif + + String exe_dir = OS::get_singleton()->get_executable_path().get_base_dir(); + +#ifdef TOOLS_ENABLED + + String data_dir_root = exe_dir.plus_file("GodotSharp"); + data_editor_tools_dir = data_dir_root.plus_file("Tools"); + data_editor_prebuilt_api_dir = data_dir_root.plus_file("Api"); + + String data_mono_root_dir = data_dir_root.plus_file("Mono"); + data_mono_bin_dir = data_mono_root_dir.plus_file("bin"); + data_mono_etc_dir = data_mono_root_dir.plus_file("etc"); + data_mono_lib_dir = data_mono_root_dir.plus_file("lib"); + +#ifdef OSX_ENABLED + if (!DirAccess::exists(data_editor_tools_dir)) { + data_editor_tools_dir = exe_dir.plus_file("../Frameworks/GodotSharp/Tools"); + } + + if (!DirAccess::exists(data_editor_prebuilt_api_dir)) { + data_editor_prebuilt_api_dir = exe_dir.plus_file("../Frameworks/GodotSharp/Api"); + } + + if (!DirAccess::exists(data_mono_root_dir)) { + data_mono_bin_dir = exe_dir.plus_file("../Frameworks/GodotSharp/Mono/bin"); + data_mono_etc_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/etc"); + data_mono_lib_dir = exe_dir.plus_file("../Frameworks/GodotSharp/Mono/lib"); + } +#endif + +#else + + String appname = OS::get_singleton()->get_safe_dir_name(ProjectSettings::get_singleton()->get("application/config/name")); + String data_dir_root = exe_dir.plus_file("data_" + appname); + if (!DirAccess::exists(data_dir_root)) { + data_dir_root = exe_dir.plus_file("data_Godot"); + } + + String data_mono_root_dir = data_dir_root.plus_file("Mono"); + data_mono_etc_dir = data_mono_root_dir.plus_file("etc"); + data_mono_lib_dir = data_mono_root_dir.plus_file("lib"); + +#ifdef OSX_ENABLED + if (!DirAccess::exists(data_mono_root_dir)) { + data_mono_etc_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/etc"); + data_mono_lib_dir = exe_dir.plus_file("../Frameworks/GodotSharp/Mono/lib"); + } +#endif - sln_filepath = ProjectSettings::get_singleton()->globalize_path(base_path + ".sln"); - csproj_filepath = ProjectSettings::get_singleton()->globalize_path(base_path + ".csproj"); #endif } @@ -192,5 +250,26 @@ String get_project_sln_path() { String get_project_csproj_path() { return _GodotSharpDirs::get_singleton().csproj_filepath; } + +String get_data_mono_bin_dir() { + return _GodotSharpDirs::get_singleton().data_mono_bin_dir; +} + +String get_data_editor_tools_dir() { + return _GodotSharpDirs::get_singleton().data_editor_tools_dir; +} + +String get_data_editor_prebuilt_api_dir() { + return _GodotSharpDirs::get_singleton().data_editor_prebuilt_api_dir; +} #endif + +String get_data_mono_etc_dir() { + return _GodotSharpDirs::get_singleton().data_mono_etc_dir; +} + +String get_data_mono_lib_dir() { + return _GodotSharpDirs::get_singleton().data_mono_lib_dir; +} + } // namespace GodotSharpDirs diff --git a/modules/mono/godotsharp_dirs.h b/modules/mono/godotsharp_dirs.h index 3466cb271d..35b564be30 100644 --- a/modules/mono/godotsharp_dirs.h +++ b/modules/mono/godotsharp_dirs.h @@ -49,11 +49,18 @@ String get_mono_logs_dir(); #ifdef TOOLS_ENABLED String get_mono_solutions_dir(); String get_build_logs_dir(); -String get_custom_project_settings_dir(); -#endif String get_project_sln_path(); String get_project_csproj_path(); + +String get_data_mono_bin_dir(); +String get_data_editor_tools_dir(); +String get_data_editor_prebuilt_api_dir(); +#endif + +String get_data_mono_etc_dir(); +String get_data_mono_lib_dir(); + } // namespace GodotSharpDirs #endif // GODOTSHARP_DIRS_H diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 9311aa3930..bf5455de16 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -162,50 +162,63 @@ void GDMono::initialize() { mono_trace_set_printerr_handler(gdmono_MonoPrintCallback); #endif + String assembly_rootdir; + String config_dir; + +#ifdef TOOLS_ENABLED #ifdef WINDOWS_ENABLED mono_reg_info = MonoRegUtils::find_mono(); - CharString assembly_dir; - CharString config_dir; - if (mono_reg_info.assembly_dir.length() && DirAccess::exists(mono_reg_info.assembly_dir)) { - assembly_dir = mono_reg_info.assembly_dir.utf8(); + assembly_rootdir = mono_reg_info.assembly_dir; } if (mono_reg_info.config_dir.length() && DirAccess::exists(mono_reg_info.config_dir)) { - config_dir = mono_reg_info.config_dir.utf8(); + config_dir = mono_reg_info.config_dir; } - - mono_set_dirs(assembly_dir.length() ? assembly_dir.get_data() : NULL, - config_dir.length() ? config_dir.get_data() : NULL); #elif OSX_ENABLED - mono_set_dirs(NULL, NULL); - - { - const char *assembly_rootdir = mono_assembly_getrootdir(); - const char *config_dir = mono_get_config_dir(); - - if (!assembly_rootdir || !config_dir || !DirAccess::exists(assembly_rootdir) || !DirAccess::exists(config_dir)) { - Vector<const char *> locations; - locations.push_back("/Library/Frameworks/Mono.framework/Versions/Current/"); - locations.push_back("/usr/local/var/homebrew/linked/mono/"); - - for (int i = 0; i < locations.size(); i++) { - 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_config_dir = path_join(locations[i], "etc"); - - if (FileAccess::exists(hint_mscorlib_path) && DirAccess::exists(hint_config_dir)) { - mono_set_dirs(hint_assembly_rootdir.utf8().get_data(), hint_config_dir.utf8().get_data()); - break; - } + const char *c_assembly_rootdir = mono_assembly_getrootdir(); + const char *c_config_dir = mono_get_config_dir(); + + if (!c_assembly_rootdir || !c_config_dir || !DirAccess::exists(c_assembly_rootdir) || !DirAccess::exists(c_config_dir)) { + Vector<const char *> locations; + locations.push_back("/Library/Frameworks/Mono.framework/Versions/Current/"); + locations.push_back("/usr/local/var/homebrew/linked/mono/"); + + for (int i = 0; i < locations.size(); i++) { + 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_config_dir = path_join(locations[i], "etc"); + + if (FileAccess::exists(hint_mscorlib_path) && DirAccess::exists(hint_config_dir)) { + need_set_mono_dirs = false; + assembly_rootdir = hint_assembly_rootdir; + config_dir = hint_config_dir; + break; } } } +#endif +#endif // TOOLS_ENABLED + + String bundled_assembly_rootdir = GodotSharpDirs::get_data_mono_lib_dir(); + String bundled_config_dir = GodotSharpDirs::get_data_mono_etc_dir(); + +#ifdef TOOLS_ENABLED + if (DirAccess::exists(bundled_assembly_rootdir) && DirAccess::exists(bundled_config_dir)) { + assembly_rootdir = bundled_assembly_rootdir; + config_dir = bundled_config_dir; + } #else - mono_set_dirs(NULL, NULL); + // These are always the directories in export templates + assembly_rootdir = bundled_assembly_rootdir; + config_dir = bundled_config_dir; #endif + // Leak if we call mono_set_dirs more than once + mono_set_dirs(assembly_rootdir.length() ? assembly_rootdir.utf8().get_data() : NULL, + config_dir.length() ? config_dir.utf8().get_data() : NULL); + GDMonoAssembly::initialize(); #ifdef DEBUG_ENABLED @@ -262,8 +275,11 @@ void GDMono::initialize() { // Everything is fine with the api assemblies, load the project assembly _load_project_assembly(); } else { - if ((core_api_assembly && (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated)) || - (editor_api_assembly && editor_api_assembly_out_of_sync)) { + if ((core_api_assembly && (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated)) +#ifdef TOOLS_ENABLED + || (editor_api_assembly && editor_api_assembly_out_of_sync) +#endif + ) { #ifdef TOOLS_ENABLED // The assembly was successfully loaded, but the full api could not be cached. // This is most likely an outdated assembly loaded because of an invalid version in the @@ -362,24 +378,34 @@ GDMonoAssembly **GDMono::get_loaded_assembly(const String &p_name) { bool GDMono::load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly) { + return load_assembly_from(p_name, String(), r_assembly, p_refonly); +} + +bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly) { + + return load_assembly_from(p_name, String(), p_aname, r_assembly, p_refonly); +} + +bool GDMono::load_assembly_from(const String &p_name, const String &p_basedir, GDMonoAssembly **r_assembly, bool p_refonly) { + CRASH_COND(!r_assembly); MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8()); - bool result = load_assembly(p_name, aname, r_assembly, p_refonly); + bool result = load_assembly_from(p_name, p_basedir, aname, r_assembly, p_refonly); mono_assembly_name_free(aname); mono_free(aname); return result; } -bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly) { +bool GDMono::load_assembly_from(const String &p_name, const String &p_basedir, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly) { CRASH_COND(!r_assembly); print_verbose("Mono: Loading assembly " + p_name + (p_refonly ? " (refonly)" : "") + "..."); MonoImageOpenStatus status = MONO_IMAGE_OK; - MonoAssembly *assembly = mono_assembly_load_full(p_aname, NULL, &status, p_refonly); + MonoAssembly *assembly = mono_assembly_load_full(p_aname, p_basedir.length() ? p_basedir.utf8().get_data() : NULL, &status, p_refonly); if (!assembly) return false; @@ -480,12 +506,10 @@ bool GDMono::_load_editor_api_assembly() { if (editor_api_assembly) return true; -#ifdef TOOLS_ENABLED if (metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR)) { print_verbose("Mono: Skipping loading of Editor API assembly because it was invalidated"); return false; } -#endif bool success = load_assembly(EDITOR_API_ASSEMBLY_NAME, &editor_api_assembly); @@ -772,7 +796,7 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) { print_verbose("Mono: Unloading domain `" + domain_name + "`..."); - if (mono_domain_get() != root_domain) + if (mono_domain_get() == p_domain) mono_domain_set(root_domain, true); mono_gc_collect(mono_gc_max_generation()); diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h index 0c5503d28e..97c2252f7c 100644 --- a/modules/mono/mono_gd/gd_mono.h +++ b/modules/mono/mono_gd/gd_mono.h @@ -142,7 +142,7 @@ class GDMono { GDMonoLog *gdmono_log; -#ifdef WINDOWS_ENABLED +#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED) MonoRegInfo mono_reg_info; #endif @@ -185,7 +185,7 @@ public: _FORCE_INLINE_ GDMonoAssembly *get_editor_tools_assembly() const { return editor_tools_assembly; } #endif -#ifdef WINDOWS_ENABLED +#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED) const MonoRegInfo &get_mono_reg_info() { return mono_reg_info; } #endif @@ -197,6 +197,9 @@ public: bool load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly = false); bool load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly = false); + bool load_assembly_from(const String &p_name, const String &p_basedir, GDMonoAssembly **r_assembly, bool p_refonly = false); + bool load_assembly_from(const String &p_name, const String &p_basedir, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly = false); + Error finalize_and_unload_domain(MonoDomain *p_domain); void initialize(); @@ -205,12 +208,14 @@ public: ~GDMono(); }; -class GDMonoScopeDomain { +namespace gdmono { + +class ScopeDomain { MonoDomain *prev_domain; public: - GDMonoScopeDomain(MonoDomain *p_domain) { + ScopeDomain(MonoDomain *p_domain) { MonoDomain *prev_domain = mono_domain_get(); if (prev_domain != p_domain) { this->prev_domain = prev_domain; @@ -220,16 +225,36 @@ public: } } - ~GDMonoScopeDomain() { + ~ScopeDomain() { if (prev_domain) mono_domain_set(prev_domain, false); } }; -#define _GDMONO_SCOPE_DOMAIN_(m_mono_domain) \ - GDMonoScopeDomain __gdmono__scope__domain__(m_mono_domain); \ +class ScopeExitDomainUnload { + MonoDomain *domain; + +public: + ScopeExitDomainUnload(MonoDomain *p_domain) : + domain(p_domain) { + } + + ~ScopeExitDomainUnload() { + if (domain) + GDMono::get_singleton()->finalize_and_unload_domain(domain); + } +}; + +} // namespace gdmono + +#define _GDMONO_SCOPE_DOMAIN_(m_mono_domain) \ + gdmono::ScopeDomain __gdmono__scope__domain__(m_mono_domain); \ (void)__gdmono__scope__domain__; +#define _GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(m_mono_domain) \ + gdmono::ScopeExitDomainUnload __gdmono__scope__exit__domain__unload__(m_mono_domain); \ + (void)__gdmono__scope__exit__domain__unload__; + class _GodotSharp : public Object { GDCLASS(_GodotSharp, Object) diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp index 27ce39b6d7..1067c11e0e 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.cpp +++ b/modules/mono/mono_gd/gd_mono_assembly.cpp @@ -46,6 +46,29 @@ bool GDMonoAssembly::in_preload = false; Vector<String> GDMonoAssembly::search_dirs; +void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config) { + + const char *rootdir = mono_assembly_getrootdir(); + if (rootdir) { + String framework_dir = String(rootdir).plus_file("mono").plus_file("4.5"); + r_search_dirs.push_back(framework_dir); + r_search_dirs.push_back(framework_dir.plus_file("Facades")); + } + + if (p_custom_config.length()) { + r_search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_base_dir().plus_file(p_custom_config)); + } else { + r_search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_dir()); + } + + r_search_dirs.push_back(GodotSharpDirs::get_res_assemblies_dir()); + r_search_dirs.push_back(OS::get_singleton()->get_resource_dir()); + r_search_dirs.push_back(OS::get_singleton()->get_executable_path().get_base_dir()); +#ifdef TOOLS_ENABLED + r_search_dirs.push_back(GodotSharpDirs::get_data_editor_tools_dir()); +#endif +} + void GDMonoAssembly::assembly_load_hook(MonoAssembly *assembly, void *user_data) { if (no_search) @@ -93,35 +116,7 @@ MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_d no_search = true; // Avoid the recursion madness - String path; - GDMonoAssembly *res = NULL; - - for (int i = 0; i < search_dirs.size(); i++) { - const String &search_dir = search_dirs[i]; - - if (has_extension) { - path = search_dir.plus_file(name); - if (FileAccess::exists(path)) { - res = _load_assembly_from(name.get_basename(), path, refonly); - if (res != NULL) - break; - } - } else { - path = search_dir.plus_file(name + ".dll"); - if (FileAccess::exists(path)) { - res = _load_assembly_from(name, path, refonly); - if (res != NULL) - break; - } - - path = search_dir.plus_file(name + ".exe"); - if (FileAccess::exists(path)) { - res = _load_assembly_from(name, path, refonly); - if (res != NULL) - break; - } - } - } + GDMonoAssembly *res = _load_assembly_search(name, search_dirs, refonly); no_search = false; @@ -130,31 +125,12 @@ MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_d static _THREAD_LOCAL_(MonoImage *) image_corlib_loading = NULL; -MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data, bool refonly) { +MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **, void *user_data, bool refonly) { (void)user_data; // UNUSED if (search_dirs.empty()) { - search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_dir()); - search_dirs.push_back(GodotSharpDirs::get_res_assemblies_dir()); - search_dirs.push_back(OS::get_singleton()->get_resource_dir()); - search_dirs.push_back(OS::get_singleton()->get_executable_path().get_base_dir()); -#ifdef GD_MONO_EDITOR_ASSEMBLIES_DIR - search_dirs.push_back(OS::get_singleton()->get_executable_path().get_base_dir().plus_file(_MKSTR(GD_MONO_EDITOR_ASSEMBLIES_DIR)).simplify_path()); -#endif - - const char *rootdir = mono_assembly_getrootdir(); - if (rootdir) { - search_dirs.push_back(String(rootdir).plus_file("mono").plus_file("4.5")); - search_dirs.push_back(String(rootdir).plus_file("mono").plus_file("4.5").plus_file("Facades")); - } - - if (assemblies_path) { - while (*assemblies_path) { - search_dirs.push_back(*assemblies_path); - ++assemblies_path; - } - } + fill_search_dirs(search_dirs); } { @@ -188,27 +164,7 @@ MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **asse if (stored_assembly) return (*stored_assembly)->get_assembly(); - String path; - - for (int i = 0; i < search_dirs.size(); i++) { - const String &search_dir = search_dirs[i]; - - if (has_extension) { - path = search_dir.plus_file(name); - if (FileAccess::exists(path)) { - res = _load_assembly_from(name.get_basename(), path, refonly); - if (res != NULL) - break; - } - } else { - path = search_dir.plus_file(name + ".dll"); - if (FileAccess::exists(path)) { - res = _load_assembly_from(name, path, refonly); - if (res != NULL) - break; - } - } - } + res = _load_assembly_search("mscorlib.dll", search_dirs, refonly); } no_search = false; @@ -217,6 +173,43 @@ MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **asse return res ? res->get_assembly() : NULL; } +GDMonoAssembly *GDMonoAssembly::_load_assembly_search(const String &p_name, const Vector<String> &p_search_dirs, bool p_refonly) { + + GDMonoAssembly *res = NULL; + String path; + + bool has_extension = p_name.ends_with(".dll") || p_name.ends_with(".exe"); + + for (int i = 0; i < p_search_dirs.size(); i++) { + const String &search_dir = p_search_dirs[i]; + + if (has_extension) { + path = search_dir.plus_file(p_name); + if (FileAccess::exists(path)) { + res = _load_assembly_from(p_name.get_basename(), path, p_refonly); + if (res != NULL) + return res; + } + } else { + path = search_dir.plus_file(p_name + ".dll"); + if (FileAccess::exists(path)) { + res = _load_assembly_from(p_name, path, p_refonly); + if (res != NULL) + return res; + } + + path = search_dir.plus_file(p_name + ".exe"); + if (FileAccess::exists(path)) { + res = _load_assembly_from(p_name, path, p_refonly); + if (res != NULL) + return res; + } + } + } + + return NULL; +} + GDMonoAssembly *GDMonoAssembly::_load_assembly_from(const String &p_name, const String &p_path, bool p_refonly) { GDMonoAssembly *assembly = memnew(GDMonoAssembly(p_name, p_path)); @@ -464,19 +457,6 @@ GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class) return match; } -GDMonoAssembly *GDMonoAssembly::load_from(const String &p_name, const String &p_path, bool p_refonly) { - - GDMonoAssembly **loaded_asm = GDMono::get_singleton()->get_loaded_assembly(p_name); - if (loaded_asm) - return *loaded_asm; - - no_search = true; - GDMonoAssembly *res = _load_assembly_from(p_name, p_path, p_refonly); - no_search = false; - - return res; -} - GDMonoAssembly::GDMonoAssembly(const String &p_name, const String &p_path) { loaded = false; diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h index 0ba11ac412..4c9b1cb10d 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.h +++ b/modules/mono/mono_gd/gd_mono_assembly.h @@ -102,6 +102,7 @@ class GDMonoAssembly { static MonoAssembly *_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data, bool refonly); static GDMonoAssembly *_load_assembly_from(const String &p_name, const String &p_path, bool p_refonly); + static GDMonoAssembly *_load_assembly_search(const String &p_name, const Vector<String> &p_search_dirs, bool p_refonly); static void _wrap_mono_assembly(MonoAssembly *assembly); friend class GDMono; @@ -125,7 +126,7 @@ public: GDMonoClass *get_object_derived_class(const StringName &p_class); - static GDMonoAssembly *load_from(const String &p_name, const String &p_path, bool p_refonly); + static void fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config = String()); GDMonoAssembly(const String &p_name, const String &p_path = String()); ~GDMonoAssembly(); diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index d72d74cf79..2a6bb0783b 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -730,7 +730,6 @@ RES ResourceFormatLoaderTheora::load(const String &p_path, const String &p_origi if (r_error) { *r_error = ERR_CANT_OPEN; } - memdelete(f); return RES(); } diff --git a/modules/webm/video_stream_webm.cpp b/modules/webm/video_stream_webm.cpp index d9a6ece085..675fc97b55 100644 --- a/modules/webm/video_stream_webm.cpp +++ b/modules/webm/video_stream_webm.cpp @@ -453,7 +453,6 @@ RES ResourceFormatLoaderWebm::load(const String &p_path, const String &p_origina if (r_error) { *r_error = ERR_CANT_OPEN; } - memdelete(f); return RES(); } diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 1c693c9ea8..6ab433203f 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -1859,28 +1859,30 @@ bool OS_OSX::can_draw() const { void OS_OSX::set_clipboard(const String &p_text) { - NSArray *types = [NSArray arrayWithObjects:NSStringPboardType, nil]; + NSString *copiedString = [NSString stringWithUTF8String:p_text.utf8().get_data()]; + NSArray *copiedStringArray = [NSArray arrayWithObject:copiedString]; NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; - [pasteboard declareTypes:types owner:nil]; - [pasteboard setString:[NSString stringWithUTF8String:p_text.utf8().get_data()] - forType:NSStringPboardType]; + [pasteboard clearContents]; + [pasteboard writeObjects:copiedStringArray]; } String OS_OSX::get_clipboard() const { NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; + NSArray *classArray = [NSArray arrayWithObject:[NSString class]]; + NSDictionary *options = [NSDictionary dictionary]; - if (![[pasteboard types] containsObject:NSStringPboardType]) { - return ""; - } + BOOL ok = [pasteboard canReadObjectForClasses:classArray options:options]; - NSString *object = [pasteboard stringForType:NSStringPboardType]; - if (!object) { + if (!ok) { return ""; } - char *utfs = strdup([object UTF8String]); + NSArray *objectsToPaste = [pasteboard readObjectsForClasses:classArray options:options]; + NSString *string = [objectsToPaste objectAtIndex:0]; + + char *utfs = strdup([string UTF8String]); String ret; ret.parse_utf8(utfs); free(utfs); diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 03eee9c6d8..c5d3def4c1 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -159,7 +159,10 @@ void ColorPicker::_html_entered(const String &p_html) { if (updating) return; + float last_alpha = color.a; color = Color::html(p_html); + if (!is_editing_alpha()) + color.a = last_alpha; if (!is_inside_tree()) return; |