summaryrefslogtreecommitdiff
path: root/modules/mono
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mono')
-rw-r--r--modules/mono/SCsub342
-rw-r--r--modules/mono/build_scripts/__init__.py0
-rw-r--r--modules/mono/build_scripts/godotsharptools_build.py263
-rw-r--r--modules/mono/build_scripts/make_cs_compressed_header.py61
-rw-r--r--modules/mono/build_scripts/mono_configure.py414
-rw-r--r--modules/mono/build_scripts/mono_reg_utils.py (renamed from modules/mono/mono_reg_utils.py)14
-rw-r--r--modules/mono/build_scripts/tls_configure.py (renamed from modules/mono/tls_configure.py)0
-rw-r--r--modules/mono/config.py424
-rw-r--r--modules/mono/csharp_script.cpp475
-rw-r--r--modules/mono/csharp_script.h71
-rw-r--r--modules/mono/doc_classes/@C#.xml4
-rw-r--r--modules/mono/doc_classes/CSharpScript.xml4
-rw-r--r--modules/mono/doc_classes/GodotSharp.xml4
-rw-r--r--modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs43
-rw-r--r--modules/mono/editor/GodotSharpTools/Editor/GodotSharpExport.cs2
-rw-r--r--modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj2
-rw-r--r--modules/mono/editor/GodotSharpTools/Project/IdentifierUtils.cs199
-rw-r--r--modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs7
-rw-r--r--modules/mono/editor/bindings_generator.cpp1285
-rw-r--r--modules/mono/editor/bindings_generator.h48
-rw-r--r--modules/mono/editor/csharp_project.cpp13
-rw-r--r--modules/mono/editor/csharp_project.h4
-rw-r--r--modules/mono/editor/dotnet_solution.cpp4
-rw-r--r--modules/mono/editor/dotnet_solution.h4
-rw-r--r--modules/mono/editor/godotsharp_builds.cpp68
-rw-r--r--modules/mono/editor/godotsharp_builds.h7
-rw-r--r--modules/mono/editor/godotsharp_editor.cpp107
-rw-r--r--modules/mono/editor/godotsharp_editor.h12
-rw-r--r--modules/mono/editor/godotsharp_export.cpp78
-rw-r--r--modules/mono/editor/godotsharp_export.h4
-rw-r--r--modules/mono/editor/mono_bottom_panel.cpp40
-rw-r--r--modules/mono/editor/mono_bottom_panel.h8
-rw-r--r--modules/mono/editor/mono_build_info.cpp4
-rw-r--r--modules/mono/editor/mono_build_info.h4
-rw-r--r--modules/mono/editor/monodevelop_instance.cpp4
-rw-r--r--modules/mono/editor/monodevelop_instance.h4
-rw-r--r--modules/mono/editor/script_class_parser.cpp73
-rw-r--r--modules/mono/editor/script_class_parser.h30
-rw-r--r--modules/mono/glue/Managed/Files/Array.cs194
-rw-r--r--modules/mono/glue/Managed/Files/Basis.cs435
-rw-r--r--modules/mono/glue/Managed/Files/Color.cs23
-rw-r--r--modules/mono/glue/Managed/Files/Colors.cs303
-rw-r--r--modules/mono/glue/Managed/Files/DebuggingUtils.cs6
-rw-r--r--modules/mono/glue/Managed/Files/Dictionary.cs265
-rw-r--r--modules/mono/glue/Managed/Files/DynamicObject.cs213
-rw-r--r--modules/mono/glue/Managed/Files/GD.cs127
-rw-r--r--modules/mono/glue/Managed/Files/GodotTraceListener.cs37
-rw-r--r--modules/mono/glue/Managed/Files/MarshalUtils.cs60
-rw-r--r--modules/mono/glue/Managed/Files/Mathf.cs14
-rw-r--r--modules/mono/glue/Managed/Files/MathfEx.cs5
-rw-r--r--modules/mono/glue/Managed/Files/NodePath.cs14
-rw-r--r--modules/mono/glue/Managed/Files/Object.base.cs44
-rw-r--r--modules/mono/glue/Managed/Files/Quat.cs31
-rw-r--r--modules/mono/glue/Managed/Files/RID.cs14
-rw-r--r--modules/mono/glue/Managed/Files/Transform.cs38
-rw-r--r--modules/mono/glue/Managed/Files/Transform2D.cs176
-rw-r--r--modules/mono/glue/Managed/Files/Vector2.cs7
-rw-r--r--modules/mono/glue/Managed/Files/Vector3.cs5
-rw-r--r--modules/mono/glue/Managed/IgnoredFiles/Variant.cs11
-rw-r--r--modules/mono/glue/Managed/Managed.csproj2
-rw-r--r--modules/mono/glue/arguments_vector.h68
-rw-r--r--modules/mono/glue/base_object_glue.cpp113
-rw-r--r--modules/mono/glue/base_object_glue.h18
-rw-r--r--modules/mono/glue/collections_glue.cpp42
-rw-r--r--modules/mono/glue/collections_glue.h28
-rw-r--r--modules/mono/glue/gd_glue.cpp49
-rw-r--r--modules/mono/glue/gd_glue.h26
-rw-r--r--modules/mono/glue/glue_header.h6
-rw-r--r--modules/mono/glue/nodepath_glue.cpp4
-rw-r--r--modules/mono/glue/nodepath_glue.h4
-rw-r--r--modules/mono/glue/rid_glue.cpp4
-rw-r--r--modules/mono/glue/rid_glue.h4
-rw-r--r--modules/mono/glue/string_glue.cpp4
-rw-r--r--modules/mono/glue/string_glue.h4
-rw-r--r--modules/mono/godotsharp_defs.h4
-rw-r--r--modules/mono/godotsharp_dirs.cpp29
-rw-r--r--modules/mono/godotsharp_dirs.h9
-rw-r--r--modules/mono/mono_gc_handle.cpp6
-rw-r--r--modules/mono/mono_gc_handle.h4
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp240
-rw-r--r--modules/mono/mono_gd/gd_mono.h34
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp24
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.h8
-rw-r--r--modules/mono/mono_gd/gd_mono_class.cpp22
-rw-r--r--modules/mono/mono_gd/gd_mono_class.h9
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp52
-rw-r--r--modules/mono/mono_gd/gd_mono_field.h20
-rw-r--r--modules/mono/mono_gd/gd_mono_header.h22
-rw-r--r--modules/mono/mono_gd/gd_mono_internals.cpp55
-rw-r--r--modules/mono/mono_gd/gd_mono_internals.h6
-rw-r--r--modules/mono/mono_gd/gd_mono_log.cpp84
-rw-r--r--modules/mono/mono_gd/gd_mono_log.h5
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp218
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h32
-rw-r--r--modules/mono/mono_gd/gd_mono_method.cpp18
-rw-r--r--modules/mono/mono_gd/gd_mono_method.h22
-rw-r--r--modules/mono/mono_gd/gd_mono_property.cpp19
-rw-r--r--modules/mono/mono_gd/gd_mono_property.h21
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp131
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h48
-rw-r--r--modules/mono/mono_gd/i_mono_class_member.h (renamed from modules/mono/mono_gd/gd_mono_class_member.h)17
-rw-r--r--modules/mono/mono_gd/managed_type.cpp58
-rw-r--r--modules/mono/mono_gd/managed_type.h58
-rw-r--r--modules/mono/register_types.cpp23
-rw-r--r--modules/mono/register_types.h4
-rw-r--r--modules/mono/signal_awaiter_utils.cpp8
-rw-r--r--modules/mono/signal_awaiter_utils.h4
-rw-r--r--modules/mono/utils/macros.h54
-rw-r--r--modules/mono/utils/mono_reg_utils.cpp14
-rw-r--r--modules/mono/utils/mono_reg_utils.h4
-rw-r--r--modules/mono/utils/mutex_utils.h4
-rw-r--r--modules/mono/utils/osx_utils.cpp8
-rw-r--r--modules/mono/utils/osx_utils.h5
-rw-r--r--modules/mono/utils/path_utils.cpp6
-rw-r--r--modules/mono/utils/path_utils.h4
-rw-r--r--modules/mono/utils/string_utils.cpp4
-rw-r--r--modules/mono/utils/string_utils.h4
-rw-r--r--modules/mono/utils/thread_local.cpp4
-rw-r--r--modules/mono/utils/thread_local.h8
119 files changed, 5357 insertions, 2604 deletions
diff --git a/modules/mono/SCsub b/modules/mono/SCsub
index e1f5e2ef28..341d57f3e4 100644
--- a/modules/mono/SCsub
+++ b/modules/mono/SCsub
@@ -5,70 +5,6 @@ Import('env_modules')
env_mono = env_modules.Clone()
-# TODO move functions to their own modules
-
-def make_cs_files_header(src, dst, version_dst):
- from compat import byte_to_str
-
- with open(dst, 'w') as header:
- header.write('/* THIS FILE IS GENERATED DO NOT EDIT */\n')
- header.write('#ifndef CS_COMPRESSED_H\n')
- header.write('#define CS_COMPRESSED_H\n\n')
- header.write('#ifdef TOOLS_ENABLED\n\n')
- header.write('#include "core/map.h"\n')
- header.write('#include "core/ustring.h"\n')
- inserted_files = ''
- import os
- latest_mtime = 0
- cs_file_count = 0
- for root, _, files in os.walk(src):
- files = [f for f in files if f.endswith('.cs')]
- for file in files:
- cs_file_count += 1
- filepath = os.path.join(root, file)
- filepath_src_rel = os.path.relpath(filepath, src)
- mtime = os.path.getmtime(filepath)
- latest_mtime = mtime if mtime > latest_mtime else latest_mtime
- with open(filepath, 'rb') as f:
- buf = f.read()
- decomp_size = len(buf)
- import zlib
- buf = zlib.compress(buf)
- name = str(cs_file_count)
- header.write('\n')
- header.write('// ' + filepath_src_rel + '\n')
- header.write('static const int _cs_' + name + '_compressed_size = ' + str(len(buf)) + ';\n')
- header.write('static const int _cs_' + name + '_uncompressed_size = ' + str(decomp_size) + ';\n')
- header.write('static const unsigned char _cs_' + name + '_compressed[] = { ')
- for i, buf_idx in enumerate(range(len(buf))):
- if i > 0:
- header.write(', ')
- header.write(byte_to_str(buf[buf_idx]))
- inserted_files += '\tr_files.insert("' + filepath_src_rel.replace('\\', '\\\\') + '", ' \
- 'CompressedFile(_cs_' + name + '_compressed_size, ' \
- '_cs_' + name + '_uncompressed_size, ' \
- '_cs_' + name + '_compressed));\n'
- header.write(' };\n')
- header.write('\nstruct CompressedFile\n' '{\n'
- '\tint compressed_size;\n' '\tint uncompressed_size;\n' '\tconst unsigned char* data;\n'
- '\n\tCompressedFile(int p_comp_size, int p_uncomp_size, const unsigned char* p_data)\n'
- '\t{\n' '\t\tcompressed_size = p_comp_size;\n' '\t\tuncompressed_size = p_uncomp_size;\n'
- '\t\tdata = p_data;\n' '\t}\n' '\n\tCompressedFile() {}\n' '};\n'
- '\nvoid get_compressed_files(Map<String, CompressedFile>& r_files)\n' '{\n' + inserted_files + '}\n'
- )
- header.write('\n#endif // TOOLS_ENABLED\n')
- header.write('\n#endif // CS_COMPRESSED_H\n')
-
- glue_version = int(latest_mtime) # The latest modified time will do for now
-
- with open(version_dst, 'w') as version_header:
- version_header.write('/* THIS FILE IS GENERATED DO NOT EDIT */\n')
- version_header.write('#ifndef CS_GLUE_VERSION_H\n')
- version_header.write('#define CS_GLUE_VERSION_H\n\n')
- version_header.write('#define CS_GLUE_VERSION UINT32_C(' + str(glue_version) + ')\n')
- version_header.write('\n#endif // CS_GLUE_VERSION_H\n')
-
-
env_mono.add_source_files(env.modules_sources, '*.cpp')
env_mono.add_source_files(env.modules_sources, 'glue/*.cpp')
env_mono.add_source_files(env.modules_sources, 'mono_gd/*.cpp')
@@ -77,7 +13,12 @@ env_mono.add_source_files(env.modules_sources, 'utils/*.cpp')
if env['tools']:
env_mono.add_source_files(env.modules_sources, 'editor/*.cpp')
# NOTE: It is safe to generate this file here, since this is still executed serially
- make_cs_files_header('glue/Managed/Files', 'glue/cs_compressed.gen.h', 'glue/cs_glue_version.gen.h')
+ import build_scripts.make_cs_compressed_header as make_cs_compressed_header
+ make_cs_compressed_header.generate_header(
+ 'glue/Managed/Files',
+ 'glue/cs_compressed.gen.h',
+ 'glue/cs_glue_version.gen.h'
+ )
vars = Variables()
vars.Add(BoolVariable('mono_glue', 'Build with the mono glue sources', True))
@@ -88,270 +29,29 @@ vars.Update(env_mono)
if env_mono['mono_glue']:
env_mono.Append(CPPDEFINES=['MONO_GLUE_ENABLED'])
-# Configure TLS checks
-
-import tls_configure
-conf = Configure(env_mono)
-tls_configure.configure(conf)
-env_mono = conf.Finish()
-
-
-# Build GodotSharpTools solution
-
-
-import os
-
-
-def find_nuget_unix():
- import os
-
- if 'NUGET_PATH' in os.environ:
- hint_path = os.environ['NUGET_PATH']
- if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
- return hint_path
- hint_path = os.path.join(hint_path, 'nuget')
- if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
- return hint_path
-
- import os.path
- import sys
-
- hint_dirs = ['/opt/novell/mono/bin']
- if sys.platform == 'darwin':
- hint_dirs = ['/Library/Frameworks/Mono.framework/Versions/Current/bin', '/usr/local/var/homebrew/linked/mono/bin'] + hint_dirs
-
- for hint_dir in hint_dirs:
- hint_path = os.path.join(hint_dir, 'nuget')
- if os.path.isfile(hint_path):
- return hint_path
- elif os.path.isfile(hint_path + '.exe'):
- return hint_path + '.exe'
-
- for hint_dir in os.environ['PATH'].split(os.pathsep):
- hint_dir = hint_dir.strip('"')
- hint_path = os.path.join(hint_dir, 'nuget')
- if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
- return hint_path
- if os.path.isfile(hint_path + '.exe') and os.access(hint_path + '.exe', os.X_OK):
- return hint_path + '.exe'
-
- return None
-
-
-def find_nuget_windows():
- import os
-
- if 'NUGET_PATH' in os.environ:
- hint_path = os.environ['NUGET_PATH']
- if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
- return hint_path
- hint_path = os.path.join(hint_path, 'nuget.exe')
- if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
- return hint_path
-
- import mono_reg_utils as monoreg
-
- mono_root = ''
- bits = env['bits']
-
- if bits == '32':
- if os.getenv('MONO32_PREFIX'):
- mono_root = os.getenv('MONO32_PREFIX')
- else:
- mono_root = monoreg.find_mono_root_dir(bits)
- else:
- if os.getenv('MONO64_PREFIX'):
- mono_root = os.getenv('MONO64_PREFIX')
- else:
- mono_root = monoreg.find_mono_root_dir(bits)
-
- if mono_root:
- mono_bin_dir = os.path.join(mono_root, 'bin')
- nuget_mono = os.path.join(mono_bin_dir, 'nuget.bat')
-
- if os.path.isfile(nuget_mono):
- return nuget_mono
-
- # Standalone NuGet
-
- for hint_dir in os.environ['PATH'].split(os.pathsep):
- hint_dir = hint_dir.strip('"')
- hint_path = os.path.join(hint_dir, 'nuget.exe')
- if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
- return hint_path
-
- return None
-
-
-def find_msbuild_unix(filename):
import os.path
- import sys
+ if not os.path.isfile('glue/mono_glue.gen.cpp'):
+ raise RuntimeError('Missing mono glue sources. Did you forget to generate them?')
- hint_dirs = ['/opt/novell/mono/bin']
- if sys.platform == 'darwin':
- hint_dirs = ['/Library/Frameworks/Mono.framework/Versions/Current/bin', '/usr/local/var/homebrew/linked/mono/bin'] + hint_dirs
+if env_mono['tools'] or env_mono['target'] != 'release':
+ env_mono.Append(CPPDEFINES=['GD_MONO_HOT_RELOAD'])
- for hint_dir in hint_dirs:
- hint_path = os.path.join(hint_dir, filename)
- if os.path.isfile(hint_path):
- return hint_path
- elif os.path.isfile(hint_path + '.exe'):
- return hint_path + '.exe'
+# Configure Thread Local Storage
- for hint_dir in os.environ['PATH'].split(os.pathsep):
- hint_dir = hint_dir.strip('"')
- hint_path = os.path.join(hint_dir, filename)
- if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
- return hint_path
- if os.path.isfile(hint_path + '.exe') and os.access(hint_path + '.exe', os.X_OK):
- return hint_path + '.exe'
+import build_scripts.tls_configure as tls_configure
- return None
-
-
-def find_msbuild_windows():
- import mono_reg_utils as monoreg
-
- mono_root = ''
- bits = env['bits']
-
- if bits == '32':
- if os.getenv('MONO32_PREFIX'):
- mono_root = os.getenv('MONO32_PREFIX')
- else:
- mono_root = monoreg.find_mono_root_dir(bits)
- else:
- if os.getenv('MONO64_PREFIX'):
- mono_root = os.getenv('MONO64_PREFIX')
- else:
- mono_root = monoreg.find_mono_root_dir(bits)
-
- if not mono_root:
- raise RuntimeError('Cannot find mono root directory')
-
- framework_path = os.path.join(mono_root, 'lib', 'mono', '4.5')
- mono_bin_dir = os.path.join(mono_root, 'bin')
- msbuild_mono = os.path.join(mono_bin_dir, 'msbuild.bat')
-
- if os.path.isfile(msbuild_mono):
- # The (Csc/Vbc/Fsc)ToolExe environment variables are required when
- # building with Mono's MSBuild. They must point to the batch files
- # in Mono's bin directory to make sure they are executed with Mono.
- mono_msbuild_env = {
- 'CscToolExe': os.path.join(mono_bin_dir, 'csc.bat'),
- 'VbcToolExe': os.path.join(mono_bin_dir, 'vbc.bat'),
- 'FscToolExe': os.path.join(mono_bin_dir, 'fsharpc.bat')
- }
- return (msbuild_mono, framework_path, mono_msbuild_env)
-
- msbuild_tools_path = monoreg.find_msbuild_tools_path_reg()
-
- if msbuild_tools_path:
- return (os.path.join(msbuild_tools_path, 'MSBuild.exe'), framework_path, {})
-
- return None
-
-
-def mono_build_solution(source, target, env):
- import subprocess
- import mono_reg_utils as monoreg
- from shutil import copyfile
-
- sln_path = os.path.abspath(str(source[0]))
- target_path = os.path.abspath(str(target[0]))
-
- framework_path = ''
- msbuild_env = os.environ.copy()
-
- # Needed when running from Developer Command Prompt for VS
- if 'PLATFORM' in msbuild_env:
- del msbuild_env['PLATFORM']
-
- # Find MSBuild
- if os.name == 'nt':
- msbuild_info = find_msbuild_windows()
- if msbuild_info is None:
- raise RuntimeError('Cannot find MSBuild executable')
- msbuild_path = msbuild_info[0]
- framework_path = msbuild_info[1]
- msbuild_env.update(msbuild_info[2])
- else:
- msbuild_path = find_msbuild_unix('msbuild')
- if msbuild_path is None:
- xbuild_fallback = env['xbuild_fallback']
-
- if xbuild_fallback and os.name == 'nt':
- print('Option \'xbuild_fallback\' not supported on Windows')
- xbuild_fallback = False
-
- if xbuild_fallback:
- print('Cannot find MSBuild executable, trying with xbuild')
- print('Warning: xbuild is deprecated')
-
- msbuild_path = find_msbuild_unix('xbuild')
-
- if msbuild_path is None:
- raise RuntimeError('Cannot find xbuild executable')
- else:
- raise RuntimeError('Cannot find MSBuild executable')
-
- print('MSBuild path: ' + msbuild_path)
-
- # Find NuGet
- nuget_path = find_nuget_windows() if os.name == 'nt' else find_nuget_unix()
- if nuget_path is None:
- raise RuntimeError('Cannot find NuGet executable')
-
- print('NuGet path: ' + nuget_path)
-
- # Do NuGet restore
-
- try:
- subprocess.check_call([nuget_path, 'restore', sln_path])
- except subprocess.CalledProcessError:
- raise RuntimeError('GodotSharpTools: NuGet restore failed')
-
- # Build solution
-
- build_config = 'Release'
-
- msbuild_args = [
- msbuild_path,
- sln_path,
- '/p:Configuration=' + build_config,
- ]
-
- if framework_path:
- msbuild_args += ['/p:FrameworkPathOverride=' + framework_path]
-
- try:
- subprocess.check_call(msbuild_args, env=msbuild_env)
- except subprocess.CalledProcessError:
- raise RuntimeError('GodotSharpTools: Build failed')
-
- # Copy files
+conf = Configure(env_mono)
+tls_configure.configure(conf)
+env_mono = conf.Finish()
- src_dir = os.path.abspath(os.path.join(sln_path, os.pardir, 'bin', build_config))
- dst_dir = os.path.abspath(os.path.join(target_path, os.pardir))
- asm_file = 'GodotSharpTools.dll'
+# Configure Mono
- if not os.path.isdir(dst_dir):
- if os.path.exists(dst_dir):
- raise RuntimeError('Target directory is a file')
- os.makedirs(dst_dir)
+import build_scripts.mono_configure as mono_configure
- copyfile(os.path.join(src_dir, asm_file), os.path.join(dst_dir, asm_file))
+mono_configure.configure(env, env_mono)
- # Dependencies
- copyfile(os.path.join(src_dir, "DotNet.Glob.dll"), os.path.join(dst_dir, "DotNet.Glob.dll"))
+# Build GodotSharpTools
-if env['tools']:
- output_dir = Dir('#bin').abspath
- editor_tools_dir = os.path.join(output_dir, 'GodotSharp', 'Tools')
+import build_scripts.godotsharptools_build as godotsharptools_build
- 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'
- )
+godotsharptools_build.build(env_mono)
diff --git a/modules/mono/build_scripts/__init__.py b/modules/mono/build_scripts/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/modules/mono/build_scripts/__init__.py
diff --git a/modules/mono/build_scripts/godotsharptools_build.py b/modules/mono/build_scripts/godotsharptools_build.py
new file mode 100644
index 0000000000..af3a5cb5c6
--- /dev/null
+++ b/modules/mono/build_scripts/godotsharptools_build.py
@@ -0,0 +1,263 @@
+# Build GodotSharpTools solution
+
+
+import os
+
+from SCons.Script import Builder, Dir
+
+
+def find_nuget_unix():
+ import os
+
+ if 'NUGET_PATH' in os.environ:
+ hint_path = os.environ['NUGET_PATH']
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+ hint_path = os.path.join(hint_path, 'nuget')
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+
+ import os.path
+ import sys
+
+ hint_dirs = ['/opt/novell/mono/bin']
+ if sys.platform == 'darwin':
+ hint_dirs = ['/Library/Frameworks/Mono.framework/Versions/Current/bin', '/usr/local/var/homebrew/linked/mono/bin'] + hint_dirs
+
+ for hint_dir in hint_dirs:
+ hint_path = os.path.join(hint_dir, 'nuget')
+ if os.path.isfile(hint_path):
+ return hint_path
+ elif os.path.isfile(hint_path + '.exe'):
+ return hint_path + '.exe'
+
+ for hint_dir in os.environ['PATH'].split(os.pathsep):
+ hint_dir = hint_dir.strip('"')
+ hint_path = os.path.join(hint_dir, 'nuget')
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+ if os.path.isfile(hint_path + '.exe') and os.access(hint_path + '.exe', os.X_OK):
+ return hint_path + '.exe'
+
+ return None
+
+
+def find_nuget_windows(env):
+ import os
+
+ if 'NUGET_PATH' in os.environ:
+ hint_path = os.environ['NUGET_PATH']
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+ hint_path = os.path.join(hint_path, 'nuget.exe')
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+
+ from . import mono_reg_utils as monoreg
+
+ mono_root = ''
+ bits = env['bits']
+
+ if bits == '32':
+ if os.getenv('MONO32_PREFIX'):
+ mono_root = os.getenv('MONO32_PREFIX')
+ else:
+ mono_root = monoreg.find_mono_root_dir(bits)
+ else:
+ if os.getenv('MONO64_PREFIX'):
+ mono_root = os.getenv('MONO64_PREFIX')
+ else:
+ mono_root = monoreg.find_mono_root_dir(bits)
+
+ if mono_root:
+ mono_bin_dir = os.path.join(mono_root, 'bin')
+ nuget_mono = os.path.join(mono_bin_dir, 'nuget.bat')
+
+ if os.path.isfile(nuget_mono):
+ return nuget_mono
+
+ # Standalone NuGet
+
+ for hint_dir in os.environ['PATH'].split(os.pathsep):
+ hint_dir = hint_dir.strip('"')
+ hint_path = os.path.join(hint_dir, 'nuget.exe')
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+
+ return None
+
+
+def find_msbuild_unix(filename):
+ import os.path
+ import sys
+
+ hint_dirs = ['/opt/novell/mono/bin']
+ if sys.platform == 'darwin':
+ hint_dirs = ['/Library/Frameworks/Mono.framework/Versions/Current/bin', '/usr/local/var/homebrew/linked/mono/bin'] + hint_dirs
+
+ for hint_dir in hint_dirs:
+ hint_path = os.path.join(hint_dir, filename)
+ if os.path.isfile(hint_path):
+ return hint_path
+ elif os.path.isfile(hint_path + '.exe'):
+ return hint_path + '.exe'
+
+ for hint_dir in os.environ['PATH'].split(os.pathsep):
+ hint_dir = hint_dir.strip('"')
+ hint_path = os.path.join(hint_dir, filename)
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+ if os.path.isfile(hint_path + '.exe') and os.access(hint_path + '.exe', os.X_OK):
+ return hint_path + '.exe'
+
+ return None
+
+
+def find_msbuild_windows(env):
+ from . import mono_reg_utils as monoreg
+
+ mono_root = ''
+ bits = env['bits']
+
+ if bits == '32':
+ if os.getenv('MONO32_PREFIX'):
+ mono_root = os.getenv('MONO32_PREFIX')
+ else:
+ mono_root = monoreg.find_mono_root_dir(bits)
+ else:
+ if os.getenv('MONO64_PREFIX'):
+ mono_root = os.getenv('MONO64_PREFIX')
+ else:
+ mono_root = monoreg.find_mono_root_dir(bits)
+
+ if not mono_root:
+ raise RuntimeError('Cannot find mono root directory')
+
+ framework_path = os.path.join(mono_root, 'lib', 'mono', '4.5')
+ mono_bin_dir = os.path.join(mono_root, 'bin')
+ msbuild_mono = os.path.join(mono_bin_dir, 'msbuild.bat')
+
+ if os.path.isfile(msbuild_mono):
+ # The (Csc/Vbc/Fsc)ToolExe environment variables are required when
+ # building with Mono's MSBuild. They must point to the batch files
+ # in Mono's bin directory to make sure they are executed with Mono.
+ mono_msbuild_env = {
+ 'CscToolExe': os.path.join(mono_bin_dir, 'csc.bat'),
+ 'VbcToolExe': os.path.join(mono_bin_dir, 'vbc.bat'),
+ 'FscToolExe': os.path.join(mono_bin_dir, 'fsharpc.bat')
+ }
+ return (msbuild_mono, framework_path, mono_msbuild_env)
+
+ msbuild_tools_path = monoreg.find_msbuild_tools_path_reg()
+
+ if msbuild_tools_path:
+ return (os.path.join(msbuild_tools_path, 'MSBuild.exe'), framework_path, {})
+
+ return None
+
+
+def mono_build_solution(source, target, env):
+ import subprocess
+ from shutil import copyfile
+
+ sln_path = os.path.abspath(str(source[0]))
+ target_path = os.path.abspath(str(target[0]))
+
+ framework_path = ''
+ msbuild_env = os.environ.copy()
+
+ # Needed when running from Developer Command Prompt for VS
+ if 'PLATFORM' in msbuild_env:
+ del msbuild_env['PLATFORM']
+
+ # Find MSBuild
+ if os.name == 'nt':
+ msbuild_info = find_msbuild_windows(env)
+ if msbuild_info is None:
+ raise RuntimeError('Cannot find MSBuild executable')
+ msbuild_path = msbuild_info[0]
+ framework_path = msbuild_info[1]
+ msbuild_env.update(msbuild_info[2])
+ else:
+ msbuild_path = find_msbuild_unix('msbuild')
+ if msbuild_path is None:
+ xbuild_fallback = env['xbuild_fallback']
+
+ if xbuild_fallback and os.name == 'nt':
+ print('Option \'xbuild_fallback\' not supported on Windows')
+ xbuild_fallback = False
+
+ if xbuild_fallback:
+ print('Cannot find MSBuild executable, trying with xbuild')
+ print('Warning: xbuild is deprecated')
+
+ msbuild_path = find_msbuild_unix('xbuild')
+
+ if msbuild_path is None:
+ raise RuntimeError('Cannot find xbuild executable')
+ else:
+ raise RuntimeError('Cannot find MSBuild executable')
+
+ print('MSBuild path: ' + msbuild_path)
+
+ # Find NuGet
+ nuget_path = find_nuget_windows(env) if os.name == 'nt' else find_nuget_unix()
+ if nuget_path is None:
+ raise RuntimeError('Cannot find NuGet executable')
+
+ print('NuGet path: ' + nuget_path)
+
+ # Do NuGet restore
+
+ try:
+ subprocess.check_call([nuget_path, 'restore', sln_path])
+ except subprocess.CalledProcessError:
+ raise RuntimeError('GodotSharpTools: NuGet restore failed')
+
+ # Build solution
+
+ build_config = 'Release'
+
+ msbuild_args = [
+ msbuild_path,
+ sln_path,
+ '/p:Configuration=' + build_config,
+ ]
+
+ if framework_path:
+ msbuild_args += ['/p:FrameworkPathOverride=' + framework_path]
+
+ try:
+ subprocess.check_call(msbuild_args, env=msbuild_env)
+ except subprocess.CalledProcessError:
+ raise RuntimeError('GodotSharpTools: Build failed')
+
+ # Copy files
+
+ src_dir = os.path.abspath(os.path.join(sln_path, os.pardir, 'bin', build_config))
+ dst_dir = os.path.abspath(os.path.join(target_path, os.pardir))
+ asm_file = 'GodotSharpTools.dll'
+
+ if not os.path.isdir(dst_dir):
+ if os.path.exists(dst_dir):
+ raise RuntimeError('Target directory is a file')
+ os.makedirs(dst_dir)
+
+ copyfile(os.path.join(src_dir, asm_file), os.path.join(dst_dir, asm_file))
+
+ # Dependencies
+ copyfile(os.path.join(src_dir, "DotNet.Glob.dll"), os.path.join(dst_dir, "DotNet.Glob.dll"))
+
+def build(env_mono):
+ if not env_mono['tools']:
+ return
+
+ 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/build_scripts/make_cs_compressed_header.py b/modules/mono/build_scripts/make_cs_compressed_header.py
new file mode 100644
index 0000000000..1f9177cef8
--- /dev/null
+++ b/modules/mono/build_scripts/make_cs_compressed_header.py
@@ -0,0 +1,61 @@
+
+def generate_header(src, dst, version_dst):
+ from compat import byte_to_str
+
+ with open(dst, 'w') as header:
+ header.write('/* THIS FILE IS GENERATED DO NOT EDIT */\n')
+ header.write('#ifndef CS_COMPRESSED_H\n')
+ header.write('#define CS_COMPRESSED_H\n\n')
+ header.write('#ifdef TOOLS_ENABLED\n\n')
+ header.write('#include "core/map.h"\n')
+ header.write('#include "core/ustring.h"\n')
+ inserted_files = ''
+ import os
+ latest_mtime = 0
+ cs_file_count = 0
+ for root, _, files in os.walk(src):
+ files = [f for f in files if f.endswith('.cs')]
+ for file in files:
+ cs_file_count += 1
+ filepath = os.path.join(root, file)
+ filepath_src_rel = os.path.relpath(filepath, src)
+ mtime = os.path.getmtime(filepath)
+ latest_mtime = mtime if mtime > latest_mtime else latest_mtime
+ with open(filepath, 'rb') as f:
+ buf = f.read()
+ decomp_size = len(buf)
+ import zlib
+ buf = zlib.compress(buf)
+ name = str(cs_file_count)
+ header.write('\n')
+ header.write('// ' + filepath_src_rel + '\n')
+ header.write('static const int _cs_' + name + '_compressed_size = ' + str(len(buf)) + ';\n')
+ header.write('static const int _cs_' + name + '_uncompressed_size = ' + str(decomp_size) + ';\n')
+ header.write('static const unsigned char _cs_' + name + '_compressed[] = { ')
+ for i, buf_idx in enumerate(range(len(buf))):
+ if i > 0:
+ header.write(', ')
+ header.write(byte_to_str(buf[buf_idx]))
+ inserted_files += '\tr_files.insert("' + filepath_src_rel.replace('\\', '\\\\') + '", ' \
+ 'CompressedFile(_cs_' + name + '_compressed_size, ' \
+ '_cs_' + name + '_uncompressed_size, ' \
+ '_cs_' + name + '_compressed));\n'
+ header.write(' };\n')
+ header.write('\nstruct CompressedFile\n' '{\n'
+ '\tint compressed_size;\n' '\tint uncompressed_size;\n' '\tconst unsigned char* data;\n'
+ '\n\tCompressedFile(int p_comp_size, int p_uncomp_size, const unsigned char* p_data)\n'
+ '\t{\n' '\t\tcompressed_size = p_comp_size;\n' '\t\tuncompressed_size = p_uncomp_size;\n'
+ '\t\tdata = p_data;\n' '\t}\n' '\n\tCompressedFile() {}\n' '};\n'
+ '\nvoid get_compressed_files(Map<String, CompressedFile>& r_files)\n' '{\n' + inserted_files + '}\n'
+ )
+ header.write('\n#endif // TOOLS_ENABLED\n')
+ header.write('\n#endif // CS_COMPRESSED_H\n')
+
+ glue_version = int(latest_mtime) # The latest modified time will do for now
+
+ with open(version_dst, 'w') as version_header:
+ version_header.write('/* THIS FILE IS GENERATED DO NOT EDIT */\n')
+ version_header.write('#ifndef CS_GLUE_VERSION_H\n')
+ version_header.write('#define CS_GLUE_VERSION_H\n\n')
+ version_header.write('#define CS_GLUE_VERSION UINT32_C(' + str(glue_version) + ')\n')
+ version_header.write('\n#endif // CS_GLUE_VERSION_H\n')
diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py
new file mode 100644
index 0000000000..160580e116
--- /dev/null
+++ b/modules/mono/build_scripts/mono_configure.py
@@ -0,0 +1,414 @@
+import imp
+import os
+import sys
+import subprocess
+
+from distutils.version import LooseVersion
+from SCons.Script import BoolVariable, Dir, Environment, Variables
+
+if os.name == 'nt':
+ from . import mono_reg_utils as monoreg
+
+
+def find_file_in_dir(directory, files, prefix='', extension=''):
+ if not extension.startswith('.'):
+ extension = '.' + extension
+ for curfile in files:
+ if os.path.isfile(os.path.join(directory, prefix + curfile + extension)):
+ return curfile
+ return ''
+
+
+def copy_file(src_dir, dst_dir, name):
+ from shutil import copyfile
+
+ src_path = os.path.join(src_dir, name)
+ dst_path = os.path.join(dst_dir, name)
+
+ if not os.path.isdir(dst_dir):
+ os.mkdir(dst_dir)
+
+ copyfile(src_path, dst_path)
+
+
+def configure(env, env_mono):
+ envvars = Variables()
+ envvars.Add(BoolVariable('mono_static', 'Statically link mono', False))
+ 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']
+ copy_mono_root = env['copy_mono_root']
+
+ mono_lib_names = ['mono-2.0-sgen', 'monosgen-2.0']
+
+ if env['platform'] == 'windows':
+ mono_root = ''
+
+ if bits == '32':
+ if os.getenv('MONO32_PREFIX'):
+ mono_root = os.getenv('MONO32_PREFIX')
+ elif os.name == 'nt':
+ mono_root = monoreg.find_mono_root_dir(bits)
+ else:
+ if os.getenv('MONO64_PREFIX'):
+ mono_root = os.getenv('MONO64_PREFIX')
+ elif os.name == 'nt':
+ mono_root = monoreg.find_mono_root_dir(bits)
+
+ if not mono_root:
+ raise RuntimeError('Mono installation directory not found')
+
+ print('Found Mono root directory: ' + mono_root)
+
+ mono_version = mono_root_try_find_mono_version(mono_root)
+ configure_for_mono_version(env_mono, mono_version)
+
+ mono_lib_path = os.path.join(mono_root, 'lib')
+
+ env.Append(LIBPATH=mono_lib_path)
+ env_mono.Append(CPPPATH=os.path.join(mono_root, 'include', 'mono-2.0'))
+
+ if mono_static:
+ lib_suffix = Environment()['LIBSUFFIX']
+
+ if env.msvc:
+ mono_static_lib_name = 'libmono-static-sgen'
+ else:
+ mono_static_lib_name = 'libmonosgen-2.0'
+
+ if not os.path.isfile(os.path.join(mono_lib_path, mono_static_lib_name + lib_suffix)):
+ raise RuntimeError('Could not find static mono library in: ' + mono_lib_path)
+
+ if env.msvc:
+ env.Append(LINKFLAGS=mono_static_lib_name + lib_suffix)
+
+ env.Append(LINKFLAGS='Mincore' + lib_suffix)
+ env.Append(LINKFLAGS='msvcrt' + lib_suffix)
+ env.Append(LINKFLAGS='LIBCMT' + lib_suffix)
+ env.Append(LINKFLAGS='Psapi' + lib_suffix)
+ else:
+ env.Append(LINKFLAGS=os.path.join(mono_lib_path, mono_static_lib_name + lib_suffix))
+
+ env.Append(LIBS='psapi')
+ env.Append(LIBS='version')
+ else:
+ mono_lib_name = find_file_in_dir(mono_lib_path, mono_lib_names, extension='.lib')
+
+ if not mono_lib_name:
+ raise RuntimeError('Could not find mono library in: ' + mono_lib_path)
+
+ if env.msvc:
+ env.Append(LINKFLAGS=mono_lib_name + Environment()['LIBSUFFIX'])
+ else:
+ env.Append(LIBS=mono_lib_name)
+
+ mono_bin_path = os.path.join(mono_root, 'bin')
+
+ mono_dll_name = find_file_in_dir(mono_bin_path, mono_lib_names, extension='.dll')
+
+ if not mono_dll_name:
+ raise RuntimeError('Could not find mono shared library in: ' + mono_bin_path)
+
+ copy_file(mono_bin_path, 'bin', mono_dll_name + '.dll')
+ else:
+ is_apple = (sys.platform == 'darwin' or "osxcross" in env)
+
+ sharedlib_ext = '.dylib' if is_apple else '.so'
+
+ mono_root = ''
+ mono_lib_path = ''
+
+ if bits == '32':
+ if os.getenv('MONO32_PREFIX'):
+ mono_root = os.getenv('MONO32_PREFIX')
+ else:
+ if os.getenv('MONO64_PREFIX'):
+ mono_root = os.getenv('MONO64_PREFIX')
+
+ if not mono_root and is_apple:
+ # Try with some known directories under OSX
+ hint_dirs = ['/Library/Frameworks/Mono.framework/Versions/Current', '/usr/local/var/homebrew/linked/mono']
+ for hint_dir in hint_dirs:
+ if os.path.isdir(hint_dir):
+ mono_root = hint_dir
+ break
+
+ # We can't use pkg-config to link mono statically,
+ # but we can still use it to find the mono root directory
+ if not mono_root and mono_static:
+ mono_root = pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext)
+ if not mono_root:
+ raise RuntimeError('Building with mono_static=yes, but failed to find the mono prefix with pkg-config. Specify one manually')
+
+ if mono_root:
+ print('Found Mono root directory: ' + mono_root)
+
+ mono_version = mono_root_try_find_mono_version(mono_root)
+ configure_for_mono_version(env_mono, mono_version)
+
+ mono_lib_path = os.path.join(mono_root, 'lib')
+
+ env.Append(LIBPATH=mono_lib_path)
+ env_mono.Append(CPPPATH=os.path.join(mono_root, 'include', 'mono-2.0'))
+
+ mono_lib = find_file_in_dir(mono_lib_path, mono_lib_names, prefix='lib', extension='.a')
+
+ if not mono_lib:
+ raise RuntimeError('Could not find mono library in: ' + mono_lib_path)
+
+ env_mono.Append(CPPFLAGS=['-D_REENTRANT'])
+
+ if mono_static:
+ mono_lib_file = os.path.join(mono_lib_path, 'lib' + mono_lib + '.a')
+
+ if is_apple:
+ env.Append(LINKFLAGS=['-Wl,-force_load,' + mono_lib_file])
+ else:
+ env.Append(LINKFLAGS=['-Wl,-whole-archive', mono_lib_file, '-Wl,-no-whole-archive'])
+ else:
+ env.Append(LIBS=[mono_lib])
+
+ if is_apple:
+ env.Append(LIBS=['iconv', 'pthread'])
+ else:
+ env.Append(LIBS=['m', 'rt', 'dl', 'pthread'])
+
+ if not mono_static:
+ mono_so_name = find_file_in_dir(mono_lib_path, mono_lib_names, prefix='lib', extension=sharedlib_ext)
+
+ if not mono_so_name:
+ raise RuntimeError('Could not find mono shared library in: ' + mono_lib_path)
+
+ copy_file(mono_lib_path, 'bin', 'lib' + mono_so_name + sharedlib_ext)
+ else:
+ assert not mono_static
+
+ # TODO: Add option to force using pkg-config
+ print('Mono root directory not found. Using pkg-config instead')
+
+ mono_version = pkgconfig_try_find_mono_version()
+ configure_for_mono_version(env_mono, mono_version)
+
+ env.ParseConfig('pkg-config monosgen-2 --libs')
+ env_mono.ParseConfig('pkg-config monosgen-2 --cflags')
+
+ mono_lib_path = ''
+ mono_so_name = ''
+
+ tmpenv = Environment()
+ tmpenv.AppendENVPath('PKG_CONFIG_PATH', os.getenv('PKG_CONFIG_PATH'))
+ tmpenv.ParseConfig('pkg-config monosgen-2 --libs-only-L')
+
+ for hint_dir in tmpenv['LIBPATH']:
+ name_found = find_file_in_dir(hint_dir, mono_lib_names, prefix='lib', extension=sharedlib_ext)
+ if name_found:
+ mono_lib_path = hint_dir
+ mono_so_name = name_found
+ break
+
+ if not mono_so_name:
+ raise RuntimeError('Could not find mono shared library in: ' + str(tmpenv['LIBPATH']))
+
+ copy_file(mono_lib_path, 'bin', 'lib' + mono_so_name + sharedlib_ext)
+
+ 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 in ['windows', 'osx', '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'):
+ env.Append(CPPFLAGS=['-DHAS_PENDING_EXCEPTIONS'])
+
+
+def pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext):
+ tmpenv = Environment()
+ tmpenv.AppendENVPath('PKG_CONFIG_PATH', os.getenv('PKG_CONFIG_PATH'))
+ tmpenv.ParseConfig('pkg-config monosgen-2 --libs-only-L')
+ for hint_dir in tmpenv['LIBPATH']:
+ name_found = find_file_in_dir(hint_dir, mono_lib_names, prefix='lib', extension=sharedlib_ext)
+ if name_found and os.path.isdir(os.path.join(hint_dir, '..', 'include', 'mono-2.0')):
+ return os.path.join(hint_dir, '..')
+ return ''
+
+
+def pkgconfig_try_find_mono_version():
+ from compat import decode_utf8
+
+ lines = subprocess.check_output(['pkg-config', 'monosgen-2', '--modversion']).splitlines()
+ greater_version = None
+ for line in lines:
+ try:
+ version = LooseVersion(decode_utf8(line))
+ if greater_version is None or version > greater_version:
+ greater_version = version
+ except ValueError:
+ pass
+ return greater_version
+
+
+def mono_root_try_find_mono_version(mono_root):
+ from compat import decode_utf8
+
+ mono_bin = os.path.join(mono_root, 'bin')
+ if os.path.isfile(os.path.join(mono_bin, 'mono')):
+ mono_binary = os.path.join(mono_bin, 'mono')
+ elif os.path.isfile(os.path.join(mono_bin, 'mono.exe')):
+ mono_binary = os.path.join(mono_bin, 'mono.exe')
+ else:
+ return None
+ output = subprocess.check_output([mono_binary, '--version'])
+ first_line = decode_utf8(output.splitlines()[0])
+ try:
+ return LooseVersion(first_line.split()[len('Mono JIT compiler version'.split())])
+ except (ValueError, IndexError):
+ return None
diff --git a/modules/mono/mono_reg_utils.py b/modules/mono/build_scripts/mono_reg_utils.py
index c8ebb54ded..583708bf07 100644
--- a/modules/mono/mono_reg_utils.py
+++ b/modules/mono/build_scripts/mono_reg_utils.py
@@ -40,7 +40,7 @@ def _reg_open_key_bits(key, subkey, bits):
def _find_mono_in_reg(subkey, bits):
try:
with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey:
- value, regtype = winreg.QueryValueEx(hKey, 'SdkInstallRoot')
+ value = winreg.QueryValueEx(hKey, 'SdkInstallRoot')[0]
return value
except (WindowsError, OSError):
return None
@@ -49,7 +49,7 @@ def _find_mono_in_reg(subkey, bits):
def _find_mono_in_reg_old(subkey, bits):
try:
with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey:
- default_clr, regtype = winreg.QueryValueEx(hKey, 'DefaultCLR')
+ default_clr = winreg.QueryValueEx(hKey, 'DefaultCLR')[0]
if default_clr:
return _find_mono_in_reg(subkey + '\\' + default_clr, bits)
return None
@@ -91,7 +91,13 @@ def find_msbuild_tools_path_reg():
if not val:
raise ValueError('Value of `installationPath` entry is empty')
- return os.path.join(val, "MSBuild\\15.0\\Bin")
+ # Since VS2019, the directory is simply named "Current"
+ msbuild_dir = os.path.join(val, 'MSBuild\\Current\\Bin')
+ if os.path.isdir(msbuild_dir):
+ return msbuild_dir
+
+ # Directory name "15.0" is used in VS 2017
+ return os.path.join(val, 'MSBuild\\15.0\\Bin')
raise ValueError('Cannot find `installationPath` entry')
except ValueError as e:
@@ -106,7 +112,7 @@ def find_msbuild_tools_path_reg():
try:
subkey = r'SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0'
with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, subkey) as hKey:
- value, regtype = winreg.QueryValueEx(hKey, 'MSBuildToolsPath')
+ value = winreg.QueryValueEx(hKey, 'MSBuildToolsPath')[0]
return value
except (WindowsError, OSError):
return ''
diff --git a/modules/mono/tls_configure.py b/modules/mono/build_scripts/tls_configure.py
index 622280b00b..622280b00b 100644
--- a/modules/mono/tls_configure.py
+++ b/modules/mono/build_scripts/tls_configure.py
diff --git a/modules/mono/config.py b/modules/mono/config.py
index 189699cca8..3b2e96765e 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -1,25 +1,12 @@
-
-import imp
-import os
-import sys
-import subprocess
-
-from distutils.version import LooseVersion
-from SCons.Script import BoolVariable, Dir, Environment, File, SCons, Variables
-
-
-monoreg = imp.load_source('mono_reg_utils', 'modules/mono/mono_reg_utils.py')
-
-
def can_build(env, platform):
if platform in ['javascript']:
return False # Not yet supported
return True
-def is_enabled():
- # The module is disabled by default. Use module_mono_enabled=yes to enable it.
- return False
+def configure(env):
+ env.use_ptrcall = True
+ env.add_module_version_string('mono')
def get_doc_classes():
@@ -34,405 +21,6 @@ def get_doc_path():
return 'doc_classes'
-def find_file_in_dir(directory, files, prefix='', extension=''):
- if not extension.startswith('.'):
- extension = '.' + extension
- for curfile in files:
- if os.path.isfile(os.path.join(directory, prefix + curfile + extension)):
- return curfile
- return ''
-
-
-def copy_file(src_dir, dst_dir, name):
- from shutil import copyfile
-
- src_path = os.path.join(src_dir, name)
- dst_path = os.path.join(dst_dir, name)
-
- if not os.path.isdir(dst_dir):
- os.mkdir(dst_dir)
-
- copyfile(src_path, dst_path)
-
-
-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(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']
- copy_mono_root = env['copy_mono_root']
-
- mono_lib_names = ['mono-2.0-sgen', 'monosgen-2.0']
-
- if env['platform'] == 'windows':
- mono_root = ''
-
- if bits == '32':
- if os.getenv('MONO32_PREFIX'):
- mono_root = os.getenv('MONO32_PREFIX')
- elif os.name == 'nt':
- mono_root = monoreg.find_mono_root_dir(bits)
- else:
- if os.getenv('MONO64_PREFIX'):
- mono_root = os.getenv('MONO64_PREFIX')
- elif os.name == 'nt':
- mono_root = monoreg.find_mono_root_dir(bits)
-
- if not mono_root:
- raise RuntimeError('Mono installation directory not found')
-
- print('Found Mono root directory: ' + mono_root)
-
- mono_version = mono_root_try_find_mono_version(mono_root)
- configure_for_mono_version(env, mono_version)
-
- mono_lib_path = os.path.join(mono_root, 'lib')
-
- env.Append(LIBPATH=mono_lib_path)
- env.Append(CPPPATH=os.path.join(mono_root, 'include', 'mono-2.0'))
-
- if mono_static:
- lib_suffix = Environment()['LIBSUFFIX']
-
- if env.msvc:
- mono_static_lib_name = 'libmono-static-sgen'
- else:
- mono_static_lib_name = 'libmonosgen-2.0'
-
- if not os.path.isfile(os.path.join(mono_lib_path, mono_static_lib_name + lib_suffix)):
- raise RuntimeError('Could not find static mono library in: ' + mono_lib_path)
-
- if env.msvc:
- env.Append(LINKFLAGS=mono_static_lib_name + lib_suffix)
-
- env.Append(LINKFLAGS='Mincore' + lib_suffix)
- env.Append(LINKFLAGS='msvcrt' + lib_suffix)
- env.Append(LINKFLAGS='LIBCMT' + lib_suffix)
- env.Append(LINKFLAGS='Psapi' + lib_suffix)
- else:
- env.Append(LINKFLAGS=os.path.join(mono_lib_path, mono_static_lib_name + lib_suffix))
-
- env.Append(LIBS='psapi')
- env.Append(LIBS='version')
- else:
- mono_lib_name = find_file_in_dir(mono_lib_path, mono_lib_names, extension='.lib')
-
- if not mono_lib_name:
- raise RuntimeError('Could not find mono library in: ' + mono_lib_path)
-
- if env.msvc:
- env.Append(LINKFLAGS=mono_lib_name + Environment()['LIBSUFFIX'])
- else:
- env.Append(LIBS=mono_lib_name)
-
- mono_bin_path = os.path.join(mono_root, 'bin')
-
- mono_dll_name = find_file_in_dir(mono_bin_path, mono_lib_names, extension='.dll')
-
- if not mono_dll_name:
- raise RuntimeError('Could not find mono shared library in: ' + mono_bin_path)
-
- copy_file(mono_bin_path, 'bin', mono_dll_name + '.dll')
- else:
- sharedlib_ext = '.dylib' if sys.platform == 'darwin' else '.so'
-
- mono_root = ''
- mono_lib_path = ''
-
- if bits == '32':
- if os.getenv('MONO32_PREFIX'):
- mono_root = os.getenv('MONO32_PREFIX')
- else:
- if os.getenv('MONO64_PREFIX'):
- mono_root = os.getenv('MONO64_PREFIX')
-
- if not mono_root and sys.platform == 'darwin':
- # Try with some known directories under OSX
- hint_dirs = ['/Library/Frameworks/Mono.framework/Versions/Current', '/usr/local/var/homebrew/linked/mono']
- for hint_dir in hint_dirs:
- if os.path.isdir(hint_dir):
- mono_root = hint_dir
- break
-
- # We can't use pkg-config to link mono statically,
- # but we can still use it to find the mono root directory
- if not mono_root and mono_static:
- mono_root = pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext)
- if not mono_root:
- raise RuntimeError('Building with mono_static=yes, but failed to find the mono prefix with pkg-config. Specify one manually')
-
- if mono_root:
- print('Found Mono root directory: ' + mono_root)
-
- mono_version = mono_root_try_find_mono_version(mono_root)
- configure_for_mono_version(env, mono_version)
-
- mono_lib_path = os.path.join(mono_root, 'lib')
-
- env.Append(LIBPATH=mono_lib_path)
- env.Append(CPPPATH=os.path.join(mono_root, 'include', 'mono-2.0'))
-
- mono_lib = find_file_in_dir(mono_lib_path, mono_lib_names, prefix='lib', extension='.a')
-
- if not mono_lib:
- raise RuntimeError('Could not find mono library in: ' + mono_lib_path)
-
- env.Append(CPPFLAGS=['-D_REENTRANT'])
-
- if mono_static:
- mono_lib_file = os.path.join(mono_lib_path, 'lib' + mono_lib + '.a')
-
- if sys.platform == 'darwin':
- env.Append(LINKFLAGS=['-Wl,-force_load,' + mono_lib_file])
- else:
- 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'])
- else:
- env.Append(LIBS=['m', 'rt', 'dl', 'pthread'])
-
- if not mono_static:
- mono_so_name = find_file_in_dir(mono_lib_path, mono_lib_names, prefix='lib', extension=sharedlib_ext)
-
- if not mono_so_name:
- raise RuntimeError('Could not find mono shared library in: ' + mono_lib_path)
-
- copy_file(mono_lib_path, 'bin', 'lib' + mono_so_name + sharedlib_ext)
- else:
- assert not mono_static
-
- # TODO: Add option to force using pkg-config
- print('Mono root directory not found. Using pkg-config instead')
-
- mono_version = pkgconfig_try_find_mono_version()
- configure_for_mono_version(env, mono_version)
-
- env.ParseConfig('pkg-config monosgen-2 --cflags --libs')
-
- mono_lib_path = ''
- mono_so_name = ''
-
- tmpenv = Environment()
- tmpenv.AppendENVPath('PKG_CONFIG_PATH', os.getenv('PKG_CONFIG_PATH'))
- tmpenv.ParseConfig('pkg-config monosgen-2 --libs-only-L')
-
- for hint_dir in tmpenv['LIBPATH']:
- name_found = find_file_in_dir(hint_dir, mono_lib_names, prefix='lib', extension=sharedlib_ext)
- if name_found:
- mono_lib_path = hint_dir
- mono_so_name = name_found
- break
-
- if not mono_so_name:
- raise RuntimeError('Could not find mono shared library in: ' + str(tmpenv['LIBPATH']))
-
- copy_file(mono_lib_path, 'bin', 'lib' + mono_so_name + sharedlib_ext)
-
- 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 in ['windows', 'osx', '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'):
- env.Append(CPPFLAGS=['-DHAS_PENDING_EXCEPTIONS'])
-
-
-def pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext):
- tmpenv = Environment()
- tmpenv.AppendENVPath('PKG_CONFIG_PATH', os.getenv('PKG_CONFIG_PATH'))
- tmpenv.ParseConfig('pkg-config monosgen-2 --libs-only-L')
- for hint_dir in tmpenv['LIBPATH']:
- name_found = find_file_in_dir(hint_dir, mono_lib_names, prefix='lib', extension=sharedlib_ext)
- if name_found and os.path.isdir(os.path.join(hint_dir, '..', 'include', 'mono-2.0')):
- return os.path.join(hint_dir, '..')
- return ''
-
-
-def pkgconfig_try_find_mono_version():
- from compat import decode_utf8
-
- lines = subprocess.check_output(['pkg-config', 'monosgen-2', '--modversion']).splitlines()
- greater_version = None
- for line in lines:
- try:
- version = LooseVersion(decode_utf8(line))
- if greater_version is None or version > greater_version:
- greater_version = version
- except ValueError:
- pass
- return greater_version
-
-
-def mono_root_try_find_mono_version(mono_root):
- from compat import decode_utf8
-
- mono_bin = os.path.join(mono_root, 'bin')
- if os.path.isfile(os.path.join(mono_bin, 'mono')):
- mono_binary = os.path.join(mono_bin, 'mono')
- elif os.path.isfile(os.path.join(mono_bin, 'mono.exe')):
- mono_binary = os.path.join(mono_bin, 'mono.exe')
- else:
- return None
- output = subprocess.check_output([mono_binary, '--version'])
- first_line = decode_utf8(output.splitlines()[0])
- try:
- return LooseVersion(first_line.split()[len('Mono JIT compiler version'.split())])
- except (ValueError, IndexError):
- return None
+def is_enabled():
+ # The module is disabled by default. Use module_mono_enabled=yes to enable it.
+ return False
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 943d95bfc9..3c9644127c 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -139,14 +139,24 @@ void CSharpLanguage::finish() {
}
#endif
- // Release gchandle bindings before finalizing mono runtime
- script_bindings.clear();
+ // Make sure all script binding gchandles are released before finalizing GDMono
+ for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) {
+ CSharpScriptBinding &script_binding = E->value();
+
+ if (script_binding.gchandle.is_valid()) {
+ script_binding.gchandle->release();
+ script_binding.inited = false;
+ }
+ }
if (gdmono) {
memdelete(gdmono);
gdmono = NULL;
}
+ // Clear here, after finalizing all domains to make sure there is nothing else referencing the elements.
+ script_bindings.clear();
+
finalizing = false;
}
@@ -439,7 +449,7 @@ static String variant_type_to_managed_name(const String &p_var_type_name) {
Variant::_RID
};
- for (int i = 0; i < sizeof(var_types) / sizeof(Variant::Type); i++) {
+ for (unsigned int i = 0; i < sizeof(var_types) / sizeof(Variant::Type); i++) {
if (p_var_type_name == Variant::get_type_name(var_types[i]))
return p_var_type_name;
}
@@ -489,6 +499,47 @@ String CSharpLanguage::_get_indentation() const {
return "\t";
}
+String CSharpLanguage::debug_get_error() const {
+
+ return _debug_error;
+}
+
+int CSharpLanguage::debug_get_stack_level_count() const {
+
+ if (_debug_parse_err_line >= 0)
+ return 1;
+
+ // TODO: StackTrace
+ return 1;
+}
+
+int CSharpLanguage::debug_get_stack_level_line(int p_level) const {
+
+ if (_debug_parse_err_line >= 0)
+ return _debug_parse_err_line;
+
+ // TODO: StackTrace
+ return 1;
+}
+
+String CSharpLanguage::debug_get_stack_level_function(int p_level) const {
+
+ if (_debug_parse_err_line >= 0)
+ return String();
+
+ // TODO: StackTrace
+ return String();
+}
+
+String CSharpLanguage::debug_get_stack_level_source(int p_level) const {
+
+ if (_debug_parse_err_line >= 0)
+ return _debug_parse_err_file;
+
+ // TODO: StackTrace
+ return String();
+}
+
Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info() {
#ifdef DEBUG_ENABLED
@@ -520,7 +571,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
MonoException *exc = NULL;
- MonoArray *frames = invoke_method_thunk(CACHED_METHOD_THUNK(System_Diagnostics_StackTrace, GetFrames), p_stack_trace, (MonoObject **)&exc);
+ MonoArray *frames = invoke_method_thunk(CACHED_METHOD_THUNK(System_Diagnostics_StackTrace, GetFrames), p_stack_trace, &exc);
if (exc) {
GDMonoUtils::debug_print_unhandled_exception(exc);
@@ -544,7 +595,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
MonoString *file_name;
int file_line_num;
MonoString *method_decl;
- invoke_method_thunk(get_sf_info, frame, &file_name, &file_line_num, &method_decl, (MonoObject **)&exc);
+ invoke_method_thunk(get_sf_info, frame, &file_name, &file_line_num, &method_decl, &exc);
if (exc) {
GDMonoUtils::debug_print_unhandled_exception(exc);
@@ -574,11 +625,11 @@ void CSharpLanguage::frame() {
if (task_scheduler) {
MonoException *exc = NULL;
- invoke_method_thunk(CACHED_METHOD_THUNK(GodotTaskScheduler, Activate), task_scheduler, (MonoObject **)&exc);
+ invoke_method_thunk(CACHED_METHOD_THUNK(GodotTaskScheduler, Activate), task_scheduler, &exc);
if (exc) {
GDMonoUtils::debug_unhandled_exception(exc);
- _UNREACHABLE_();
+ GD_UNREACHABLE();
}
}
}
@@ -607,31 +658,10 @@ struct CSharpScriptDepSort {
void CSharpLanguage::reload_all_scripts() {
-#ifdef DEBUG_ENABLED
-
- List<Ref<CSharpScript> > scripts;
-
- {
- SCOPED_MUTEX_LOCK(script_instances_mutex);
-
- SelfList<CSharpScript> *elem = script_list.first();
- while (elem) {
- if (elem->self()->get_path().is_resource_file()) {
- scripts.push_back(Ref<CSharpScript>(elem->self())); //cast to gdscript to avoid being erased by accident
- }
- elem = elem->next();
- }
- }
-
- //as scripts are going to be reloaded, must proceed without locking here
-
- scripts.sort_custom<CSharpScriptDepSort>(); //update in inheritance dependency order
-
- for (List<Ref<CSharpScript> >::Element *E = scripts.front(); E; E = E->next()) {
- E->get()->load_source_code(E->get()->get_path());
- E->get()->reload(true);
+#ifdef GD_MONO_HOT_RELOAD
+ if (is_assembly_reloading_needed()) {
+ reload_assemblies(false);
}
-
#endif
}
@@ -639,15 +669,20 @@ void CSharpLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft
(void)p_script; // UNUSED
+ CRASH_COND(!Engine::get_singleton()->is_editor_hint());
+
#ifdef TOOLS_ENABLED
MonoReloadNode::get_singleton()->restart_reload_timer();
+#endif
+
+#ifdef GD_MONO_HOT_RELOAD
if (is_assembly_reloading_needed()) {
reload_assemblies(p_soft_reload);
}
#endif
}
-#ifdef TOOLS_ENABLED
+#ifdef GD_MONO_HOT_RELOAD
bool CSharpLanguage::is_assembly_reloading_needed() {
if (!gdmono->is_runtime_initialized())
@@ -679,11 +714,13 @@ bool CSharpLanguage::is_assembly_reloading_needed() {
return false; // No assembly to load
}
+#ifdef TOOLS_ENABLED
if (!gdmono->get_core_api_assembly() && gdmono->metadata_is_api_assembly_invalidated(APIAssembly::API_CORE))
return false; // The core API assembly to load is invalidated
if (!gdmono->get_editor_api_assembly() && gdmono->metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR))
return false; // The editor API assembly to load is invalidated
+#endif
return true;
}
@@ -723,13 +760,13 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
// Script::instances are deleted during managed object disposal, which happens on domain finalize.
// Only placeholders are kept. Therefore we need to keep a copy before that happens.
- for (Set<Object *>::Element *E = script->instances.front(); E; E = E->next()) {
- script->pending_reload_instances.insert(E->get()->get_instance_id());
+ for (Set<Object *>::Element *F = script->instances.front(); F; F = F->next()) {
+ script->pending_reload_instances.insert(F->get()->get_instance_id());
}
#ifdef TOOLS_ENABLED
- for (Set<PlaceHolderScriptInstance *>::Element *E = script->placeholders.front(); E; E = E->next()) {
- script->pending_reload_instances.insert(E->get()->get_owner()->get_instance_id());
+ for (Set<PlaceHolderScriptInstance *>::Element *F = script->placeholders.front(); F; F = F->next()) {
+ script->pending_reload_instances.insert(F->get()->get_owner()->get_instance_id());
}
#endif
@@ -781,9 +818,11 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
PlaceHolderScriptInstance *placeholder = scr->placeholder_instance_create(obj);
obj->set_script_instance(placeholder);
+#ifdef TOOLS_ENABLED
// Even though build didn't fail, this tells the placeholder to keep properties and
// it allows using property_set_fallback for restoring the state without a valid script.
- placeholder->set_build_failed(true);
+ scr->placeholder_fallback_enabled = true;
+#endif
// Restore Variant properties state, it will be kept by the placeholder until the next script reloading
for (List<Pair<StringName, Variant> >::Element *G = scr->pending_reload_state[obj_id].properties.front(); G; G = G->next()) {
@@ -799,13 +838,14 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
for (List<Ref<CSharpScript> >::Element *E = to_reload.front(); E; E = E->next()) {
Ref<CSharpScript> scr = E->get();
+#ifdef TOOLS_ENABLED
scr->exports_invalidated = true;
+#endif
scr->signals_invalidated = true;
scr->reload(p_soft_reload);
scr->update_exports();
{
-#ifdef DEBUG_ENABLED
for (Set<ObjectID>::Element *F = scr->pending_reload_instances.front(); F; F = F->next()) {
ObjectID obj_id = F->get();
Object *obj = ObjectDB::get_instance(obj_id);
@@ -829,7 +869,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
CSharpScript::StateBackup &state_backup = scr->pending_reload_state[obj_id];
// Backup placeholder script instance state before replacing it with a script instance
- obj->get_script_instance()->get_property_state(state_backup.properties);
+ si->get_property_state(state_backup.properties);
ScriptInstance *script_instance = scr->instance_create(obj);
@@ -864,17 +904,18 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
scr->pending_reload_state.erase(obj_id);
}
-#endif
scr->pending_reload_instances.clear();
}
}
+#ifdef TOOLS_ENABLED
// FIXME: Hack to refresh editor in order to display new properties and signals. See if there is a better alternative.
if (Engine::get_singleton()->is_editor_hint()) {
EditorNode::get_singleton()->get_inspector()->update_tree();
NodeDock::singleton->update_lists();
}
+#endif
}
#endif
@@ -958,12 +999,11 @@ void CSharpLanguage::thread_exit() {
bool CSharpLanguage::debug_break_parse(const String &p_file, int p_line, const String &p_error) {
- // Break because of parse error
+ // Not a parser error in our case, but it's still used for other type of errors
if (ScriptDebugger::get_singleton() && Thread::get_caller_id() == Thread::get_main_id()) {
- // TODO
- //_debug_parse_err_line = p_line;
- //_debug_parse_err_file = p_file;
- //_debug_error = p_error;
+ _debug_parse_err_line = p_line;
+ _debug_parse_err_file = p_file;
+ _debug_error = p_error;
ScriptDebugger::get_singleton()->debug(this, false);
return true;
} else {
@@ -974,10 +1014,9 @@ bool CSharpLanguage::debug_break_parse(const String &p_file, int p_line, const S
bool CSharpLanguage::debug_break(const String &p_error, bool p_allow_continue) {
if (ScriptDebugger::get_singleton() && Thread::get_caller_id() == Thread::get_main_id()) {
- // TODO
- //_debug_parse_err_line = -1;
- //_debug_parse_err_file = "";
- //_debug_error = p_error;
+ _debug_parse_err_line = -1;
+ _debug_parse_err_file = "";
+ _debug_error = p_error;
ScriptDebugger::get_singleton()->debug(this, p_allow_continue);
return true;
} else {
@@ -985,6 +1024,13 @@ bool CSharpLanguage::debug_break(const String &p_error, bool p_allow_continue) {
}
}
+void CSharpLanguage::_uninitialize_script_bindings() {
+ for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) {
+ CSharpScriptBinding &script_binding = E->value();
+ script_binding.inited = false;
+ }
+}
+
void CSharpLanguage::set_language_index(int p_idx) {
ERR_FAIL_COND(lang_idx != -1);
@@ -1064,12 +1110,14 @@ CSharpLanguage::~CSharpLanguage() {
singleton = NULL;
}
-void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) {
+bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_binding, Object *p_object) {
#ifdef DEBUG_ENABLED
// I don't trust you
- if (p_object->get_script_instance())
- CRASH_COND(NULL != CAST_CSHARP_INSTANCE(p_object->get_script_instance()));
+ if (p_object->get_script_instance()) {
+ CSharpInstance *csharp_instance = CAST_CSHARP_INSTANCE(p_object->get_script_instance());
+ CRASH_COND(csharp_instance != NULL && !csharp_instance->is_destructing_script_instance());
+ }
#endif
StringName type_name = p_object->get_class_name();
@@ -1078,29 +1126,21 @@ void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) {
const ClassDB::ClassInfo *classinfo = ClassDB::classes.getptr(type_name);
while (classinfo && !classinfo->exposed)
classinfo = classinfo->inherits_ptr;
- ERR_FAIL_NULL_V(classinfo, NULL);
+ ERR_FAIL_NULL_V(classinfo, false);
type_name = classinfo->name;
GDMonoClass *type_class = GDMonoUtils::type_get_proxy_class(type_name);
- ERR_FAIL_NULL_V(type_class, NULL);
+ ERR_FAIL_NULL_V(type_class, false);
MonoObject *mono_object = GDMonoUtils::create_managed_for_godot_object(type_class, type_name, p_object);
- ERR_FAIL_NULL_V(mono_object, NULL);
-
- CSharpScriptBinding script_binding;
-
- script_binding.type_name = type_name;
- script_binding.wrapper_class = type_class; // cache
- script_binding.gchandle = MonoGCHandle::create_strong(mono_object);
-
- void *data;
+ ERR_FAIL_NULL_V(mono_object, false);
- {
- SCOPED_MUTEX_LOCK(language_bind_mutex);
- data = (void *)script_bindings.insert(p_object, script_binding);
- }
+ r_script_binding.inited = true;
+ r_script_binding.type_name = type_name;
+ r_script_binding.wrapper_class = type_class; // cache
+ r_script_binding.gchandle = MonoGCHandle::create_strong(mono_object);
// Tie managed to unmanaged
Reference *ref = Object::cast_to<Reference>(p_object);
@@ -1114,7 +1154,28 @@ void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) {
ref->reference();
}
- return data;
+ return true;
+}
+
+void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) {
+
+ SCOPED_MUTEX_LOCK(language_bind_mutex);
+
+ Map<Object *, CSharpScriptBinding>::Element *match = script_bindings.find(p_object);
+ if (match)
+ return (void *)match;
+
+ CSharpScriptBinding script_binding;
+
+ if (!setup_csharp_script_binding(script_binding, p_object))
+ return NULL;
+
+ return (void *)insert_script_binding(p_object, script_binding);
+}
+
+Map<Object *, CSharpScriptBinding>::Element *CSharpLanguage::insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding) {
+
+ return script_bindings.insert(p_object, p_script_binding);
}
void CSharpLanguage::free_instance_binding_data(void *p_data) {
@@ -1135,10 +1196,15 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) {
Map<Object *, CSharpScriptBinding>::Element *data = (Map<Object *, CSharpScriptBinding>::Element *)p_data;
- // Set the native instance field to IntPtr.Zero, if not yet garbage collected
- MonoObject *mono_object = data->value().gchandle->get_target();
- if (mono_object) {
- CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, NULL);
+ CSharpScriptBinding &script_binding = data->value();
+
+ if (script_binding.inited) {
+ // Set the native instance field to IntPtr.Zero, if not yet garbage collected.
+ // This is done to avoid trying to dispose the native instance from Dispose(bool).
+ MonoObject *mono_object = script_binding.gchandle->get_target();
+ if (mono_object) {
+ CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, NULL);
+ }
}
script_bindings.erase(data);
@@ -1154,9 +1220,10 @@ void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) {
#endif
void *data = p_object->get_script_instance_binding(get_language_index());
- if (!data)
- return;
- Ref<MonoGCHandle> &gchandle = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get().gchandle;
+ CRASH_COND(!data);
+
+ CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
+ Ref<MonoGCHandle> &gchandle = script_binding.gchandle;
if (ref_owner->reference_get_count() > 1 && gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
// The reference count was increased after the managed side was the only one referencing our owner.
@@ -1185,11 +1252,12 @@ bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) {
int refcount = ref_owner->reference_get_count();
void *data = p_object->get_script_instance_binding(get_language_index());
- if (!data)
- return refcount == 0;
- Ref<MonoGCHandle> &gchandle = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get().gchandle;
+ CRASH_COND(!data);
- if (refcount == 1 && !gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
+ CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
+ Ref<MonoGCHandle> &gchandle = script_binding.gchandle;
+
+ if (refcount == 1 && gchandle.is_valid() && !gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
// If owner owner is no longer referenced by the unmanaged side,
// the managed instance takes responsibility of deleting the owner when GCed.
@@ -1233,6 +1301,10 @@ MonoObject *CSharpInstance::get_mono_object() const {
return gchandle->get_target();
}
+Object *CSharpInstance::get_owner() {
+ return owner;
+}
+
bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) {
ERR_FAIL_COND_V(!script.is_valid(), false);
@@ -1243,14 +1315,14 @@ bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) {
GDMonoClass *top = script->script_class;
while (top && top != script->native) {
- GDMonoField *field = script->script_class->get_field(p_name);
+ GDMonoField *field = top->get_field(p_name);
if (field) {
field->set_value_from_variant(mono_object, p_value);
return true;
}
- GDMonoProperty *property = script->script_class->get_property(p_name);
+ GDMonoProperty *property = top->get_property(p_name);
if (property) {
property->set_value(mono_object, GDMonoMarshal::variant_to_mono_object(p_value, property->get_type()));
@@ -1352,6 +1424,34 @@ void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const {
for (Map<StringName, PropertyInfo>::Element *E = script->member_info.front(); E; E = E->next()) {
p_properties->push_back(E->value());
}
+
+ // Call _get_property_list
+
+ ERR_FAIL_COND(!script.is_valid());
+
+ MonoObject *mono_object = get_mono_object();
+ ERR_FAIL_NULL(mono_object);
+
+ GDMonoClass *top = script->script_class;
+
+ while (top && top != script->native) {
+ GDMonoMethod *method = top->get_method(CACHED_STRING_NAME(_get_property_list), 0);
+
+ if (method) {
+ MonoObject *ret = method->invoke(mono_object);
+
+ if (ret) {
+ Array array = Array(GDMonoMarshal::mono_object_to_variant(ret));
+ for (int i = 0, size = array.size(); i < size; i++)
+ p_properties->push_back(PropertyInfo::from_dict(array.get(i)));
+ return;
+ }
+
+ break;
+ }
+
+ top = top->get_parent_class();
+ }
}
Variant::Type CSharpInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const {
@@ -1493,14 +1593,8 @@ bool CSharpInstance::_unreference_owner_unsafe() {
// Unsafe refcount decrement. The managed instance also counts as a reference.
// See: _reference_owner_unsafe()
- bool die = static_cast<Reference *>(owner)->unreference();
-
- if (die) {
- memdelete(owner);
- owner = NULL;
- }
-
- return die;
+ // Destroying the owner here means self destructing, so we defer the owner destruction to the caller.
+ return static_cast<Reference *>(owner)->unreference();
}
MonoObject *CSharpInstance::_internal_new_managed() {
@@ -1508,32 +1602,46 @@ MonoObject *CSharpInstance::_internal_new_managed() {
CRASH_COND(!gchandle.is_valid());
#endif
+ // Search the constructor first, to fail with an error if it's not found before allocating anything else.
+ GDMonoMethod *ctor = script->script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
+ if (ctor == NULL) {
+ ERR_PRINTS("Cannot create script instance because the class does not define a parameterless constructor: " + script->get_path());
+
+ ERR_EXPLAIN("Constructor not found");
+ ERR_FAIL_V(NULL);
+ }
+
CSharpLanguage::get_singleton()->release_script_gchandle(gchandle);
ERR_FAIL_NULL_V(owner, NULL);
ERR_FAIL_COND_V(script.is_null(), NULL);
- if (base_ref)
- _reference_owner_unsafe();
-
MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, script->script_class->get_mono_ptr());
if (!mono_object) {
+ // Important to clear this before destroying the script instance here
script = Ref<CSharpScript>();
- owner->set_script_instance(NULL);
+ owner = NULL;
+
+ bool die = _unreference_owner_unsafe();
+ // Not ok for the owner to die here. If there is a situation where this can happen, it will be considered a bug.
+ CRASH_COND(die == true);
+
ERR_EXPLAIN("Failed to allocate memory for the object");
ERR_FAIL_V(NULL);
}
+ // Tie managed to unmanaged
+ gchandle = MonoGCHandle::create_strong(mono_object);
+
+ if (base_ref)
+ _reference_owner_unsafe(); // Here, after assigning the gchandle (for the refcount_incremented callback)
+
CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, owner);
// Construct
- GDMonoMethod *ctor = script->script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
ctor->invoke_raw(mono_object, NULL);
- // Tie managed to unmanaged
- gchandle = MonoGCHandle::create_strong(mono_object);
-
return mono_object;
}
@@ -1546,25 +1654,36 @@ void CSharpInstance::mono_object_disposed(MonoObject *p_obj) {
CSharpLanguage::get_singleton()->release_script_gchandle(p_obj, gchandle);
}
-void CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_owner_deleted) {
+void CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_delete_owner, bool &r_remove_script_instance) {
#ifdef DEBUG_ENABLED
CRASH_COND(!base_ref);
CRASH_COND(gchandle.is_null());
#endif
+
+ r_remove_script_instance = false;
+
if (_unreference_owner_unsafe()) {
- r_owner_deleted = true;
+ // Safe to self destruct here with memdelete(owner), but it's deferred to the caller to prevent future mistakes.
+ r_delete_owner = true;
} else {
- r_owner_deleted = false;
+ r_delete_owner = false;
CSharpLanguage::get_singleton()->release_script_gchandle(p_obj, gchandle);
- if (p_is_finalizer && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
- // If the native instance is still alive, then it was
- // referenced from another thread before the finalizer could
- // unreference it and delete it, so we want to keep it.
- // GC.ReRegisterForFinalize(this) is not safe because the objects
- // referenced by this could have already been collected.
- // Instead we will create a new managed instance here.
- _internal_new_managed();
+
+ if (!p_is_finalizer) {
+ // If the native instance is still alive and Dispose() was called
+ // (instead of the finalizer), then we remove the script instance.
+ r_remove_script_instance = true;
+ } else if (!GDMono::get_singleton()->is_finalizing_scripts_domain()) {
+ // If the native instance is still alive and this is called from the finalizer,
+ // then it was referenced from another thread before the finalizer could
+ // unreference and delete it, so we want to keep it.
+ // GC.ReRegisterForFinalize(this) is not safe because the objects referenced by 'this'
+ // could have already been collected. Instead we will create a new managed instance here.
+ MonoObject *new_managed = _internal_new_managed();
+ if (!new_managed) {
+ r_remove_script_instance = true;
+ }
}
}
}
@@ -1618,7 +1737,7 @@ bool CSharpInstance::refcount_decremented() {
return ref_dying;
}
-MultiplayerAPI::RPCMode CSharpInstance::_member_get_rpc_mode(GDMonoClassMember *p_member) const {
+MultiplayerAPI::RPCMode CSharpInstance::_member_get_rpc_mode(IMonoClassMember *p_member) const {
if (p_member->has_attribute(CACHED_CLASS(RemoteAttribute)))
return MultiplayerAPI::RPC_MODE_REMOTE;
@@ -1760,6 +1879,8 @@ CSharpInstance::CSharpInstance() :
CSharpInstance::~CSharpInstance() {
+ destructing_script_instance = true;
+
if (gchandle.is_valid()) {
if (!predelete_notified && !ref_dying) {
// This destructor is not called from the owners destructor.
@@ -1772,9 +1893,7 @@ CSharpInstance::~CSharpInstance() {
if (mono_object) {
MonoException *exc = NULL;
- destructing_script_instance = true;
GDMonoUtils::dispose(mono_object, &exc);
- destructing_script_instance = false;
if (exc) {
GDMonoUtils::set_pending_exception(exc);
@@ -1782,11 +1901,23 @@ CSharpInstance::~CSharpInstance() {
}
}
- gchandle->release(); // Make sure it's released
+ gchandle->release(); // Make sure the gchandle is released
}
- if (base_ref && !ref_dying && owner) { // it may be called from the owner's destructor
- _unreference_owner_unsafe();
+ // If not being called from the owner's destructor, and we still hold a reference to the owner
+ if (base_ref && !ref_dying && owner && unsafe_referenced) {
+ // The owner's script or script instance is being replaced (or removed)
+
+ // Transfer ownership to an "instance binding"
+
+ void *data = owner->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
+ CRASH_COND(data == NULL);
+
+ CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
+ CRASH_COND(!script_binding.inited);
+
+ bool die = _unreference_owner_unsafe();
+ CRASH_COND(die == true); // The "instance binding" should be holding a reference
}
if (script.is_valid() && owner) {
@@ -1830,12 +1961,13 @@ void CSharpScript::_update_exports_values(Map<StringName, Variant> &values, List
bool CSharpScript::_update_exports() {
#ifdef TOOLS_ENABLED
- if (!valid) {
- for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
- E->get()->set_build_failed(true);
- }
+ if (!Engine::get_singleton()->is_editor_hint())
+ return false;
+
+ placeholder_fallback_enabled = true; // until proven otherwise
+
+ if (!valid)
return false;
- }
bool changed = false;
@@ -1853,13 +1985,21 @@ bool CSharpScript::_update_exports() {
MonoObject *tmp_object = mono_object_new(SCRIPTS_DOMAIN, script_class->get_mono_ptr());
if (!tmp_object) {
- ERR_PRINT("Failed to create temporary MonoObject");
+ ERR_PRINT("Failed to allocate temporary MonoObject");
return false;
}
uint32_t tmp_pinned_gchandle = MonoGCHandle::new_strong_handle_pinned(tmp_object); // pin it (not sure if needed)
GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
+
+ if (ctor == NULL) {
+ ERR_PRINTS("Cannot construct temporary MonoObject because the class does not define a parameterless constructor: " + get_path());
+
+ ERR_EXPLAIN("Constructor not found");
+ ERR_FAIL_V(NULL);
+ }
+
MonoException *ctor_exc = NULL;
ctor->invoke(tmp_object, NULL, &ctor_exc);
@@ -1944,6 +2084,8 @@ bool CSharpScript::_update_exports() {
tmp_object = NULL;
}
+ placeholder_fallback_enabled = false;
+
if (placeholders.size()) {
// Update placeholders if any
Map<StringName, Variant> values;
@@ -1951,7 +2093,6 @@ bool CSharpScript::_update_exports() {
_update_exports_values(values, propnames);
for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
- E->get()->set_build_failed(false);
E->get()->update(propnames, values);
}
}
@@ -2030,7 +2171,7 @@ bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Ve
* Returns false if there was an error, otherwise true.
* If there was an error, r_prop_info and r_exported are not assigned any value.
*/
-bool CSharpScript::_get_member_export(GDMonoClass *p_class, GDMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported) {
+bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported) {
StringName name = p_member->get_name();
@@ -2045,15 +2186,16 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, GDMonoClassMember *p
ManagedType type;
- if (p_member->get_member_type() == GDMonoClassMember::MEMBER_TYPE_FIELD) {
+ if (p_member->get_member_type() == IMonoClassMember::MEMBER_TYPE_FIELD) {
type = static_cast<GDMonoField *>(p_member)->get_type();
- } else if (p_member->get_member_type() == GDMonoClassMember::MEMBER_TYPE_PROPERTY) {
+ } else if (p_member->get_member_type() == IMonoClassMember::MEMBER_TYPE_PROPERTY) {
type = static_cast<GDMonoProperty *>(p_member)->get_type();
} else {
CRASH_NOW();
}
- Variant::Type variant_type = GDMonoMarshal::managed_to_variant_type(type);
+ GDMonoMarshal::ExportInfo export_info;
+ Variant::Type variant_type = GDMonoMarshal::managed_to_variant_type(type, &export_info);
if (!p_member->has_attribute(CACHED_CLASS(ExportAttribute))) {
r_prop_info = PropertyInfo(variant_type, name.operator String(), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_SCRIPT_VARIABLE);
@@ -2061,7 +2203,7 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, GDMonoClassMember *p
return true;
}
- if (p_member->get_member_type() == GDMonoClassMember::MEMBER_TYPE_PROPERTY) {
+ if (p_member->get_member_type() == IMonoClassMember::MEMBER_TYPE_PROPERTY) {
GDMonoProperty *property = static_cast<GDMonoProperty *>(p_member);
if (!property->has_getter() || !property->has_setter()) {
ERR_PRINTS("Cannot export property because it does not provide a getter or a setter: " + p_class->get_full_name() + "." + name.operator String());
@@ -2078,6 +2220,7 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, GDMonoClassMember *p
ERR_PRINTS("Unknown type of exported member: " + p_class->get_full_name() + "." + name.operator String());
return false;
} else if (variant_type == Variant::INT && type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(type.type_class->get_mono_ptr())) {
+ // TODO: Move to ExportInfo?
variant_type = Variant::INT;
hint = PROPERTY_HINT_ENUM;
@@ -2124,7 +2267,7 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, GDMonoClassMember *p
return false;
}
- if (val != i) {
+ if (val != (unsigned int)i) {
uses_default_values = false;
}
@@ -2139,8 +2282,16 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, GDMonoClassMember *p
hint_string = name_only_hint_string;
}
} else if (variant_type == Variant::OBJECT && CACHED_CLASS(GodotReference)->is_assignable_from(type.type_class)) {
+ GDMonoClass *field_native_class = GDMonoUtils::get_class_native_base(type.type_class);
+ CRASH_COND(field_native_class == NULL);
+
hint = PROPERTY_HINT_RESOURCE_TYPE;
- hint_string = NATIVE_GDMONOCLASS_NAME(type.type_class);
+ hint_string = NATIVE_GDMONOCLASS_NAME(field_native_class);
+ } else if (variant_type == Variant::ARRAY && export_info.array.element_type != Variant::NIL) {
+ hint = PROPERTY_HINT_TYPE_STRING;
+ hint_string = itos(export_info.array.element_type) + ":";
+ } else if (variant_type == Variant::DICTIONARY && export_info.dictionary.key_type != Variant::NIL && export_info.dictionary.value_type != Variant::NIL) {
+ // TODO: There is no hint for this yet
} else {
hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr));
hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr);
@@ -2235,17 +2386,18 @@ void CSharpScript::_bind_methods() {
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &CSharpScript::_new, MethodInfo(Variant::OBJECT, "new"));
}
-Ref<CSharpScript> CSharpScript::create_for_managed_type(GDMonoClass *p_class) {
+Ref<CSharpScript> CSharpScript::create_for_managed_type(GDMonoClass *p_class, GDMonoClass *p_native) {
// This method should not fail
CRASH_COND(!p_class);
+ // TODO: Cache the 'CSharpScript' associated with this 'p_class' instead of allocating a new one every time
Ref<CSharpScript> script = memnew(CSharpScript);
script->name = p_class->get_name();
script->script_class = p_class;
- script->native = GDMonoUtils::get_class_native_base(script->script_class);
+ script->native = p_native;
CRASH_COND(script->native == NULL);
@@ -2339,22 +2491,64 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
/* STEP 1, CREATE */
+ // Search the constructor first, to fail with an error if it's not found before allocating anything else.
+ GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), p_argcount);
+ if (ctor == NULL) {
+ if (p_argcount == 0) {
+ ERR_PRINTS("Cannot create script instance because the class does not define a parameterless constructor: " + get_path());
+ }
+
+ ERR_EXPLAIN("Constructor not found");
+ ERR_FAIL_V(NULL);
+ }
+
+ Ref<Reference> ref;
+ if (p_isref) {
+ // Hold it alive. Important if we have to dispose a script instance binding before creating the CSharpInstance.
+ ref = Ref<Reference>(static_cast<Reference *>(p_owner));
+ }
+
+ // If the object had a script instance binding, dispose it before adding the CSharpInstance
+ if (p_owner->has_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index())) {
+ void *data = p_owner->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
+ CRASH_COND(data == NULL);
+
+ CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
+ if (script_binding.inited && script_binding.gchandle.is_valid()) {
+ MonoObject *mono_object = script_binding.gchandle->get_target();
+ if (mono_object) {
+ MonoException *exc = NULL;
+ GDMonoUtils::dispose(mono_object, &exc);
+
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
+ }
+ }
+
+ script_binding.inited = false;
+ }
+ }
+
CSharpInstance *instance = memnew(CSharpInstance);
instance->base_ref = p_isref;
instance->script = Ref<CSharpScript>(this);
instance->owner = p_owner;
instance->owner->set_script_instance(instance);
- if (instance->base_ref)
- instance->_reference_owner_unsafe();
-
/* STEP 2, INITIALIZE AND CONSTRUCT */
MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, script_class->get_mono_ptr());
if (!mono_object) {
+ // Important to clear this before destroying the script instance here
instance->script = Ref<CSharpScript>();
- instance->owner->set_script_instance(NULL);
+ instance->owner = NULL;
+
+ bool die = instance->_unreference_owner_unsafe();
+ // Not ok for the owner to die here. If there is a situation where this can happen, it will be considered a bug.
+ CRASH_COND(die == true);
+
+ p_owner->set_script_instance(NULL);
r_error.error = Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL;
ERR_EXPLAIN("Failed to allocate memory for the object");
ERR_FAIL_V(NULL);
@@ -2363,6 +2557,9 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
// Tie managed to unmanaged
instance->gchandle = MonoGCHandle::create_strong(mono_object);
+ if (instance->base_ref)
+ instance->_reference_owner_unsafe(); // Here, after assigning the gchandle (for the refcount_incremented callback)
+
{
SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->script_instances_mutex);
instances.insert(instance->owner);
@@ -2371,7 +2568,6 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, instance->owner);
// Construct
- GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), p_argcount);
ctor->invoke(mono_object, p_args);
/* STEP 3, PARTY */
@@ -2590,6 +2786,7 @@ Error CSharpScript::reload(bool p_keep_state) {
}
load_script_signals(script_class, native);
+ _update_exports();
}
return OK;
@@ -2697,6 +2894,7 @@ CSharpScript::CSharpScript() :
#ifdef TOOLS_ENABLED
source_changed_cache = false;
+ placeholder_fallback_enabled = false;
exports_invalidated = true;
#endif
@@ -2831,9 +3029,11 @@ Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_r
file->close();
memdelete(file);
+#ifdef TOOLS_ENABLED
if (ScriptServer::is_reload_scripts_on_save_enabled()) {
CSharpLanguage::get_singleton()->reload_tool_script(p_resource, false);
}
+#endif
return OK;
}
@@ -2855,6 +3055,7 @@ CSharpLanguage::StringNameCache::StringNameCache() {
_signal_callback = StaticCString::create("_signal_callback");
_set = StaticCString::create("_set");
_get = StaticCString::create("_get");
+ _get_property_list = StaticCString::create("_get_property_list");
_notification = StaticCString::create("_notification");
_script_source = StaticCString::create("script/source");
dotctor = StaticCString::create(".ctor");
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 08466bae58..050527d52b 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -82,10 +82,7 @@ class CSharpScript : public Script {
Set<Object *> instances;
-#ifdef DEBUG_ENABLED
- Set<ObjectID> pending_reload_instances;
-#endif
-
+#ifdef GD_MONO_HOT_RELOAD
struct StateBackup {
// TODO
// Replace with buffer containing the serialized state of managed scripts.
@@ -93,8 +90,8 @@ class CSharpScript : public Script {
List<Pair<StringName, Variant> > properties;
};
-#ifdef TOOLS_ENABLED
- Map<ObjectID, CSharpScript::StateBackup> pending_reload_state;
+ Set<ObjectID> pending_reload_instances;
+ Map<ObjectID, StateBackup> pending_reload_state;
#endif
String source;
@@ -115,6 +112,7 @@ class CSharpScript : public Script {
Map<StringName, Variant> exported_members_defval_cache; // member_default_values_cache
Set<PlaceHolderScriptInstance *> placeholders;
bool source_changed_cache;
+ bool placeholder_fallback_enabled;
bool exports_invalidated;
void _update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames);
virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder);
@@ -129,7 +127,7 @@ class CSharpScript : public Script {
bool _update_exports();
#ifdef TOOLS_ENABLED
- bool _get_member_export(GDMonoClass *p_class, GDMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported);
+ bool _get_member_export(GDMonoClass *p_class, IMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported);
#endif
CSharpInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error);
@@ -137,7 +135,7 @@ class CSharpScript : public Script {
// Do not use unless you know what you are doing
friend void GDMonoInternals::tie_managed_to_unmanaged(MonoObject *, Object *);
- static Ref<CSharpScript> create_for_managed_type(GDMonoClass *p_class);
+ static Ref<CSharpScript> create_for_managed_type(GDMonoClass *p_class, GDMonoClass *p_native);
protected:
static void _bind_methods();
@@ -164,7 +162,7 @@ public:
virtual bool has_script_signal(const StringName &p_signal) const;
virtual void get_script_signal_list(List<MethodInfo> *r_signals) const;
- /* TODO */ virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const;
+ virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const;
virtual void get_script_property_list(List<PropertyInfo> *p_list) const;
virtual void update_exports();
@@ -180,6 +178,10 @@ public:
virtual int get_member_line(const StringName &p_member) const;
+#ifdef TOOLS_ENABLED
+ virtual bool is_placeholder_fallback_enabled() const { return placeholder_fallback_enabled; }
+#endif
+
Error load_source_code(const String &p_path);
StringName get_script_name() const;
@@ -204,8 +206,15 @@ class CSharpInstance : public ScriptInstance {
Ref<MonoGCHandle> gchandle;
bool _reference_owner_unsafe();
+
+ /*
+ * If true is returned, the caller must memdelete the script instance's owner.
+ */
bool _unreference_owner_unsafe();
+ /*
+ * If NULL is returned, the caller must destroy the script instance by removing it from its owner.
+ */
MonoObject *_internal_new_managed();
// Do not use unless you know what you are doing
@@ -214,13 +223,15 @@ class CSharpInstance : public ScriptInstance {
void _call_multilevel(MonoObject *p_mono_object, const StringName &p_method, const Variant **p_args, int p_argcount);
- MultiplayerAPI::RPCMode _member_get_rpc_mode(GDMonoClassMember *p_member) const;
+ MultiplayerAPI::RPCMode _member_get_rpc_mode(IMonoClassMember *p_member) const;
public:
MonoObject *get_mono_object() const;
_FORCE_INLINE_ bool is_destructing_script_instance() { return destructing_script_instance; }
+ virtual Object *get_owner();
+
virtual bool set(const StringName &p_name, const Variant &p_value);
virtual bool get(const StringName &p_name, Variant &r_ret) const;
virtual void get_property_list(List<PropertyInfo> *p_properties) const;
@@ -233,7 +244,12 @@ public:
virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount);
void mono_object_disposed(MonoObject *p_obj);
- void mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_owner_deleted);
+
+ /*
+ * If 'r_delete_owner' is set to true, the caller must memdelete the script instance's owner. Otherwise, if
+ * 'r_remove_script_instance' is set to true, the caller must destroy the script instance by removing it from its owner.
+ */
+ void mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_delete_owner, bool &r_remove_script_instance);
virtual void refcount_incremented();
virtual bool refcount_decremented();
@@ -253,6 +269,7 @@ public:
};
struct CSharpScriptBinding {
+ bool inited;
StringName type_name;
GDMonoClass *wrapper_class;
Ref<MonoGCHandle> gchandle;
@@ -281,6 +298,7 @@ class CSharpLanguage : public ScriptLanguage {
StringName _signal_callback;
StringName _set;
StringName _get;
+ StringName _get_property_list;
StringName _notification;
StringName _script_source;
StringName dotctor; // .ctor
@@ -292,9 +310,19 @@ class CSharpLanguage : public ScriptLanguage {
Dictionary scripts_metadata;
+ // For debug_break and debug_break_parse
+ int _debug_parse_err_line;
+ String _debug_parse_err_file;
+ String _debug_error;
+
+ friend class GDMono;
+ void _uninitialize_script_bindings();
+
public:
StringNameCache string_names;
+ Mutex *get_language_bind_mutex() { return language_bind_mutex; }
+
_FORCE_INLINE_ int get_language_index() { return lang_idx; }
void set_language_index(int p_idx);
@@ -308,7 +336,7 @@ public:
bool debug_break(const String &p_error, bool p_allow_continue = true);
bool debug_break_parse(const String &p_file, int p_line, const String &p_error);
-#ifdef TOOLS_ENABLED
+#ifdef GD_MONO_HOT_RELOAD
bool is_assembly_reloading_needed();
void reload_assemblies(bool p_soft_reload);
#endif
@@ -346,11 +374,11 @@ public:
/* TODO */ virtual void add_global_constant(const StringName &p_variable, const Variant &p_value) {}
/* DEBUGGER FUNCTIONS */
- /* TODO */ virtual String debug_get_error() const { return ""; }
- /* TODO */ virtual int debug_get_stack_level_count() const { return 1; }
- /* TODO */ virtual int debug_get_stack_level_line(int p_level) const { return 1; }
- /* TODO */ virtual String debug_get_stack_level_function(int p_level) const { return ""; }
- /* TODO */ virtual String debug_get_stack_level_source(int p_level) const { return ""; }
+ virtual String debug_get_error() const;
+ virtual int debug_get_stack_level_count() const;
+ virtual int debug_get_stack_level_line(int p_level) const;
+ virtual String debug_get_stack_level_function(int p_level) const;
+ virtual String debug_get_stack_level_source(int p_level) const;
/* TODO */ virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {}
/* TODO */ virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {}
/* TODO */ virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {}
@@ -389,6 +417,9 @@ public:
virtual void refcount_incremented_instance_binding(Object *p_object);
virtual bool refcount_decremented_instance_binding(Object *p_object);
+ Map<Object *, CSharpScriptBinding>::Element *insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding);
+ bool setup_csharp_script_binding(CSharpScriptBinding &r_script_binding, Object *p_object);
+
#ifdef DEBUG_ENABLED
Vector<StackInfo> stack_trace_get_info(MonoObject *p_stack_trace);
#endif
@@ -398,6 +429,7 @@ public:
};
class ResourceFormatLoaderCSharpScript : public ResourceFormatLoader {
+ GDCLASS(ResourceFormatLoaderCSharpScript, ResourceFormatLoader)
public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
@@ -406,6 +438,7 @@ public:
};
class ResourceFormatSaverCSharpScript : public ResourceFormatSaver {
+ GDCLASS(ResourceFormatSaverCSharpScript, ResourceFormatSaver)
public:
virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const;
diff --git a/modules/mono/doc_classes/@C#.xml b/modules/mono/doc_classes/@C#.xml
index 082bc30fd8..826c106d7e 100644
--- a/modules/mono/doc_classes/@C#.xml
+++ b/modules/mono/doc_classes/@C#.xml
@@ -1,13 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="@C#" category="Core" version="3.1">
+<class name="@C#" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
- <demos>
- </demos>
<methods>
</methods>
<constants>
diff --git a/modules/mono/doc_classes/CSharpScript.xml b/modules/mono/doc_classes/CSharpScript.xml
index a1f7399653..de2e246ea9 100644
--- a/modules/mono/doc_classes/CSharpScript.xml
+++ b/modules/mono/doc_classes/CSharpScript.xml
@@ -1,13 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSharpScript" inherits="Script" category="Core" version="3.1">
+<class name="CSharpScript" inherits="Script" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
- <demos>
- </demos>
<methods>
<method name="new" qualifiers="vararg">
<return type="Object">
diff --git a/modules/mono/doc_classes/GodotSharp.xml b/modules/mono/doc_classes/GodotSharp.xml
index 921c1ca825..18556a84ba 100644
--- a/modules/mono/doc_classes/GodotSharp.xml
+++ b/modules/mono/doc_classes/GodotSharp.xml
@@ -1,13 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GodotSharp" inherits="Object" category="Core" version="3.1">
+<class name="GodotSharp" inherits="Object" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
- <demos>
- </demos>
<methods>
<method name="attach_thread">
<return type="void">
diff --git a/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs
index 16beacb45c..967e3bcc19 100644
--- a/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs
+++ b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs
@@ -18,11 +18,11 @@ namespace GodotSharpTools.Build
[MethodImpl(MethodImplOptions.InternalCall)]
private extern static string godot_icall_BuildInstance_get_MSBuildPath();
[MethodImpl(MethodImplOptions.InternalCall)]
- private extern static string godot_icall_BuildInstance_get_FrameworkPath();
- [MethodImpl(MethodImplOptions.InternalCall)]
private extern static string godot_icall_BuildInstance_get_MonoWindowsBinDir();
[MethodImpl(MethodImplOptions.InternalCall)]
private extern static bool godot_icall_BuildInstance_get_UsingMonoMSBuildOnWindows();
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private extern static bool godot_icall_BuildInstance_get_PrintBuildOutput();
private static string GetMSBuildPath()
{
@@ -34,11 +34,6 @@ namespace GodotSharpTools.Build
return msbuildPath;
}
- private static string GetFrameworkPath()
- {
- return godot_icall_BuildInstance_get_FrameworkPath();
- }
-
private static string MonoWindowsBinDir
{
get
@@ -60,6 +55,14 @@ namespace GodotSharpTools.Build
}
}
+ private static bool PrintBuildOutput
+ {
+ get
+ {
+ return godot_icall_BuildInstance_get_PrintBuildOutput();
+ }
+ }
+
private string solution;
private string config;
@@ -78,23 +81,19 @@ namespace GodotSharpTools.Build
public bool Build(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties = null)
{
- bool debugMSBuild = IsDebugMSBuildRequested();
-
List<string> customPropertiesList = new List<string>();
if (customProperties != null)
customPropertiesList.AddRange(customProperties);
- string frameworkPath = GetFrameworkPath();
-
- if (!string.IsNullOrEmpty(frameworkPath))
- customPropertiesList.Add("FrameworkPathOverride=" + frameworkPath);
-
string compilerArgs = BuildArguments(loggerAssemblyPath, loggerOutputDir, customPropertiesList);
ProcessStartInfo startInfo = new ProcessStartInfo(GetMSBuildPath(), compilerArgs);
- bool redirectOutput = !debugMSBuild;
+ bool redirectOutput = !IsDebugMSBuildRequested() && !PrintBuildOutput;
+
+ if (!redirectOutput) // TODO: or if stdout verbose
+ Console.WriteLine($"Running: \"{startInfo.FileName}\" {startInfo.Arguments}");
startInfo.RedirectStandardOutput = redirectOutput;
startInfo.RedirectStandardError = redirectOutput;
@@ -135,8 +134,6 @@ namespace GodotSharpTools.Build
public bool BuildAsync(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties = null)
{
- bool debugMSBuild = IsDebugMSBuildRequested();
-
if (process != null)
throw new InvalidOperationException("Already in use");
@@ -145,16 +142,14 @@ namespace GodotSharpTools.Build
if (customProperties != null)
customPropertiesList.AddRange(customProperties);
- string frameworkPath = GetFrameworkPath();
-
- if (!string.IsNullOrEmpty(frameworkPath))
- customPropertiesList.Add("FrameworkPathOverride=" + frameworkPath);
-
string compilerArgs = BuildArguments(loggerAssemblyPath, loggerOutputDir, customPropertiesList);
ProcessStartInfo startInfo = new ProcessStartInfo(GetMSBuildPath(), compilerArgs);
- bool redirectOutput = !debugMSBuild;
+ bool redirectOutput = !IsDebugMSBuildRequested() && !PrintBuildOutput;
+
+ if (!redirectOutput) // TODO: or if stdout verbose
+ Console.WriteLine($"Running: \"{startInfo.FileName}\" {startInfo.Arguments}");
startInfo.RedirectStandardOutput = redirectOutput;
startInfo.RedirectStandardError = redirectOutput;
@@ -257,7 +252,7 @@ namespace GodotSharpTools.Build
if (null == Parameters)
throw new LoggerException("Log directory was not set.");
- string[] parameters = Parameters.Split(';');
+ string[] parameters = Parameters.Split(new[] { ';' });
string logDir = parameters[0];
diff --git a/modules/mono/editor/GodotSharpTools/Editor/GodotSharpExport.cs b/modules/mono/editor/GodotSharpTools/Editor/GodotSharpExport.cs
index 5fd708d539..e45dd2025b 100644
--- a/modules/mono/editor/GodotSharpTools/Editor/GodotSharpExport.cs
+++ b/modules/mono/editor/GodotSharpTools/Editor/GodotSharpExport.cs
@@ -30,7 +30,7 @@ namespace GodotSharpTools.Editor
throw new NotSupportedException("Target platform not supported");
}
- templateDirName += debug ? ".debug" : ".release";
+ templateDirName += debug ? ".release_debug" : ".release";
string templateDirPath = Path.Combine(GetTemplatesDir(), templateDirName);
diff --git a/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj b/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj
index f9e9f41977..2871c041f5 100644
--- a/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj
+++ b/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj
@@ -8,6 +8,7 @@
<RootNamespace>GodotSharpTools</RootNamespace>
<AssemblyName>GodotSharpTools</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <BaseIntermediateOutputPath>obj</BaseIntermediateOutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -40,6 +41,7 @@
<Compile Include="Build\BuildSystem.cs" />
<Compile Include="Editor\MonoDevelopInstance.cs" />
<Compile Include="Project\ProjectExtensions.cs" />
+ <Compile Include="Project\IdentifierUtils.cs" />
<Compile Include="Project\ProjectGenerator.cs" />
<Compile Include="Project\ProjectUtils.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
diff --git a/modules/mono/editor/GodotSharpTools/Project/IdentifierUtils.cs b/modules/mono/editor/GodotSharpTools/Project/IdentifierUtils.cs
new file mode 100644
index 0000000000..83e2d2cf8d
--- /dev/null
+++ b/modules/mono/editor/GodotSharpTools/Project/IdentifierUtils.cs
@@ -0,0 +1,199 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+
+namespace GodotSharpTools.Project
+{
+ public static class IdentifierUtils
+ {
+ public static string SanitizeQualifiedIdentifier(string qualifiedIdentifier, bool allowEmptyIdentifiers)
+ {
+ if (string.IsNullOrEmpty(qualifiedIdentifier))
+ throw new ArgumentException($"{nameof(qualifiedIdentifier)} cannot be empty", nameof(qualifiedIdentifier));
+
+ string[] identifiers = qualifiedIdentifier.Split(new[] { '.' });
+
+ for (int i = 0; i < identifiers.Length; i++)
+ {
+ identifiers[i] = SanitizeIdentifier(identifiers[i], allowEmpty: allowEmptyIdentifiers);
+ }
+
+ return string.Join(".", identifiers);
+ }
+
+ public static string SanitizeIdentifier(string identifier, bool allowEmpty)
+ {
+ if (string.IsNullOrEmpty(identifier))
+ {
+ if (allowEmpty)
+ return "Empty"; // Default value for empty identifiers
+
+ throw new ArgumentException($"{nameof(identifier)} cannot be empty if {nameof(allowEmpty)} is false", nameof(identifier));
+ }
+
+ if (identifier.Length > 511)
+ identifier = identifier.Substring(0, 511);
+
+ var identifierBuilder = new StringBuilder();
+ int startIndex = 0;
+
+ if (identifier[0] == '@')
+ {
+ identifierBuilder.Append('@');
+ startIndex += 1;
+ }
+
+ for (int i = startIndex; i < identifier.Length; i++)
+ {
+ char @char = identifier[i];
+
+ switch (Char.GetUnicodeCategory(@char))
+ {
+ case UnicodeCategory.UppercaseLetter:
+ case UnicodeCategory.LowercaseLetter:
+ case UnicodeCategory.TitlecaseLetter:
+ case UnicodeCategory.ModifierLetter:
+ case UnicodeCategory.LetterNumber:
+ case UnicodeCategory.OtherLetter:
+ identifierBuilder.Append(@char);
+ break;
+ case UnicodeCategory.NonSpacingMark:
+ case UnicodeCategory.SpacingCombiningMark:
+ case UnicodeCategory.ConnectorPunctuation:
+ case UnicodeCategory.DecimalDigitNumber:
+ // Identifiers may start with underscore
+ if (identifierBuilder.Length > startIndex || @char == '_')
+ identifierBuilder.Append(@char);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (identifierBuilder.Length == startIndex)
+ {
+ // All characters were invalid so now it's empty. Fill it with something.
+ identifierBuilder.Append("Empty");
+ }
+
+ identifier = identifierBuilder.ToString();
+
+ if (identifier[0] != '@' && IsKeyword(identifier, anyDoubleUnderscore: true))
+ identifier = '@' + identifier;
+
+ return identifier;
+ }
+
+ static bool IsKeyword(string value, bool anyDoubleUnderscore)
+ {
+ // Identifiers that start with double underscore are meant to be used for reserved keywords.
+ // Only existing keywords are enforced, but it may be useful to forbid any identifier
+ // that begins with double underscore to prevent issues with future C# versions.
+ if (anyDoubleUnderscore)
+ {
+ if (value.Length > 2 && value[0] == '_' && value[1] == '_' && value[2] != '_')
+ return true;
+ }
+ else
+ {
+ if (_doubleUnderscoreKeywords.Contains(value))
+ return true;
+ }
+
+ return _keywords.Contains(value);
+ }
+
+ static HashSet<string> _doubleUnderscoreKeywords = new HashSet<string>
+ {
+ "__arglist",
+ "__makeref",
+ "__reftype",
+ "__refvalue",
+ };
+
+ static HashSet<string> _keywords = new HashSet<string>
+ {
+ "as",
+ "do",
+ "if",
+ "in",
+ "is",
+ "for",
+ "int",
+ "new",
+ "out",
+ "ref",
+ "try",
+ "base",
+ "bool",
+ "byte",
+ "case",
+ "char",
+ "else",
+ "enum",
+ "goto",
+ "lock",
+ "long",
+ "null",
+ "this",
+ "true",
+ "uint",
+ "void",
+ "break",
+ "catch",
+ "class",
+ "const",
+ "event",
+ "false",
+ "fixed",
+ "float",
+ "sbyte",
+ "short",
+ "throw",
+ "ulong",
+ "using",
+ "where",
+ "while",
+ "yield",
+ "double",
+ "extern",
+ "object",
+ "params",
+ "public",
+ "return",
+ "sealed",
+ "sizeof",
+ "static",
+ "string",
+ "struct",
+ "switch",
+ "typeof",
+ "unsafe",
+ "ushort",
+ "checked",
+ "decimal",
+ "default",
+ "finally",
+ "foreach",
+ "partial",
+ "private",
+ "virtual",
+ "abstract",
+ "continue",
+ "delegate",
+ "explicit",
+ "implicit",
+ "internal",
+ "operator",
+ "override",
+ "readonly",
+ "volatile",
+ "interface",
+ "namespace",
+ "protected",
+ "unchecked",
+ "stackalloc",
+ };
+ }
+}
diff --git a/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs b/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs
index 2ce7837a27..89279c69a6 100644
--- a/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs
+++ b/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs
@@ -21,6 +21,7 @@ namespace GodotSharpTools.Project
mainGroup.AddProperty("DocumentationFile", Path.Combine("$(OutputPath)", "$(AssemblyName).xml"));
mainGroup.SetProperty("RootNamespace", "Godot");
mainGroup.SetProperty("ProjectGuid", CoreApiProjectGuid);
+ mainGroup.SetProperty("BaseIntermediateOutputPath", "obj");
GenAssemblyInfoFile(root, dir, CoreApiProjectName,
new string[] { "[assembly: InternalsVisibleTo(\"" + EditorApiProjectName + "\")]" },
@@ -46,6 +47,7 @@ namespace GodotSharpTools.Project
mainGroup.AddProperty("DocumentationFile", Path.Combine("$(OutputPath)", "$(AssemblyName).xml"));
mainGroup.SetProperty("RootNamespace", "Godot");
mainGroup.SetProperty("ProjectGuid", EditorApiProjectGuid);
+ mainGroup.SetProperty("BaseIntermediateOutputPath", "obj");
GenAssemblyInfoFile(root, dir, EditorApiProjectName);
@@ -138,6 +140,9 @@ namespace GodotSharpTools.Project
public static ProjectRootElement CreateLibraryProject(string name, out ProjectPropertyGroupElement mainGroup)
{
+ if (string.IsNullOrEmpty(name))
+ throw new ArgumentException($"{nameof(name)} cannot be empty", nameof(name));
+
var root = ProjectRootElement.Create();
root.DefaultTargets = "Build";
@@ -147,7 +152,7 @@ namespace GodotSharpTools.Project
mainGroup.AddProperty("ProjectGuid", "{" + Guid.NewGuid().ToString().ToUpper() + "}");
mainGroup.AddProperty("OutputType", "Library");
mainGroup.AddProperty("OutputPath", Path.Combine("bin", "$(Configuration)"));
- mainGroup.AddProperty("RootNamespace", name);
+ mainGroup.AddProperty("RootNamespace", IdentifierUtils.SanitizeQualifiedIdentifier(name, allowEmptyIdentifiers: true));
mainGroup.AddProperty("AssemblyName", name);
mainGroup.AddProperty("TargetFrameworkVersion", "v4.5");
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 166b3e1324..259c0ffece 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -80,6 +80,7 @@
#define ICALL_GET_METHODBIND ICALL_PREFIX "Object_ClassDB_get_method"
#define C_LOCAL_RET "ret"
+#define C_LOCAL_VARARG_RET "vararg_ret"
#define C_LOCAL_PTRCALL_ARGS "call_args"
#define C_MACRO_OBJECT_CONSTRUCT "GODOTSHARP_INSTANCE_OBJECT"
@@ -96,14 +97,24 @@
#define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type
#define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array"
-#define BINDINGS_GENERATOR_VERSION UINT32_C(5)
+#define BINDINGS_GENERATOR_VERSION UINT32_C(8)
-const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN = "\t%0 %1_in = %1;\n";
+const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN("\t%0 %1_in = %1;\n");
bool BindingsGenerator::verbose_output = false;
BindingsGenerator *BindingsGenerator::singleton = NULL;
+static String fix_doc_description(const String &p_bbcode) {
+
+ // This seems to be the correct way to do this. It's the same EditorHelp does.
+
+ return p_bbcode.dedent()
+ .replace("\t", "")
+ .replace("\r", "")
+ .strip_edges();
+}
+
static String snake_to_pascal_case(const String &p_identifier, bool p_input_is_upper = false) {
String ret;
@@ -172,6 +183,457 @@ static String snake_to_camel_case(const String &p_identifier, bool p_input_is_up
return ret;
}
+String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterface *p_itype) {
+
+ // Based on the version in EditorHelp
+
+ if (p_bbcode.empty())
+ return String();
+
+ DocData *doc = EditorHelp::get_doc_data();
+
+ String bbcode = p_bbcode;
+
+ StringBuilder xml_output;
+
+ xml_output.append("<para>");
+
+ List<String> tag_stack;
+ bool code_tag = false;
+
+ int pos = 0;
+ while (pos < bbcode.length()) {
+ int brk_pos = bbcode.find("[", pos);
+
+ if (brk_pos < 0)
+ brk_pos = bbcode.length();
+
+ if (brk_pos > pos) {
+ String text = bbcode.substr(pos, brk_pos - pos);
+ if (code_tag || tag_stack.size() > 0) {
+ xml_output.append(text.xml_escape());
+ } else {
+ Vector<String> lines = text.split("\n");
+ for (int i = 0; i < lines.size(); i++) {
+ if (i != 0)
+ xml_output.append("<para>");
+
+ xml_output.append(lines[i].xml_escape());
+
+ if (i != lines.size() - 1)
+ xml_output.append("</para>\n");
+ }
+ }
+ }
+
+ if (brk_pos == bbcode.length())
+ break; // nothing else to add
+
+ int brk_end = bbcode.find("]", brk_pos + 1);
+
+ if (brk_end == -1) {
+ String text = bbcode.substr(brk_pos, bbcode.length() - brk_pos);
+ if (code_tag || tag_stack.size() > 0) {
+ xml_output.append(text.xml_escape());
+ } else {
+ Vector<String> lines = text.split("\n");
+ for (int i = 0; i < lines.size(); i++) {
+ if (i != 0)
+ xml_output.append("<para>");
+
+ xml_output.append(lines[i].xml_escape());
+
+ if (i != lines.size() - 1)
+ xml_output.append("</para>\n");
+ }
+ }
+
+ break;
+ }
+
+ String tag = bbcode.substr(brk_pos + 1, brk_end - brk_pos - 1);
+
+ if (tag.begins_with("/")) {
+ bool tag_ok = tag_stack.size() && tag_stack.front()->get() == tag.substr(1, tag.length());
+
+ if (!tag_ok) {
+ xml_output.append("[");
+ pos = brk_pos + 1;
+ continue;
+ }
+
+ tag_stack.pop_front();
+ pos = brk_end + 1;
+ code_tag = false;
+
+ if (tag == "/url") {
+ xml_output.append("</a>");
+ } else if (tag == "/code") {
+ xml_output.append("</c>");
+ } else if (tag == "/codeblock") {
+ xml_output.append("</code>");
+ }
+ } else if (code_tag) {
+ xml_output.append("[");
+ pos = brk_pos + 1;
+ } else if (tag.begins_with("method ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ") || tag.begins_with("constant ")) {
+ String link_target = tag.substr(tag.find(" ") + 1, tag.length());
+ String link_tag = tag.substr(0, tag.find(" "));
+
+ Vector<String> link_target_parts = link_target.split(".");
+
+ if (link_target_parts.size() <= 0 || link_target_parts.size() > 2) {
+ ERR_PRINTS("Invalid reference format: " + tag);
+
+ xml_output.append("<c>");
+ xml_output.append(tag);
+ xml_output.append("</c>");
+
+ pos = brk_end + 1;
+ continue;
+ }
+
+ const TypeInterface *target_itype;
+ StringName target_cname;
+
+ if (link_target_parts.size() == 2) {
+ target_itype = _get_type_or_null(TypeReference(link_target_parts[0]));
+ if (!target_itype) {
+ target_itype = _get_type_or_null(TypeReference("_" + link_target_parts[0]));
+ }
+ target_cname = link_target_parts[1];
+ } else {
+ target_itype = p_itype;
+ target_cname = link_target_parts[0];
+ }
+
+ if (link_tag == "method") {
+ if (!target_itype || !target_itype->is_object_type) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ if (target_itype) {
+ OS::get_singleton()->print("Cannot resolve method reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data());
+ } else {
+ OS::get_singleton()->print("Cannot resolve type from method reference in documentation: %s\n", link_target.utf8().get_data());
+ }
+ }
+
+ // TODO Map what we can
+ xml_output.append("<c>");
+ xml_output.append(link_target);
+ xml_output.append("</c>");
+ } else {
+ const MethodInterface *target_imethod = target_itype->find_method_by_name(target_cname);
+
+ if (target_imethod) {
+ xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
+ xml_output.append(target_itype->proxy_name);
+ xml_output.append(".");
+ xml_output.append(target_imethod->proxy_name);
+ xml_output.append("\"/>");
+ }
+ }
+ } else if (link_tag == "member") {
+ if (!target_itype || !target_itype->is_object_type) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ if (target_itype) {
+ OS::get_singleton()->print("Cannot resolve member reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data());
+ } else {
+ OS::get_singleton()->print("Cannot resolve type from member reference in documentation: %s\n", link_target.utf8().get_data());
+ }
+ }
+
+ // TODO Map what we can
+ xml_output.append("<c>");
+ xml_output.append(link_target);
+ xml_output.append("</c>");
+ } else {
+ const PropertyInterface *target_iprop = target_itype->find_property_by_name(target_cname);
+
+ if (target_iprop) {
+ xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
+ xml_output.append(target_itype->proxy_name);
+ xml_output.append(".");
+ xml_output.append(target_iprop->proxy_name);
+ xml_output.append("\"/>");
+ }
+ }
+ } else if (link_tag == "signal") {
+ // We do not declare signals in any way in C#, so there is nothing to reference
+ xml_output.append("<c>");
+ xml_output.append(link_target);
+ xml_output.append("</c>");
+ } else if (link_tag == "enum") {
+ StringName search_cname = !target_itype ? target_cname :
+ StringName(target_itype->name + "." + (String)target_cname);
+
+ const Map<StringName, TypeInterface>::Element *enum_match = enum_types.find(search_cname);
+
+ if (!enum_match && search_cname != target_cname) {
+ enum_match = enum_types.find(target_cname);
+ }
+
+ if (enum_match) {
+ const TypeInterface &target_enum_itype = enum_match->value();
+
+ xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
+ xml_output.append(target_enum_itype.proxy_name); // Includes nesting class if any
+ xml_output.append("\"/>");
+ } else {
+ ERR_PRINTS("Cannot resolve enum reference in documentation: " + link_target);
+
+ xml_output.append("<c>");
+ xml_output.append(link_target);
+ xml_output.append("</c>");
+ }
+ } else if (link_tag == "const") {
+ if (!target_itype || !target_itype->is_object_type) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ if (target_itype) {
+ OS::get_singleton()->print("Cannot resolve constant reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data());
+ } else {
+ OS::get_singleton()->print("Cannot resolve type from constant reference in documentation: %s\n", link_target.utf8().get_data());
+ }
+ }
+
+ // TODO Map what we can
+ xml_output.append("<c>");
+ xml_output.append(link_target);
+ xml_output.append("</c>");
+ } else if (!target_itype && target_cname == name_cache.type_at_GlobalScope) {
+ String target_name = (String)target_cname;
+
+ // Try to find as a global constant
+ const ConstantInterface *target_iconst = find_constant_by_name(target_name, global_constants);
+
+ if (target_iconst) {
+ // Found global constant
+ xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "." BINDINGS_GLOBAL_SCOPE_CLASS ".");
+ xml_output.append(target_iconst->proxy_name);
+ xml_output.append("\"/>");
+ } else {
+ // Try to find as global enum constant
+ const EnumInterface *target_ienum = NULL;
+
+ for (const List<EnumInterface>::Element *E = global_enums.front(); E; E = E->next()) {
+ target_ienum = &E->get();
+ target_iconst = find_constant_by_name(target_name, target_ienum->constants);
+ if (target_iconst)
+ break;
+ }
+
+ if (target_iconst) {
+ xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
+ xml_output.append(target_ienum->cname);
+ xml_output.append(".");
+ xml_output.append(target_iconst->proxy_name);
+ xml_output.append("\"/>");
+ } else {
+ ERR_PRINTS("Cannot resolve global constant reference in documentation: " + link_target);
+
+ xml_output.append("<c>");
+ xml_output.append(link_target);
+ xml_output.append("</c>");
+ }
+ }
+ } else {
+ String target_name = (String)target_cname;
+
+ // Try to find the constant in the current class
+ const ConstantInterface *target_iconst = find_constant_by_name(target_name, target_itype->constants);
+
+ if (target_iconst) {
+ // Found constant in current class
+ xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
+ xml_output.append(target_itype->proxy_name);
+ xml_output.append(".");
+ xml_output.append(target_iconst->proxy_name);
+ xml_output.append("\"/>");
+ } else {
+ // Try to find as enum constant in the current class
+ const EnumInterface *target_ienum = NULL;
+
+ for (const List<EnumInterface>::Element *E = target_itype->enums.front(); E; E = E->next()) {
+ target_ienum = &E->get();
+ target_iconst = find_constant_by_name(target_name, target_ienum->constants);
+ if (target_iconst)
+ break;
+ }
+
+ if (target_iconst) {
+ xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
+ xml_output.append(target_itype->proxy_name);
+ xml_output.append(".");
+ xml_output.append(target_ienum->cname);
+ xml_output.append(".");
+ xml_output.append(target_iconst->proxy_name);
+ xml_output.append("\"/>");
+ } else {
+ ERR_PRINTS("Cannot resolve constant reference in documentation: " + link_target);
+
+ xml_output.append("<c>");
+ xml_output.append(link_target);
+ xml_output.append("</c>");
+ }
+ }
+ }
+ }
+
+ pos = brk_end + 1;
+ } else if (doc->class_list.has(tag)) {
+ if (tag == "Array" || tag == "Dictionary") {
+ xml_output.append("<see cref=\"" BINDINGS_NAMESPACE_COLLECTIONS ".");
+ xml_output.append(tag);
+ xml_output.append("\"/>");
+ } else if (tag == "bool" || tag == "int") {
+ xml_output.append("<see cref=\"");
+ xml_output.append(tag);
+ xml_output.append("\"/>");
+ } else if (tag == "float") {
+ xml_output.append("<see cref=\""
+#ifdef REAL_T_IS_DOUBLE
+ "double"
+#else
+ "float"
+#endif
+ "\"/>");
+ } else if (tag == "Variant") {
+ // We use System.Object for Variant, so there is no Variant type in C#
+ xml_output.append("<c>Variant</c>");
+ } else if (tag == "String") {
+ xml_output.append("<see cref=\"string\"/>");
+ } else if (tag == "Nil") {
+ xml_output.append("<see langword=\"null\"/>");
+ } else if (tag.begins_with("@")) {
+ // @GlobalScope, @GDScript, etc
+ xml_output.append("<c>");
+ xml_output.append(tag);
+ xml_output.append("</c>");
+ } else if (tag == "PoolByteArray") {
+ xml_output.append("<see cref=\"byte\"/>");
+ } else if (tag == "PoolIntArray") {
+ xml_output.append("<see cref=\"int\"/>");
+ } else if (tag == "PoolRealArray") {
+#ifdef REAL_T_IS_DOUBLE
+ xml_output.append("<see cref=\"double\"/>");
+#else
+ xml_output.append("<see cref=\"float\"/>");
+#endif
+ } else if (tag == "PoolStringArray") {
+ xml_output.append("<see cref=\"string\"/>");
+ } else if (tag == "PoolVector2Array") {
+ xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Vector2\"/>");
+ } else if (tag == "PoolVector3Array") {
+ xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Vector3\"/>");
+ } else if (tag == "PoolColorArray") {
+ xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Color\"/>");
+ } else {
+ const TypeInterface *target_itype = _get_type_or_null(TypeReference(tag));
+
+ if (!target_itype) {
+ target_itype = _get_type_or_null(TypeReference("_" + tag));
+ }
+
+ if (target_itype) {
+ xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
+ xml_output.append(target_itype->proxy_name);
+ xml_output.append("\"/>");
+ } else {
+ ERR_PRINTS("Cannot resolve type reference in documentation: " + tag);
+
+ xml_output.append("<c>");
+ xml_output.append(tag);
+ xml_output.append("</c>");
+ }
+ }
+
+ pos = brk_end + 1;
+ } else if (tag == "b") {
+ // bold is not supported in xml comments
+ pos = brk_end + 1;
+ tag_stack.push_front(tag);
+ } else if (tag == "i") {
+ // italics is not supported in xml comments
+ pos = brk_end + 1;
+ tag_stack.push_front(tag);
+ } else if (tag == "code") {
+ xml_output.append("<c>");
+
+ code_tag = true;
+ pos = brk_end + 1;
+ tag_stack.push_front(tag);
+ } else if (tag == "codeblock") {
+ xml_output.append("<code>");
+
+ code_tag = true;
+ pos = brk_end + 1;
+ tag_stack.push_front(tag);
+ } else if (tag == "center") {
+ // center is alignment not supported in xml comments
+ pos = brk_end + 1;
+ tag_stack.push_front(tag);
+ } else if (tag == "br") {
+ xml_output.append("\n"); // FIXME: Should use <para> instead. Luckily this tag isn't used for now.
+ pos = brk_end + 1;
+ } else if (tag == "u") {
+ // underline is not supported in xml comments
+ pos = brk_end + 1;
+ tag_stack.push_front(tag);
+ } else if (tag == "s") {
+ // strikethrough is not supported in xml comments
+ pos = brk_end + 1;
+ tag_stack.push_front(tag);
+ } else if (tag == "url") {
+ int end = bbcode.find("[", brk_end);
+ if (end == -1)
+ end = bbcode.length();
+ String url = bbcode.substr(brk_end + 1, end - brk_end - 1);
+ xml_output.append("<a href=\"");
+ xml_output.append(url);
+ xml_output.append("\">");
+ xml_output.append(url);
+
+ pos = brk_end + 1;
+ tag_stack.push_front(tag);
+ } else if (tag.begins_with("url=")) {
+ String url = tag.substr(4, tag.length());
+ xml_output.append("<a href=\"");
+ xml_output.append(url);
+ xml_output.append("\">");
+
+ pos = brk_end + 1;
+ tag_stack.push_front("url");
+ } else if (tag == "img") {
+ int end = bbcode.find("[", brk_end);
+ if (end == -1)
+ end = bbcode.length();
+ String image = bbcode.substr(brk_end + 1, end - brk_end - 1);
+
+ // Not supported. Just append the bbcode.
+ xml_output.append("[img]");
+ xml_output.append(image);
+ xml_output.append("[/img]");
+
+ pos = end;
+ tag_stack.push_front(tag);
+ } else if (tag.begins_with("color=")) {
+ // Not supported.
+ pos = brk_end + 1;
+ tag_stack.push_front("color");
+ } else if (tag.begins_with("font=")) {
+ // Not supported.
+ pos = brk_end + 1;
+ tag_stack.push_front("font");
+ } else {
+ xml_output.append("["); // ignore
+ pos = brk_pos + 1;
+ }
+ }
+
+ xml_output.append("</para>");
+
+ return xml_output.as_string();
+}
+
int BindingsGenerator::_determine_enum_prefix(const EnumInterface &p_ienum) {
CRASH_COND(p_ienum.constants.empty());
@@ -294,44 +756,47 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
}
}
-void BindingsGenerator::_generate_global_constants(List<String> &p_output) {
+void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
// Constants (in partial GD class)
- p_output.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
- p_output.push_back(INDENT1 "public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n" INDENT1 "{");
+ p_output.append("\n#pragma warning disable CS1591 // Disable warning: "
+ "'Missing XML comment for publicly visible type or member'\n");
+
+ p_output.append("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
+ p_output.append(INDENT1 "public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n" INDENT1 "{");
for (const List<ConstantInterface>::Element *E = global_constants.front(); E; E = E->next()) {
const ConstantInterface &iconstant = E->get();
if (iconstant.const_doc && iconstant.const_doc->description.size()) {
- p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
+ String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), NULL);
+ Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>();
- Vector<String> description_lines = iconstant.const_doc->description.split("\n");
+ if (summary_lines.size()) {
+ p_output.append(MEMBER_BEGIN "/// <summary>\n");
- for (int i = 0; i < description_lines.size(); i++) {
- String description_line = description_lines[i].strip_edges();
- if (description_line.size()) {
- p_output.push_back(INDENT2 "/// ");
- p_output.push_back(description_line.xml_escape());
- p_output.push_back("\n");
+ for (int i = 0; i < summary_lines.size(); i++) {
+ p_output.append(INDENT2 "/// ");
+ p_output.append(summary_lines[i]);
+ p_output.append("\n");
}
- }
- p_output.push_back(INDENT2 "/// </summary>");
+ p_output.append(INDENT2 "/// </summary>");
+ }
}
- p_output.push_back(MEMBER_BEGIN "public const int ");
- p_output.push_back(iconstant.proxy_name);
- p_output.push_back(" = ");
- p_output.push_back(itos(iconstant.value));
- p_output.push_back(";");
+ p_output.append(MEMBER_BEGIN "public const int ");
+ p_output.append(iconstant.proxy_name);
+ p_output.append(" = ");
+ p_output.append(itos(iconstant.value));
+ p_output.append(";");
}
if (!global_constants.empty())
- p_output.push_back("\n");
+ p_output.append("\n");
- p_output.push_back(INDENT1 CLOSE_BLOCK); // end of GD class
+ p_output.append(INDENT1 CLOSE_BLOCK); // end of GD class
// Enums
@@ -355,49 +820,51 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) {
WARN_PRINTS("Declaring global enum `" + enum_proxy_name + "` inside static class `" + enum_class_name + "`");
}
- p_output.push_back("\n" INDENT1 "public static partial class ");
- p_output.push_back(enum_class_name);
- p_output.push_back("\n" INDENT1 OPEN_BLOCK);
+ p_output.append("\n" INDENT1 "public static partial class ");
+ p_output.append(enum_class_name);
+ p_output.append("\n" INDENT1 OPEN_BLOCK);
}
- p_output.push_back("\n" INDENT1 "public enum ");
- p_output.push_back(enum_proxy_name);
- p_output.push_back("\n" INDENT1 OPEN_BLOCK);
+ p_output.append("\n" INDENT1 "public enum ");
+ p_output.append(enum_proxy_name);
+ p_output.append("\n" INDENT1 OPEN_BLOCK);
- for (const List<ConstantInterface>::Element *E = ienum.constants.front(); E; E = E->next()) {
- const ConstantInterface &iconstant = E->get();
+ for (const List<ConstantInterface>::Element *F = ienum.constants.front(); F; F = F->next()) {
+ const ConstantInterface &iconstant = F->get();
if (iconstant.const_doc && iconstant.const_doc->description.size()) {
- p_output.push_back(INDENT2 "/// <summary>\n");
+ String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), NULL);
+ Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>();
- Vector<String> description_lines = iconstant.const_doc->description.split("\n");
+ if (summary_lines.size()) {
+ p_output.append(INDENT2 "/// <summary>\n");
- for (int i = 0; i < description_lines.size(); i++) {
- String description_line = description_lines[i].strip_edges();
- if (description_line.size()) {
- p_output.push_back(INDENT2 "/// ");
- p_output.push_back(description_line.xml_escape());
- p_output.push_back("\n");
+ for (int i = 0; i < summary_lines.size(); i++) {
+ p_output.append(INDENT2 "/// ");
+ p_output.append(summary_lines[i]);
+ p_output.append("\n");
}
- }
- p_output.push_back(INDENT2 "/// </summary>\n");
+ p_output.append(INDENT2 "/// </summary>\n");
+ }
}
- p_output.push_back(INDENT2);
- p_output.push_back(iconstant.proxy_name);
- p_output.push_back(" = ");
- p_output.push_back(itos(iconstant.value));
- p_output.push_back(E != ienum.constants.back() ? ",\n" : "\n");
+ p_output.append(INDENT2);
+ p_output.append(iconstant.proxy_name);
+ p_output.append(" = ");
+ p_output.append(itos(iconstant.value));
+ p_output.append(F != ienum.constants.back() ? ",\n" : "\n");
}
- p_output.push_back(INDENT1 CLOSE_BLOCK);
+ p_output.append(INDENT1 CLOSE_BLOCK);
if (enum_in_static_class)
- p_output.push_back(INDENT1 CLOSE_BLOCK);
+ p_output.append(INDENT1 CLOSE_BLOCK);
}
- p_output.push_back(CLOSE_BLOCK); // end of namespace
+ p_output.append(CLOSE_BLOCK); // end of namespace
+
+ p_output.append("\n#pragma warning restore CS1591\n");
}
Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output) {
@@ -425,7 +892,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir,
// Generate source file for global scope constants and enums
{
- List<String> constants_source;
+ StringBuilder constants_source;
_generate_global_constants(constants_source);
String output_file = path_join(core_dir, BINDINGS_GLOBAL_SCOPE_CLASS "_constants.cs");
Error save_err = _save_file(output_file, constants_source);
@@ -471,8 +938,6 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir,
String output_dir = output_file.get_base_dir();
if (!DirAccess::exists(output_dir)) {
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
Error err = da->make_dir_recursive(ProjectSettings::get_singleton()->globalize_path(output_dir));
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
}
@@ -485,28 +950,28 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir,
compile_items.push_back(output_file);
}
- List<String> cs_icalls_content;
-
- cs_icalls_content.push_back("using System;\n"
- "using System.Runtime.CompilerServices;\n"
- "\n");
- cs_icalls_content.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
- cs_icalls_content.push_back(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS "\n" INDENT1 OPEN_BLOCK);
-
- cs_icalls_content.push_back(MEMBER_BEGIN "internal static ulong godot_api_hash = ");
- cs_icalls_content.push_back(String::num_uint64(GDMono::get_singleton()->get_api_core_hash()) + ";\n");
- cs_icalls_content.push_back(MEMBER_BEGIN "internal static uint bindings_version = ");
- cs_icalls_content.push_back(String::num_uint64(BINDINGS_GENERATOR_VERSION) + ";\n");
- cs_icalls_content.push_back(MEMBER_BEGIN "internal static uint cs_glue_version = ");
- cs_icalls_content.push_back(String::num_uint64(CS_GLUE_VERSION) + ";\n");
-
-#define ADD_INTERNAL_CALL(m_icall) \
- if (!m_icall.editor_only) { \
- cs_icalls_content.push_back(MEMBER_BEGIN "[MethodImpl(MethodImplOptions.InternalCall)]\n"); \
- cs_icalls_content.push_back(INDENT2 "internal extern static "); \
- cs_icalls_content.push_back(m_icall.im_type_out + " "); \
- cs_icalls_content.push_back(m_icall.name + "("); \
- cs_icalls_content.push_back(m_icall.im_sig + ");\n"); \
+ StringBuilder cs_icalls_content;
+
+ cs_icalls_content.append("using System;\n"
+ "using System.Runtime.CompilerServices;\n"
+ "\n");
+ cs_icalls_content.append("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
+ cs_icalls_content.append(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS "\n" INDENT1 OPEN_BLOCK);
+
+ cs_icalls_content.append(MEMBER_BEGIN "internal static ulong godot_api_hash = ");
+ cs_icalls_content.append(String::num_uint64(GDMono::get_singleton()->get_api_core_hash()) + ";\n");
+ cs_icalls_content.append(MEMBER_BEGIN "internal static uint bindings_version = ");
+ cs_icalls_content.append(String::num_uint64(BINDINGS_GENERATOR_VERSION) + ";\n");
+ cs_icalls_content.append(MEMBER_BEGIN "internal static uint cs_glue_version = ");
+ cs_icalls_content.append(String::num_uint64(CS_GLUE_VERSION) + ";\n");
+
+#define ADD_INTERNAL_CALL(m_icall) \
+ if (!m_icall.editor_only) { \
+ cs_icalls_content.append(MEMBER_BEGIN "[MethodImpl(MethodImplOptions.InternalCall)]\n"); \
+ cs_icalls_content.append(INDENT2 "internal extern static "); \
+ cs_icalls_content.append(m_icall.im_type_out + " "); \
+ cs_icalls_content.append(m_icall.name + "("); \
+ cs_icalls_content.append(m_icall.im_sig + ");\n"); \
}
for (const List<InternalCall>::Element *E = core_custom_icalls.front(); E; E = E->next())
@@ -516,7 +981,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir,
#undef ADD_INTERNAL_CALL
- cs_icalls_content.push_back(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");
@@ -583,29 +1048,29 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_solution_dir
compile_items.push_back(output_file);
}
- List<String> cs_icalls_content;
-
- cs_icalls_content.push_back("using System;\n"
- "using System.Runtime.CompilerServices;\n"
- "\n");
- cs_icalls_content.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
- cs_icalls_content.push_back(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS_EDITOR "\n" INDENT1 OPEN_BLOCK);
-
- cs_icalls_content.push_back(INDENT2 "internal static ulong godot_api_hash = ");
- cs_icalls_content.push_back(String::num_uint64(GDMono::get_singleton()->get_api_editor_hash()) + ";\n");
- cs_icalls_content.push_back(INDENT2 "internal static uint bindings_version = ");
- cs_icalls_content.push_back(String::num_uint64(BINDINGS_GENERATOR_VERSION) + ";\n");
- cs_icalls_content.push_back(INDENT2 "internal static uint cs_glue_version = ");
- cs_icalls_content.push_back(String::num_uint64(CS_GLUE_VERSION) + ";\n");
- cs_icalls_content.push_back("\n");
-
-#define ADD_INTERNAL_CALL(m_icall) \
- if (m_icall.editor_only) { \
- cs_icalls_content.push_back(INDENT2 "[MethodImpl(MethodImplOptions.InternalCall)]\n"); \
- cs_icalls_content.push_back(INDENT2 "internal extern static "); \
- cs_icalls_content.push_back(m_icall.im_type_out + " "); \
- cs_icalls_content.push_back(m_icall.name + "("); \
- cs_icalls_content.push_back(m_icall.im_sig + ");\n"); \
+ StringBuilder cs_icalls_content;
+
+ cs_icalls_content.append("using System;\n"
+ "using System.Runtime.CompilerServices;\n"
+ "\n");
+ cs_icalls_content.append("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
+ cs_icalls_content.append(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS_EDITOR "\n" INDENT1 OPEN_BLOCK);
+
+ cs_icalls_content.append(INDENT2 "internal static ulong godot_api_hash = ");
+ cs_icalls_content.append(String::num_uint64(GDMono::get_singleton()->get_api_editor_hash()) + ";\n");
+ cs_icalls_content.append(INDENT2 "internal static uint bindings_version = ");
+ cs_icalls_content.append(String::num_uint64(BINDINGS_GENERATOR_VERSION) + ";\n");
+ cs_icalls_content.append(INDENT2 "internal static uint cs_glue_version = ");
+ cs_icalls_content.append(String::num_uint64(CS_GLUE_VERSION) + ";\n");
+ cs_icalls_content.append("\n");
+
+#define ADD_INTERNAL_CALL(m_icall) \
+ if (m_icall.editor_only) { \
+ cs_icalls_content.append(INDENT2 "[MethodImpl(MethodImplOptions.InternalCall)]\n"); \
+ cs_icalls_content.append(INDENT2 "internal extern static "); \
+ cs_icalls_content.append(m_icall.im_type_out + " "); \
+ cs_icalls_content.append(m_icall.name + "("); \
+ cs_icalls_content.append(m_icall.im_sig + ");\n"); \
}
for (const List<InternalCall>::Element *E = editor_custom_icalls.front(); E; E = E->next())
@@ -615,7 +1080,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_solution_dir
#undef ADD_INTERNAL_CALL
- cs_icalls_content.push_back(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");
@@ -704,61 +1169,64 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls;
if (verbose_output)
- OS::get_singleton()->print(String("Generating " + itype.proxy_name + ".cs...\n").utf8());
+ OS::get_singleton()->print("Generating %s.cs...\n", itype.proxy_name.utf8().get_data());
String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor"); // Used only for derived types
- List<String> output;
+ StringBuilder output;
- output.push_back("using System;\n"); // IntPtr
- output.push_back("using System.Diagnostics;\n"); // DebuggerBrowsable
+ output.append("using System;\n"); // IntPtr
+ output.append("using System.Diagnostics;\n"); // DebuggerBrowsable
- output.push_back("\n#pragma warning disable CS1591 // Disable warning: "
- "'Missing XML comment for publicly visible type or member'\n");
+ output.append("\n"
+ "#pragma warning disable CS1591 // Disable warning: "
+ "'Missing XML comment for publicly visible type or member'\n"
+ "#pragma warning disable CS1573 // Disable warning: "
+ "'Parameter has no matching param tag in the XML comment'\n");
- output.push_back("\nnamespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
+ output.append("\nnamespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
const DocData::ClassDoc *class_doc = itype.class_doc;
if (class_doc && class_doc->description.size()) {
- output.push_back(INDENT1 "/// <summary>\n");
+ String xml_summary = bbcode_to_xml(fix_doc_description(class_doc->description), &itype);
+ Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>();
- Vector<String> description_lines = class_doc->description.split("\n");
+ if (summary_lines.size()) {
+ output.append(INDENT1 "/// <summary>\n");
- for (int i = 0; i < description_lines.size(); i++) {
- String description_line = description_lines[i].strip_edges();
- if (description_line.size()) {
- output.push_back(INDENT1 "/// ");
- output.push_back(description_line.xml_escape());
- output.push_back("\n");
+ for (int i = 0; i < summary_lines.size(); i++) {
+ output.append(INDENT1 "/// ");
+ output.append(summary_lines[i]);
+ output.append("\n");
}
- }
- output.push_back(INDENT1 "/// </summary>\n");
+ output.append(INDENT1 "/// </summary>\n");
+ }
}
- output.push_back(INDENT1 "public ");
+ output.append(INDENT1 "public ");
if (itype.is_singleton) {
- output.push_back("static partial class ");
+ output.append("static partial class ");
} else {
- output.push_back(itype.is_instantiable ? "partial class " : "abstract partial class ");
+ output.append(itype.is_instantiable ? "partial class " : "abstract partial class ");
}
- output.push_back(itype.proxy_name);
+ output.append(itype.proxy_name);
if (itype.is_singleton) {
- output.push_back("\n");
+ output.append("\n");
} else if (is_derived_type) {
if (obj_types.has(itype.base_name)) {
- output.push_back(" : ");
- output.push_back(obj_types[itype.base_name].proxy_name);
- output.push_back("\n");
+ output.append(" : ");
+ output.append(obj_types[itype.base_name].proxy_name);
+ output.append("\n");
} else {
ERR_PRINTS("Base type '" + itype.base_name.operator String() + "' does not exist, for class " + itype.name);
return ERR_INVALID_DATA;
}
}
- output.push_back(INDENT1 "{");
+ output.append(INDENT1 "{");
if (class_doc) {
@@ -768,31 +1236,31 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
const ConstantInterface &iconstant = E->get();
if (iconstant.const_doc && iconstant.const_doc->description.size()) {
- output.push_back(MEMBER_BEGIN "/// <summary>\n");
+ String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), &itype);
+ Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>();
- Vector<String> description_lines = iconstant.const_doc->description.split("\n");
+ if (summary_lines.size()) {
+ output.append(MEMBER_BEGIN "/// <summary>\n");
- for (int i = 0; i < description_lines.size(); i++) {
- String description_line = description_lines[i].strip_edges();
- if (description_line.size()) {
- output.push_back(INDENT2 "/// ");
- output.push_back(description_line.xml_escape());
- output.push_back("\n");
+ for (int i = 0; i < summary_lines.size(); i++) {
+ output.append(INDENT2 "/// ");
+ output.append(summary_lines[i]);
+ output.append("\n");
}
- }
- output.push_back(INDENT2 "/// </summary>");
+ output.append(INDENT2 "/// </summary>");
+ }
}
- output.push_back(MEMBER_BEGIN "public const int ");
- output.push_back(iconstant.proxy_name);
- output.push_back(" = ");
- output.push_back(itos(iconstant.value));
- output.push_back(";");
+ output.append(MEMBER_BEGIN "public const int ");
+ output.append(iconstant.proxy_name);
+ output.append(" = ");
+ output.append(itos(iconstant.value));
+ output.append(";");
}
if (itype.constants.size())
- output.push_back("\n");
+ output.append("\n");
// Add enums
@@ -801,38 +1269,38 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
ERR_FAIL_COND_V(ienum.constants.empty(), ERR_BUG);
- output.push_back(MEMBER_BEGIN "public enum ");
- output.push_back(ienum.cname.operator String());
- output.push_back(MEMBER_BEGIN OPEN_BLOCK);
+ output.append(MEMBER_BEGIN "public enum ");
+ output.append(ienum.cname.operator String());
+ output.append(MEMBER_BEGIN OPEN_BLOCK);
- for (const List<ConstantInterface>::Element *E = ienum.constants.front(); E; E = E->next()) {
- const ConstantInterface &iconstant = E->get();
+ for (const List<ConstantInterface>::Element *F = ienum.constants.front(); F; F = F->next()) {
+ const ConstantInterface &iconstant = F->get();
if (iconstant.const_doc && iconstant.const_doc->description.size()) {
- output.push_back(INDENT3 "/// <summary>\n");
+ String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), &itype);
+ Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>();
- Vector<String> description_lines = iconstant.const_doc->description.split("\n");
+ if (summary_lines.size()) {
+ output.append(INDENT3 "/// <summary>\n");
- for (int i = 0; i < description_lines.size(); i++) {
- String description_line = description_lines[i].strip_edges();
- if (description_line.size()) {
- output.push_back(INDENT3 "/// ");
- output.push_back(description_line.xml_escape());
- output.push_back("\n");
+ for (int i = 0; i < summary_lines.size(); i++) {
+ output.append(INDENT3 "/// ");
+ output.append(summary_lines[i]);
+ output.append("\n");
}
- }
- output.push_back(INDENT3 "/// </summary>\n");
+ output.append(INDENT3 "/// </summary>\n");
+ }
}
- output.push_back(INDENT3);
- output.push_back(iconstant.proxy_name);
- output.push_back(" = ");
- output.push_back(itos(iconstant.value));
- output.push_back(E != ienum.constants.back() ? ",\n" : "\n");
+ output.append(INDENT3);
+ output.append(iconstant.proxy_name);
+ output.append(" = ");
+ output.append(itos(iconstant.value));
+ output.append(F != ienum.constants.back() ? ",\n" : "\n");
}
- output.push_back(INDENT2 CLOSE_BLOCK);
+ output.append(INDENT2 CLOSE_BLOCK);
}
// Add properties
@@ -848,50 +1316,58 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
}
}
+ // TODO: BINDINGS_NATIVE_NAME_FIELD should be StringName, once we support it in C#
+
if (itype.is_singleton) {
// Add the type name and the singleton pointer as static fields
- output.push_back(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \"");
- output.push_back(itype.name);
- output.push_back("\";\n");
-
- output.push_back(INDENT2 "internal static IntPtr " BINDINGS_PTR_FIELD " = ");
- output.push_back(itype.api_type == ClassDB::API_EDITOR ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS);
- output.push_back("." ICALL_PREFIX);
- output.push_back(itype.name);
- output.push_back(SINGLETON_ICALL_SUFFIX "();\n");
+ output.append(MEMBER_BEGIN "private static Godot.Object singleton;\n");
+ output.append(MEMBER_BEGIN "public static Godot.Object Singleton\n" INDENT2 "{\n" INDENT3
+ "get\n" INDENT3 "{\n" INDENT4 "if (singleton == null)\n" INDENT5
+ "singleton = Engine.GetSingleton(" BINDINGS_NATIVE_NAME_FIELD ");\n" INDENT4
+ "return singleton;\n" INDENT3 "}\n" INDENT2 "}\n");
+
+ output.append(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \"");
+ output.append(itype.name);
+ output.append("\";\n");
+
+ output.append(INDENT2 "internal static IntPtr " BINDINGS_PTR_FIELD " = ");
+ output.append(itype.api_type == ClassDB::API_EDITOR ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS);
+ output.append("." ICALL_PREFIX);
+ output.append(itype.name);
+ output.append(SINGLETON_ICALL_SUFFIX "();\n");
} else if (is_derived_type) {
// Add member fields
- output.push_back(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \"");
- output.push_back(itype.name);
- output.push_back("\";\n");
+ output.append(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \"");
+ output.append(itype.name);
+ output.append("\";\n");
// Add default constructor
if (itype.is_instantiable) {
- output.push_back(MEMBER_BEGIN "public ");
- output.push_back(itype.proxy_name);
- output.push_back("() : this(");
- output.push_back(itype.memory_own ? "true" : "false");
+ output.append(MEMBER_BEGIN "public ");
+ output.append(itype.proxy_name);
+ output.append("() : this(");
+ output.append(itype.memory_own ? "true" : "false");
// The default constructor may also be called by the engine when instancing existing native objects
// The engine will initialize the pointer field of the managed side before calling the constructor
// This is why we only allocate a new native object from the constructor if the pointer field is not set
- output.push_back(")\n" OPEN_BLOCK_L2 "if (" BINDINGS_PTR_FIELD " == IntPtr.Zero)\n" INDENT4 BINDINGS_PTR_FIELD " = ");
- output.push_back(itype.api_type == ClassDB::API_EDITOR ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS);
- output.push_back("." + ctor_method);
- output.push_back("(this);\n" CLOSE_BLOCK_L2);
+ output.append(")\n" OPEN_BLOCK_L2 "if (" BINDINGS_PTR_FIELD " == IntPtr.Zero)\n" INDENT4 BINDINGS_PTR_FIELD " = ");
+ output.append(itype.api_type == ClassDB::API_EDITOR ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS);
+ output.append("." + ctor_method);
+ output.append("(this);\n" CLOSE_BLOCK_L2);
} else {
// Hide the constructor
- output.push_back(MEMBER_BEGIN "internal ");
- output.push_back(itype.proxy_name);
- output.push_back("() {}\n");
+ output.append(MEMBER_BEGIN "internal ");
+ output.append(itype.proxy_name);
+ output.append("() {}\n");
}
// Add.. em.. trick constructor. Sort of.
- output.push_back(MEMBER_BEGIN "internal ");
- output.push_back(itype.proxy_name);
- output.push_back("(bool " CS_FIELD_MEMORYOWN ") : base(" CS_FIELD_MEMORYOWN ") {}\n");
+ output.append(MEMBER_BEGIN "internal ");
+ output.append(itype.proxy_name);
+ output.append("(bool " CS_FIELD_MEMORYOWN ") : base(" CS_FIELD_MEMORYOWN ") {}\n");
}
int method_bind_count = 0;
@@ -918,15 +1394,17 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
custom_icalls.push_back(ctor_icall);
}
- output.push_back(INDENT1 CLOSE_BLOCK /* class */
+ output.append(INDENT1 CLOSE_BLOCK /* class */
CLOSE_BLOCK /* namespace */);
- output.push_back("\n#pragma warning restore CS1591\n");
+ output.append("\n"
+ "#pragma warning restore CS1591\n"
+ "#pragma warning restore CS1573\n");
return _save_file(p_output_file, output);
}
-Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInterface &p_itype, const PropertyInterface &p_iprop, List<String> &p_output) {
+Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInterface &p_itype, const PropertyInterface &p_iprop, StringBuilder &p_output) {
const MethodInterface *setter = p_itype.find_method_by_name(p_iprop.setter);
@@ -971,86 +1449,74 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
const TypeInterface *prop_itype = _get_type_or_null(proptype_name);
ERR_FAIL_NULL_V(prop_itype, ERR_BUG); // Property type not found
- String prop_proxy_name = escape_csharp_keyword(snake_to_pascal_case(p_iprop.cname));
-
- // Prevent property and enclosing type from sharing the same name
- if (prop_proxy_name == p_itype.proxy_name) {
- if (verbose_output) {
- WARN_PRINTS("Name of property `" + prop_proxy_name + "` is ambiguous with the name of its class `" +
- p_itype.proxy_name + "`. Renaming property to `" + prop_proxy_name + "_`");
- }
-
- prop_proxy_name += "_";
- }
-
if (p_iprop.prop_doc && p_iprop.prop_doc->description.size()) {
- p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
+ String xml_summary = bbcode_to_xml(fix_doc_description(p_iprop.prop_doc->description), &p_itype);
+ Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>();
- Vector<String> description_lines = p_iprop.prop_doc->description.split("\n");
+ if (summary_lines.size()) {
+ p_output.append(MEMBER_BEGIN "/// <summary>\n");
- for (int i = 0; i < description_lines.size(); i++) {
- String description_line = description_lines[i].strip_edges();
- if (description_line.size()) {
- p_output.push_back(INDENT2 "/// ");
- p_output.push_back(description_line.xml_escape());
- p_output.push_back("\n");
+ for (int i = 0; i < summary_lines.size(); i++) {
+ p_output.append(INDENT2 "/// ");
+ p_output.append(summary_lines[i]);
+ p_output.append("\n");
}
- }
- p_output.push_back(INDENT2 "/// </summary>");
+ p_output.append(INDENT2 "/// </summary>");
+ }
}
- p_output.push_back(MEMBER_BEGIN "public ");
+ p_output.append(MEMBER_BEGIN "public ");
if (p_itype.is_singleton)
- p_output.push_back("static ");
+ p_output.append("static ");
- p_output.push_back(prop_itype->cs_type);
- p_output.push_back(" ");
- p_output.push_back(prop_proxy_name.replace("/", "__"));
- p_output.push_back("\n" INDENT2 OPEN_BLOCK);
+ p_output.append(prop_itype->cs_type);
+ p_output.append(" ");
+ p_output.append(p_iprop.proxy_name);
+ p_output.append("\n" INDENT2 OPEN_BLOCK);
if (getter) {
- p_output.push_back(INDENT3 "get\n" OPEN_BLOCK_L3);
- p_output.push_back("return ");
- p_output.push_back(getter->proxy_name + "(");
+ p_output.append(INDENT3 "get\n" OPEN_BLOCK_L3);
+ p_output.append("return ");
+ p_output.append(getter->proxy_name + "(");
if (p_iprop.index != -1) {
const ArgumentInterface &idx_arg = getter->arguments.front()->get();
if (idx_arg.type.cname != name_cache.type_int) {
// Assume the index parameter is an enum
const TypeInterface *idx_arg_type = _get_type_or_null(idx_arg.type);
CRASH_COND(idx_arg_type == NULL);
- p_output.push_back("(" + idx_arg_type->proxy_name + ")" + itos(p_iprop.index));
+ p_output.append("(" + idx_arg_type->proxy_name + ")" + itos(p_iprop.index));
} else {
- p_output.push_back(itos(p_iprop.index));
+ p_output.append(itos(p_iprop.index));
}
}
- p_output.push_back(");\n" CLOSE_BLOCK_L3);
+ p_output.append(");\n" CLOSE_BLOCK_L3);
}
if (setter) {
- p_output.push_back(INDENT3 "set\n" OPEN_BLOCK_L3);
- p_output.push_back(setter->proxy_name + "(");
+ p_output.append(INDENT3 "set\n" OPEN_BLOCK_L3);
+ p_output.append(setter->proxy_name + "(");
if (p_iprop.index != -1) {
const ArgumentInterface &idx_arg = setter->arguments.front()->get();
if (idx_arg.type.cname != name_cache.type_int) {
// Assume the index parameter is an enum
const TypeInterface *idx_arg_type = _get_type_or_null(idx_arg.type);
CRASH_COND(idx_arg_type == NULL);
- p_output.push_back("(" + idx_arg_type->proxy_name + ")" + itos(p_iprop.index) + ", ");
+ p_output.append("(" + idx_arg_type->proxy_name + ")" + itos(p_iprop.index) + ", ");
} else {
- p_output.push_back(itos(p_iprop.index) + ", ");
+ p_output.append(itos(p_iprop.index) + ", ");
}
}
- p_output.push_back("value);\n" CLOSE_BLOCK_L3);
+ p_output.append("value);\n" CLOSE_BLOCK_L3);
}
- p_output.push_back(CLOSE_BLOCK_L2);
+ p_output.append(CLOSE_BLOCK_L2);
return OK;
}
-Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, int &p_method_bind_count, List<String> &p_output) {
+Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output) {
const TypeInterface *return_type = _get_type_or_placeholder(p_imethod.return_type);
@@ -1062,7 +1528,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
String icall_params = method_bind_field + ", ";
icall_params += sformat(p_itype.cs_in, "this");
- List<String> default_args_doc;
+ StringBuilder default_args_doc;
// Retrieve information from the arguments
for (const List<ArgumentInterface>::Element *F = p_imethod.arguments.front(); F; F = F->next()) {
@@ -1128,7 +1594,10 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
icall_params += arg_type->cs_in.empty() ? arg_in : sformat(arg_type->cs_in, arg_in);
- default_args_doc.push_back(INDENT2 "/// <param name=\"" + iarg.name + "\">If the param is null, then the default value is " + def_arg + "</param>\n");
+ // Apparently the name attribute must not include the @
+ String param_tag_name = iarg.name.begins_with("@") ? iarg.name.substr(1, iarg.name.length()) : iarg.name;
+
+ default_args_doc.append(INDENT2 "/// <param name=\"" + param_tag_name + "\">If the parameter is null, then the default value is " + def_arg + "</param>\n");
} else {
icall_params += arg_type->cs_in.empty() ? iarg.name : sformat(arg_type->cs_in, iarg.name);
}
@@ -1137,61 +1606,58 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
// Generate method
{
if (!p_imethod.is_virtual && !p_imethod.requires_object_call) {
- p_output.push_back(MEMBER_BEGIN "[DebuggerBrowsable(DebuggerBrowsableState.Never)]" MEMBER_BEGIN "private static IntPtr ");
- p_output.push_back(method_bind_field + " = Object." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \"");
- p_output.push_back(p_imethod.name);
- p_output.push_back("\");\n");
+ p_output.append(MEMBER_BEGIN "[DebuggerBrowsable(DebuggerBrowsableState.Never)]" MEMBER_BEGIN "private static IntPtr ");
+ p_output.append(method_bind_field + " = Object." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \"");
+ p_output.append(p_imethod.name);
+ p_output.append("\");\n");
}
if (p_imethod.method_doc && p_imethod.method_doc->description.size()) {
- p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
+ String xml_summary = bbcode_to_xml(fix_doc_description(p_imethod.method_doc->description), &p_itype);
+ Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>();
- Vector<String> description_lines = p_imethod.method_doc->description.split("\n");
+ if (summary_lines.size() || default_args_doc.get_string_length()) {
+ p_output.append(MEMBER_BEGIN "/// <summary>\n");
- for (int i = 0; i < description_lines.size(); i++) {
- String description_line = description_lines[i].strip_edges();
- if (description_line.size()) {
- p_output.push_back(INDENT2 "/// ");
- p_output.push_back(description_line.xml_escape());
- p_output.push_back("\n");
+ for (int i = 0; i < summary_lines.size(); i++) {
+ p_output.append(INDENT2 "/// ");
+ p_output.append(summary_lines[i]);
+ p_output.append("\n");
}
- }
- for (List<String>::Element *E = default_args_doc.front(); E; E = E->next()) {
- p_output.push_back(E->get().xml_escape());
+ p_output.append(default_args_doc.as_string());
+ p_output.append(INDENT2 "/// </summary>");
}
-
- p_output.push_back(INDENT2 "/// </summary>");
}
if (!p_imethod.is_internal) {
- p_output.push_back(MEMBER_BEGIN "[GodotMethod(\"");
- p_output.push_back(p_imethod.name);
- p_output.push_back("\")]");
+ p_output.append(MEMBER_BEGIN "[GodotMethod(\"");
+ p_output.append(p_imethod.name);
+ p_output.append("\")]");
}
- p_output.push_back(MEMBER_BEGIN);
- p_output.push_back(p_imethod.is_internal ? "internal " : "public ");
+ p_output.append(MEMBER_BEGIN);
+ p_output.append(p_imethod.is_internal ? "internal " : "public ");
if (p_itype.is_singleton) {
- p_output.push_back("static ");
+ p_output.append("static ");
} else if (p_imethod.is_virtual) {
- p_output.push_back("virtual ");
+ p_output.append("virtual ");
}
- p_output.push_back(return_type->cs_type + " ");
- p_output.push_back(p_imethod.proxy_name + "(");
- p_output.push_back(arguments_sig + ")\n" OPEN_BLOCK_L2);
+ p_output.append(return_type->cs_type + " ");
+ p_output.append(p_imethod.proxy_name + "(");
+ p_output.append(arguments_sig + ")\n" OPEN_BLOCK_L2);
if (p_imethod.is_virtual) {
// Godot virtual method must be overridden, therefore we return a default value by default.
if (return_type->cname == name_cache.type_void) {
- p_output.push_back("return;\n" CLOSE_BLOCK_L2);
+ p_output.append("return;\n" CLOSE_BLOCK_L2);
} else {
- p_output.push_back("return default(");
- p_output.push_back(return_type->cs_type);
- p_output.push_back(");\n" CLOSE_BLOCK_L2);
+ p_output.append("return default(");
+ p_output.append(return_type->cs_type);
+ p_output.append(");\n" CLOSE_BLOCK_L2);
}
return OK; // Won't increment method bind count
@@ -1200,16 +1666,16 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
if (p_imethod.requires_object_call) {
// Fallback to Godot's object.Call(string, params)
- p_output.push_back(CS_METHOD_CALL "(\"");
- p_output.push_back(p_imethod.name);
- p_output.push_back("\"");
+ p_output.append(CS_METHOD_CALL "(\"");
+ p_output.append(p_imethod.name);
+ p_output.append("\"");
for (const List<ArgumentInterface>::Element *F = p_imethod.arguments.front(); F; F = F->next()) {
- p_output.push_back(", ");
- p_output.push_back(F->get().name);
+ p_output.append(", ");
+ p_output.append(F->get().name);
}
- p_output.push_back(");\n" CLOSE_BLOCK_L2);
+ p_output.append(");\n" CLOSE_BLOCK_L2);
return OK; // Won't increment method bind count
}
@@ -1223,21 +1689,22 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
im_call += "." + im_icall->name + "(" + icall_params + ")";
if (p_imethod.arguments.size())
- p_output.push_back(cs_in_statements);
+ p_output.append(cs_in_statements);
if (return_type->cname == name_cache.type_void) {
- p_output.push_back(im_call + ";\n");
+ p_output.append(im_call + ";\n");
} else if (return_type->cs_out.empty()) {
- p_output.push_back("return " + im_call + ";\n");
+ p_output.append("return " + im_call + ";\n");
} else {
- p_output.push_back(sformat(return_type->cs_out, im_call, return_type->cs_type, return_type->im_type_out));
- p_output.push_back("\n");
+ p_output.append(sformat(return_type->cs_out, im_call, return_type->cs_type, return_type->im_type_out));
+ p_output.append("\n");
}
- p_output.push_back(CLOSE_BLOCK_L2);
+ p_output.append(CLOSE_BLOCK_L2);
}
p_method_bind_count++;
+
return OK;
}
@@ -1249,11 +1716,11 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
ERR_EXPLAIN("The output directory does not exist.");
ERR_FAIL_COND_V(!dir_exists, ERR_FILE_BAD_PATH);
- List<String> output;
+ StringBuilder output;
- output.push_back("/* THIS FILE IS GENERATED DO NOT EDIT */\n");
- output.push_back("#include \"" GLUE_HEADER_FILE "\"\n");
- output.push_back("\n#ifdef MONO_GLUE_ENABLED\n");
+ output.append("/* THIS FILE IS GENERATED DO NOT EDIT */\n");
+ output.append("#include \"" GLUE_HEADER_FILE "\"\n");
+ output.append("\n#ifdef MONO_GLUE_ENABLED\n");
generated_icall_funcs.clear();
@@ -1273,7 +1740,7 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls;
- OS::get_singleton()->print(String("Generating " + itype.name + "...\n").utf8());
+ OS::get_singleton()->print("Generating %s...\n", itype.name.utf8().get_data());
String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor"); // Used only for derived types
@@ -1293,11 +1760,11 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
if (!find_icall_by_name(singleton_icall.name, custom_icalls))
custom_icalls.push_back(singleton_icall);
- output.push_back("Object* ");
- output.push_back(singleton_icall_name);
- output.push_back("() " OPEN_BLOCK "\treturn Engine::get_singleton()->get_singleton_object(\"");
- output.push_back(itype.proxy_name);
- output.push_back("\");\n" CLOSE_BLOCK "\n");
+ output.append("Object* ");
+ output.append(singleton_icall_name);
+ output.append("() " OPEN_BLOCK "\treturn Engine::get_singleton()->get_singleton_object(\"");
+ output.append(itype.proxy_name);
+ output.append("\");\n" CLOSE_BLOCK "\n");
}
if (is_derived_type && itype.is_instantiable) {
@@ -1306,43 +1773,43 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
if (!find_icall_by_name(ctor_icall.name, custom_icalls))
custom_icalls.push_back(ctor_icall);
- output.push_back("Object* ");
- output.push_back(ctor_method);
- output.push_back("(MonoObject* obj) " OPEN_BLOCK
- "\t" C_MACRO_OBJECT_CONSTRUCT "(instance, \"");
- output.push_back(itype.name);
- output.push_back("\");\n"
- "\t" C_METHOD_TIE_MANAGED_TO_UNMANAGED "(obj, instance);\n"
- "\treturn instance;\n" CLOSE_BLOCK "\n");
+ output.append("Object* ");
+ output.append(ctor_method);
+ output.append("(MonoObject* obj) " OPEN_BLOCK
+ "\t" C_MACRO_OBJECT_CONSTRUCT "(instance, \"");
+ output.append(itype.name);
+ output.append("\");\n"
+ "\t" C_METHOD_TIE_MANAGED_TO_UNMANAGED "(obj, instance);\n"
+ "\treturn instance;\n" CLOSE_BLOCK "\n");
}
}
- output.push_back("namespace GodotSharpBindings\n" OPEN_BLOCK "\n");
+ output.append("namespace GodotSharpBindings\n" OPEN_BLOCK "\n");
- output.push_back("uint64_t get_core_api_hash() { return ");
- output.push_back(String::num_uint64(GDMono::get_singleton()->get_api_core_hash()) + "U; }\n");
+ output.append("uint64_t get_core_api_hash() { return ");
+ output.append(String::num_uint64(GDMono::get_singleton()->get_api_core_hash()) + "U; }\n");
- output.push_back("#ifdef TOOLS_ENABLED\n"
- "uint64_t get_editor_api_hash() { return ");
- output.push_back(String::num_uint64(GDMono::get_singleton()->get_api_editor_hash()) + "U; }\n");
- output.push_back("#endif // TOOLS_ENABLED\n");
+ output.append("#ifdef TOOLS_ENABLED\n"
+ "uint64_t get_editor_api_hash() { return ");
+ output.append(String::num_uint64(GDMono::get_singleton()->get_api_editor_hash()) + "U; }\n");
+ output.append("#endif // TOOLS_ENABLED\n");
- output.push_back("uint32_t get_bindings_version() { return ");
- output.push_back(String::num_uint64(BINDINGS_GENERATOR_VERSION) + "; }\n");
+ output.append("uint32_t get_bindings_version() { return ");
+ output.append(String::num_uint64(BINDINGS_GENERATOR_VERSION) + "; }\n");
- output.push_back("\nvoid register_generated_icalls() " OPEN_BLOCK);
- output.push_back("\tgodot_register_glue_header_icalls();\n");
+ output.append("\nvoid register_generated_icalls() " OPEN_BLOCK);
+ output.append("\tgodot_register_glue_header_icalls();\n");
-#define ADD_INTERNAL_CALL_REGISTRATION(m_icall) \
- { \
- output.push_back("\tmono_add_internal_call("); \
- output.push_back("\"" BINDINGS_NAMESPACE "."); \
- output.push_back(m_icall.editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS); \
- output.push_back("::"); \
- output.push_back(m_icall.name); \
- output.push_back("\", (void*)"); \
- output.push_back(m_icall.name); \
- output.push_back(");\n"); \
+#define ADD_INTERNAL_CALL_REGISTRATION(m_icall) \
+ { \
+ output.append("\tmono_add_internal_call("); \
+ output.append("\"" BINDINGS_NAMESPACE "."); \
+ output.append(m_icall.editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS); \
+ output.append("::"); \
+ output.append(m_icall.name); \
+ output.append("\", (void*)"); \
+ output.append(m_icall.name); \
+ output.append(");\n"); \
}
bool tools_sequence = false;
@@ -1351,11 +1818,11 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
if (tools_sequence) {
if (!E->get().editor_only) {
tools_sequence = false;
- output.push_back("#endif\n");
+ output.append("#endif\n");
}
} else {
if (E->get().editor_only) {
- output.push_back("#ifdef TOOLS_ENABLED\n");
+ output.append("#ifdef TOOLS_ENABLED\n");
tools_sequence = true;
}
}
@@ -1365,23 +1832,23 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
if (tools_sequence) {
tools_sequence = false;
- output.push_back("#endif\n");
+ output.append("#endif\n");
}
- output.push_back("#ifdef TOOLS_ENABLED\n");
+ output.append("#ifdef TOOLS_ENABLED\n");
for (const List<InternalCall>::Element *E = editor_custom_icalls.front(); E; E = E->next())
ADD_INTERNAL_CALL_REGISTRATION(E->get());
- output.push_back("#endif // TOOLS_ENABLED\n");
+ output.append("#endif // TOOLS_ENABLED\n");
for (const List<InternalCall>::Element *E = method_icalls.front(); E; E = E->next()) {
if (tools_sequence) {
if (!E->get().editor_only) {
tools_sequence = false;
- output.push_back("#endif\n");
+ output.append("#endif\n");
}
} else {
if (E->get().editor_only) {
- output.push_back("#ifdef TOOLS_ENABLED\n");
+ output.append("#ifdef TOOLS_ENABLED\n");
tools_sequence = true;
}
}
@@ -1391,14 +1858,14 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
if (tools_sequence) {
tools_sequence = false;
- output.push_back("#endif\n");
+ output.append("#endif\n");
}
#undef ADD_INTERNAL_CALL_REGISTRATION
- output.push_back(CLOSE_BLOCK "\n} // namespace GodotSharpBindings\n");
+ output.append(CLOSE_BLOCK "\n} // namespace GodotSharpBindings\n");
- output.push_back("\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);
if (save_err != OK)
@@ -1413,23 +1880,20 @@ uint32_t BindingsGenerator::get_version() {
return BINDINGS_GENERATOR_VERSION;
}
-Error BindingsGenerator::_save_file(const String &p_path, const List<String> &p_content) {
+Error BindingsGenerator::_save_file(const String &p_path, const StringBuilder &p_content) {
FileAccessRef file = FileAccess::open(p_path, FileAccess::WRITE);
ERR_EXPLAIN("Cannot open file: " + p_path);
ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE);
- for (const List<String>::Element *E = p_content.front(); E; E = E->next()) {
- file->store_string(E->get());
- }
-
+ file->store_string(p_content.as_string());
file->close();
return OK;
}
-Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, List<String> &p_output) {
+Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, StringBuilder &p_output) {
if (p_imethod.is_virtual)
return OK; // Ignore
@@ -1485,15 +1949,15 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
generated_icall_funcs.push_back(im_icall);
if (im_icall->editor_only)
- p_output.push_back("#ifdef TOOLS_ENABLED\n");
+ p_output.append("#ifdef TOOLS_ENABLED\n");
// Generate icall function
- p_output.push_back(ret_void ? "void " : return_type->c_type_out + " ");
- p_output.push_back(icall_method);
- p_output.push_back("(");
- p_output.push_back(c_func_sig);
- p_output.push_back(") " OPEN_BLOCK);
+ p_output.append(ret_void ? "void " : return_type->c_type_out + " ");
+ p_output.append(icall_method);
+ p_output.append("(");
+ p_output.append(c_func_sig);
+ p_output.append(") " OPEN_BLOCK);
String fail_ret = ret_void ? "" : ", " + (return_type->c_type_out.ends_with("*") ? "NULL" : return_type->c_type_out + "()");
@@ -1501,6 +1965,15 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
String ptrcall_return_type;
String initialization;
+ if (p_imethod.is_vararg && return_type->cname != name_cache.type_Variant) {
+ // VarArg methods always return Variant, but there are some cases in which MethodInfo provides
+ // a specific return type. We trust this information is valid. We need a temporary local to keep
+ // the Variant alive until the method returns. Otherwise, if the returned Variant holds a RefPtr,
+ // it could be deleted too early. This is the case with GDScript.new() which returns OBJECT.
+ // Alternatively, we could just return Variant, but that would result in a worse API.
+ p_output.append("\tVariant " C_LOCAL_VARARG_RET ";\n");
+ }
+
if (return_type->is_object_type) {
ptrcall_return_type = return_type->is_reference ? "Ref<Reference>" : return_type->c_type;
initialization = return_type->is_reference ? "" : " = NULL";
@@ -1508,79 +1981,82 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
ptrcall_return_type = return_type->c_type;
}
- p_output.push_back("\t" + ptrcall_return_type);
- p_output.push_back(" " C_LOCAL_RET);
- p_output.push_back(initialization + ";\n");
- p_output.push_back("\tERR_FAIL_NULL_V(" CS_PARAM_INSTANCE);
- p_output.push_back(fail_ret);
- p_output.push_back(");\n");
+ p_output.append("\t" + ptrcall_return_type);
+ p_output.append(" " C_LOCAL_RET);
+ p_output.append(initialization + ";\n");
+ p_output.append("\tERR_FAIL_NULL_V(" CS_PARAM_INSTANCE);
+ p_output.append(fail_ret);
+ p_output.append(");\n");
} else {
- p_output.push_back("\tERR_FAIL_NULL(" CS_PARAM_INSTANCE ");\n");
+ p_output.append("\tERR_FAIL_NULL(" CS_PARAM_INSTANCE ");\n");
}
if (p_imethod.arguments.size()) {
if (p_imethod.is_vararg) {
- String err_fail_macro = ret_void ? "ERR_FAIL_COND" : "ERR_FAIL_COND_V";
String vararg_arg = "arg" + argc_str;
String real_argc_str = itos(p_imethod.arguments.size() - 1); // Arguments count without vararg
- p_output.push_back("\tVector<Variant> varargs;\n"
- "\tint vararg_length = mono_array_length(");
- p_output.push_back(vararg_arg);
- p_output.push_back(");\n\tint total_length = ");
- p_output.push_back(real_argc_str);
- p_output.push_back(" + vararg_length;\n\t");
- p_output.push_back(err_fail_macro);
- p_output.push_back("(varargs.resize(vararg_length) != OK");
- p_output.push_back(fail_ret);
- p_output.push_back(");\n\tVector<Variant*> " C_LOCAL_PTRCALL_ARGS ";\n\t");
- p_output.push_back(err_fail_macro);
- p_output.push_back("(call_args.resize(total_length) != OK");
- p_output.push_back(fail_ret);
- p_output.push_back(");\n");
- p_output.push_back(c_in_statements);
- p_output.push_back("\tfor (int i = 0; i < vararg_length; i++) " OPEN_BLOCK
- "\t\tMonoObject* elem = mono_array_get(");
- p_output.push_back(vararg_arg);
- p_output.push_back(", MonoObject*, i);\n"
- "\t\tvarargs.set(i, GDMonoMarshal::mono_object_to_variant(elem));\n"
- "\t\t" C_LOCAL_PTRCALL_ARGS ".set(");
- p_output.push_back(real_argc_str);
- p_output.push_back(" + i, &varargs.write[i]);\n\t" CLOSE_BLOCK);
+ p_output.append("\tint vararg_length = mono_array_length(");
+ p_output.append(vararg_arg);
+ p_output.append(");\n\tint total_length = ");
+ p_output.append(real_argc_str);
+ p_output.append(" + vararg_length;\n"
+ "\tArgumentsVector<Variant> varargs(vararg_length);\n"
+ "\tArgumentsVector<const Variant *> " C_LOCAL_PTRCALL_ARGS "(total_length);\n");
+ p_output.append(c_in_statements);
+ p_output.append("\tfor (int i = 0; i < vararg_length; i++) " OPEN_BLOCK
+ "\t\tMonoObject* elem = mono_array_get(");
+ p_output.append(vararg_arg);
+ p_output.append(", MonoObject*, i);\n"
+ "\t\tvarargs.set(i, GDMonoMarshal::mono_object_to_variant(elem));\n"
+ "\t\t" C_LOCAL_PTRCALL_ARGS ".set(");
+ p_output.append(real_argc_str);
+ p_output.append(" + i, &varargs.get(i));\n\t" CLOSE_BLOCK);
} else {
- p_output.push_back(c_in_statements);
- p_output.push_back("\tconst void* " C_LOCAL_PTRCALL_ARGS "[");
- p_output.push_back(argc_str + "] = { ");
- p_output.push_back(c_args_var_content + " };\n");
+ p_output.append(c_in_statements);
+ p_output.append("\tconst void* " C_LOCAL_PTRCALL_ARGS "[");
+ p_output.append(argc_str + "] = { ");
+ p_output.append(c_args_var_content + " };\n");
}
}
if (p_imethod.is_vararg) {
- p_output.push_back("\tVariant::CallError vcall_error;\n\t");
+ p_output.append("\tVariant::CallError vcall_error;\n\t");
- if (!ret_void)
- p_output.push_back(C_LOCAL_RET " = ");
+ if (!ret_void) {
+ // See the comment on the C_LOCAL_VARARG_RET declaration
+ if (return_type->cname != name_cache.type_Variant) {
+ p_output.append(C_LOCAL_VARARG_RET " = ");
+ } else {
+ p_output.append(C_LOCAL_RET " = ");
+ }
+ }
- p_output.push_back(CS_PARAM_METHODBIND "->call(" CS_PARAM_INSTANCE ", ");
- p_output.push_back(p_imethod.arguments.size() ? "(const Variant**)" C_LOCAL_PTRCALL_ARGS ".ptr()" : "NULL");
- p_output.push_back(", total_length, vcall_error);\n");
+ p_output.append(CS_PARAM_METHODBIND "->call(" CS_PARAM_INSTANCE ", ");
+ p_output.append(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ".ptr()" : "NULL");
+ p_output.append(", total_length, vcall_error);\n");
+
+ // See the comment on the C_LOCAL_VARARG_RET declaration
+ if (return_type->cname != name_cache.type_Variant) {
+ p_output.append("\t" C_LOCAL_RET " = " C_LOCAL_VARARG_RET ";\n");
+ }
} else {
- p_output.push_back("\t" CS_PARAM_METHODBIND "->ptrcall(" CS_PARAM_INSTANCE ", ");
- p_output.push_back(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ", " : "NULL, ");
- p_output.push_back(!ret_void ? "&" C_LOCAL_RET ");\n" : "NULL);\n");
+ p_output.append("\t" CS_PARAM_METHODBIND "->ptrcall(" CS_PARAM_INSTANCE ", ");
+ p_output.append(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ", " : "NULL, ");
+ p_output.append(!ret_void ? "&" C_LOCAL_RET ");\n" : "NULL);\n");
}
if (!ret_void) {
if (return_type->c_out.empty())
- p_output.push_back("\treturn " C_LOCAL_RET ";\n");
+ p_output.append("\treturn " C_LOCAL_RET ";\n");
else
- p_output.push_back(sformat(return_type->c_out, return_type->c_type_out, C_LOCAL_RET, return_type->name));
+ p_output.append(sformat(return_type->c_out, return_type->c_type_out, C_LOCAL_RET, return_type->name));
}
- p_output.push_back(CLOSE_BLOCK "\n");
+ p_output.append(CLOSE_BLOCK "\n");
if (im_icall->editor_only)
- p_output.push_back("#endif // TOOLS_ENABLED\n");
+ p_output.append("#endif // TOOLS_ENABLED\n");
}
return OK;
@@ -1701,7 +2177,6 @@ void BindingsGenerator::_populate_object_type_interfaces() {
PropertyInterface iprop;
iprop.cname = property.name;
- iprop.proxy_name = escape_csharp_keyword(snake_to_pascal_case(iprop.cname));
iprop.setter = ClassDB::get_property_setter(type_cname, iprop.cname);
iprop.getter = ClassDB::get_property_getter(type_cname, iprop.cname);
@@ -1709,6 +2184,8 @@ void BindingsGenerator::_populate_object_type_interfaces() {
iprop.index = ClassDB::get_property_index(type_cname, iprop.cname, &valid);
ERR_FAIL_COND(!valid);
+ iprop.proxy_name = escape_csharp_keyword(snake_to_pascal_case(iprop.cname));
+
// Prevent property and enclosing type from sharing the same name
if (iprop.proxy_name == itype.proxy_name) {
if (verbose_output) {
@@ -1719,6 +2196,8 @@ void BindingsGenerator::_populate_object_type_interfaces() {
iprop.proxy_name += "_";
}
+ iprop.proxy_name = iprop.proxy_name.replace("/", "__"); // Some members have a slash...
+
iprop.prop_doc = NULL;
for (int i = 0; i < itype.class_doc->properties.size(); i++) {
@@ -1860,8 +2339,8 @@ void BindingsGenerator::_populate_object_type_interfaces() {
}
if (!imethod.is_virtual && imethod.name[0] == '_') {
- for (const List<PropertyInterface>::Element *E = itype.properties.front(); E; E = E->next()) {
- const PropertyInterface &iprop = E->get();
+ for (const List<PropertyInterface>::Element *F = itype.properties.front(); F; F = F->next()) {
+ const PropertyInterface &iprop = F->get();
if (iprop.setter == imethod.name || iprop.getter == imethod.name) {
imethod.is_internal = true;
@@ -1876,8 +2355,8 @@ void BindingsGenerator::_populate_object_type_interfaces() {
// Populate enums and constants
- List<String> constant_list;
- ClassDB::get_integer_constant_list(type_cname, &constant_list, true);
+ List<String> constants;
+ ClassDB::get_integer_constant_list(type_cname, &constants, true);
const HashMap<StringName, List<StringName> > &enum_map = class_info->enum_map;
const StringName *k = NULL;
@@ -1892,13 +2371,13 @@ void BindingsGenerator::_populate_object_type_interfaces() {
enum_proxy_cname = StringName(enum_proxy_name);
}
EnumInterface ienum(enum_proxy_cname);
- const List<StringName> &constants = enum_map.get(*k);
- for (const List<StringName>::Element *E = constants.front(); E; E = E->next()) {
+ const List<StringName> &enum_constants = enum_map.get(*k);
+ for (const List<StringName>::Element *E = enum_constants.front(); E; E = E->next()) {
const StringName &constant_cname = E->get();
String constant_name = constant_cname.operator String();
int *value = class_info->constant_map.getptr(constant_cname);
ERR_FAIL_NULL(value);
- constant_list.erase(constant_name);
+ constants.erase(constant_name);
ConstantInterface iconstant(constant_name, snake_to_pascal_case(constant_name, true), *value);
@@ -1930,7 +2409,7 @@ void BindingsGenerator::_populate_object_type_interfaces() {
enum_types.insert(enum_itype.cname, enum_itype);
}
- for (const List<String>::Element *E = constant_list.front(); E; E = E->next()) {
+ for (const List<String>::Element *E = constants.front(); E; E = E->next()) {
const String &constant_name = E->get();
int *value = class_info->constant_map.getptr(StringName(E->get()));
ERR_FAIL_NULL(value);
@@ -2011,6 +2490,7 @@ void BindingsGenerator::_default_argument_from_variant(const Variant &p_val, Arg
r_iarg.default_argument = "null";
break;
}
+ FALLTHROUGH;
case Variant::DICTIONARY:
case Variant::_RID:
r_iarg.default_argument = "new %s()";
@@ -2033,7 +2513,8 @@ void BindingsGenerator::_default_argument_from_variant(const Variant &p_val, Arg
r_iarg.default_argument = Variant::get_type_name(p_val.get_type()) + ".Identity";
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
break;
- default: {}
+ default: {
+ }
}
if (r_iarg.def_param_mode == ArgumentInterface::CONSTANT && r_iarg.type.cname == name_cache.type_Variant && r_iarg.default_argument != "null")
@@ -2323,9 +2804,9 @@ void BindingsGenerator::_populate_global_constants() {
if (enum_name != StringName()) {
EnumInterface ienum(enum_name);
- List<EnumInterface>::Element *match = global_enums.find(ienum);
- if (match) {
- match->get().constants.push_back(iconstant);
+ List<EnumInterface>::Element *enum_match = global_enums.find(ienum);
+ if (enum_match) {
+ enum_match->get().constants.push_back(iconstant);
} else {
ienum.constants.push_back(iconstant);
global_enums.push_back(ienum);
@@ -2410,9 +2891,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
const List<String>::Element *elem = p_cmdline_args.front();
while (elem && options_left) {
-
if (elem->get() == mono_glue_option) {
-
const List<String>::Element *path_elem = elem->next();
if (path_elem) {
@@ -2424,9 +2903,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
}
--options_left;
-
} else if (elem->get() == cs_api_option) {
-
const List<String>::Element *path_elem = elem->next();
if (path_elem) {
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index 91c474c4f0..a073c09910 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,6 +32,7 @@
#define BINDINGS_GENERATOR_H
#include "core/class_db.h"
+#include "core/string_builder.h"
#include "dotnet_solution.h"
#include "editor/doc/doc_data.h"
#include "editor/editor_help.h"
@@ -87,8 +88,13 @@ class BindingsGenerator {
StringName cname;
bool is_enum;
- TypeReference() {
- is_enum = false;
+ TypeReference() :
+ is_enum(false) {
+ }
+
+ TypeReference(const StringName &p_cname) :
+ cname(p_cname),
+ is_enum(false) {
}
};
@@ -321,6 +327,15 @@ class BindingsGenerator {
return NULL;
}
+ const PropertyInterface *find_property_by_name(const StringName &p_cname) const {
+ for (const List<PropertyInterface>::Element *E = properties.front(); E; E = E->next()) {
+ if (E->get().cname == p_cname)
+ return &E->get();
+ }
+
+ return NULL;
+ }
+
const PropertyInterface *find_property_by_proxy_name(const String &p_proxy_name) const {
for (const List<PropertyInterface>::Element *E = properties.front(); E; E = E->next()) {
if (E->get().proxy_name == p_proxy_name)
@@ -482,6 +497,8 @@ class BindingsGenerator {
StringName type_VarArg;
StringName type_Object;
StringName type_Reference;
+ StringName type_String;
+ StringName type_at_GlobalScope;
StringName enum_Error;
NameCache() {
@@ -493,6 +510,8 @@ class BindingsGenerator {
type_VarArg = StaticCString::create("VarArg");
type_Object = StaticCString::create("Object");
type_Reference = StaticCString::create("Reference");
+ type_String = StaticCString::create("String");
+ type_at_GlobalScope = StaticCString::create("@GlobalScope");
enum_Error = StaticCString::create("Error");
}
@@ -511,6 +530,15 @@ class BindingsGenerator {
return NULL;
}
+ const ConstantInterface *find_constant_by_name(const String &p_name, const List<ConstantInterface> &p_constants) const {
+ for (const List<ConstantInterface>::Element *E = p_constants.front(); E; E = E->next()) {
+ if (E->get().name == p_name)
+ return &E->get();
+ }
+
+ return NULL;
+ }
+
inline String get_unique_sig(const TypeInterface &p_type) {
if (p_type.is_reference)
return "Ref";
@@ -522,6 +550,8 @@ class BindingsGenerator {
return p_type.name;
}
+ String bbcode_to_xml(const String &p_bbcode, const TypeInterface *p_itype);
+
int _determine_enum_prefix(const EnumInterface &p_ienum);
void _apply_prefix_to_enum_constants(EnumInterface &p_ienum, int p_prefix_length);
@@ -539,14 +569,14 @@ class BindingsGenerator {
Error _generate_cs_type(const TypeInterface &itype, const String &p_output_file);
- Error _generate_cs_property(const TypeInterface &p_itype, const PropertyInterface &p_iprop, List<String> &p_output);
- Error _generate_cs_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, int &p_method_bind_count, List<String> &p_output);
+ Error _generate_cs_property(const TypeInterface &p_itype, const PropertyInterface &p_iprop, StringBuilder &p_output);
+ Error _generate_cs_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output);
- void _generate_global_constants(List<String> &p_output);
+ void _generate_global_constants(StringBuilder &p_output);
- Error _generate_glue_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, List<String> &p_output);
+ Error _generate_glue_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, StringBuilder &p_output);
- Error _save_file(const String &p_path, const List<String> &p_content);
+ Error _save_file(const String &p_path, const StringBuilder &p_content);
BindingsGenerator() {}
diff --git a/modules/mono/editor/csharp_project.cpp b/modules/mono/editor/csharp_project.cpp
index 416108603b..beeff51bc2 100644
--- a/modules/mono/editor/csharp_project.cpp
+++ b/modules/mono/editor/csharp_project.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -228,6 +228,15 @@ Error generate_scripts_metadata(const String &p_project_path, const String &p_ou
if (new_dict.size()) {
String json = JSON::print(new_dict, "", false);
+ String base_dir = p_output_path.get_base_dir();
+
+ if (!DirAccess::exists(base_dir)) {
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+
+ Error err = da->make_dir_recursive(base_dir);
+ ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
+ }
+
Error ferr;
FileAccess *f = FileAccess::open(p_output_path, FileAccess::WRITE, &ferr);
ERR_EXPLAIN("Cannot open file for writing: " + p_output_path);
diff --git a/modules/mono/editor/csharp_project.h b/modules/mono/editor/csharp_project.h
index aeeeff50f0..3d5a65f8da 100644
--- a/modules/mono/editor/csharp_project.h
+++ b/modules/mono/editor/csharp_project.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/editor/dotnet_solution.cpp b/modules/mono/editor/dotnet_solution.cpp
index ab92e2e378..324752cafc 100644
--- a/modules/mono/editor/dotnet_solution.cpp
+++ b/modules/mono/editor/dotnet_solution.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/editor/dotnet_solution.h b/modules/mono/editor/dotnet_solution.h
index 629605ad18..18933364fa 100644
--- a/modules/mono/editor/dotnet_solution.h
+++ b/modules/mono/editor/dotnet_solution.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp
index 0f12fc5243..00c780d1b7 100644
--- a/modules/mono/editor/godotsharp_builds.cpp
+++ b/modules/mono/editor/godotsharp_builds.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -100,22 +100,24 @@ MonoString *godot_icall_BuildInstance_get_MSBuildPath() {
if (msbuild_tools_path.empty() || !FileAccess::exists(msbuild_tools_path)) {
// Try to search it again if it wasn't found last time or if it was removed from its location
msbuild_tools_path = MonoRegUtils::find_msbuild_tools_path();
- }
-
- if (msbuild_tools_path.length()) {
- if (!msbuild_tools_path.ends_with("\\"))
- msbuild_tools_path += "\\";
- return GDMonoMarshal::mono_string_from_godot(msbuild_tools_path + "MSBuild.exe");
+ if (msbuild_tools_path.empty()) {
+ ERR_PRINTS("Cannot find executable for '" PROP_NAME_MSBUILD_VS "'. Tried with path: " + msbuild_tools_path);
+ return NULL;
+ }
}
- print_verbose("Cannot find executable for '" PROP_NAME_MSBUILD_VS "'. Trying with '" PROP_NAME_MSBUILD_MONO "'...");
- } // FALL THROUGH
+ if (!msbuild_tools_path.ends_with("\\"))
+ msbuild_tools_path += "\\";
+
+ return GDMonoMarshal::mono_string_from_godot(msbuild_tools_path + "MSBuild.exe");
+ } break;
case GodotSharpBuilds::MSBUILD_MONO: {
String msbuild_path = GDMono::get_singleton()->get_mono_reg_info().bin_dir.plus_file("msbuild.bat");
if (!FileAccess::exists(msbuild_path)) {
- WARN_PRINTS("Cannot find executable for '" PROP_NAME_MSBUILD_MONO "'. Tried with path: " + msbuild_path);
+ ERR_PRINTS("Cannot find executable for '" PROP_NAME_MSBUILD_MONO "'. Tried with path: " + msbuild_path);
+ return NULL;
}
return GDMonoMarshal::mono_string_from_godot(msbuild_path);
@@ -124,7 +126,8 @@ MonoString *godot_icall_BuildInstance_get_MSBuildPath() {
String xbuild_path = GDMono::get_singleton()->get_mono_reg_info().bin_dir.plus_file("xbuild.bat");
if (!FileAccess::exists(xbuild_path)) {
- WARN_PRINTS("Cannot find executable for '" PROP_NAME_XBUILD "'. Tried with path: " + xbuild_path);
+ ERR_PRINTS("Cannot find executable for '" PROP_NAME_XBUILD "'. Tried with path: " + xbuild_path);
+ return NULL;
}
return GDMonoMarshal::mono_string_from_godot(xbuild_path);
@@ -144,7 +147,7 @@ MonoString *godot_icall_BuildInstance_get_MSBuildPath() {
}
if (xbuild_path.empty()) {
- WARN_PRINT("Cannot find binary for '" PROP_NAME_XBUILD "'");
+ ERR_PRINT("Cannot find binary for '" PROP_NAME_XBUILD "'");
return NULL;
}
} else {
@@ -154,7 +157,7 @@ MonoString *godot_icall_BuildInstance_get_MSBuildPath() {
}
if (msbuild_path.empty()) {
- WARN_PRINT("Cannot find binary for '" PROP_NAME_MSBUILD_MONO "'");
+ ERR_PRINT("Cannot find binary for '" PROP_NAME_MSBUILD_MONO "'");
return NULL;
}
}
@@ -168,22 +171,6 @@ MonoString *godot_icall_BuildInstance_get_MSBuildPath() {
#endif
}
-MonoString *godot_icall_BuildInstance_get_FrameworkPath() {
-
-#if defined(WINDOWS_ENABLED)
- const MonoRegInfo &mono_reg_info = GDMono::get_singleton()->get_mono_reg_info();
- if (mono_reg_info.assembly_dir.length()) {
- String framework_path = path_join(mono_reg_info.assembly_dir, "mono", "4.5");
- return GDMonoMarshal::mono_string_from_godot(framework_path);
- }
-
- ERR_EXPLAIN("Cannot find Mono's assemblies directory in the registry");
- ERR_FAIL_V(NULL);
-#else
- return NULL;
-#endif
-}
-
MonoString *godot_icall_BuildInstance_get_MonoWindowsBinDir() {
#if defined(WINDOWS_ENABLED)
@@ -208,6 +195,11 @@ MonoBoolean godot_icall_BuildInstance_get_UsingMonoMSBuildOnWindows() {
#endif
}
+MonoBoolean godot_icall_BuildInstance_get_PrintBuildOutput() {
+
+ return (bool)EDITOR_GET("mono/builds/print_build_output");
+}
+
void GodotSharpBuilds::register_internal_calls() {
static bool registered = false;
@@ -216,9 +208,9 @@ void GodotSharpBuilds::register_internal_calls() {
mono_add_internal_call("GodotSharpTools.Build.BuildSystem::godot_icall_BuildInstance_ExitCallback", (void *)godot_icall_BuildInstance_ExitCallback);
mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_MSBuildPath", (void *)godot_icall_BuildInstance_get_MSBuildPath);
- mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_FrameworkPath", (void *)godot_icall_BuildInstance_get_FrameworkPath);
mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_MonoWindowsBinDir", (void *)godot_icall_BuildInstance_get_MonoWindowsBinDir);
mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_UsingMonoMSBuildOnWindows", (void *)godot_icall_BuildInstance_get_UsingMonoMSBuildOnWindows);
+ mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_PrintBuildOutput", (void *)godot_icall_BuildInstance_get_PrintBuildOutput);
}
void GodotSharpBuilds::show_build_error_dialog(const String &p_message) {
@@ -381,6 +373,9 @@ bool GodotSharpBuilds::build_project_blocking(const String &p_config) {
bool GodotSharpBuilds::editor_build_callback() {
+ if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path()))
+ return true; // No solution to build
+
String scripts_metadata_path_editor = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata.editor");
String scripts_metadata_path_player = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata.editor_player");
@@ -456,7 +451,11 @@ GodotSharpBuilds::GodotSharpBuilds() {
// Build tool settings
EditorSettings *ed_settings = EditorSettings::get_singleton();
+#ifdef WINDOWS_ENABLED
+ EDITOR_DEF("mono/builds/build_tool", MSBUILD_VS);
+#else
EDITOR_DEF("mono/builds/build_tool", MSBUILD_MONO);
+#endif
ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/builds/build_tool", PROPERTY_HINT_ENUM,
PROP_NAME_MSBUILD_MONO
@@ -464,6 +463,8 @@ GodotSharpBuilds::GodotSharpBuilds() {
"," PROP_NAME_MSBUILD_VS
#endif
"," PROP_NAME_XBUILD));
+
+ EDITOR_DEF("mono/builds/print_build_output", false);
}
GodotSharpBuilds::~GodotSharpBuilds() {
@@ -514,7 +515,7 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) {
// Remove old issues file
- String issues_file = "msbuild_issues.csv";
+ String issues_file = get_msbuild_issues_filename();
DirAccessRef d = DirAccess::create_for_path(log_dirpath);
if (d->file_exists(issues_file)) {
Error err = d->remove(issues_file);
@@ -581,7 +582,8 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) {
exit_code = klass->get_field("exitCode")->get_int_value(mono_object);
if (exit_code != 0) {
- print_verbose("MSBuild finished with exit code " + itos(exit_code));
+ String log_filepath = build_info.get_log_dirpath().plus_file(get_msbuild_log_filename());
+ print_verbose("MSBuild exited with code: " + itos(exit_code) + ". Log file: " + log_filepath);
}
build_tab->on_build_exit(exit_code == 0 ? MonoBuildTab::RESULT_SUCCESS : MonoBuildTab::RESULT_ERROR);
diff --git a/modules/mono/editor/godotsharp_builds.h b/modules/mono/editor/godotsharp_builds.h
index 7f38b0aa49..652d30538a 100644
--- a/modules/mono/editor/godotsharp_builds.h
+++ b/modules/mono/editor/godotsharp_builds.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -76,6 +76,9 @@ public:
static void show_build_error_dialog(const String &p_message);
+ static const char *get_msbuild_issues_filename() { return "msbuild_issues.csv"; }
+ static const char *get_msbuild_log_filename() { return "msbuild_log.txt"; }
+
void build_exit_callback(const MonoBuildInfo &p_build_info, int p_exit_code);
void restart_build(MonoBuildTab *p_build_tab);
diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp
index cce86efbf5..9d42528927 100644
--- a/modules/mono/editor/godotsharp_editor.cpp
+++ b/modules/mono/editor/godotsharp_editor.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,6 +30,7 @@
#include "godotsharp_editor.h"
+#include "core/message_queue.h"
#include "core/os/os.h"
#include "core/project_settings.h"
#include "scene/gui/control.h"
@@ -114,10 +115,33 @@ bool GodotSharpEditor::_create_project_solution() {
void GodotSharpEditor::_make_api_solutions_if_needed() {
// I'm sick entirely of ProgressDialog
+
+ static int attempts_left = 100;
+
+ if (MessageQueue::get_singleton()->is_flushing() || !SceneTree::get_singleton()) {
+ ERR_FAIL_COND(attempts_left == 0); // You've got to be kidding
+
+ if (SceneTree::get_singleton()) {
+ SceneTree::get_singleton()->connect("idle_frame", this, "_make_api_solutions_if_needed", Vector<Variant>());
+ } else {
+ call_deferred("_make_api_solutions_if_needed");
+ }
+
+ attempts_left--;
+ return;
+ }
+
+ // Recursion guard needed because signals don't play well with ProgressDialog either, but unlike
+ // the message queue, with signals the collateral damage should be minimal in the worst case.
static bool recursion_guard = false;
if (!recursion_guard) {
recursion_guard = true;
+
+ // Oneshot signals don't play well with ProgressDialog either, so we do it this way instead
+ SceneTree::get_singleton()->disconnect("idle_frame", this, "_make_api_solutions_if_needed");
+
_make_api_solutions_if_needed_impl();
+
recursion_guard = false;
}
}
@@ -143,9 +167,6 @@ void GodotSharpEditor::_remove_create_sln_menu_option() {
menu_popup->remove_item(menu_popup->get_item_index(MENU_CREATE_SLN));
- if (menu_popup->get_item_count() == 0)
- menu_button->hide();
-
bottom_panel_btn->show();
}
@@ -164,6 +185,16 @@ void GodotSharpEditor::_toggle_about_dialog_on_start(bool p_enabled) {
}
}
+void GodotSharpEditor::_build_solution_pressed() {
+
+ if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path())) {
+ if (!_create_project_solution())
+ return; // Failed to create solution
+ }
+
+ MonoBottomPanel::get_singleton()->call("_build_project_pressed");
+}
+
void GodotSharpEditor::_menu_option_pressed(int p_id) {
switch (p_id) {
@@ -199,6 +230,7 @@ void GodotSharpEditor::_notification(int p_notification) {
void GodotSharpEditor::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_build_solution_pressed"), &GodotSharpEditor::_build_solution_pressed);
ClassDB::bind_method(D_METHOD("_create_project_solution"), &GodotSharpEditor::_create_project_solution);
ClassDB::bind_method(D_METHOD("_make_api_solutions_if_needed"), &GodotSharpEditor::_make_api_solutions_if_needed);
ClassDB::bind_method(D_METHOD("_remove_create_sln_menu_option"), &GodotSharpEditor::_remove_create_sln_menu_option);
@@ -249,7 +281,29 @@ Error GodotSharpEditor::open_in_external_editor(const Ref<Script> &p_script, int
if (vscode_path.empty() || !FileAccess::exists(vscode_path)) {
// Try to search it again if it wasn't found last time or if it was removed from its location
- vscode_path = path_which("code");
+ bool found = false;
+
+ // TODO: Use initializer lists once C++11 is allowed
+
+ static Vector<String> vscode_names;
+ if (vscode_names.empty()) {
+ vscode_names.push_back("code");
+ vscode_names.push_back("code-oss");
+ vscode_names.push_back("vscode");
+ vscode_names.push_back("vscode-oss");
+ vscode_names.push_back("visual-studio-code");
+ vscode_names.push_back("visual-studio-code-oss");
+ }
+ for (int i = 0; i < vscode_names.size(); i++) {
+ vscode_path = path_which(vscode_names[i]);
+ if (!vscode_path.empty()) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ vscode_path.clear(); // Not found, clear so next time the empty() check is enough
}
List<String> args;
@@ -367,9 +421,12 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) {
editor->add_child(memnew(MonoReloadNode));
- menu_button = memnew(MenuButton);
- menu_button->set_text(TTR("Mono"));
- menu_popup = menu_button->get_popup();
+ menu_popup = memnew(PopupMenu);
+ menu_popup->hide();
+ menu_popup->set_as_toplevel(true);
+ menu_popup->set_pass_on_modal_close_click(false);
+
+ editor->add_tool_submenu_item("Mono", menu_popup);
// TODO: Remove or edit this info dialog once Mono support is no longer in alpha
{
@@ -400,12 +457,12 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) {
about_label->set_v_size_flags(Control::SIZE_EXPAND_FILL);
about_label->set_autowrap(true);
String about_text =
- String("C# support in Godot Engine is a brand new feature and a work in progress.\n") +
- "It is currently in an alpha stage and is not suitable for use in production.\n\n" +
- "As of Godot 3.1, C# support is not feature-complete and may crash in some situations. " +
- "Bugs and usability issues will be addressed gradually over future 3.x releases, " +
- "including compatibility breaking changes as new features are implemented for a better overall C# experience.\n\n" +
- "If you experience issues with this Mono build, please report them on Godot's issue tracker with details about your system, Mono version, IDE, etc:\n\n" +
+ String("C# support in Godot Engine is in late alpha stage and, while already usable, ") +
+ "it is not meant for use in production.\n\n" +
+ "Projects can be exported to Linux, macOS and Windows, but not yet to mobile or web platforms. " +
+ "Bugs and usability issues will be addressed gradually over future releases, " +
+ "potentially including compatibility breaking changes as new features are implemented for a better overall C# experience.\n\n" +
+ "If you experience issues with this Mono build, please report them on Godot's issue tracker with details about your system, MSBuild version, IDE, etc.:\n\n" +
" https://github.com/godotengine/godot/issues\n\n" +
"Your critical feedback at this stage will play a great role in shaping the C# support in future releases, so thank you!";
about_label->set_text(about_text);
@@ -423,7 +480,7 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) {
String csproj_path = GodotSharpDirs::get_project_csproj_path();
if (FileAccess::exists(sln_path) && FileAccess::exists(csproj_path)) {
- // We can't use EditorProgress here. It calls Main::iterarion() and the main loop is not initialized yet.
+ // Defer this task because EditorProgress calls Main::iterarion() and the main loop is not yet initialized.
call_deferred("_make_api_solutions_if_needed");
} else {
bottom_panel_btn->hide();
@@ -432,22 +489,24 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) {
menu_popup->connect("id_pressed", this, "_menu_option_pressed");
- if (menu_popup->get_item_count() == 0)
- menu_button->hide();
-
- editor->get_menu_hb()->add_child(menu_button);
+ ToolButton *build_button = memnew(ToolButton);
+ build_button->set_text("Build");
+ build_button->set_tooltip("Build solution");
+ build_button->set_focus_mode(Control::FOCUS_NONE);
+ build_button->connect("pressed", this, "_build_solution_pressed");
+ editor->get_menu_hb()->add_child(build_button);
// External editor settings
EditorSettings *ed_settings = EditorSettings::get_singleton();
EDITOR_DEF("mono/editor/external_editor", EDITOR_NONE);
- String settings_hint_str = "None";
+ String settings_hint_str = "Disabled";
-#ifdef WINDOWS_ENABLED
+#if defined(WINDOWS_ENABLED)
settings_hint_str += ",MonoDevelop,Visual Studio Code";
-#elif OSX_ENABLED
+#elif defined(OSX_ENABLED)
settings_hint_str += ",Visual Studio,MonoDevelop,Visual Studio Code";
-#elif UNIX_ENABLED
+#elif defined(UNIX_ENABLED)
settings_hint_str += ",MonoDevelop,Visual Studio Code";
#endif
diff --git a/modules/mono/editor/godotsharp_editor.h b/modules/mono/editor/godotsharp_editor.h
index 9fb0e40132..d9523c384c 100644
--- a/modules/mono/editor/godotsharp_editor.h
+++ b/modules/mono/editor/godotsharp_editor.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -65,6 +65,8 @@ class GodotSharpEditor : public Node {
void _menu_option_pressed(int p_id);
+ void _build_solution_pressed();
+
static GodotSharpEditor *singleton;
protected:
@@ -79,15 +81,15 @@ public:
enum ExternalEditor {
EDITOR_NONE,
-#ifdef WINDOWS_ENABLED
+#if defined(WINDOWS_ENABLED)
//EDITOR_VISUALSTUDIO, // TODO
EDITOR_MONODEVELOP,
EDITOR_VSCODE
-#elif OSX_ENABLED
+#elif defined(OSX_ENABLED)
EDITOR_VISUALSTUDIO_MAC,
EDITOR_MONODEVELOP,
EDITOR_VSCODE
-#elif UNIX_ENABLED
+#elif defined(UNIX_ENABLED)
EDITOR_MONODEVELOP,
EDITOR_VSCODE
#endif
diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp
index 34c710320a..ee5fed1a0c 100644
--- a/modules/mono/editor/godotsharp_export.cpp
+++ b/modules/mono/editor/godotsharp_export.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -85,53 +85,55 @@ void GodotSharpExport::_export_begin(const Set<String> &p_features, bool p_debug
ERR_FAIL_NULL(TOOLS_DOMAIN);
ERR_FAIL_NULL(GDMono::get_singleton()->get_editor_tools_assembly());
- String build_config = p_debug ? "Debug" : "Release";
+ if (FileAccess::exists(GodotSharpDirs::get_project_sln_path())) {
+ String build_config = p_debug ? "Debug" : "Release";
- String scripts_metadata_path = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata." + String(p_debug ? "debug" : "release"));
- Error metadata_err = CSharpProject::generate_scripts_metadata(GodotSharpDirs::get_project_csproj_path(), scripts_metadata_path);
- ERR_FAIL_COND(metadata_err != OK);
+ String scripts_metadata_path = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata." + String(p_debug ? "debug" : "release"));
+ Error metadata_err = CSharpProject::generate_scripts_metadata(GodotSharpDirs::get_project_csproj_path(), scripts_metadata_path);
+ ERR_FAIL_COND(metadata_err != OK);
- ERR_FAIL_COND(!_add_file(scripts_metadata_path, scripts_metadata_path));
+ ERR_FAIL_COND(!_add_file(scripts_metadata_path, scripts_metadata_path));
- ERR_FAIL_COND(!GodotSharpBuilds::build_project_blocking(build_config));
+ ERR_FAIL_COND(!GodotSharpBuilds::build_project_blocking(build_config));
- // Add dependency assemblies
+ // Add dependency assemblies
- Map<String, String> dependencies;
+ 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_name = ProjectSettings::get_singleton()->get("application/config/name");
+ if (project_dll_name.empty()) {
+ project_dll_name = "UnnamedProject";
+ }
- 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);
+ 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);
- {
- MonoDomain *export_domain = GDMonoUtils::create_domain("GodotEngine.ProjectExportDomain");
- ERR_FAIL_NULL(export_domain);
- _GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(export_domain);
+ {
+ MonoDomain *export_domain = GDMonoUtils::create_domain("GodotEngine.ProjectExportDomain");
+ ERR_FAIL_NULL(export_domain);
+ _GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(export_domain);
- _GDMONO_SCOPE_DOMAIN_(export_domain);
+ _GDMONO_SCOPE_DOMAIN_(export_domain);
- GDMonoAssembly *scripts_assembly = NULL;
- bool load_success = GDMono::get_singleton()->load_assembly_from(project_dll_name,
- project_dll_src_path, &scripts_assembly, /* refonly: */ true);
+ GDMonoAssembly *scripts_assembly = NULL;
+ bool load_success = GDMono::get_singleton()->load_assembly_from(project_dll_name,
+ project_dll_src_path, &scripts_assembly, /* refonly: */ true);
- ERR_EXPLAIN("Cannot load refonly assembly: " + project_dll_name);
- ERR_FAIL_COND(!load_success);
+ ERR_EXPLAIN("Cannot load refonly assembly: " + project_dll_name);
+ ERR_FAIL_COND(!load_success);
- 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);
- }
+ Vector<String> search_dirs;
+ GDMonoAssembly::fill_search_dirs(search_dirs, build_config);
+ 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_file(depend_src_path, depend_dst_path));
+ 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_file(depend_src_path, depend_dst_path));
+ }
}
// Mono specific export template extras (data dir)
@@ -192,8 +194,8 @@ Error GodotSharpExport::_get_assembly_dependencies(GDMonoAssembly *p_assembly, c
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];
+ for (int j = 0; j < p_search_dirs.size(); j++) {
+ const String &search_dir = p_search_dirs[j];
if (has_extension) {
path = search_dir.plus_file(ref_name);
diff --git a/modules/mono/editor/godotsharp_export.h b/modules/mono/editor/godotsharp_export.h
index 10d4375567..4dc8ea75d5 100644
--- a/modules/mono/editor/godotsharp_export.h
+++ b/modules/mono/editor/godotsharp_export.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/editor/mono_bottom_panel.cpp b/modules/mono/editor/mono_bottom_panel.cpp
index e89d21d92d..21ce9ca5c4 100644
--- a/modules/mono/editor/mono_bottom_panel.cpp
+++ b/modules/mono/editor/mono_bottom_panel.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,6 +30,9 @@
#include "mono_bottom_panel.h"
+#include "editor/plugins/script_editor_plugin.h"
+#include "editor/script_editor_debugger.h"
+
#include "../csharp_script.h"
#include "../godotsharp_dirs.h"
#include "csharp_project.h"
@@ -122,9 +125,14 @@ void MonoBottomPanel::_build_tabs_item_selected(int p_idx) {
void MonoBottomPanel::_build_tabs_nothing_selected() {
- if (build_tabs->get_tab_count() != 0) // just in case
+ if (build_tabs->get_tab_count() != 0) { // just in case
build_tabs->set_visible(false);
+ // This callback is called when clicking on the empty space of the list.
+ // ItemList won't deselect the items automatically, so we must do it ourselves.
+ build_tabs_list->unselect_all();
+ }
+
warnings_btn->set_visible(false);
errors_btn->set_visible(false);
view_log_btn->set_visible(false);
@@ -150,14 +158,32 @@ void MonoBottomPanel::_errors_toggled(bool p_pressed) {
void MonoBottomPanel::_build_project_pressed() {
- String scripts_metadata_path = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata.editor");
- Error metadata_err = CSharpProject::generate_scripts_metadata(GodotSharpDirs::get_project_csproj_path(), scripts_metadata_path);
+ if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path()))
+ return; // No solution to build
+
+ String scripts_metadata_path_editor = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata.editor");
+ String scripts_metadata_path_player = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata.editor_player");
+
+ Error metadata_err = CSharpProject::generate_scripts_metadata(GodotSharpDirs::get_project_csproj_path(), scripts_metadata_path_editor);
ERR_FAIL_COND(metadata_err != OK);
+ if (FileAccess::exists(scripts_metadata_path_editor)) {
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ Error copy_err = da->copy(scripts_metadata_path_editor, scripts_metadata_path_player);
+
+ ERR_EXPLAIN("Failed to copy scripts metadata file");
+ ERR_FAIL_COND(copy_err != OK);
+ }
+
bool build_success = GodotSharpBuilds::get_singleton()->build_project_blocking("Tools");
if (build_success) {
+ // Notify running game for hot-reload
+ ScriptEditor::get_singleton()->get_debugger()->reload_scripts();
+
+ // Hot-reload in the editor
MonoReloadNode::get_singleton()->restart_reload_timer();
+
if (CSharpLanguage::get_singleton()->is_assembly_reloading_needed()) {
CSharpLanguage::get_singleton()->reload_assemblies(false);
}
@@ -176,7 +202,7 @@ void MonoBottomPanel::_view_log_pressed() {
String log_dirpath = build_tab->get_build_info().get_log_dirpath();
- OS::get_singleton()->shell_open(log_dirpath.plus_file("msbuild_log.txt"));
+ OS::get_singleton()->shell_open(log_dirpath.plus_file(GodotSharpBuilds::get_msbuild_log_filename()));
}
}
@@ -410,7 +436,7 @@ void MonoBuildTab::on_build_exit(BuildResult result) {
build_exited = true;
build_result = result;
- _load_issues_from_file(logs_dir.plus_file("msbuild_issues.csv"));
+ _load_issues_from_file(logs_dir.plus_file(GodotSharpBuilds::get_msbuild_issues_filename()));
_update_issues_list();
MonoBottomPanel::get_singleton()->raise_build_tab(this);
diff --git a/modules/mono/editor/mono_bottom_panel.h b/modules/mono/editor/mono_bottom_panel.h
index 03240e9a13..406e46f7ce 100644
--- a/modules/mono/editor/mono_bottom_panel.h
+++ b/modules/mono/editor/mono_bottom_panel.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -51,8 +51,8 @@ class MonoBottomPanel : public VBoxContainer {
ItemList *build_tabs_list;
TabContainer *build_tabs;
- Button *warnings_btn;
- Button *errors_btn;
+ ToolButton *warnings_btn;
+ ToolButton *errors_btn;
Button *view_log_btn;
void _update_build_tabs_list();
diff --git a/modules/mono/editor/mono_build_info.cpp b/modules/mono/editor/mono_build_info.cpp
index e4af2aac4f..b386c06435 100644
--- a/modules/mono/editor/mono_build_info.cpp
+++ b/modules/mono/editor/mono_build_info.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/editor/mono_build_info.h b/modules/mono/editor/mono_build_info.h
index 64ba0f4037..b0ae2ed52e 100644
--- a/modules/mono/editor/mono_build_info.h
+++ b/modules/mono/editor/mono_build_info.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/editor/monodevelop_instance.cpp b/modules/mono/editor/monodevelop_instance.cpp
index 1d858d80bf..3caa56d1d0 100644
--- a/modules/mono/editor/monodevelop_instance.cpp
+++ b/modules/mono/editor/monodevelop_instance.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/editor/monodevelop_instance.h b/modules/mono/editor/monodevelop_instance.h
index 29de4a4735..3b3af9607b 100644
--- a/modules/mono/editor/monodevelop_instance.h
+++ b/modules/mono/editor/monodevelop_instance.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/editor/script_class_parser.cpp b/modules/mono/editor/script_class_parser.cpp
index 9042bff74a..dfb652a7aa 100644
--- a/modules/mono/editor/script_class_parser.cpp
+++ b/modules/mono/editor/script_class_parser.cpp
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* script_class_parser.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
#include "script_class_parser.h"
#include "core/map.h"
@@ -236,6 +266,20 @@ Error ScriptClassParser::_skip_generic_type_params() {
if (tk == TK_IDENTIFIER) {
tk = get_token();
+ // Type specifications can end with "?" to denote nullable types, such as IList<int?>
+ if (tk == TK_SYMBOL) {
+ tk = get_token();
+ if (value.operator String() != "?") {
+ error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found unexpected symbol '" + value + "'";
+ error = true;
+ return ERR_PARSE_ERROR;
+ }
+ if (tk != TK_OP_GREATER && tk != TK_COMMA) {
+ error_str = "Nullable type symbol '?' is only allowed after an identifier, but found " + get_token_name(tk) + " next.";
+ error = true;
+ return ERR_PARSE_ERROR;
+ }
+ }
if (tk == TK_PERIOD) {
while (true) {
@@ -292,6 +336,15 @@ Error ScriptClassParser::_parse_type_full_name(String &r_full_name) {
r_full_name += String(value);
+ if (code[idx] == '<') {
+ idx++;
+
+ // We don't mind if the base is generic, but we skip it any ways since this information is not needed
+ Error err = _skip_generic_type_params();
+ if (err)
+ return err;
+ }
+
if (code[idx] != '.') // We only want to take the next token if it's a period
return OK;
@@ -314,22 +367,12 @@ Error ScriptClassParser::_parse_class_base(Vector<String> &r_base) {
Token tk = get_token();
- bool generic = false;
- if (tk == TK_OP_LESS) {
- Error err = _skip_generic_type_params();
- if (err)
- return err;
- // We don't add it to the base list if it's generic
- generic = true;
- tk = get_token();
- }
-
if (tk == TK_COMMA) {
- Error err = _parse_class_base(r_base);
+ err = _parse_class_base(r_base);
if (err)
return err;
} else if (tk == TK_IDENTIFIER && String(value) == "where") {
- Error err = _parse_type_constraints();
+ err = _parse_type_constraints();
if (err) {
return err;
}
@@ -343,9 +386,7 @@ Error ScriptClassParser::_parse_class_base(Vector<String> &r_base) {
return ERR_PARSE_ERROR;
}
- if (!generic) {
- r_base.push_back(name);
- }
+ r_base.push_back(name);
return OK;
}
@@ -537,7 +578,7 @@ Error ScriptClassParser::parse(const String &p_code) {
if (full_name.length())
full_name += ".";
full_name += class_decl.name;
- OS::get_singleton()->print(String("Ignoring generic class declaration: " + class_decl.name).utf8());
+ OS::get_singleton()->print("Ignoring generic class declaration: %s\n", class_decl.name.utf8().get_data());
}
}
} else if (tk == TK_IDENTIFIER && String(value) == "struct") {
diff --git a/modules/mono/editor/script_class_parser.h b/modules/mono/editor/script_class_parser.h
index 184adebaf2..39003336ac 100644
--- a/modules/mono/editor/script_class_parser.h
+++ b/modules/mono/editor/script_class_parser.h
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* script_class_parser.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
#ifndef SCRIPT_CLASS_PARSER_H
#define SCRIPT_CLASS_PARSER_H
diff --git a/modules/mono/glue/Managed/Files/Array.cs b/modules/mono/glue/Managed/Files/Array.cs
index d5a35d7ae0..0e7b0362e0 100644
--- a/modules/mono/glue/Managed/Files/Array.cs
+++ b/modules/mono/glue/Managed/Files/Array.cs
@@ -28,7 +28,7 @@ namespace Godot.Collections
}
}
- public class Array : IList<object>, ICollection<object>, IEnumerable<object>, IDisposable
+ public class Array : IList, IDisposable
{
ArraySafeHandle safeHandle;
bool disposed = false;
@@ -38,6 +38,14 @@ namespace Godot.Collections
safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor());
}
+ public Array(IEnumerable collection) : this()
+ {
+ if (collection == null)
+ throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'");
+
+ MarshalUtils.EnumerableToArray(collection, GetPtr());
+ }
+
internal Array(ArraySafeHandle handle)
{
safeHandle = handle;
@@ -50,9 +58,19 @@ namespace Godot.Collections
internal IntPtr GetPtr()
{
+ if (disposed)
+ throw new ObjectDisposedException(GetType().FullName);
+
return safeHandle.DangerousGetHandle();
}
+ public Error Resize(int newSize)
+ {
+ return godot_icall_Array_Resize(GetPtr(), newSize);
+ }
+
+ // IDisposable
+
public void Dispose()
{
if (disposed)
@@ -67,62 +85,55 @@ namespace Godot.Collections
disposed = true;
}
+ // IList
+
+ public bool IsReadOnly => false;
+
+ public bool IsFixedSize => false;
+
public object this[int index]
{
- get
- {
- return godot_icall_Array_At(GetPtr(), index);
- }
- set
- {
- godot_icall_Array_SetAt(GetPtr(), index, value);
- }
+ get => godot_icall_Array_At(GetPtr(), index);
+ set => godot_icall_Array_SetAt(GetPtr(), index, value);
}
- public int Count
- {
- get
- {
- return godot_icall_Array_Count(GetPtr());
- }
- }
+ public int Add(object value) => godot_icall_Array_Add(GetPtr(), value);
- public bool IsReadOnly
- {
- get
- {
- return false;
- }
- }
+ public bool Contains(object value) => godot_icall_Array_Contains(GetPtr(), value);
- public void Add(object item)
- {
- godot_icall_Array_Add(GetPtr(), item);
- }
+ public void Clear() => godot_icall_Array_Clear(GetPtr());
- public void Clear()
- {
- godot_icall_Array_Clear(GetPtr());
- }
+ public int IndexOf(object value) => godot_icall_Array_IndexOf(GetPtr(), value);
- public bool Contains(object item)
- {
- return godot_icall_Array_Contains(GetPtr(), item);
- }
+ public void Insert(int index, object value) => godot_icall_Array_Insert(GetPtr(), index, value);
+
+ public void Remove(object value) => godot_icall_Array_Remove(GetPtr(), value);
- public void CopyTo(object[] array, int arrayIndex)
+ public void RemoveAt(int index) => godot_icall_Array_RemoveAt(GetPtr(), index);
+
+ // ICollection
+
+ public int Count => godot_icall_Array_Count(GetPtr());
+
+ public object SyncRoot => this;
+
+ public bool IsSynchronized => false;
+
+ public void CopyTo(System.Array array, int index)
{
if (array == null)
throw new ArgumentNullException(nameof(array), "Value cannot be null.");
- if (arrayIndex < 0)
- throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension.");
+ if (index < 0)
+ throw new ArgumentOutOfRangeException(nameof(index), "Number was less than the array's lower bound in the first dimension.");
// Internal call may throw ArgumentException
- godot_icall_Array_CopyTo(GetPtr(), array, arrayIndex);
+ godot_icall_Array_CopyTo(GetPtr(), array, index);
}
- public IEnumerator<object> GetEnumerator()
+ // IEnumerable
+
+ public IEnumerator GetEnumerator()
{
int count = Count;
@@ -132,29 +143,9 @@ namespace Godot.Collections
}
}
- public int IndexOf(object item)
+ public override string ToString()
{
- return godot_icall_Array_IndexOf(GetPtr(), item);
- }
-
- public void Insert(int index, object item)
- {
- godot_icall_Array_Insert(GetPtr(), index, item);
- }
-
- public bool Remove(object item)
- {
- return godot_icall_Array_Remove(GetPtr(), item);
- }
-
- public void RemoveAt(int index)
- {
- godot_icall_Array_RemoveAt(GetPtr(), index);
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
+ return godot_icall_Array_ToString(GetPtr());
}
[MethodImpl(MethodImplOptions.InternalCall)]
@@ -176,7 +167,7 @@ namespace Godot.Collections
internal extern static int godot_icall_Array_Count(IntPtr ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static void godot_icall_Array_Add(IntPtr ptr, object item);
+ internal extern static int godot_icall_Array_Add(IntPtr ptr, object item);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_Array_Clear(IntPtr ptr);
@@ -185,7 +176,7 @@ namespace Godot.Collections
internal extern static bool godot_icall_Array_Contains(IntPtr ptr, object item);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static void godot_icall_Array_CopyTo(IntPtr ptr, object[] array, int arrayIndex);
+ internal extern static void godot_icall_Array_CopyTo(IntPtr ptr, System.Array array, int arrayIndex);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static int godot_icall_Array_IndexOf(IntPtr ptr, object item);
@@ -200,7 +191,13 @@ namespace Godot.Collections
internal extern static void godot_icall_Array_RemoveAt(IntPtr ptr, int index);
[MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static Error godot_icall_Array_Resize(IntPtr ptr, int newSize);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_Array_Generic_GetElementTypeInfo(Type elemType, out int elemTypeEncoding, out IntPtr elemTypeClass);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static string godot_icall_Array_ToString(IntPtr ptr);
}
public class Array<T> : IList<T>, ICollection<T>, IEnumerable<T>
@@ -220,6 +217,14 @@ namespace Godot.Collections
objectArray = new Array();
}
+ public Array(IEnumerable<T> collection)
+ {
+ if (collection == null)
+ throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'");
+
+ objectArray = new Array(collection);
+ }
+
public Array(Array array)
{
objectArray = array;
@@ -235,11 +240,23 @@ namespace Godot.Collections
objectArray = new Array(handle);
}
+ internal IntPtr GetPtr()
+ {
+ return objectArray.GetPtr();
+ }
+
public static explicit operator Array(Array<T> from)
{
return from.objectArray;
}
+ public Error Resize(int newSize)
+ {
+ return objectArray.Resize(newSize);
+ }
+
+ // IList<T>
+
public T this[int index]
{
get
@@ -252,6 +269,23 @@ namespace Godot.Collections
}
}
+ public int IndexOf(T item)
+ {
+ return objectArray.IndexOf(item);
+ }
+
+ public void Insert(int index, T item)
+ {
+ objectArray.Insert(index, item);
+ }
+
+ public void RemoveAt(int index)
+ {
+ objectArray.RemoveAt(index);
+ }
+
+ // ICollection<T>
+
public int Count
{
get
@@ -306,6 +340,13 @@ namespace Godot.Collections
}
}
+ public bool Remove(T item)
+ {
+ return Array.godot_icall_Array_Remove(GetPtr(), item);
+ }
+
+ // IEnumerable<T>
+
public IEnumerator<T> GetEnumerator()
{
int count = objectArray.Count;
@@ -316,34 +357,11 @@ namespace Godot.Collections
}
}
- public int IndexOf(T item)
- {
- return objectArray.IndexOf(item);
- }
-
- public void Insert(int index, T item)
- {
- objectArray.Insert(index, item);
- }
-
- public bool Remove(T item)
- {
- return objectArray.Remove(item);
- }
-
- public void RemoveAt(int index)
- {
- objectArray.RemoveAt(index);
- }
-
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
- internal IntPtr GetPtr()
- {
- return objectArray.GetPtr();
- }
+ public override string ToString() => objectArray.ToString();
}
}
diff --git a/modules/mono/glue/Managed/Files/Basis.cs b/modules/mono/glue/Managed/Files/Basis.cs
index b318d96bb9..ac9576cebd 100644
--- a/modules/mono/glue/Managed/Files/Basis.cs
+++ b/modules/mono/glue/Managed/Files/Basis.cs
@@ -45,74 +45,119 @@ namespace Godot
new Basis(0f, -1f, 0f, 0f, 0f, -1f, 1f, 0f, 0f)
};
+ // NOTE: x, y and z are public-only. Use Column0, Column1 and Column2 internally.
+
+ /// <summary>
+ /// Returns the basis matrix’s x vector.
+ /// This is equivalent to <see cref="Column0"/>.
+ /// </summary>
public Vector3 x
{
- get { return GetAxis(0); }
- set { SetAxis(0, value); }
+ get => Column0;
+ set => Column0 = value;
}
+ /// <summary>
+ /// Returns the basis matrix’s y vector.
+ /// This is equivalent to <see cref="Column1"/>.
+ /// </summary>
public Vector3 y
{
- get { return GetAxis(1); }
- set { SetAxis(1, value); }
+
+ get => Column1;
+ set => Column1 = value;
}
+ /// <summary>
+ /// Returns the basis matrix’s z vector.
+ /// This is equivalent to <see cref="Column2"/>.
+ /// </summary>
public Vector3 z
{
- get { return GetAxis(2); }
- set { SetAxis(2, value); }
+
+ get => Column2;
+ set => Column2 = value;
}
- private Vector3 _x;
- private Vector3 _y;
- private Vector3 _z;
+ public Vector3 Row0;
+ public Vector3 Row1;
+ public Vector3 Row2;
- public static Basis Identity
+ public Vector3 Column0
+ {
+ get => new Vector3(Row0.x, Row1.x, Row2.x);
+ set
+ {
+ this.Row0.x = value.x;
+ this.Row1.x = value.y;
+ this.Row2.x = value.z;
+ }
+ }
+ public Vector3 Column1
{
- get { return identity; }
+ get => new Vector3(Row0.y, Row1.y, Row2.y);
+ set
+ {
+ this.Row0.y = value.x;
+ this.Row1.y = value.y;
+ this.Row2.y = value.z;
+ }
+ }
+ public Vector3 Column2
+ {
+ get => new Vector3(Row0.z, Row1.z, Row2.z);
+ set
+ {
+ this.Row0.z = value.x;
+ this.Row1.z = value.y;
+ this.Row2.z = value.z;
+ }
}
+ public static Basis Identity => identity;
+
public Vector3 Scale
{
get
{
- return new Vector3
+ real_t detSign = Mathf.Sign(Determinant());
+ return detSign * new Vector3
(
- new Vector3(this[0, 0], this[1, 0], this[2, 0]).Length(),
- new Vector3(this[0, 1], this[1, 1], this[2, 1]).Length(),
- new Vector3(this[0, 2], this[1, 2], this[2, 2]).Length()
+ new Vector3(this.Row0[0], this.Row1[0], this.Row2[0]).Length(),
+ new Vector3(this.Row0[1], this.Row1[1], this.Row2[1]).Length(),
+ new Vector3(this.Row0[2], this.Row1[2], this.Row2[2]).Length()
);
}
}
- public Vector3 this[int index]
+ public Vector3 this[int columnIndex]
{
get
{
- switch (index)
+ switch (columnIndex)
{
case 0:
- return _x;
+ return Column0;
case 1:
- return _y;
+ return Column1;
case 2:
- return _z;
+ return Column2;
default:
throw new IndexOutOfRangeException();
}
}
set
{
- switch (index)
+ switch (columnIndex)
{
case 0:
- _x = value;
+ Column0 = value;
return;
case 1:
- _y = value;
+ Column1 = value;
return;
case 2:
- _z = value;
+ Column2 = value;
return;
default:
throw new IndexOutOfRangeException();
@@ -120,51 +165,53 @@ namespace Godot
}
}
- public real_t this[int index, int axis]
+ public real_t this[int columnIndex, int rowIndex]
{
get
{
- switch (index)
+ switch (columnIndex)
{
case 0:
- return _x[axis];
+ return Column0[rowIndex];
case 1:
- return _y[axis];
+ return Column1[rowIndex];
case 2:
- return _z[axis];
+ return Column2[rowIndex];
default:
throw new IndexOutOfRangeException();
}
}
set
{
- switch (index)
+ switch (columnIndex)
{
case 0:
- _x[axis] = value;
+ {
+ var column0 = Column0;
+ column0[rowIndex] = value;
+ Column0 = column0;
return;
+ }
case 1:
- _y[axis] = value;
+ {
+ var column1 = Column1;
+ column1[rowIndex] = value;
+ Column1 = column1;
return;
+ }
case 2:
- _z[axis] = value;
+ {
+ var column2 = Column2;
+ column2[rowIndex] = value;
+ Column2 = column2;
return;
+ }
default:
throw new IndexOutOfRangeException();
}
}
}
- internal static Basis CreateFromAxes(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis)
- {
- return new Basis
- (
- xAxis.x, yAxis.x, zAxis.x,
- xAxis.y, yAxis.y, zAxis.y,
- xAxis.z, yAxis.z, zAxis.z
- );
- }
-
internal Quat RotationQuat()
{
Basis orthonormalizedBasis = Orthonormalized();
@@ -191,29 +238,19 @@ namespace Godot
private void SetDiagonal(Vector3 diagonal)
{
- _x = new Vector3(diagonal.x, 0, 0);
- _y = new Vector3(0, diagonal.y, 0);
- _z = new Vector3(0, 0, diagonal.z);
+ Row0 = new Vector3(diagonal.x, 0, 0);
+ Row1 = new Vector3(0, diagonal.y, 0);
+ Row2 = new Vector3(0, 0, diagonal.z);
}
public real_t Determinant()
{
- return this[0, 0] * (this[1, 1] * this[2, 2] - this[2, 1] * this[1, 2]) -
- this[1, 0] * (this[0, 1] * this[2, 2] - this[2, 1] * this[0, 2]) +
- this[2, 0] * (this[0, 1] * this[1, 2] - this[1, 1] * this[0, 2]);
- }
+ real_t cofac00 = Row1[1] * Row2[2] - Row1[2] * Row2[1];
+ real_t cofac10 = Row1[2] * Row2[0] - Row1[0] * Row2[2];
+ real_t cofac20 = Row1[0] * Row2[1] - Row1[1] * Row2[0];
- public Vector3 GetAxis(int axis)
- {
- return new Vector3(this[0, axis], this[1, axis], this[2, axis]);
- }
-
- public void SetAxis(int axis, Vector3 value)
- {
- this[0, axis] = value.x;
- this[1, axis] = value.y;
- this[2, axis] = value.z;
+ return Row0[0] * cofac00 + Row0[1] * cofac10 + Row0[2] * cofac20;
}
public Vector3 GetEuler()
@@ -223,32 +260,80 @@ namespace Godot
Vector3 euler;
euler.z = 0.0f;
- real_t mxy = m[1, 2];
-
+ real_t mxy = m.Row1[2];
if (mxy < 1.0f)
{
if (mxy > -1.0f)
{
euler.x = Mathf.Asin(-mxy);
- euler.y = Mathf.Atan2(m[0, 2], m[2, 2]);
- euler.z = Mathf.Atan2(m[1, 0], m[1, 1]);
+ euler.y = Mathf.Atan2(m.Row0[2], m.Row2[2]);
+ euler.z = Mathf.Atan2(m.Row1[0], m.Row1[1]);
}
else
{
euler.x = Mathf.Pi * 0.5f;
- euler.y = -Mathf.Atan2(-m[0, 1], m[0, 0]);
+ euler.y = -Mathf.Atan2(-m.Row0[1], m.Row0[0]);
}
}
else
{
euler.x = -Mathf.Pi * 0.5f;
- euler.y = -Mathf.Atan2(-m[0, 1], m[0, 0]);
+ euler.y = -Mathf.Atan2(-m.Row0[1], m.Row0[0]);
}
return euler;
}
+ public Vector3 GetRow(int index)
+ {
+ switch (index)
+ {
+ case 0:
+ return Row0;
+ case 1:
+ return Row1;
+ case 2:
+ return Row2;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+
+ public void SetRow(int index, Vector3 value)
+ {
+ switch (index)
+ {
+ case 0:
+ Row0 = value;
+ return;
+ case 1:
+ Row1 = value;
+ return;
+ case 2:
+ Row2 = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+
+ public Vector3 GetColumn(int index)
+ {
+ return this[index];
+ }
+
+ public void SetColumn(int index, Vector3 value)
+ {
+ this[index] = value;
+ }
+
+ [Obsolete("GetAxis is deprecated. Use GetColumn instead.")]
+ public Vector3 GetAxis(int axis)
+ {
+ return new Vector3(this.Row0[axis], this.Row1[axis], this.Row2[axis]);
+ }
+
public int GetOrthogonalIndex()
{
var orth = this;
@@ -257,7 +342,9 @@ namespace Godot
{
for (int j = 0; j < 3; j++)
{
- real_t v = orth[i, j];
+ var row = orth.GetRow(i);
+
+ real_t v = row[j];
if (v > 0.5f)
v = 1.0f;
@@ -266,7 +353,9 @@ namespace Godot
else
v = 0f;
- orth[i, j] = v;
+ row[j] = v;
+
+ orth.SetRow(i, row);
}
}
@@ -281,57 +370,45 @@ namespace Godot
public Basis Inverse()
{
- var inv = this;
-
- real_t[] co = {
- inv[1, 1] * inv[2, 2] - inv[1, 2] * inv[2, 1],
- inv[1, 2] * inv[2, 0] - inv[1, 0] * inv[2, 2],
- inv[1, 0] * inv[2, 1] - inv[1, 1] * inv[2, 0]
- };
+ real_t cofac00 = Row1[1] * Row2[2] - Row1[2] * Row2[1];
+ real_t cofac10 = Row1[2] * Row2[0] - Row1[0] * Row2[2];
+ real_t cofac20 = Row1[0] * Row2[1] - Row1[1] * Row2[0];
- real_t det = inv[0, 0] * co[0] + inv[0, 1] * co[1] + inv[0, 2] * co[2];
+ real_t det = Row0[0] * cofac00 + Row0[1] * cofac10 + Row0[2] * cofac20;
if (det == 0)
- {
- return new Basis
- (
- real_t.NaN, real_t.NaN, real_t.NaN,
- real_t.NaN, real_t.NaN, real_t.NaN,
- real_t.NaN, real_t.NaN, real_t.NaN
- );
- }
+ throw new InvalidOperationException("Matrix determinant is zero and cannot be inverted.");
- real_t s = 1.0f / det;
+ real_t detInv = 1.0f / det;
- inv = new Basis
+ real_t cofac01 = Row0[2] * Row2[1] - Row0[1] * Row2[2];
+ real_t cofac02 = Row0[1] * Row1[2] - Row0[2] * Row1[1];
+ real_t cofac11 = Row0[0] * Row2[2] - Row0[2] * Row2[0];
+ real_t cofac12 = Row0[2] * Row1[0] - Row0[0] * Row1[2];
+ real_t cofac21 = Row0[1] * Row2[0] - Row0[0] * Row2[1];
+ real_t cofac22 = Row0[0] * Row1[1] - Row0[1] * Row1[0];
+
+ return new Basis
(
- co[0] * s,
- inv[0, 2] * inv[2, 1] - inv[0, 1] * inv[2, 2] * s,
- inv[0, 1] * inv[1, 2] - inv[0, 2] * inv[1, 1] * s,
- co[1] * s,
- inv[0, 0] * inv[2, 2] - inv[0, 2] * inv[2, 0] * s,
- inv[0, 2] * inv[1, 0] - inv[0, 0] * inv[1, 2] * s,
- co[2] * s,
- inv[0, 1] * inv[2, 0] - inv[0, 0] * inv[2, 1] * s,
- inv[0, 0] * inv[1, 1] - inv[0, 1] * inv[1, 0] * s
+ cofac00 * detInv, cofac01 * detInv, cofac02 * detInv,
+ cofac10 * detInv, cofac11 * detInv, cofac12 * detInv,
+ cofac20 * detInv, cofac21 * detInv, cofac22 * detInv
);
-
- return inv;
}
public Basis Orthonormalized()
{
- Vector3 xAxis = GetAxis(0);
- Vector3 yAxis = GetAxis(1);
- Vector3 zAxis = GetAxis(2);
+ Vector3 column0 = GetColumn(0);
+ Vector3 column1 = GetColumn(1);
+ Vector3 column2 = GetColumn(2);
- xAxis.Normalize();
- yAxis = yAxis - xAxis * xAxis.Dot(yAxis);
- yAxis.Normalize();
- zAxis = zAxis - xAxis * xAxis.Dot(zAxis) - yAxis * yAxis.Dot(zAxis);
- zAxis.Normalize();
+ column0.Normalize();
+ column1 = column1 - column0 * column0.Dot(column1);
+ column1.Normalize();
+ column2 = column2 - column0 * column0.Dot(column2) - column1 * column1.Dot(column2);
+ column2.Normalize();
- return CreateFromAxes(xAxis, yAxis, zAxis);
+ return new Basis(column0, column1, column2);
}
public Basis Rotated(Vector3 axis, real_t phi)
@@ -343,49 +420,49 @@ namespace Godot
{
var m = this;
- m[0, 0] *= scale.x;
- m[0, 1] *= scale.x;
- m[0, 2] *= scale.x;
- m[1, 0] *= scale.y;
- m[1, 1] *= scale.y;
- m[1, 2] *= scale.y;
- m[2, 0] *= scale.z;
- m[2, 1] *= scale.z;
- m[2, 2] *= scale.z;
+ m.Row0[0] *= scale.x;
+ m.Row0[1] *= scale.x;
+ m.Row0[2] *= scale.x;
+ m.Row1[0] *= scale.y;
+ m.Row1[1] *= scale.y;
+ m.Row1[2] *= scale.y;
+ m.Row2[0] *= scale.z;
+ m.Row2[1] *= scale.z;
+ m.Row2[2] *= scale.z;
return m;
}
public real_t Tdotx(Vector3 with)
{
- return this[0, 0] * with[0] + this[1, 0] * with[1] + this[2, 0] * with[2];
+ return this.Row0[0] * with[0] + this.Row1[0] * with[1] + this.Row2[0] * with[2];
}
public real_t Tdoty(Vector3 with)
{
- return this[0, 1] * with[0] + this[1, 1] * with[1] + this[2, 1] * with[2];
+ return this.Row0[1] * with[0] + this.Row1[1] * with[1] + this.Row2[1] * with[2];
}
public real_t Tdotz(Vector3 with)
{
- return this[0, 2] * with[0] + this[1, 2] * with[1] + this[2, 2] * with[2];
+ return this.Row0[2] * with[0] + this.Row1[2] * with[1] + this.Row2[2] * with[2];
}
public Basis Transposed()
{
var tr = this;
- real_t temp = tr[0, 1];
- tr[0, 1] = tr[1, 0];
- tr[1, 0] = temp;
+ real_t temp = tr.Row0[1];
+ tr.Row0[1] = tr.Row1[0];
+ tr.Row1[0] = temp;
- temp = tr[0, 2];
- tr[0, 2] = tr[2, 0];
- tr[2, 0] = temp;
+ temp = tr.Row0[2];
+ tr.Row0[2] = tr.Row2[0];
+ tr.Row2[0] = temp;
- temp = tr[1, 2];
- tr[1, 2] = tr[2, 1];
- tr[2, 1] = temp;
+ temp = tr.Row1[2];
+ tr.Row1[2] = tr.Row2[1];
+ tr.Row2[1] = temp;
return tr;
}
@@ -394,9 +471,9 @@ namespace Godot
{
return new Vector3
(
- this[0].Dot(v),
- this[1].Dot(v),
- this[2].Dot(v)
+ this.Row0.Dot(v),
+ this.Row1.Dot(v),
+ this.Row2.Dot(v)
);
}
@@ -404,60 +481,60 @@ namespace Godot
{
return new Vector3
(
- this[0, 0] * v.x + this[1, 0] * v.y + this[2, 0] * v.z,
- this[0, 1] * v.x + this[1, 1] * v.y + this[2, 1] * v.z,
- this[0, 2] * v.x + this[1, 2] * v.y + this[2, 2] * v.z
+ this.Row0[0] * v.x + this.Row1[0] * v.y + this.Row2[0] * v.z,
+ this.Row0[1] * v.x + this.Row1[1] * v.y + this.Row2[1] * v.z,
+ this.Row0[2] * v.x + this.Row1[2] * v.y + this.Row2[2] * v.z
);
}
public Quat Quat()
{
- real_t trace = _x[0] + _y[1] + _z[2];
+ real_t trace = Row0[0] + Row1[1] + Row2[2];
if (trace > 0.0f)
{
real_t s = Mathf.Sqrt(trace + 1.0f) * 2f;
real_t inv_s = 1f / s;
return new Quat(
- (_z[1] - _y[2]) * inv_s,
- (_x[2] - _z[0]) * inv_s,
- (_y[0] - _x[1]) * inv_s,
+ (Row2[1] - Row1[2]) * inv_s,
+ (Row0[2] - Row2[0]) * inv_s,
+ (Row1[0] - Row0[1]) * inv_s,
s * 0.25f
);
}
- if (_x[0] > _y[1] && _x[0] > _z[2])
+ if (Row0[0] > Row1[1] && Row0[0] > Row2[2])
{
- real_t s = Mathf.Sqrt(_x[0] - _y[1] - _z[2] + 1.0f) * 2f;
+ real_t s = Mathf.Sqrt(Row0[0] - Row1[1] - Row2[2] + 1.0f) * 2f;
real_t inv_s = 1f / s;
return new Quat(
s * 0.25f,
- (_x[1] + _y[0]) * inv_s,
- (_x[2] + _z[0]) * inv_s,
- (_z[1] - _y[2]) * inv_s
+ (Row0[1] + Row1[0]) * inv_s,
+ (Row0[2] + Row2[0]) * inv_s,
+ (Row2[1] - Row1[2]) * inv_s
);
}
- if (_y[1] > _z[2])
+ if (Row1[1] > Row2[2])
{
- real_t s = Mathf.Sqrt(-_x[0] + _y[1] - _z[2] + 1.0f) * 2f;
+ real_t s = Mathf.Sqrt(-Row0[0] + Row1[1] - Row2[2] + 1.0f) * 2f;
real_t inv_s = 1f / s;
return new Quat(
- (_x[1] + _y[0]) * inv_s,
+ (Row0[1] + Row1[0]) * inv_s,
s * 0.25f,
- (_y[2] + _z[1]) * inv_s,
- (_x[2] - _z[0]) * inv_s
+ (Row1[2] + Row2[1]) * inv_s,
+ (Row0[2] - Row2[0]) * inv_s
);
}
else
{
- real_t s = Mathf.Sqrt(-_x[0] - _y[1] + _z[2] + 1.0f) * 2f;
+ real_t s = Mathf.Sqrt(-Row0[0] - Row1[1] + Row2[2] + 1.0f) * 2f;
real_t inv_s = 1f / s;
return new Quat(
- (_x[2] + _z[0]) * inv_s,
- (_y[2] + _z[1]) * inv_s,
+ (Row0[2] + Row2[0]) * inv_s,
+ (Row1[2] + Row2[1]) * inv_s,
s * 0.25f,
- (_y[0] - _x[1]) * inv_s
+ (Row1[0] - Row0[1]) * inv_s
);
}
}
@@ -479,9 +556,9 @@ namespace Godot
real_t yz = quat.y * zs;
real_t zz = quat.z * zs;
- _x = new Vector3(1.0f - (yy + zz), xy - wz, xz + wy);
- _y = new Vector3(xy + wz, 1.0f - (xx + zz), yz - wx);
- _z = new Vector3(xz - wy, yz + wx, 1.0f - (xx + yy));
+ Row0 = new Vector3(1.0f - (yy + zz), xy - wz, xz + wy);
+ Row1 = new Vector3(xy + wz, 1.0f - (xx + zz), yz - wx);
+ Row2 = new Vector3(xz - wy, yz + wx, 1.0f - (xx + yy));
}
public Basis(Vector3 euler)
@@ -511,21 +588,21 @@ namespace Godot
real_t cosine = Mathf.Cos(phi);
real_t sine = Mathf.Sin(phi);
- _x = new Vector3
+ Row0 = new Vector3
(
axis_sq.x + cosine * (1.0f - axis_sq.x),
axis.x * axis.y * (1.0f - cosine) - axis.z * sine,
axis.z * axis.x * (1.0f - cosine) + axis.y * sine
);
- _y = new Vector3
+ Row1 = new Vector3
(
axis.x * axis.y * (1.0f - cosine) + axis.z * sine,
axis_sq.y + cosine * (1.0f - axis_sq.y),
axis.y * axis.z * (1.0f - cosine) - axis.x * sine
);
- _z = new Vector3
+ Row2 = new Vector3
(
axis.z * axis.x * (1.0f - cosine) - axis.y * sine,
axis.y * axis.z * (1.0f - cosine) + axis.x * sine,
@@ -533,32 +610,32 @@ namespace Godot
);
}
- public Basis(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis)
+ public Basis(Vector3 column0, Vector3 column1, Vector3 column2)
{
- _x = new Vector3(xAxis.x, yAxis.x, zAxis.x);
- _y = new Vector3(xAxis.y, yAxis.y, zAxis.y);
- _z = new Vector3(xAxis.z, yAxis.z, zAxis.z);
+ Row0 = new Vector3(column0.x, column1.x, column2.x);
+ Row1 = new Vector3(column0.y, column1.y, column2.y);
+ Row2 = new Vector3(column0.z, column1.z, column2.z);
// Same as:
- // SetAxis(0, xAxis);
- // SetAxis(1, yAxis);
- // SetAxis(2, zAxis);
- // We need to assign the struct fields so we can't do that...
+ // Column0 = column0;
+ // Column1 = column1;
+ // Column2 = column2;
+ // We need to assign the struct fields here first so we can't do it that way...
}
internal Basis(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz)
{
- _x = new Vector3(xx, xy, xz);
- _y = new Vector3(yx, yy, yz);
- _z = new Vector3(zx, zy, zz);
+ Row0 = new Vector3(xx, xy, xz);
+ Row1 = new Vector3(yx, yy, yz);
+ Row2 = new Vector3(zx, zy, zz);
}
public static Basis operator *(Basis left, Basis right)
{
return new Basis
(
- right.Tdotx(left[0]), right.Tdoty(left[0]), right.Tdotz(left[0]),
- right.Tdotx(left[1]), right.Tdoty(left[1]), right.Tdotz(left[1]),
- right.Tdotx(left[2]), right.Tdoty(left[2]), right.Tdotz(left[2])
+ right.Tdotx(left.Row0), right.Tdoty(left.Row0), right.Tdotz(left.Row0),
+ right.Tdotx(left.Row1), right.Tdoty(left.Row1), right.Tdotz(left.Row1),
+ right.Tdotx(left.Row2), right.Tdoty(left.Row2), right.Tdotz(left.Row2)
);
}
@@ -584,21 +661,21 @@ namespace Godot
public bool Equals(Basis other)
{
- return _x.Equals(other[0]) && _y.Equals(other[1]) && _z.Equals(other[2]);
+ return Row0.Equals(other.Row0) && Row1.Equals(other.Row1) && Row2.Equals(other.Row2);
}
public override int GetHashCode()
{
- return _x.GetHashCode() ^ _y.GetHashCode() ^ _z.GetHashCode();
+ return Row0.GetHashCode() ^ Row1.GetHashCode() ^ Row2.GetHashCode();
}
public override string ToString()
{
return String.Format("({0}, {1}, {2})", new object[]
{
- _x.ToString(),
- _y.ToString(),
- _z.ToString()
+ Row0.ToString(),
+ Row1.ToString(),
+ Row2.ToString()
});
}
@@ -606,9 +683,9 @@ namespace Godot
{
return String.Format("({0}, {1}, {2})", new object[]
{
- _x.ToString(format),
- _y.ToString(format),
- _z.ToString(format)
+ Row0.ToString(format),
+ Row1.ToString(format),
+ Row2.ToString(format)
});
}
}
diff --git a/modules/mono/glue/Managed/Files/Color.cs b/modules/mono/glue/Managed/Files/Color.cs
index fc5bb010a9..88fa3323c2 100644
--- a/modules/mono/glue/Managed/Files/Color.cs
+++ b/modules/mono/glue/Managed/Files/Color.cs
@@ -104,17 +104,26 @@ namespace Godot
}
}
- private static readonly Color black = new Color(0f, 0f, 0f);
-
- public Color Black
+ public static Color ColorN(string name, float alpha = 1f)
{
- get
+ name = name.Replace(" ", String.Empty);
+ name = name.Replace("-", String.Empty);
+ name = name.Replace("_", String.Empty);
+ name = name.Replace("'", String.Empty);
+ name = name.Replace(".", String.Empty);
+ name = name.ToLower();
+
+ if (!Colors.namedColors.ContainsKey(name))
{
- return black;
+ throw new ArgumentOutOfRangeException($"Invalid Color Name: {name}");
}
+
+ Color color = Colors.namedColors[name];
+ color.a = alpha;
+ return color;
}
- public float this [int index]
+ public float this[int index]
{
get
{
@@ -380,7 +389,7 @@ namespace Godot
return txt;
}
- // Constructors
+ // Constructors
public Color(float r, float g, float b, float a = 1.0f)
{
this.r = r;
diff --git a/modules/mono/glue/Managed/Files/Colors.cs b/modules/mono/glue/Managed/Files/Colors.cs
new file mode 100644
index 0000000000..bc2a1a3bd7
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/Colors.cs
@@ -0,0 +1,303 @@
+using System;
+using System.Collections.Generic;
+
+namespace Godot
+{
+ public static class Colors
+ {
+ // Color names and values are derived from core/color_names.inc
+ internal static readonly Dictionary<string, Color> namedColors = new Dictionary<string, Color> {
+ {"aliceblue", new Color(0.94f, 0.97f, 1.00f)},
+ {"antiquewhite", new Color(0.98f, 0.92f, 0.84f)},
+ {"aqua", new Color(0.00f, 1.00f, 1.00f)},
+ {"aquamarine", new Color(0.50f, 1.00f, 0.83f)},
+ {"azure", new Color(0.94f, 1.00f, 1.00f)},
+ {"beige", new Color(0.96f, 0.96f, 0.86f)},
+ {"bisque", new Color(1.00f, 0.89f, 0.77f)},
+ {"black", new Color(0.00f, 0.00f, 0.00f)},
+ {"blanchedalmond", new Color(1.00f, 0.92f, 0.80f)},
+ {"blue", new Color(0.00f, 0.00f, 1.00f)},
+ {"blueviolet", new Color(0.54f, 0.17f, 0.89f)},
+ {"brown", new Color(0.65f, 0.16f, 0.16f)},
+ {"burlywood", new Color(0.87f, 0.72f, 0.53f)},
+ {"cadetblue", new Color(0.37f, 0.62f, 0.63f)},
+ {"chartreuse", new Color(0.50f, 1.00f, 0.00f)},
+ {"chocolate", new Color(0.82f, 0.41f, 0.12f)},
+ {"coral", new Color(1.00f, 0.50f, 0.31f)},
+ {"cornflower", new Color(0.39f, 0.58f, 0.93f)},
+ {"cornsilk", new Color(1.00f, 0.97f, 0.86f)},
+ {"crimson", new Color(0.86f, 0.08f, 0.24f)},
+ {"cyan", new Color(0.00f, 1.00f, 1.00f)},
+ {"darkblue", new Color(0.00f, 0.00f, 0.55f)},
+ {"darkcyan", new Color(0.00f, 0.55f, 0.55f)},
+ {"darkgoldenrod", new Color(0.72f, 0.53f, 0.04f)},
+ {"darkgray", new Color(0.66f, 0.66f, 0.66f)},
+ {"darkgreen", new Color(0.00f, 0.39f, 0.00f)},
+ {"darkkhaki", new Color(0.74f, 0.72f, 0.42f)},
+ {"darkmagenta", new Color(0.55f, 0.00f, 0.55f)},
+ {"darkolivegreen", new Color(0.33f, 0.42f, 0.18f)},
+ {"darkorange", new Color(1.00f, 0.55f, 0.00f)},
+ {"darkorchid", new Color(0.60f, 0.20f, 0.80f)},
+ {"darkred", new Color(0.55f, 0.00f, 0.00f)},
+ {"darksalmon", new Color(0.91f, 0.59f, 0.48f)},
+ {"darkseagreen", new Color(0.56f, 0.74f, 0.56f)},
+ {"darkslateblue", new Color(0.28f, 0.24f, 0.55f)},
+ {"darkslategray", new Color(0.18f, 0.31f, 0.31f)},
+ {"darkturquoise", new Color(0.00f, 0.81f, 0.82f)},
+ {"darkviolet", new Color(0.58f, 0.00f, 0.83f)},
+ {"deeppink", new Color(1.00f, 0.08f, 0.58f)},
+ {"deepskyblue", new Color(0.00f, 0.75f, 1.00f)},
+ {"dimgray", new Color(0.41f, 0.41f, 0.41f)},
+ {"dodgerblue", new Color(0.12f, 0.56f, 1.00f)},
+ {"firebrick", new Color(0.70f, 0.13f, 0.13f)},
+ {"floralwhite", new Color(1.00f, 0.98f, 0.94f)},
+ {"forestgreen", new Color(0.13f, 0.55f, 0.13f)},
+ {"fuchsia", new Color(1.00f, 0.00f, 1.00f)},
+ {"gainsboro", new Color(0.86f, 0.86f, 0.86f)},
+ {"ghostwhite", new Color(0.97f, 0.97f, 1.00f)},
+ {"gold", new Color(1.00f, 0.84f, 0.00f)},
+ {"goldenrod", new Color(0.85f, 0.65f, 0.13f)},
+ {"gray", new Color(0.75f, 0.75f, 0.75f)},
+ {"green", new Color(0.00f, 1.00f, 0.00f)},
+ {"greenyellow", new Color(0.68f, 1.00f, 0.18f)},
+ {"honeydew", new Color(0.94f, 1.00f, 0.94f)},
+ {"hotpink", new Color(1.00f, 0.41f, 0.71f)},
+ {"indianred", new Color(0.80f, 0.36f, 0.36f)},
+ {"indigo", new Color(0.29f, 0.00f, 0.51f)},
+ {"ivory", new Color(1.00f, 1.00f, 0.94f)},
+ {"khaki", new Color(0.94f, 0.90f, 0.55f)},
+ {"lavender", new Color(0.90f, 0.90f, 0.98f)},
+ {"lavenderblush", new Color(1.00f, 0.94f, 0.96f)},
+ {"lawngreen", new Color(0.49f, 0.99f, 0.00f)},
+ {"lemonchiffon", new Color(1.00f, 0.98f, 0.80f)},
+ {"lightblue", new Color(0.68f, 0.85f, 0.90f)},
+ {"lightcoral", new Color(0.94f, 0.50f, 0.50f)},
+ {"lightcyan", new Color(0.88f, 1.00f, 1.00f)},
+ {"lightgoldenrod", new Color(0.98f, 0.98f, 0.82f)},
+ {"lightgray", new Color(0.83f, 0.83f, 0.83f)},
+ {"lightgreen", new Color(0.56f, 0.93f, 0.56f)},
+ {"lightpink", new Color(1.00f, 0.71f, 0.76f)},
+ {"lightsalmon", new Color(1.00f, 0.63f, 0.48f)},
+ {"lightseagreen", new Color(0.13f, 0.70f, 0.67f)},
+ {"lightskyblue", new Color(0.53f, 0.81f, 0.98f)},
+ {"lightslategray", new Color(0.47f, 0.53f, 0.60f)},
+ {"lightsteelblue", new Color(0.69f, 0.77f, 0.87f)},
+ {"lightyellow", new Color(1.00f, 1.00f, 0.88f)},
+ {"lime", new Color(0.00f, 1.00f, 0.00f)},
+ {"limegreen", new Color(0.20f, 0.80f, 0.20f)},
+ {"linen", new Color(0.98f, 0.94f, 0.90f)},
+ {"magenta", new Color(1.00f, 0.00f, 1.00f)},
+ {"maroon", new Color(0.69f, 0.19f, 0.38f)},
+ {"mediumaquamarine", new Color(0.40f, 0.80f, 0.67f)},
+ {"mediumblue", new Color(0.00f, 0.00f, 0.80f)},
+ {"mediumorchid", new Color(0.73f, 0.33f, 0.83f)},
+ {"mediumpurple", new Color(0.58f, 0.44f, 0.86f)},
+ {"mediumseagreen", new Color(0.24f, 0.70f, 0.44f)},
+ {"mediumslateblue", new Color(0.48f, 0.41f, 0.93f)},
+ {"mediumspringgreen", new Color(0.00f, 0.98f, 0.60f)},
+ {"mediumturquoise", new Color(0.28f, 0.82f, 0.80f)},
+ {"mediumvioletred", new Color(0.78f, 0.08f, 0.52f)},
+ {"midnightblue", new Color(0.10f, 0.10f, 0.44f)},
+ {"mintcream", new Color(0.96f, 1.00f, 0.98f)},
+ {"mistyrose", new Color(1.00f, 0.89f, 0.88f)},
+ {"moccasin", new Color(1.00f, 0.89f, 0.71f)},
+ {"navajowhite", new Color(1.00f, 0.87f, 0.68f)},
+ {"navyblue", new Color(0.00f, 0.00f, 0.50f)},
+ {"oldlace", new Color(0.99f, 0.96f, 0.90f)},
+ {"olive", new Color(0.50f, 0.50f, 0.00f)},
+ {"olivedrab", new Color(0.42f, 0.56f, 0.14f)},
+ {"orange", new Color(1.00f, 0.65f, 0.00f)},
+ {"orangered", new Color(1.00f, 0.27f, 0.00f)},
+ {"orchid", new Color(0.85f, 0.44f, 0.84f)},
+ {"palegoldenrod", new Color(0.93f, 0.91f, 0.67f)},
+ {"palegreen", new Color(0.60f, 0.98f, 0.60f)},
+ {"paleturquoise", new Color(0.69f, 0.93f, 0.93f)},
+ {"palevioletred", new Color(0.86f, 0.44f, 0.58f)},
+ {"papayawhip", new Color(1.00f, 0.94f, 0.84f)},
+ {"peachpuff", new Color(1.00f, 0.85f, 0.73f)},
+ {"peru", new Color(0.80f, 0.52f, 0.25f)},
+ {"pink", new Color(1.00f, 0.75f, 0.80f)},
+ {"plum", new Color(0.87f, 0.63f, 0.87f)},
+ {"powderblue", new Color(0.69f, 0.88f, 0.90f)},
+ {"purple", new Color(0.63f, 0.13f, 0.94f)},
+ {"rebeccapurple", new Color(0.40f, 0.20f, 0.60f)},
+ {"red", new Color(1.00f, 0.00f, 0.00f)},
+ {"rosybrown", new Color(0.74f, 0.56f, 0.56f)},
+ {"royalblue", new Color(0.25f, 0.41f, 0.88f)},
+ {"saddlebrown", new Color(0.55f, 0.27f, 0.07f)},
+ {"salmon", new Color(0.98f, 0.50f, 0.45f)},
+ {"sandybrown", new Color(0.96f, 0.64f, 0.38f)},
+ {"seagreen", new Color(0.18f, 0.55f, 0.34f)},
+ {"seashell", new Color(1.00f, 0.96f, 0.93f)},
+ {"sienna", new Color(0.63f, 0.32f, 0.18f)},
+ {"silver", new Color(0.75f, 0.75f, 0.75f)},
+ {"skyblue", new Color(0.53f, 0.81f, 0.92f)},
+ {"slateblue", new Color(0.42f, 0.35f, 0.80f)},
+ {"slategray", new Color(0.44f, 0.50f, 0.56f)},
+ {"snow", new Color(1.00f, 0.98f, 0.98f)},
+ {"springgreen", new Color(0.00f, 1.00f, 0.50f)},
+ {"steelblue", new Color(0.27f, 0.51f, 0.71f)},
+ {"tan", new Color(0.82f, 0.71f, 0.55f)},
+ {"teal", new Color(0.00f, 0.50f, 0.50f)},
+ {"thistle", new Color(0.85f, 0.75f, 0.85f)},
+ {"tomato", new Color(1.00f, 0.39f, 0.28f)},
+ {"turquoise", new Color(0.25f, 0.88f, 0.82f)},
+ {"violet", new Color(0.93f, 0.51f, 0.93f)},
+ {"webgreen", new Color(0.00f, 0.50f, 0.00f)},
+ {"webgray", new Color(0.50f, 0.50f, 0.50f)},
+ {"webmaroon", new Color(0.50f, 0.00f, 0.00f)},
+ {"webpurple", new Color(0.50f, 0.00f, 0.50f)},
+ {"wheat", new Color(0.96f, 0.87f, 0.70f)},
+ {"white", new Color(1.00f, 1.00f, 1.00f)},
+ {"whitesmoke", new Color(0.96f, 0.96f, 0.96f)},
+ {"yellow", new Color(1.00f, 1.00f, 0.00f)},
+ {"yellowgreen", new Color(0.60f, 0.80f, 0.20f)},
+ };
+
+ public static Color AliceBlue { get { return namedColors["aliceblue"]; } }
+ public static Color AntiqueWhite { get { return namedColors["antiquewhite"]; } }
+ public static Color Aqua { get { return namedColors["aqua"]; } }
+ public static Color Aquamarine { get { return namedColors["aquamarine"]; } }
+ public static Color Azure { get { return namedColors["azure"]; } }
+ public static Color Beige { get { return namedColors["beige"]; } }
+ public static Color Bisque { get { return namedColors["bisque"]; } }
+ public static Color Black { get { return namedColors["black"]; } }
+ public static Color BlanchedAlmond { get { return namedColors["blanchedalmond"]; } }
+ public static Color Blue { get { return namedColors["blue"]; } }
+ public static Color BlueViolet { get { return namedColors["blueviolet"]; } }
+ public static Color Brown { get { return namedColors["brown"]; } }
+ public static Color BurlyWood { get { return namedColors["burlywood"]; } }
+ public static Color CadetBlue { get { return namedColors["cadetblue"]; } }
+ public static Color Chartreuse { get { return namedColors["chartreuse"]; } }
+ public static Color Chocolate { get { return namedColors["chocolate"]; } }
+ public static Color Coral { get { return namedColors["coral"]; } }
+ public static Color Cornflower { get { return namedColors["cornflower"]; } }
+ public static Color Cornsilk { get { return namedColors["cornsilk"]; } }
+ public static Color Crimson { get { return namedColors["crimson"]; } }
+ public static Color Cyan { get { return namedColors["cyan"]; } }
+ public static Color DarkBlue { get { return namedColors["darkblue"]; } }
+ public static Color DarkCyan { get { return namedColors["darkcyan"]; } }
+ public static Color DarkGoldenrod { get { return namedColors["darkgoldenrod"]; } }
+ public static Color DarkGray { get { return namedColors["darkgray"]; } }
+ public static Color DarkGreen { get { return namedColors["darkgreen"]; } }
+ public static Color DarkKhaki { get { return namedColors["darkkhaki"]; } }
+ public static Color DarkMagenta { get { return namedColors["darkmagenta"]; } }
+ public static Color DarkOliveGreen { get { return namedColors["darkolivegreen"]; } }
+ public static Color DarkOrange { get { return namedColors["darkorange"]; } }
+ public static Color DarkOrchid { get { return namedColors["darkorchid"]; } }
+ public static Color DarkRed { get { return namedColors["darkred"]; } }
+ public static Color DarkSalmon { get { return namedColors["darksalmon"]; } }
+ public static Color DarkSeagreen { get { return namedColors["darkseagreen"]; } }
+ public static Color DarkSlateBlue { get { return namedColors["darkslateblue"]; } }
+ public static Color DarkSlateGray { get { return namedColors["darkslategray"]; } }
+ public static Color DarkTurquoise { get { return namedColors["darkturquoise"]; } }
+ public static Color DarkViolet { get { return namedColors["darkviolet"]; } }
+ public static Color DeepPink { get { return namedColors["deeppink"]; } }
+ public static Color DeepSkyBlue { get { return namedColors["deepskyblue"]; } }
+ public static Color DimGray { get { return namedColors["dimgray"]; } }
+ public static Color DodgerBlue { get { return namedColors["dodgerblue"]; } }
+ public static Color Firebrick { get { return namedColors["firebrick"]; } }
+ public static Color FloralWhite { get { return namedColors["floralwhite"]; } }
+ public static Color ForestGreen { get { return namedColors["forestgreen"]; } }
+ public static Color Fuchsia { get { return namedColors["fuchsia"]; } }
+ public static Color Gainsboro { get { return namedColors["gainsboro"]; } }
+ public static Color GhostWhite { get { return namedColors["ghostwhite"]; } }
+ public static Color Gold { get { return namedColors["gold"]; } }
+ public static Color Goldenrod { get { return namedColors["goldenrod"]; } }
+ public static Color Gray { get { return namedColors["gray"]; } }
+ public static Color Green { get { return namedColors["green"]; } }
+ public static Color GreenYellow { get { return namedColors["greenyellow"]; } }
+ public static Color Honeydew { get { return namedColors["honeydew"]; } }
+ public static Color HotPink { get { return namedColors["hotpink"]; } }
+ public static Color IndianRed { get { return namedColors["indianred"]; } }
+ public static Color Indigo { get { return namedColors["indigo"]; } }
+ public static Color Ivory { get { return namedColors["ivory"]; } }
+ public static Color Khaki { get { return namedColors["khaki"]; } }
+ public static Color Lavender { get { return namedColors["lavender"]; } }
+ public static Color LavenderBlush { get { return namedColors["lavenderblush"]; } }
+ public static Color LawnGreen { get { return namedColors["lawngreen"]; } }
+ public static Color LemonChiffon { get { return namedColors["lemonchiffon"]; } }
+ public static Color LightBlue { get { return namedColors["lightblue"]; } }
+ public static Color LightCoral { get { return namedColors["lightcoral"]; } }
+ public static Color LightCyan { get { return namedColors["lightcyan"]; } }
+ public static Color LightGoldenrod { get { return namedColors["lightgoldenrod"]; } }
+ public static Color LightGray { get { return namedColors["lightgray"]; } }
+ public static Color LightGreen { get { return namedColors["lightgreen"]; } }
+ public static Color LightPink { get { return namedColors["lightpink"]; } }
+ public static Color LightSalmon { get { return namedColors["lightsalmon"]; } }
+ public static Color LightSeaGreen { get { return namedColors["lightseagreen"]; } }
+ public static Color LightSkyBlue { get { return namedColors["lightskyblue"]; } }
+ public static Color LightSlateGray { get { return namedColors["lightslategray"]; } }
+ public static Color LightSteelBlue { get { return namedColors["lightsteelblue"]; } }
+ public static Color LightYellow { get { return namedColors["lightyellow"]; } }
+ public static Color Lime { get { return namedColors["lime"]; } }
+ public static Color Limegreen { get { return namedColors["limegreen"]; } }
+ public static Color Linen { get { return namedColors["linen"]; } }
+ public static Color Magenta { get { return namedColors["magenta"]; } }
+ public static Color Maroon { get { return namedColors["maroon"]; } }
+ public static Color MediumAquamarine { get { return namedColors["mediumaquamarine"]; } }
+ public static Color MediumBlue { get { return namedColors["mediumblue"]; } }
+ public static Color MediumOrchid { get { return namedColors["mediumorchid"]; } }
+ public static Color MediumPurple { get { return namedColors["mediumpurple"]; } }
+ public static Color MediumSeaGreen { get { return namedColors["mediumseagreen"]; } }
+ public static Color MediumSlateBlue { get { return namedColors["mediumslateblue"]; } }
+ public static Color MediumSpringGreen { get { return namedColors["mediumspringgreen"]; } }
+ public static Color MediumTurquoise { get { return namedColors["mediumturquoise"]; } }
+ public static Color MediumVioletRed { get { return namedColors["mediumvioletred"]; } }
+ public static Color MidnightBlue { get { return namedColors["midnightblue"]; } }
+ public static Color MintCream { get { return namedColors["mintcream"]; } }
+ public static Color MistyRose { get { return namedColors["mistyrose"]; } }
+ public static Color Moccasin { get { return namedColors["moccasin"]; } }
+ public static Color NavajoWhite { get { return namedColors["navajowhite"]; } }
+ public static Color NavyBlue { get { return namedColors["navyblue"]; } }
+ public static Color OldLace { get { return namedColors["oldlace"]; } }
+ public static Color Olive { get { return namedColors["olive"]; } }
+ public static Color OliveDrab { get { return namedColors["olivedrab"]; } }
+ public static Color Orange { get { return namedColors["orange"]; } }
+ public static Color OrangeRed { get { return namedColors["orangered"]; } }
+ public static Color Orchid { get { return namedColors["orchid"]; } }
+ public static Color PaleGoldenrod { get { return namedColors["palegoldenrod"]; } }
+ public static Color PaleGreen { get { return namedColors["palegreen"]; } }
+ public static Color PaleTurquoise { get { return namedColors["paleturquoise"]; } }
+ public static Color PaleVioletRed { get { return namedColors["palevioletred"]; } }
+ public static Color PapayaWhip { get { return namedColors["papayawhip"]; } }
+ public static Color PeachPuff { get { return namedColors["peachpuff"]; } }
+ public static Color Peru { get { return namedColors["peru"]; } }
+ public static Color Pink { get { return namedColors["pink"]; } }
+ public static Color Plum { get { return namedColors["plum"]; } }
+ public static Color PowderBlue { get { return namedColors["powderblue"]; } }
+ public static Color Purple { get { return namedColors["purple"]; } }
+ public static Color RebeccaPurple { get { return namedColors["rebeccapurple"]; } }
+ public static Color Red { get { return namedColors["red"]; } }
+ public static Color RosyBrown { get { return namedColors["rosybrown"]; } }
+ public static Color RoyalBlue { get { return namedColors["royalblue"]; } }
+ public static Color SaddleBrown { get { return namedColors["saddlebrown"]; } }
+ public static Color Salmon { get { return namedColors["salmon"]; } }
+ public static Color SandyBrown { get { return namedColors["sandybrown"]; } }
+ public static Color SeaGreen { get { return namedColors["seagreen"]; } }
+ public static Color SeaShell { get { return namedColors["seashell"]; } }
+ public static Color Sienna { get { return namedColors["sienna"]; } }
+ public static Color Silver { get { return namedColors["silver"]; } }
+ public static Color SkyBlue { get { return namedColors["skyblue"]; } }
+ public static Color SlateBlue { get { return namedColors["slateblue"]; } }
+ public static Color SlateGray { get { return namedColors["slategray"]; } }
+ public static Color Snow { get { return namedColors["snow"]; } }
+ public static Color SpringGreen { get { return namedColors["springgreen"]; } }
+ public static Color SteelBlue { get { return namedColors["steelblue"]; } }
+ public static Color Tan { get { return namedColors["tan"]; } }
+ public static Color Teal { get { return namedColors["teal"]; } }
+ public static Color Thistle { get { return namedColors["thistle"]; } }
+ public static Color Tomato { get { return namedColors["tomato"]; } }
+ public static Color Turquoise { get { return namedColors["turquoise"]; } }
+ public static Color Violet { get { return namedColors["violet"]; } }
+ public static Color WebGreen { get { return namedColors["webgreen"]; } }
+ public static Color WebGray { get { return namedColors["webgray"]; } }
+ public static Color WebMaroon { get { return namedColors["webmaroon"]; } }
+ public static Color WebPurple { get { return namedColors["webpurple"]; } }
+ public static Color Wheat { get { return namedColors["wheat"]; } }
+ public static Color White { get { return namedColors["white"]; } }
+ public static Color WhiteSmoke { get { return namedColors["whitesmoke"]; } }
+ public static Color Yellow { get { return namedColors["yellow"]; } }
+ public static Color YellowGreen { get { return namedColors["yellowgreen"]; } }
+ }
+}
diff --git a/modules/mono/glue/Managed/Files/DebuggingUtils.cs b/modules/mono/glue/Managed/Files/DebuggingUtils.cs
index b27816084e..edfe3464ec 100644
--- a/modules/mono/glue/Managed/Files/DebuggingUtils.cs
+++ b/modules/mono/glue/Managed/Files/DebuggingUtils.cs
@@ -19,6 +19,12 @@ namespace Godot
sb.Append(" ");
}
+ public static void InstallTraceListener()
+ {
+ Trace.Listeners.Clear();
+ Trace.Listeners.Add(new GodotTraceListener());
+ }
+
public static void GetStackFrameInfo(StackFrame frame, out string fileName, out int fileLineNumber, out string methodDecl)
{
fileName = frame.GetFileName();
diff --git a/modules/mono/glue/Managed/Files/Dictionary.cs b/modules/mono/glue/Managed/Files/Dictionary.cs
index 7695f03cd6..6ab8549a01 100644
--- a/modules/mono/glue/Managed/Files/Dictionary.cs
+++ b/modules/mono/glue/Managed/Files/Dictionary.cs
@@ -29,9 +29,7 @@ namespace Godot.Collections
}
public class Dictionary :
- IDictionary<object, object>,
- ICollection<KeyValuePair<object, object>>,
- IEnumerable<KeyValuePair<object, object>>,
+ IDictionary,
IDisposable
{
DictionarySafeHandle safeHandle;
@@ -42,6 +40,14 @@ namespace Godot.Collections
safeHandle = new DictionarySafeHandle(godot_icall_Dictionary_Ctor());
}
+ public Dictionary(IDictionary dictionary) : this()
+ {
+ if (dictionary == null)
+ throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'");
+
+ MarshalUtils.IDictionaryToDictionary(dictionary, GetPtr());
+ }
+
internal Dictionary(DictionarySafeHandle handle)
{
safeHandle = handle;
@@ -54,6 +60,9 @@ namespace Godot.Collections
internal IntPtr GetPtr()
{
+ if (disposed)
+ throw new ObjectDisposedException(GetType().FullName);
+
return safeHandle.DangerousGetHandle();
}
@@ -71,19 +80,9 @@ namespace Godot.Collections
disposed = true;
}
- public object this[object key]
- {
- get
- {
- return godot_icall_Dictionary_GetValue(GetPtr(), key);
- }
- set
- {
- godot_icall_Dictionary_SetValue(GetPtr(), key, value);
- }
- }
+ // IDictionary
- public ICollection<object> Keys
+ public ICollection Keys
{
get
{
@@ -92,7 +91,7 @@ namespace Godot.Collections
}
}
- public ICollection<object> Values
+ public ICollection Values
{
get
{
@@ -101,97 +100,102 @@ namespace Godot.Collections
}
}
- public int Count
- {
- get
- {
- return godot_icall_Dictionary_Count(GetPtr());
- }
- }
+ public bool IsFixedSize => false;
- public bool IsReadOnly
- {
- get
- {
- return false;
- }
- }
+ public bool IsReadOnly => false;
- public void Add(object key, object value)
+ public object this[object key]
{
- godot_icall_Dictionary_Add(GetPtr(), key, value);
+ get => godot_icall_Dictionary_GetValue(GetPtr(), key);
+ set => godot_icall_Dictionary_SetValue(GetPtr(), key, value);
}
- public void Add(KeyValuePair<object, object> item)
- {
- Add(item.Key, item.Value);
- }
+ public void Add(object key, object value) => godot_icall_Dictionary_Add(GetPtr(), key, value);
- public void Clear()
- {
- godot_icall_Dictionary_Clear(GetPtr());
- }
+ public void Clear() => godot_icall_Dictionary_Clear(GetPtr());
- public bool Contains(KeyValuePair<object, object> item)
- {
- return godot_icall_Dictionary_Contains(GetPtr(), item.Key, item.Value);
- }
+ public bool Contains(object key) => godot_icall_Dictionary_ContainsKey(GetPtr(), key);
- public bool ContainsKey(object key)
- {
- return godot_icall_Dictionary_ContainsKey(GetPtr(), key);
- }
+ public IDictionaryEnumerator GetEnumerator() => new DictionaryEnumerator(this);
+
+ public void Remove(object key) => godot_icall_Dictionary_RemoveKey(GetPtr(), key);
- public void CopyTo(KeyValuePair<object, object>[] array, int arrayIndex)
+ // ICollection
+
+ public object SyncRoot => this;
+
+ public bool IsSynchronized => false;
+
+ public int Count => godot_icall_Dictionary_Count(GetPtr());
+
+ public void CopyTo(System.Array array, int index)
{
- // TODO 3 internal calls, can reduce to 1
+ // TODO Can be done with single internal call
+
+ if (array == null)
+ throw new ArgumentNullException(nameof(array), "Value cannot be null.");
+
+ if (index < 0)
+ throw new ArgumentOutOfRangeException(nameof(index), "Number was less than the array's lower bound in the first dimension.");
+
Array keys = (Array)Keys;
Array values = (Array)Values;
int count = Count;
+ if (array.Length < (index + count))
+ throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
+
for (int i = 0; i < count; i++)
{
- // TODO 2 internal calls, can reduce to 1
- array[arrayIndex] = new KeyValuePair<object, object>(keys[i], values[i]);
- arrayIndex++;
+ array.SetValue(new DictionaryEntry(keys[i], values[i]), index);
+ index++;
}
}
- public IEnumerator<KeyValuePair<object, object>> GetEnumerator()
+ // IEnumerable
+
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+
+ private class DictionaryEnumerator : IDictionaryEnumerator
{
- // TODO 3 internal calls, can reduce to 1
- Array keys = (Array)Keys;
- Array values = (Array)Values;
- int count = Count;
+ Array keys;
+ Array values;
+ int count;
+ int index = -1;
- for (int i = 0; i < count; i++)
+ public DictionaryEnumerator(Dictionary dictionary)
{
- // TODO 2 internal calls, can reduce to 1
- yield return new KeyValuePair<object, object>(keys[i], values[i]);
+ // TODO 3 internal calls, can reduce to 1
+ keys = (Array)dictionary.Keys;
+ values = (Array)dictionary.Values;
+ count = dictionary.Count;
}
- }
- public bool Remove(object key)
- {
- return godot_icall_Dictionary_RemoveKey(GetPtr(), key);
- }
+ public object Current => Entry;
- public bool Remove(KeyValuePair<object, object> item)
- {
- return godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value);
- }
+ public DictionaryEntry Entry =>
+ // TODO 2 internal calls, can reduce to 1
+ new DictionaryEntry(keys[index], values[index]);
- public bool TryGetValue(object key, out object value)
- {
- object retValue;
- bool found = godot_icall_Dictionary_TryGetValue(GetPtr(), key, out retValue);
- value = found ? retValue : default(object);
- return found;
+ public object Key => Entry.Key;
+
+ public object Value => Entry.Value;
+
+ public bool MoveNext()
+ {
+ index++;
+ return index < count;
+ }
+
+ public void Reset()
+ {
+ index = -1;
+ }
}
- IEnumerator IEnumerable.GetEnumerator()
+ public override string ToString()
{
- return GetEnumerator();
+ return godot_icall_Dictionary_ToString(GetPtr());
}
[MethodImpl(MethodImplOptions.InternalCall)]
@@ -244,12 +248,13 @@ namespace Godot.Collections
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_Dictionary_Generic_GetValueTypeInfo(Type valueType, out int valTypeEncoding, out IntPtr valTypeClass);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static string godot_icall_Dictionary_ToString(IntPtr ptr);
}
public class Dictionary<TKey, TValue> :
- IDictionary<TKey, TValue>,
- ICollection<KeyValuePair<TKey, TValue>>,
- IEnumerable<KeyValuePair<TKey, TValue>>
+ IDictionary<TKey, TValue>
{
Dictionary objectDict;
@@ -266,6 +271,23 @@ namespace Godot.Collections
objectDict = new Dictionary();
}
+ public Dictionary(IDictionary<TKey, TValue> dictionary)
+ {
+ objectDict = new Dictionary();
+
+ if (dictionary == null)
+ throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'");
+
+ // TODO: Can be optimized
+
+ IntPtr godotDictionaryPtr = GetPtr();
+
+ foreach (KeyValuePair<TKey, TValue> entry in dictionary)
+ {
+ Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, entry.Key, entry.Value);
+ }
+ }
+
public Dictionary(Dictionary dictionary)
{
objectDict = dictionary;
@@ -286,6 +308,13 @@ namespace Godot.Collections
return from.objectDict;
}
+ internal IntPtr GetPtr()
+ {
+ return objectDict.GetPtr();
+ }
+
+ // IDictionary<TKey, TValue>
+
public TValue this[TKey key]
{
get
@@ -316,6 +345,31 @@ namespace Godot.Collections
}
}
+ public void Add(TKey key, TValue value)
+ {
+ objectDict.Add(key, value);
+ }
+
+ public bool ContainsKey(TKey key)
+ {
+ return objectDict.Contains(key);
+ }
+
+ public bool Remove(TKey key)
+ {
+ return Dictionary.godot_icall_Dictionary_RemoveKey(GetPtr(), key);
+ }
+
+ public bool TryGetValue(TKey key, out TValue value)
+ {
+ object retValue;
+ bool found = Dictionary.godot_icall_Dictionary_TryGetValue_Generic(GetPtr(), key, out retValue, valTypeEncoding, valTypeClass);
+ value = found ? (TValue)retValue : default(TValue);
+ return found;
+ }
+
+ // ICollection<KeyValuePair<TKey, TValue>>
+
public int Count
{
get
@@ -332,11 +386,6 @@ namespace Godot.Collections
}
}
- public void Add(TKey key, TValue value)
- {
- objectDict.Add(key, value);
- }
-
public void Add(KeyValuePair<TKey, TValue> item)
{
objectDict.Add(item.Key, item.Value);
@@ -352,18 +401,22 @@ namespace Godot.Collections
return objectDict.Contains(new KeyValuePair<object, object>(item.Key, item.Value));
}
- public bool ContainsKey(TKey key)
- {
- return objectDict.ContainsKey(key);
- }
-
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
+ if (array == null)
+ throw new ArgumentNullException(nameof(array), "Value cannot be null.");
+
+ if (arrayIndex < 0)
+ throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension.");
+
// TODO 3 internal calls, can reduce to 1
Array<TKey> keys = (Array<TKey>)Keys;
Array<TValue> values = (Array<TValue>)Values;
int count = Count;
+ if (array.Length < (arrayIndex + count))
+ throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
+
for (int i = 0; i < count; i++)
{
// TODO 2 internal calls, can reduce to 1
@@ -372,6 +425,13 @@ namespace Godot.Collections
}
}
+ public bool Remove(KeyValuePair<TKey, TValue> item)
+ {
+ return Dictionary.godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value); ;
+ }
+
+ // IEnumerable<KeyValuePair<TKey, TValue>>
+
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
// TODO 3 internal calls, can reduce to 1
@@ -386,32 +446,11 @@ namespace Godot.Collections
}
}
- public bool Remove(TKey key)
- {
- return objectDict.Remove(key);
- }
-
- public bool Remove(KeyValuePair<TKey, TValue> item)
- {
- return objectDict.Remove(new KeyValuePair<object, object>(item.Key, item.Value));
- }
-
- public bool TryGetValue(TKey key, out TValue value)
- {
- object retValue;
- bool found = Dictionary.godot_icall_Dictionary_TryGetValue_Generic(GetPtr(), key, out retValue, valTypeEncoding, valTypeClass);
- value = found ? (TValue)retValue : default(TValue);
- return found;
- }
-
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
- internal IntPtr GetPtr()
- {
- return objectDict.GetPtr();
- }
+ public override string ToString() => objectDict.ToString();
}
}
diff --git a/modules/mono/glue/Managed/Files/DynamicObject.cs b/modules/mono/glue/Managed/Files/DynamicObject.cs
new file mode 100644
index 0000000000..9860feafdd
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/DynamicObject.cs
@@ -0,0 +1,213 @@
+
+using System;
+using System.Collections.Generic;
+using System.Dynamic;
+using System.Linq.Expressions;
+using System.Runtime.CompilerServices;
+
+namespace Godot
+{
+ /// <summary>
+ /// Represents an <see cref="Godot.Object"/> whose members can be dynamically accessed at runtime through the Variant API.
+ /// </summary>
+ /// <remarks>
+ /// <para>
+ /// The <see cref="Godot.DynamicGodotObject"/> class enables access to the Variant
+ /// members of a <see cref="Godot.Object"/> instance at runtime.
+ /// </para>
+ /// <para>
+ /// This allows accessing the class members using their original names in the engine as well as the members from the
+ /// script attached to the <see cref="Godot.Object"/>, regardless of the scripting language it was written in.
+ /// </para>
+ /// </remarks>
+ /// <example>
+ /// This sample shows how to use <see cref="Godot.DynamicGodotObject"/> to dynamically access the engine members of a <see cref="Godot.Object"/>.
+ /// <code>
+ /// dynamic sprite = GetNode("Sprite").DynamicGodotObject;
+ /// sprite.add_child(this);
+ ///
+ /// if ((sprite.hframes * sprite.vframes) &gt; 0)
+ /// sprite.frame = 0;
+ /// </code>
+ /// </example>
+ /// <example>
+ /// This sample shows how to use <see cref="Godot.DynamicGodotObject"/> to dynamically access the members of the script attached to a <see cref="Godot.Object"/>.
+ /// <code>
+ /// dynamic childNode = GetNode("ChildNode").DynamicGodotObject;
+ ///
+ /// if (childNode.print_allowed)
+ /// {
+ /// childNode.message = "Hello from C#";
+ /// childNode.print_message(3);
+ /// }
+ /// </code>
+ /// The <c>ChildNode</c> node has the following GDScript script attached:
+ /// <code>
+ /// // # ChildNode.gd
+ /// // var print_allowed = true
+ /// // var message = ""
+ /// //
+ /// // func print_message(times):
+ /// // for i in times:
+ /// // print(message)
+ /// </code>
+ /// </example>
+ public class DynamicGodotObject : DynamicObject
+ {
+ /// <summary>
+ /// Gets the <see cref="Godot.Object"/> associated with this <see cref="Godot.DynamicGodotObject"/>.
+ /// </summary>
+ public Object Value { get; }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="Godot.DynamicGodotObject"/> class.
+ /// </summary>
+ /// <param name="godotObject">
+ /// The <see cref="Godot.Object"/> that will be associated with this <see cref="Godot.DynamicGodotObject"/>.
+ /// </param>
+ /// <exception cref="System.ArgumentNullException">
+ /// Thrown when the <paramref name="godotObject"/> parameter is null.
+ /// </exception>
+ public DynamicGodotObject(Object godotObject)
+ {
+ if (godotObject == null)
+ throw new ArgumentNullException(nameof(godotObject));
+
+ this.Value = godotObject;
+ }
+
+ public override IEnumerable<string> GetDynamicMemberNames()
+ {
+ return godot_icall_DynamicGodotObject_SetMemberList(Object.GetPtr(Value));
+ }
+
+ public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result)
+ {
+ switch (binder.Operation)
+ {
+ case ExpressionType.Equal:
+ case ExpressionType.NotEqual:
+ if (binder.ReturnType == typeof(bool) || binder.ReturnType.IsAssignableFrom(typeof(bool)))
+ {
+ if (arg == null)
+ {
+ bool boolResult = Object.IsInstanceValid(Value);
+
+ if (binder.Operation == ExpressionType.Equal)
+ boolResult = !boolResult;
+
+ result = boolResult;
+ return true;
+ }
+
+ if (arg is Object other)
+ {
+ bool boolResult = (Value == other);
+
+ if (binder.Operation == ExpressionType.NotEqual)
+ boolResult = !boolResult;
+
+ result = boolResult;
+ return true;
+ }
+ }
+
+ break;
+ default:
+ // We're not implementing operators <, <=, >, and >= (LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual).
+ // These are used on the actual pointers in variant_op.cpp. It's better to let the user do that explicitly.
+ break;
+ }
+
+ return base.TryBinaryOperation(binder, arg, out result);
+ }
+
+ public override bool TryConvert(ConvertBinder binder, out object result)
+ {
+ if (binder.Type == typeof(Object))
+ {
+ result = Value;
+ return true;
+ }
+
+ if (typeof(Object).IsAssignableFrom(binder.Type))
+ {
+ // Throws InvalidCastException when the cast fails
+ result = Convert.ChangeType(Value, binder.Type);
+ return true;
+ }
+
+ return base.TryConvert(binder, out result);
+ }
+
+ public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
+ {
+ if (indexes.Length == 1)
+ {
+ if (indexes[0] is string name)
+ {
+ return godot_icall_DynamicGodotObject_GetMember(Object.GetPtr(Value), name, out result);
+ }
+ }
+
+ return base.TryGetIndex(binder, indexes, out result);
+ }
+
+ public override bool TryGetMember(GetMemberBinder binder, out object result)
+ {
+ return godot_icall_DynamicGodotObject_GetMember(Object.GetPtr(Value), binder.Name, out result);
+ }
+
+ public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
+ {
+ return godot_icall_DynamicGodotObject_InvokeMember(Object.GetPtr(Value), binder.Name, args, out result);
+ }
+
+ public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
+ {
+ if (indexes.Length == 1)
+ {
+ if (indexes[0] is string name)
+ {
+ return godot_icall_DynamicGodotObject_SetMember(Object.GetPtr(Value), name, value);
+ }
+ }
+
+ return base.TrySetIndex(binder, indexes, value);
+ }
+
+ public override bool TrySetMember(SetMemberBinder binder, object value)
+ {
+ return godot_icall_DynamicGodotObject_SetMember(Object.GetPtr(Value), binder.Name, value);
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static string[] godot_icall_DynamicGodotObject_SetMemberList(IntPtr godotObject);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static bool godot_icall_DynamicGodotObject_InvokeMember(IntPtr godotObject, string name, object[] args, out object result);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static bool godot_icall_DynamicGodotObject_GetMember(IntPtr godotObject, string name, out object result);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static bool godot_icall_DynamicGodotObject_SetMember(IntPtr godotObject, string name, object value);
+
+ #region We don't override these methods
+
+ // Looks like this is not usable from C#
+ //public override bool TryCreateInstance(CreateInstanceBinder binder, object[] args, out object result);
+
+ // Object members cannot be deleted
+ //public override bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes);
+ //public override bool TryDeleteMember(DeleteMemberBinder binder);
+
+ // Invokation on the object itself, e.g.: obj(param)
+ //public override bool TryInvoke(InvokeBinder binder, object[] args, out object result);
+
+ // No unnary operations to handle
+ //public override bool TryUnaryOperation(UnaryOperationBinder binder, out object result);
+
+ #endregion
+ }
+}
diff --git a/modules/mono/glue/Managed/Files/GD.cs b/modules/mono/glue/Managed/Files/GD.cs
index 75a35a9eea..5b591646ea 100644
--- a/modules/mono/glue/Managed/Files/GD.cs
+++ b/modules/mono/glue/Managed/Files/GD.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Runtime.CompilerServices;
#if REAL_T_IS_DOUBLE
using real_t = System.Double;
@@ -12,12 +13,12 @@ namespace Godot
{
public static partial class GD
{
- public static object Bytes2Var(byte[] bytes)
+ public static object Bytes2Var(byte[] bytes, bool allow_objects = false)
{
- return godot_icall_GD_bytes2var(bytes);
+ return godot_icall_GD_bytes2var(bytes, allow_objects);
}
- public static object Convert(object what, int type)
+ public static object Convert(object what, Variant.Type type)
{
return godot_icall_GD_convert(what, type);
}
@@ -50,7 +51,7 @@ namespace Godot
return godot_icall_GD_hash(var);
}
- public static Object InstanceFromId(int instanceId)
+ public static Object InstanceFromId(ulong instanceId)
{
return godot_icall_GD_instance_from_id(instanceId);
}
@@ -82,7 +83,7 @@ namespace Godot
public static void Print(params object[] what)
{
- godot_icall_GD_print(what);
+ godot_icall_GD_print(Array.ConvertAll(what, x => x.ToString()));
}
public static void PrintStack()
@@ -92,89 +93,80 @@ namespace Godot
public static void PrintErr(params object[] what)
{
- godot_icall_GD_printerr(what);
+ godot_icall_GD_printerr(Array.ConvertAll(what, x => x.ToString()));
}
public static void PrintRaw(params object[] what)
{
- godot_icall_GD_printraw(what);
+ godot_icall_GD_printraw(Array.ConvertAll(what, x => x.ToString()));
}
public static void PrintS(params object[] what)
{
- godot_icall_GD_prints(what);
+ godot_icall_GD_prints(Array.ConvertAll(what, x => x.ToString()));
}
public static void PrintT(params object[] what)
{
- godot_icall_GD_printt(what);
+ godot_icall_GD_printt(Array.ConvertAll(what, x => x.ToString()));
}
- public static int[] Range(int length)
+ public static double Randf()
{
- var ret = new int[length];
-
- for (int i = 0; i < length; i++)
- {
- ret[i] = i;
- }
-
- return ret;
+ return godot_icall_GD_randf();
}
- public static int[] Range(int from, int to)
+ public static uint Randi()
{
- if (to < from)
- return new int[0];
+ return godot_icall_GD_randi();
+ }
- var ret = new int[to - from];
+ public static void Randomize()
+ {
+ godot_icall_GD_randomize();
+ }
- for (int i = from; i < to; i++)
- {
- ret[i - from] = i;
- }
+ public static double RandRange(double from, double to)
+ {
+ return godot_icall_GD_rand_range(from, to);
+ }
- return ret;
+ public static uint RandSeed(ulong seed, out ulong newSeed)
+ {
+ return godot_icall_GD_rand_seed(seed, out newSeed);
}
- public static int[] Range(int from, int to, int increment)
+ public static IEnumerable<int> Range(int end)
{
- if (to < from && increment > 0)
- return new int[0];
- if (to > from && increment < 0)
- return new int[0];
+ return Range(0, end, 1);
+ }
- // Calculate count
- int count;
+ public static IEnumerable<int> Range(int start, int end)
+ {
+ return Range(start, end, 1);
+ }
- if (increment > 0)
- count = (to - from - 1) / increment + 1;
- else
- count = (from - to - 1) / -increment + 1;
+ public static IEnumerable<int> Range(int start, int end, int step)
+ {
+ if (end < start && step > 0)
+ yield break;
- var ret = new int[count];
+ if (end > start && step < 0)
+ yield break;
- if (increment > 0)
+ if (step > 0)
{
- int idx = 0;
- for (int i = from; i < to; i += increment)
- {
- ret[idx++] = i;
- }
+ for (int i = start; i < end; i += step)
+ yield return i;
}
else
{
- int idx = 0;
- for (int i = from; i > to; i += increment)
- {
- ret[idx++] = i;
- }
+ for (int i = start; i > end; i += step)
+ yield return i;
}
-
- return ret;
}
- public static void Seed(int seed)
+ public static void Seed(ulong seed)
{
godot_icall_GD_seed(seed);
}
@@ -194,9 +186,9 @@ namespace Godot
return godot_icall_GD_type_exists(type);
}
- public static byte[] Var2Bytes(object var)
+ public static byte[] Var2Bytes(object var, bool full_objects = false)
{
- return godot_icall_GD_var2bytes(var);
+ return godot_icall_GD_var2bytes(var, full_objects);
}
public static string Var2Str(object var)
@@ -205,16 +197,16 @@ namespace Godot
}
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static object godot_icall_GD_bytes2var(byte[] bytes);
+ internal extern static object godot_icall_GD_bytes2var(byte[] bytes, bool allow_objects);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static object godot_icall_GD_convert(object what, int type);
+ internal extern static object godot_icall_GD_convert(object what, Variant.Type type);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static int godot_icall_GD_hash(object var);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static Object godot_icall_GD_instance_from_id(int instance_id);
+ internal extern static Object godot_icall_GD_instance_from_id(ulong instance_id);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_GD_print(object[] what);
@@ -232,7 +224,22 @@ namespace Godot
internal extern static void godot_icall_GD_printt(object[] what);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static void godot_icall_GD_seed(int seed);
+ internal extern static double godot_icall_GD_randf();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static uint godot_icall_GD_randi();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_GD_randomize();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static double godot_icall_GD_rand_range(double from, double to);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static uint godot_icall_GD_rand_seed(ulong seed, out ulong newSeed);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_GD_seed(ulong seed);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static string godot_icall_GD_str(object[] what);
@@ -244,7 +251,7 @@ namespace Godot
internal extern static bool godot_icall_GD_type_exists(string type);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static byte[] godot_icall_GD_var2bytes(object what);
+ internal extern static byte[] godot_icall_GD_var2bytes(object what, bool full_objects);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static string godot_icall_GD_var2str(object var);
diff --git a/modules/mono/glue/Managed/Files/GodotTraceListener.cs b/modules/mono/glue/Managed/Files/GodotTraceListener.cs
new file mode 100644
index 0000000000..f1a00ae0fa
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/GodotTraceListener.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Diagnostics;
+
+namespace Godot
+{
+ internal class GodotTraceListener : TraceListener
+ {
+ public override void Write(string message)
+ {
+ GD.PrintRaw(message);
+ }
+
+ public override void WriteLine(string message)
+ {
+ GD.Print(message);
+ }
+
+ public override void Fail(string message, string detailMessage)
+ {
+ GD.PrintErr("Assertion failed: ", message);
+ if (detailMessage != null)
+ {
+ GD.PrintErr(" Details: ", detailMessage);
+ }
+
+ try
+ {
+ var stackTrace = new StackTrace(true).ToString();
+ GD.PrintErr(stackTrace);
+ }
+ catch
+ {
+ // ignored
+ }
+ }
+ }
+}
diff --git a/modules/mono/glue/Managed/Files/MarshalUtils.cs b/modules/mono/glue/Managed/Files/MarshalUtils.cs
index f7699a15bf..7e72b0edb5 100644
--- a/modules/mono/glue/Managed/Files/MarshalUtils.cs
+++ b/modules/mono/glue/Managed/Files/MarshalUtils.cs
@@ -1,18 +1,68 @@
using System;
-using Godot.Collections;
+using System.Collections;
namespace Godot
{
+ using Array = Godot.Collections.Array;
+ using Dictionary = Godot.Collections.Dictionary;
+
static class MarshalUtils
{
- static bool IsArrayGenericType(Type type)
+ static bool TypeIsGenericArray(Type type)
{
- return type.GetGenericTypeDefinition() == typeof(Array<>);
+ return type.GetGenericTypeDefinition() == typeof(Godot.Collections.Array<>);
+ }
+
+ static bool TypeIsGenericDictionary(Type type)
+ {
+ return type.GetGenericTypeDefinition() == typeof(Godot.Collections.Dictionary<,>);
+ }
+
+ static void ArrayGetElementType(Type type, out Type elementType)
+ {
+ elementType = type.GetGenericArguments()[0];
+ }
+
+ static void DictionaryGetKeyValueTypes(Type type, out Type keyType, out Type valueType)
+ {
+ var genericArgs = type.GetGenericArguments();
+
+ keyType = genericArgs[0];
+ valueType = genericArgs[1];
+ }
+
+ // TODO Add support for IEnumerable<T> and IDictionary<TKey, TValue>
+ // TODO: EnumerableToArray and IDictionaryToDictionary can be optimized
+
+ internal static void EnumerableToArray(IEnumerable enumerable, IntPtr godotArrayPtr)
+ {
+ if (enumerable is ICollection collection)
+ {
+ int count = collection.Count;
+
+ object[] tempArray = new object[count];
+ collection.CopyTo(tempArray, 0);
+
+ for (int i = 0; i < count; i++)
+ {
+ Array.godot_icall_Array_Add(godotArrayPtr, tempArray[i]);
+ }
+ }
+ else
+ {
+ foreach (object element in enumerable)
+ {
+ Array.godot_icall_Array_Add(godotArrayPtr, element);
+ }
+ }
}
- static bool IsDictionaryGenericType(Type type)
+ internal static void IDictionaryToDictionary(IDictionary dictionary, IntPtr godotDictionaryPtr)
{
- return type.GetGenericTypeDefinition() == typeof(Dictionary<, >);
+ foreach (DictionaryEntry entry in dictionary)
+ {
+ Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, entry.Key, entry.Value);
+ }
}
}
}
diff --git a/modules/mono/glue/Managed/Files/Mathf.cs b/modules/mono/glue/Managed/Files/Mathf.cs
index dcab3c1ffc..a064278237 100644
--- a/modules/mono/glue/Managed/Files/Mathf.cs
+++ b/modules/mono/glue/Managed/Files/Mathf.cs
@@ -261,6 +261,16 @@ namespace Godot
return (real_t)Math.Sinh(s);
}
+ public static real_t SmoothStep(real_t from, real_t to, real_t weight)
+ {
+ if (IsEqualApprox(from, to))
+ {
+ return from;
+ }
+ real_t x = Clamp((weight - from) / (to - from), (real_t)0.0, (real_t)1.0);
+ return x * x * (3 - 2 * x);
+ }
+
public static real_t Sqrt(real_t s)
{
return (real_t)Math.Sqrt(s);
@@ -289,13 +299,13 @@ namespace Godot
public static int Wrap(int value, int min, int max)
{
int rng = max - min;
- return min + ((value - min) % rng + rng) % rng;
+ return rng != 0 ? min + ((value - min) % rng + rng) % rng : min;
}
public static real_t Wrap(real_t value, real_t min, real_t max)
{
real_t rng = max - min;
- return min + ((value - min) % rng + rng) % rng;
+ return !IsEqualApprox(rng, default(real_t)) ? min + ((value - min) % rng + rng) % rng : min;
}
}
}
diff --git a/modules/mono/glue/Managed/Files/MathfEx.cs b/modules/mono/glue/Managed/Files/MathfEx.cs
index 2ef02cc288..414762f7b1 100644
--- a/modules/mono/glue/Managed/Files/MathfEx.cs
+++ b/modules/mono/glue/Managed/Files/MathfEx.cs
@@ -35,5 +35,10 @@ namespace Godot
{
return (int)Math.Round(s);
}
+
+ public static bool IsEqualApprox(real_t a, real_t b, real_t ratio = Mathf.Epsilon)
+ {
+ return Abs(a - b) < ratio;
+ }
}
} \ No newline at end of file
diff --git a/modules/mono/glue/Managed/Files/NodePath.cs b/modules/mono/glue/Managed/Files/NodePath.cs
index 2c89bec87f..94a4ed1de9 100644
--- a/modules/mono/glue/Managed/Files/NodePath.cs
+++ b/modules/mono/glue/Managed/Files/NodePath.cs
@@ -3,7 +3,7 @@ using System.Runtime.CompilerServices;
namespace Godot
{
- public partial class NodePath : IDisposable
+ public sealed partial class NodePath : IDisposable
{
private bool disposed = false;
@@ -11,7 +11,13 @@ namespace Godot
internal static IntPtr GetPtr(NodePath instance)
{
- return instance == null ? IntPtr.Zero : instance.ptr;
+ if (instance == null)
+ return IntPtr.Zero;
+
+ if (instance.disposed)
+ throw new ObjectDisposedException(instance.GetType().FullName);
+
+ return instance.ptr;
}
~NodePath()
@@ -25,7 +31,7 @@ namespace Godot
GC.SuppressFinalize(this);
}
- protected virtual void Dispose(bool disposing)
+ private void Dispose(bool disposing)
{
if (disposed)
return;
@@ -49,7 +55,7 @@ namespace Godot
get { return ptr; }
}
- public NodePath() : this(string.Empty) {}
+ public NodePath() : this(string.Empty) { }
public NodePath(string path)
{
diff --git a/modules/mono/glue/Managed/Files/Object.base.cs b/modules/mono/glue/Managed/Files/Object.base.cs
index 30490a715f..de80f7fddc 100644
--- a/modules/mono/glue/Managed/Files/Object.base.cs
+++ b/modules/mono/glue/Managed/Files/Object.base.cs
@@ -30,7 +30,13 @@ namespace Godot
internal static IntPtr GetPtr(Object instance)
{
- return instance == null ? IntPtr.Zero : instance.ptr;
+ if (instance == null)
+ return IntPtr.Zero;
+
+ if (instance.disposed)
+ throw new ObjectDisposedException(instance.GetType().FullName);
+
+ return instance.ptr;
}
~Object()
@@ -67,11 +73,44 @@ namespace Godot
disposed = true;
}
+ public override string ToString()
+ {
+ return godot_icall_Object_ToString(GetPtr(this));
+ }
+
+ /// <summary>
+ /// Returns a new <see cref="Godot.SignalAwaiter"/> awaiter configured to complete when the instance
+ /// <paramref name="source"/> emits the signal specified by the <paramref name="signal"/> parameter.
+ /// </summary>
+ /// <param name="source">
+ /// The instance the awaiter will be listening to.
+ /// </param>
+ /// <param name="signal">
+ /// The signal the awaiter will be waiting for.
+ /// </param>
+ /// <example>
+ /// This sample prints a message once every frame up to 100 times.
+ /// <code>
+ /// public override void _Ready()
+ /// {
+ /// for (int i = 0; i &lt; 100; i++)
+ /// {
+ /// await ToSignal(GetTree(), "idle_frame");
+ /// GD.Print($"Frame {i}");
+ /// }
+ /// }
+ /// </code>
+ /// </example>
public SignalAwaiter ToSignal(Object source, string signal)
{
return new SignalAwaiter(source, signal, this);
}
+ /// <summary>
+ /// Gets a new <see cref="Godot.DynamicGodotObject"/> associated with this instance.
+ /// </summary>
+ public dynamic DynamicObject => new DynamicGodotObject(this);
+
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static IntPtr godot_icall_Object_Ctor(Object obj);
@@ -81,6 +120,9 @@ namespace Godot
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_Reference_Disposed(Object obj, IntPtr ptr, bool isFinalizer);
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static string godot_icall_Object_ToString(IntPtr ptr);
+
// Used by the generated API
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static IntPtr godot_icall_Object_ClassDB_get_method(string type, string method);
diff --git a/modules/mono/glue/Managed/Files/Quat.cs b/modules/mono/glue/Managed/Files/Quat.cs
index fd1ac01083..d0c15146a5 100644
--- a/modules/mono/glue/Managed/Files/Quat.cs
+++ b/modules/mono/glue/Managed/Files/Quat.cs
@@ -123,22 +123,23 @@ namespace Godot
// Calculate cosine
real_t cosom = x * b.x + y * b.y + z * b.z + w * b.w;
- var to1 = new real_t[4];
+ var to1 = new Quat();
// Adjust signs if necessary
if (cosom < 0.0)
{
- cosom = -cosom; to1[0] = -b.x;
- to1[1] = -b.y;
- to1[2] = -b.z;
- to1[3] = -b.w;
+ cosom = -cosom;
+ to1.x = -b.x;
+ to1.y = -b.y;
+ to1.z = -b.z;
+ to1.w = -b.w;
}
else
{
- to1[0] = b.x;
- to1[1] = b.y;
- to1[2] = b.z;
- to1[3] = b.w;
+ to1.x = b.x;
+ to1.y = b.y;
+ to1.z = b.z;
+ to1.w = b.w;
}
real_t sinom, scale0, scale1;
@@ -162,10 +163,10 @@ namespace Godot
// Calculate final values
return new Quat
(
- scale0 * x + scale1 * to1[0],
- scale0 * y + scale1 * to1[1],
- scale0 * z + scale1 * to1[2],
- scale0 * w + scale1 * to1[3]
+ scale0 * x + scale1 * to1.x,
+ scale0 * y + scale1 * to1.y,
+ scale0 * z + scale1 * to1.z,
+ scale0 * w + scale1 * to1.w
);
}
@@ -347,9 +348,9 @@ namespace Godot
public override bool Equals(object obj)
{
- if (obj is Vector2)
+ if (obj is Quat)
{
- return Equals((Vector2)obj);
+ return Equals((Quat)obj);
}
return false;
diff --git a/modules/mono/glue/Managed/Files/RID.cs b/modules/mono/glue/Managed/Files/RID.cs
index b862b8cac0..12064beca2 100644
--- a/modules/mono/glue/Managed/Files/RID.cs
+++ b/modules/mono/glue/Managed/Files/RID.cs
@@ -3,7 +3,7 @@ using System.Runtime.CompilerServices;
namespace Godot
{
- public partial class RID : IDisposable
+ public sealed partial class RID : IDisposable
{
private bool disposed = false;
@@ -11,7 +11,13 @@ namespace Godot
internal static IntPtr GetPtr(RID instance)
{
- return instance == null ? IntPtr.Zero : instance.ptr;
+ if (instance == null)
+ return IntPtr.Zero;
+
+ if (instance.disposed)
+ throw new ObjectDisposedException(instance.GetType().FullName);
+
+ return instance.ptr;
}
~RID()
@@ -25,7 +31,7 @@ namespace Godot
GC.SuppressFinalize(this);
}
- protected virtual void Dispose(bool disposing)
+ private void Dispose(bool disposing)
{
if (disposed)
return;
@@ -64,6 +70,8 @@ namespace Godot
return godot_icall_RID_get_id(RID.GetPtr(this));
}
+ public override string ToString() => "[RID]";
+
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static IntPtr godot_icall_RID_Ctor(IntPtr from);
diff --git a/modules/mono/glue/Managed/Files/Transform.cs b/modules/mono/glue/Managed/Files/Transform.cs
index fa85855edd..bd79144873 100644
--- a/modules/mono/glue/Managed/Files/Transform.cs
+++ b/modules/mono/glue/Managed/Files/Transform.cs
@@ -71,21 +71,21 @@ namespace Godot
{
// Make rotation matrix
// Z vector
- Vector3 zAxis = eye - target;
+ Vector3 column2 = eye - target;
- zAxis.Normalize();
+ column2.Normalize();
- Vector3 yAxis = up;
+ Vector3 column1 = up;
- Vector3 xAxis = yAxis.Cross(zAxis);
+ Vector3 column0 = column1.Cross(column2);
// Recompute Y = Z cross X
- yAxis = zAxis.Cross(xAxis);
+ column1 = column2.Cross(column0);
- xAxis.Normalize();
- yAxis.Normalize();
+ column0.Normalize();
+ column1.Normalize();
- basis = Basis.CreateFromAxes(xAxis, yAxis, zAxis);
+ basis = new Basis(column0, column1, column2);
origin = eye;
}
@@ -94,9 +94,9 @@ namespace Godot
{
return new Transform(basis, new Vector3
(
- origin[0] += basis[0].Dot(ofs),
- origin[1] += basis[1].Dot(ofs),
- origin[2] += basis[2].Dot(ofs)
+ origin[0] += basis.Row0.Dot(ofs),
+ origin[1] += basis.Row1.Dot(ofs),
+ origin[2] += basis.Row2.Dot(ofs)
));
}
@@ -104,9 +104,9 @@ namespace Godot
{
return new Vector3
(
- basis[0].Dot(v) + origin.x,
- basis[1].Dot(v) + origin.y,
- basis[2].Dot(v) + origin.z
+ basis.Row0.Dot(v) + origin.x,
+ basis.Row1.Dot(v) + origin.y,
+ basis.Row2.Dot(v) + origin.z
);
}
@@ -116,9 +116,9 @@ namespace Godot
return new Vector3
(
- basis[0, 0] * vInv.x + basis[1, 0] * vInv.y + basis[2, 0] * vInv.z,
- basis[0, 1] * vInv.x + basis[1, 1] * vInv.y + basis[2, 1] * vInv.z,
- basis[0, 2] * vInv.x + basis[1, 2] * vInv.y + basis[2, 2] * vInv.z
+ basis.Row0[0] * vInv.x + basis.Row1[0] * vInv.y + basis.Row2[0] * vInv.z,
+ basis.Row0[1] * vInv.x + basis.Row1[1] * vInv.y + basis.Row2[1] * vInv.z,
+ basis.Row0[2] * vInv.x + basis.Row1[2] * vInv.y + basis.Row2[2] * vInv.z
);
}
@@ -134,9 +134,9 @@ namespace Godot
public static Transform FlipZ { get { return _flipZ; } }
// Constructors
- public Transform(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis, Vector3 origin)
+ public Transform(Vector3 column0, Vector3 column1, Vector3 column2, Vector3 origin)
{
- basis = Basis.CreateFromAxes(xAxis, yAxis, zAxis);
+ basis = new Basis(column0, column1, column2);
this.origin = origin;
}
diff --git a/modules/mono/glue/Managed/Files/Transform2D.cs b/modules/mono/glue/Managed/Files/Transform2D.cs
index c9e5b560b2..f7bb41d523 100644
--- a/modules/mono/glue/Managed/Files/Transform2D.cs
+++ b/modules/mono/glue/Managed/Files/Transform2D.cs
@@ -13,42 +13,65 @@ namespace Godot
{
public Vector2 x;
public Vector2 y;
- public Vector2 o;
-
- public Vector2 Origin
- {
- get { return o; }
- }
+ public Vector2 origin;
public real_t Rotation
{
- get { return Mathf.Atan2(y.x, o.y); }
+ get
+ {
+ real_t det = BasisDeterminant();
+ Transform2D t = Orthonormalized();
+ if (det < 0)
+ {
+ t.ScaleBasis(new Vector2(1, -1));
+ }
+ return Mathf.Atan2(t.x.y, t.x.x);
+ }
+ set
+ {
+ Vector2 scale = Scale;
+ x.x = y.y = Mathf.Cos(value);
+ x.y = y.x = Mathf.Sin(value);
+ y.x *= -1;
+ Scale = scale;
+ }
}
public Vector2 Scale
{
- get { return new Vector2(x.Length(), y.Length()); }
+ get
+ {
+ real_t detSign = Mathf.Sign(BasisDeterminant());
+ return new Vector2(x.Length(), detSign * y.Length());
+ }
+ set
+ {
+ x = x.Normalized();
+ y = y.Normalized();
+ x *= value.x;
+ y *= value.y;
+ }
}
- public Vector2 this[int index]
+ public Vector2 this[int rowIndex]
{
get
{
- switch (index)
+ switch (rowIndex)
{
case 0:
return x;
case 1:
return y;
case 2:
- return o;
+ return origin;
default:
throw new IndexOutOfRangeException();
}
}
set
{
- switch (index)
+ switch (rowIndex)
{
case 0:
x = value;
@@ -57,7 +80,7 @@ namespace Godot
y = value;
return;
case 2:
- o = value;
+ origin = value;
return;
default:
throw new IndexOutOfRangeException();
@@ -65,30 +88,29 @@ namespace Godot
}
}
-
- public real_t this[int index, int axis]
+ public real_t this[int rowIndex, int columnIndex]
{
get
{
- switch (index)
+ switch (rowIndex)
{
case 0:
- return x[axis];
+ return x[columnIndex];
case 1:
- return y[axis];
+ return y[columnIndex];
default:
throw new IndexOutOfRangeException();
}
}
set
{
- switch (index)
+ switch (rowIndex)
{
case 0:
- x[axis] = value;
+ x[columnIndex] = value;
return;
case 1:
- y[axis] = value;
+ y[columnIndex] = value;
return;
default:
throw new IndexOutOfRangeException();
@@ -98,34 +120,32 @@ namespace Godot
public Transform2D AffineInverse()
{
- var inv = this;
-
- real_t det = this[0, 0] * this[1, 1] - this[1, 0] * this[0, 1];
+ real_t det = BasisDeterminant();
if (det == 0)
- {
- return new Transform2D
- (
- float.NaN, float.NaN,
- float.NaN, float.NaN,
- float.NaN, float.NaN
- );
- }
+ throw new InvalidOperationException("Matrix determinant is zero and cannot be inverted.");
- real_t idet = 1.0f / det;
+ var inv = this;
+
+ real_t temp = inv[0, 0];
+ inv[0, 0] = inv[1, 1];
+ inv[1, 1] = temp;
- real_t temp = this[0, 0];
- this[0, 0] = this[1, 1];
- this[1, 1] = temp;
+ real_t detInv = 1.0f / det;
- this[0] *= new Vector2(idet, -idet);
- this[1] *= new Vector2(-idet, idet);
+ inv[0] *= new Vector2(detInv, -detInv);
+ inv[1] *= new Vector2(-detInv, detInv);
- this[2] = BasisXform(-this[2]);
+ inv[2] = BasisXform(-inv[2]);
return inv;
}
+ private real_t BasisDeterminant()
+ {
+ return x.x * y.y - x.y * y.x;
+ }
+
public Vector2 BasisXform(Vector2 v)
{
return new Vector2(Tdotx(v), Tdoty(v));
@@ -168,8 +188,8 @@ namespace Godot
}
// Extract parameters
- Vector2 p1 = Origin;
- Vector2 p2 = m.Origin;
+ Vector2 p1 = origin;
+ Vector2 p2 = m.origin;
// Construct matrix
var res = new Transform2D(Mathf.Atan2(v.y, v.x), p1.LinearInterpolate(p2, c));
@@ -189,7 +209,7 @@ namespace Godot
inv.x.y = inv.y.x;
inv.y.x = temp;
- inv.o = inv.BasisXform(-inv.o);
+ inv.origin = inv.BasisXform(-inv.origin);
return inv;
}
@@ -221,10 +241,18 @@ namespace Godot
var copy = this;
copy.x *= scale;
copy.y *= scale;
- copy.o *= scale;
+ copy.origin *= scale;
return copy;
}
+ private void ScaleBasis(Vector2 scale)
+ {
+ x.x *= scale.x;
+ x.y *= scale.y;
+ y.x *= scale.x;
+ y.y *= scale.y;
+ }
+
private real_t Tdotx(Vector2 with)
{
return this[0, 0] * with[0] + this[1, 0] * with[1];
@@ -238,66 +266,61 @@ namespace Godot
public Transform2D Translated(Vector2 offset)
{
var copy = this;
- copy.o += copy.BasisXform(offset);
+ copy.origin += copy.BasisXform(offset);
return copy;
}
public Vector2 Xform(Vector2 v)
{
- return new Vector2(Tdotx(v), Tdoty(v)) + o;
+ return new Vector2(Tdotx(v), Tdoty(v)) + origin;
}
public Vector2 XformInv(Vector2 v)
{
- Vector2 vInv = v - o;
+ Vector2 vInv = v - origin;
return new Vector2(x.Dot(vInv), y.Dot(vInv));
}
// Constants
- private static readonly Transform2D _identity = new Transform2D(new Vector2(1f, 0f), new Vector2(0f, 1f), Vector2.Zero);
- private static readonly Transform2D _flipX = new Transform2D(new Vector2(-1f, 0f), new Vector2(0f, 1f), Vector2.Zero);
- private static readonly Transform2D _flipY = new Transform2D(new Vector2(1f, 0f), new Vector2(0f, -1f), Vector2.Zero);
+ private static readonly Transform2D _identity = new Transform2D(1, 0, 0, 1, 0, 0);
+ private static readonly Transform2D _flipX = new Transform2D(-1, 0, 0, 1, 0, 0);
+ private static readonly Transform2D _flipY = new Transform2D(1, 0, 0, -1, 0, 0);
- public static Transform2D Identity { get { return _identity; } }
- public static Transform2D FlipX { get { return _flipX; } }
- public static Transform2D FlipY { get { return _flipY; } }
+ public static Transform2D Identity => _identity;
+ public static Transform2D FlipX => _flipX;
+ public static Transform2D FlipY => _flipY;
// Constructors
- public Transform2D(Vector2 xAxis, Vector2 yAxis, Vector2 origin)
+ public Transform2D(Vector2 xAxis, Vector2 yAxis, Vector2 originPos)
{
x = xAxis;
y = yAxis;
- o = origin;
+ origin = originPos;
}
public Transform2D(real_t xx, real_t xy, real_t yx, real_t yy, real_t ox, real_t oy)
{
x = new Vector2(xx, xy);
y = new Vector2(yx, yy);
- o = new Vector2(ox, oy);
+ origin = new Vector2(ox, oy);
}
public Transform2D(real_t rot, Vector2 pos)
{
- real_t cr = Mathf.Cos(rot);
- real_t sr = Mathf.Sin(rot);
- x.x = cr;
- y.y = cr;
- x.y = -sr;
- y.x = sr;
- o = pos;
+ x.x = y.y = Mathf.Cos(rot);
+ x.y = y.x = Mathf.Sin(rot);
+ y.x *= -1;
+ origin = pos;
}
public static Transform2D operator *(Transform2D left, Transform2D right)
{
- left.o = left.Xform(right.o);
+ left.origin = left.Xform(right.origin);
- real_t x0, x1, y0, y1;
-
- x0 = left.Tdotx(right.x);
- x1 = left.Tdoty(right.x);
- y0 = left.Tdotx(right.y);
- y1 = left.Tdoty(right.y);
+ real_t x0 = left.Tdotx(right.x);
+ real_t x1 = left.Tdoty(right.x);
+ real_t y0 = left.Tdotx(right.y);
+ real_t y1 = left.Tdoty(right.y);
left.x.x = x0;
left.x.y = x1;
@@ -319,22 +342,17 @@ namespace Godot
public override bool Equals(object obj)
{
- if (obj is Transform2D)
- {
- return Equals((Transform2D)obj);
- }
-
- return false;
+ return obj is Transform2D transform2D && Equals(transform2D);
}
public bool Equals(Transform2D other)
{
- return x.Equals(other.x) && y.Equals(other.y) && o.Equals(other.o);
+ return x.Equals(other.x) && y.Equals(other.y) && origin.Equals(other.origin);
}
public override int GetHashCode()
{
- return x.GetHashCode() ^ y.GetHashCode() ^ o.GetHashCode();
+ return x.GetHashCode() ^ y.GetHashCode() ^ origin.GetHashCode();
}
public override string ToString()
@@ -343,7 +361,7 @@ namespace Godot
{
x.ToString(),
y.ToString(),
- o.ToString()
+ origin.ToString()
});
}
@@ -353,7 +371,7 @@ namespace Godot
{
x.ToString(format),
y.ToString(format),
- o.ToString(format)
+ origin.ToString(format)
});
}
}
diff --git a/modules/mono/glue/Managed/Files/Vector2.cs b/modules/mono/glue/Managed/Files/Vector2.cs
index ce41886bfc..908162ec45 100644
--- a/modules/mono/glue/Managed/Files/Vector2.cs
+++ b/modules/mono/glue/Managed/Files/Vector2.cs
@@ -84,7 +84,7 @@ namespace Godot
public real_t AngleToPoint(Vector2 to)
{
- return Mathf.Atan2(x - to.x, y - to.y);
+ return Mathf.Atan2(y - to.y, x - to.x);
}
public real_t Aspect()
@@ -132,6 +132,11 @@ namespace Godot
(-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3);
}
+ public Vector2 DirectionTo(Vector2 b)
+ {
+ return new Vector2(b.x - x, b.y - y).Normalized();
+ }
+
public real_t DistanceSquaredTo(Vector2 to)
{
return (x - to.x) * (x - to.x) + (y - to.y) * (y - to.y);
diff --git a/modules/mono/glue/Managed/Files/Vector3.cs b/modules/mono/glue/Managed/Files/Vector3.cs
index f6ff27989d..0c96d346a9 100644
--- a/modules/mono/glue/Managed/Files/Vector3.cs
+++ b/modules/mono/glue/Managed/Files/Vector3.cs
@@ -126,6 +126,11 @@ namespace Godot
);
}
+ public Vector3 DirectionTo(Vector3 b)
+ {
+ return new Vector3(b.x - x, b.y - y, b.z - z).Normalized();
+ }
+
public real_t DistanceSquaredTo(Vector3 b)
{
return (b - this).LengthSquared();
diff --git a/modules/mono/glue/Managed/IgnoredFiles/Variant.cs b/modules/mono/glue/Managed/IgnoredFiles/Variant.cs
new file mode 100644
index 0000000000..802140b062
--- /dev/null
+++ b/modules/mono/glue/Managed/IgnoredFiles/Variant.cs
@@ -0,0 +1,11 @@
+
+namespace Godot
+{
+ public static class Variant
+ {
+ public enum Type
+ {
+
+ }
+ }
+}
diff --git a/modules/mono/glue/Managed/Managed.csproj b/modules/mono/glue/Managed/Managed.csproj
index 1f82dde5e7..61f738922b 100644
--- a/modules/mono/glue/Managed/Managed.csproj
+++ b/modules/mono/glue/Managed/Managed.csproj
@@ -11,7 +11,7 @@
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
+ <DebugType>portable</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
diff --git a/modules/mono/glue/arguments_vector.h b/modules/mono/glue/arguments_vector.h
new file mode 100644
index 0000000000..8c0f308c15
--- /dev/null
+++ b/modules/mono/glue/arguments_vector.h
@@ -0,0 +1,68 @@
+/*************************************************************************/
+/* arguments_vector.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef ARGUMENTS_VECTOR_H
+#define ARGUMENTS_VECTOR_H
+
+#include "core/os/memory.h"
+
+template <typename T, int POOL_SIZE = 5>
+struct ArgumentsVector {
+
+private:
+ T pool[POOL_SIZE];
+ T *_ptr;
+ int size;
+
+ ArgumentsVector();
+ ArgumentsVector(const ArgumentsVector &);
+
+public:
+ T *ptr() { return _ptr; }
+ T &get(int p_idx) { return _ptr[p_idx]; }
+ void set(int p_idx, const T &p_value) { _ptr[p_idx] = p_value; }
+
+ explicit ArgumentsVector(int p_size) :
+ size(p_size) {
+ if (p_size <= POOL_SIZE) {
+ _ptr = pool;
+ } else {
+ _ptr = memnew_arr(T, p_size);
+ }
+ }
+
+ ~ArgumentsVector() {
+ if (size > POOL_SIZE) {
+ memdelete_arr(_ptr);
+ }
+ }
+};
+
+#endif // ARGUMENTS_VECTOR_H
diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp
index 58916c5283..7385014a53 100644
--- a/modules/mono/glue/base_object_glue.cpp
+++ b/modules/mono/glue/base_object_glue.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,12 +33,14 @@
#ifdef MONO_GLUE_ENABLED
#include "core/reference.h"
-#include "core/string_db.h"
+#include "core/string_name.h"
#include "../csharp_script.h"
+#include "../mono_gd/gd_mono_class.h"
#include "../mono_gd/gd_mono_internals.h"
#include "../mono_gd/gd_mono_utils.h"
#include "../signal_awaiter_utils.h"
+#include "arguments_vector.h"
Object *godot_icall_Object_Ctor(MonoObject *p_obj) {
Object *instance = memnew(Object);
@@ -65,14 +67,17 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) {
void *data = p_ptr->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
if (data) {
- Ref<MonoGCHandle> &gchandle = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get().gchandle;
- if (gchandle.is_valid()) {
- CSharpLanguage::release_script_gchandle(p_obj, gchandle);
+ CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
+ if (script_binding.inited) {
+ Ref<MonoGCHandle> &gchandle = script_binding.gchandle;
+ if (gchandle.is_valid()) {
+ CSharpLanguage::release_script_gchandle(p_obj, gchandle);
+ }
}
}
}
-void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, bool p_is_finalizer) {
+void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer) {
#ifdef DEBUG_ENABLED
CRASH_COND(p_ptr == NULL);
// This is only called with Reference derived classes
@@ -85,11 +90,14 @@ void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, bool p_is_
CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(ref->get_script_instance());
if (cs_instance) {
if (!cs_instance->is_destructing_script_instance()) {
- bool r_owner_deleted;
- cs_instance->mono_object_disposed_baseref(p_obj, p_is_finalizer, r_owner_deleted);
- if (!r_owner_deleted && !p_is_finalizer) {
- // If the native instance is still alive and Dispose() was called
- // (instead of the finalizer), then we remove the script instance.
+ bool delete_owner;
+ bool remove_script_instance;
+
+ cs_instance->mono_object_disposed_baseref(p_obj, p_is_finalizer, delete_owner, remove_script_instance);
+
+ if (delete_owner) {
+ memdelete(ref);
+ } else if (remove_script_instance) {
ref->set_script_instance(NULL);
}
}
@@ -105,9 +113,12 @@ void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, bool p_is_
void *data = ref->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
if (data) {
- Ref<MonoGCHandle> &gchandle = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get().gchandle;
- if (gchandle.is_valid()) {
- CSharpLanguage::release_script_gchandle(p_obj, gchandle);
+ CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
+ if (script_binding.inited) {
+ Ref<MonoGCHandle> &gchandle = script_binding.gchandle;
+ if (gchandle.is_valid()) {
+ CSharpLanguage::release_script_gchandle(p_obj, gchandle);
+ }
}
}
}
@@ -138,7 +149,7 @@ MonoObject *godot_icall_Object_weakref(Object *p_obj) {
wref->set_obj(p_obj);
}
- return GDMonoUtils::create_managed_for_godot_object(CACHED_CLASS(WeakRef), Reference::get_class_static(), Object::cast_to<Object>(wref.ptr()));
+ return GDMonoUtils::unmanaged_get_managed(wref.ptr());
}
Error godot_icall_SignalAwaiter_connect(Object *p_source, MonoString *p_signal, Object *p_target, MonoObject *p_awaiter) {
@@ -146,13 +157,83 @@ Error godot_icall_SignalAwaiter_connect(Object *p_source, MonoString *p_signal,
return SignalAwaiterUtils::connect_signal_awaiter(p_source, signal, p_target, p_awaiter);
}
+MonoArray *godot_icall_DynamicGodotObject_SetMemberList(Object *p_ptr) {
+ List<PropertyInfo> property_list;
+ p_ptr->get_property_list(&property_list);
+
+ MonoArray *result = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(String), property_list.size());
+
+ int i = 0;
+ for (List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) {
+ MonoString *boxed = GDMonoMarshal::mono_string_from_godot(E->get().name);
+ mono_array_set(result, MonoString *, i, boxed);
+ i++;
+ }
+
+ return result;
+}
+
+MonoBoolean godot_icall_DynamicGodotObject_InvokeMember(Object *p_ptr, MonoString *p_name, MonoArray *p_args, MonoObject **r_result) {
+ String name = GDMonoMarshal::mono_string_to_godot(p_name);
+
+ int argc = mono_array_length(p_args);
+
+ ArgumentsVector<Variant> arg_store(argc);
+ ArgumentsVector<const Variant *> args(argc);
+
+ for (int i = 0; i < argc; i++) {
+ MonoObject *elem = mono_array_get(p_args, MonoObject *, i);
+ arg_store.set(i, GDMonoMarshal::mono_object_to_variant(elem));
+ args.set(i, &arg_store.get(i));
+ }
+
+ Variant::CallError error;
+ Variant result = p_ptr->call(StringName(name), args.ptr(), argc, error);
+
+ *r_result = GDMonoMarshal::variant_to_mono_object(result);
+
+ return error.error == Variant::CallError::CALL_OK;
+}
+
+MonoBoolean godot_icall_DynamicGodotObject_GetMember(Object *p_ptr, MonoString *p_name, MonoObject **r_result) {
+ String name = GDMonoMarshal::mono_string_to_godot(p_name);
+
+ bool valid;
+ Variant value = p_ptr->get(StringName(name), &valid);
+
+ if (valid) {
+ *r_result = GDMonoMarshal::variant_to_mono_object(value);
+ }
+
+ return valid;
+}
+
+MonoBoolean godot_icall_DynamicGodotObject_SetMember(Object *p_ptr, MonoString *p_name, MonoObject *p_value) {
+ String name = GDMonoMarshal::mono_string_to_godot(p_name);
+ Variant value = GDMonoMarshal::mono_object_to_variant(p_value);
+
+ bool valid;
+ p_ptr->set(StringName(name), value, &valid);
+
+ return valid;
+}
+
+MonoString *godot_icall_Object_ToString(Object *p_ptr) {
+ return GDMonoMarshal::mono_string_from_godot(Variant(p_ptr).operator String());
+}
+
void godot_register_object_icalls() {
mono_add_internal_call("Godot.Object::godot_icall_Object_Ctor", (void *)godot_icall_Object_Ctor);
mono_add_internal_call("Godot.Object::godot_icall_Object_Disposed", (void *)godot_icall_Object_Disposed);
mono_add_internal_call("Godot.Object::godot_icall_Reference_Disposed", (void *)godot_icall_Reference_Disposed);
mono_add_internal_call("Godot.Object::godot_icall_Object_ClassDB_get_method", (void *)godot_icall_Object_ClassDB_get_method);
+ mono_add_internal_call("Godot.Object::godot_icall_Object_ToString", (void *)godot_icall_Object_ToString);
mono_add_internal_call("Godot.Object::godot_icall_Object_weakref", (void *)godot_icall_Object_weakref);
mono_add_internal_call("Godot.SignalAwaiter::godot_icall_SignalAwaiter_connect", (void *)godot_icall_SignalAwaiter_connect);
+ mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMemberList", (void *)godot_icall_DynamicGodotObject_SetMemberList);
+ mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_InvokeMember", (void *)godot_icall_DynamicGodotObject_InvokeMember);
+ mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_GetMember", (void *)godot_icall_DynamicGodotObject_GetMember);
+ mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMember", (void *)godot_icall_DynamicGodotObject_SetMember);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/base_object_glue.h b/modules/mono/glue/base_object_glue.h
index 2d4d66ebb8..e4ac9fb99d 100644
--- a/modules/mono/glue/base_object_glue.h
+++ b/modules/mono/glue/base_object_glue.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -42,7 +42,7 @@ Object *godot_icall_Object_Ctor(MonoObject *p_obj);
void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr);
-void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, bool p_is_finalizer);
+void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer);
MethodBind *godot_icall_Object_ClassDB_get_method(MonoString *p_type, MonoString *p_method);
@@ -50,6 +50,18 @@ MonoObject *godot_icall_Object_weakref(Object *p_obj);
Error godot_icall_SignalAwaiter_connect(Object *p_source, MonoString *p_signal, Object *p_target, MonoObject *p_awaiter);
+// DynamicGodotObject
+
+MonoArray *godot_icall_DynamicGodotObject_SetMemberList(Object *p_ptr);
+
+MonoBoolean godot_icall_DynamicGodotObject_InvokeMember(Object *p_ptr, MonoString *p_name, MonoArray *p_args, MonoObject **r_result);
+
+MonoBoolean godot_icall_DynamicGodotObject_GetMember(Object *p_ptr, MonoString *p_name, MonoObject **r_result);
+
+MonoBoolean godot_icall_DynamicGodotObject_SetMember(Object *p_ptr, MonoString *p_name, MonoObject *p_value);
+
+MonoString *godot_icall_Object_ToString(Object *p_ptr);
+
// Register internal calls
void godot_register_object_icalls();
diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp
index 059e2ff6de..4aef5684fd 100644
--- a/modules/mono/glue/collections_glue.cpp
+++ b/modules/mono/glue/collections_glue.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -73,20 +73,21 @@ int godot_icall_Array_Count(Array *ptr) {
return ptr->size();
}
-void godot_icall_Array_Add(Array *ptr, MonoObject *item) {
+int godot_icall_Array_Add(Array *ptr, MonoObject *item) {
ptr->append(GDMonoMarshal::mono_object_to_variant(item));
+ return ptr->size();
}
void godot_icall_Array_Clear(Array *ptr) {
ptr->clear();
}
-bool godot_icall_Array_Contains(Array *ptr, MonoObject *item) {
+MonoBoolean godot_icall_Array_Contains(Array *ptr, MonoObject *item) {
return ptr->find(GDMonoMarshal::mono_object_to_variant(item)) != -1;
}
void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int array_index) {
- int count = ptr->size();
+ unsigned int count = ptr->size();
if (mono_array_length(array) < (array_index + count)) {
MonoException *exc = mono_get_exception_argument("", "Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
@@ -94,7 +95,7 @@ void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int array_index) {
return;
}
- for (int i = 0; i < count; i++) {
+ for (unsigned int i = 0; i < count; i++) {
MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(ptr->operator[](i));
mono_array_setref(array, array_index, boxed);
array_index++;
@@ -113,7 +114,7 @@ void godot_icall_Array_Insert(Array *ptr, int index, MonoObject *item) {
ptr->insert(index, GDMonoMarshal::mono_object_to_variant(item));
}
-bool godot_icall_Array_Remove(Array *ptr, MonoObject *item) {
+MonoBoolean godot_icall_Array_Remove(Array *ptr, MonoObject *item) {
int idx = ptr->find(GDMonoMarshal::mono_object_to_variant(item));
if (idx >= 0) {
ptr->remove(idx);
@@ -130,6 +131,10 @@ void godot_icall_Array_RemoveAt(Array *ptr, int index) {
ptr->remove(index);
}
+Error godot_icall_Array_Resize(Array *ptr, int new_size) {
+ return ptr->resize(new_size);
+}
+
void godot_icall_Array_Generic_GetElementTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class) {
MonoType *elem_type = mono_reflection_type_get_type(refltype);
@@ -138,6 +143,10 @@ void godot_icall_Array_Generic_GetElementTypeInfo(MonoReflectionType *refltype,
*type_class = GDMono::get_singleton()->get_class(type_class_raw);
}
+MonoString *godot_icall_Array_ToString(Array *ptr) {
+ return GDMonoMarshal::mono_string_from_godot(Variant(*ptr).operator String());
+}
+
Dictionary *godot_icall_Dictionary_Ctor() {
return memnew(Dictionary);
}
@@ -204,21 +213,21 @@ void godot_icall_Dictionary_Clear(Dictionary *ptr) {
ptr->clear();
}
-bool godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value) {
+MonoBoolean godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value) {
// no dupes
Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
return ret != NULL && *ret == GDMonoMarshal::mono_object_to_variant(value);
}
-bool godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key) {
+MonoBoolean godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key) {
return ptr->has(GDMonoMarshal::mono_object_to_variant(key));
}
-bool godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key) {
+MonoBoolean godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key) {
return ptr->erase(GDMonoMarshal::mono_object_to_variant(key));
}
-bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value) {
+MonoBoolean godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value) {
Variant varKey = GDMonoMarshal::mono_object_to_variant(key);
// no dupes
@@ -231,7 +240,7 @@ bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject
return false;
}
-bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value) {
+MonoBoolean godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value) {
Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
if (ret == NULL) {
*value = NULL;
@@ -241,7 +250,7 @@ bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoOb
return true;
}
-bool godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class) {
+MonoBoolean godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class) {
Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
if (ret == NULL) {
*value = NULL;
@@ -259,6 +268,10 @@ void godot_icall_Dictionary_Generic_GetValueTypeInfo(MonoReflectionType *refltyp
*type_class = GDMono::get_singleton()->get_class(type_class_raw);
}
+MonoString *godot_icall_Dictionary_ToString(Dictionary *ptr) {
+ return GDMonoMarshal::mono_string_from_godot(Variant(*ptr).operator String());
+}
+
void godot_register_collections_icalls() {
mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor", (void *)godot_icall_Array_Ctor);
mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Dtor", (void *)godot_icall_Array_Dtor);
@@ -274,7 +287,9 @@ void godot_register_collections_icalls() {
mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Insert", (void *)godot_icall_Array_Insert);
mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Remove", (void *)godot_icall_Array_Remove);
mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_RemoveAt", (void *)godot_icall_Array_RemoveAt);
+ mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Resize", (void *)godot_icall_Array_Resize);
mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Generic_GetElementTypeInfo", (void *)godot_icall_Array_Generic_GetElementTypeInfo);
+ mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_ToString", (void *)godot_icall_Array_ToString);
mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Ctor", (void *)godot_icall_Dictionary_Ctor);
mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Dtor", (void *)godot_icall_Dictionary_Dtor);
@@ -293,6 +308,7 @@ void godot_register_collections_icalls() {
mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue", (void *)godot_icall_Dictionary_TryGetValue);
mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue_Generic", (void *)godot_icall_Dictionary_TryGetValue_Generic);
mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Generic_GetValueTypeInfo", (void *)godot_icall_Dictionary_Generic_GetValueTypeInfo);
+ mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ToString", (void *)godot_icall_Dictionary_ToString);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/collections_glue.h b/modules/mono/glue/collections_glue.h
index b9b1338510..54ed42c3b6 100644
--- a/modules/mono/glue/collections_glue.h
+++ b/modules/mono/glue/collections_glue.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -51,11 +51,11 @@ void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value);
int godot_icall_Array_Count(Array *ptr);
-void godot_icall_Array_Add(Array *ptr, MonoObject *item);
+int godot_icall_Array_Add(Array *ptr, MonoObject *item);
void godot_icall_Array_Clear(Array *ptr);
-bool godot_icall_Array_Contains(Array *ptr, MonoObject *item);
+MonoBoolean godot_icall_Array_Contains(Array *ptr, MonoObject *item);
void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int array_index);
@@ -63,12 +63,16 @@ int godot_icall_Array_IndexOf(Array *ptr, MonoObject *item);
void godot_icall_Array_Insert(Array *ptr, int index, MonoObject *item);
-bool godot_icall_Array_Remove(Array *ptr, MonoObject *item);
+MonoBoolean godot_icall_Array_Remove(Array *ptr, MonoObject *item);
void godot_icall_Array_RemoveAt(Array *ptr, int index);
+Error godot_icall_Array_Resize(Array *ptr, int new_size);
+
void godot_icall_Array_Generic_GetElementTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class);
+MonoString *godot_icall_Array_ToString(Array *ptr);
+
// Dictionary
Dictionary *godot_icall_Dictionary_Ctor();
@@ -91,20 +95,22 @@ void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *va
void godot_icall_Dictionary_Clear(Dictionary *ptr);
-bool godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value);
+MonoBoolean godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value);
-bool godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key);
+MonoBoolean godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key);
-bool godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key);
+MonoBoolean godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key);
-bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value);
+MonoBoolean godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value);
-bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value);
+MonoBoolean godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value);
-bool godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class);
+MonoBoolean godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class);
void godot_icall_Dictionary_Generic_GetValueTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class);
+MonoString *godot_icall_Dictionary_ToString(Dictionary *ptr);
+
// Register internal calls
void godot_register_collections_icalls();
diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp
index 9f5bcecdd9..d756131ac9 100644
--- a/modules/mono/glue/gd_glue.cpp
+++ b/modules/mono/glue/gd_glue.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -41,18 +41,18 @@
#include "../mono_gd/gd_mono_utils.h"
-MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes) {
+MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes, MonoBoolean p_allow_objects) {
Variant ret;
PoolByteArray varr = GDMonoMarshal::mono_array_to_PoolByteArray(p_bytes);
PoolByteArray::Read r = varr.read();
- Error err = decode_variant(ret, r.ptr(), varr.size(), NULL);
+ Error err = decode_variant(ret, r.ptr(), varr.size(), NULL, p_allow_objects);
if (err != OK) {
ret = RTR("Not enough bytes for decoding bytes, or invalid format.");
}
return GDMonoMarshal::variant_to_mono_object(ret);
}
-MonoObject *godot_icall_GD_convert(MonoObject *p_what, int p_type) {
+MonoObject *godot_icall_GD_convert(MonoObject *p_what, int32_t p_type) {
Variant what = GDMonoMarshal::mono_object_to_variant(p_what);
const Variant *args[1] = { &what };
Variant::CallError ce;
@@ -65,7 +65,7 @@ int godot_icall_GD_hash(MonoObject *p_var) {
return GDMonoMarshal::mono_object_to_variant(p_var).hash();
}
-MonoObject *godot_icall_GD_instance_from_id(int p_instance_id) {
+MonoObject *godot_icall_GD_instance_from_id(uint64_t p_instance_id) {
return GDMonoUtils::unmanaged_get_managed(ObjectDB::get_instance(p_instance_id));
}
@@ -115,7 +115,29 @@ void godot_icall_GD_printt(MonoArray *p_what) {
print_line(str);
}
-void godot_icall_GD_seed(int p_seed) {
+double godot_icall_GD_randf() {
+ return Math::randf();
+}
+
+uint32_t godot_icall_GD_randi() {
+ return Math::rand();
+}
+
+void godot_icall_GD_randomize() {
+ Math::randomize();
+}
+
+double godot_icall_GD_rand_range(double from, double to) {
+ return Math::random(from, to);
+}
+
+uint32_t godot_icall_GD_rand_seed(uint64_t seed, uint64_t *newSeed) {
+ int ret = Math::rand_from_seed(&seed);
+ *newSeed = seed;
+ return ret;
+}
+
+void godot_icall_GD_seed(uint64_t p_seed) {
Math::seed(p_seed);
}
@@ -153,7 +175,7 @@ MonoObject *godot_icall_GD_str2var(MonoString *p_str) {
return GDMonoMarshal::variant_to_mono_object(ret);
}
-bool godot_icall_GD_type_exists(MonoString *p_type) {
+MonoBoolean godot_icall_GD_type_exists(MonoString *p_type) {
return ClassDB::class_exists(GDMonoMarshal::mono_string_to_godot(p_type));
}
@@ -165,19 +187,19 @@ void godot_icall_GD_pushwarning(MonoString *p_str) {
WARN_PRINTS(GDMonoMarshal::mono_string_to_godot(p_str));
}
-MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var) {
+MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var, MonoBoolean p_full_objects) {
Variant var = GDMonoMarshal::mono_object_to_variant(p_var);
PoolByteArray barr;
int len;
- Error err = encode_variant(var, NULL, len);
+ Error err = encode_variant(var, NULL, len, p_full_objects);
ERR_EXPLAIN("Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).");
ERR_FAIL_COND_V(err != OK, NULL);
barr.resize(len);
{
PoolByteArray::Write w = barr.write();
- encode_variant(var, w.ptr(), len);
+ encode_variant(var, w.ptr(), len, p_full_objects);
}
return GDMonoMarshal::PoolByteArray_to_mono_array(barr);
@@ -201,6 +223,11 @@ void godot_register_gd_icalls() {
mono_add_internal_call("Godot.GD::godot_icall_GD_printraw", (void *)godot_icall_GD_printraw);
mono_add_internal_call("Godot.GD::godot_icall_GD_prints", (void *)godot_icall_GD_prints);
mono_add_internal_call("Godot.GD::godot_icall_GD_printt", (void *)godot_icall_GD_printt);
+ mono_add_internal_call("Godot.GD::godot_icall_GD_randf", (void *)godot_icall_GD_randf);
+ mono_add_internal_call("Godot.GD::godot_icall_GD_randi", (void *)godot_icall_GD_randi);
+ mono_add_internal_call("Godot.GD::godot_icall_GD_randomize", (void *)godot_icall_GD_randomize);
+ mono_add_internal_call("Godot.GD::godot_icall_GD_rand_range", (void *)godot_icall_GD_rand_range);
+ mono_add_internal_call("Godot.GD::godot_icall_GD_rand_seed", (void *)godot_icall_GD_rand_seed);
mono_add_internal_call("Godot.GD::godot_icall_GD_seed", (void *)godot_icall_GD_seed);
mono_add_internal_call("Godot.GD::godot_icall_GD_str", (void *)godot_icall_GD_str);
mono_add_internal_call("Godot.GD::godot_icall_GD_str2var", (void *)godot_icall_GD_str2var);
diff --git a/modules/mono/glue/gd_glue.h b/modules/mono/glue/gd_glue.h
index 6f846f221d..910979aae3 100644
--- a/modules/mono/glue/gd_glue.h
+++ b/modules/mono/glue/gd_glue.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,13 +35,13 @@
#include "../mono_gd/gd_mono_marshal.h"
-MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes);
+MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes, MonoBoolean p_allow_objects);
-MonoObject *godot_icall_GD_convert(MonoObject *p_what, int p_type);
+MonoObject *godot_icall_GD_convert(MonoObject *p_what, int32_t p_type);
int godot_icall_GD_hash(MonoObject *p_var);
-MonoObject *godot_icall_GD_instance_from_id(int p_instance_id);
+MonoObject *godot_icall_GD_instance_from_id(uint64_t p_instance_id);
void godot_icall_GD_print(MonoArray *p_what);
@@ -53,15 +53,25 @@ void godot_icall_GD_prints(MonoArray *p_what);
void godot_icall_GD_printt(MonoArray *p_what);
-void godot_icall_GD_seed(int p_seed);
+double godot_icall_GD_randf();
+
+uint32_t godot_icall_GD_randi();
+
+void godot_icall_GD_randomize();
+
+double godot_icall_GD_rand_range(double from, double to);
+
+uint32_t godot_icall_GD_rand_seed(uint64_t seed, uint64_t *newSeed);
+
+void godot_icall_GD_seed(uint64_t p_seed);
MonoString *godot_icall_GD_str(MonoArray *p_what);
MonoObject *godot_icall_GD_str2var(MonoString *p_str);
-bool godot_icall_GD_type_exists(MonoString *p_type);
+MonoBoolean godot_icall_GD_type_exists(MonoString *p_type);
-MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var);
+MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var, MonoBoolean p_full_objects);
MonoString *godot_icall_GD_var2str(MonoObject *p_var);
diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h
index 69c5c6dcdb..1836130b76 100644
--- a/modules/mono/glue/glue_header.h
+++ b/modules/mono/glue/glue_header.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -74,4 +74,6 @@ void godot_register_glue_header_icalls() {
} \
Object *m_instance = ci->creation_func();
+#include "arguments_vector.h"
+
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/nodepath_glue.cpp b/modules/mono/glue/nodepath_glue.cpp
index 422d73104d..2edc43af8d 100644
--- a/modules/mono/glue/nodepath_glue.cpp
+++ b/modules/mono/glue/nodepath_glue.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/glue/nodepath_glue.h b/modules/mono/glue/nodepath_glue.h
index 92579399a6..2192444336 100644
--- a/modules/mono/glue/nodepath_glue.h
+++ b/modules/mono/glue/nodepath_glue.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/glue/rid_glue.cpp b/modules/mono/glue/rid_glue.cpp
index 6c002b5b9d..6a9810d0d4 100644
--- a/modules/mono/glue/rid_glue.cpp
+++ b/modules/mono/glue/rid_glue.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/glue/rid_glue.h b/modules/mono/glue/rid_glue.h
index c725a9b5de..4b593e8a95 100644
--- a/modules/mono/glue/rid_glue.h
+++ b/modules/mono/glue/rid_glue.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/glue/string_glue.cpp b/modules/mono/glue/string_glue.cpp
index e1a2f1affd..a5c72160d7 100644
--- a/modules/mono/glue/string_glue.cpp
+++ b/modules/mono/glue/string_glue.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/glue/string_glue.h b/modules/mono/glue/string_glue.h
index 8b1553e28b..c9052edd40 100644
--- a/modules/mono/glue/string_glue.h
+++ b/modules/mono/glue/string_glue.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/godotsharp_defs.h b/modules/mono/godotsharp_defs.h
index 5a6a2d1742..0d3b96d789 100644
--- a/modules/mono/godotsharp_defs.h
+++ b/modules/mono/godotsharp_defs.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp
index d3fb2cb640..09a1fc6fbc 100644
--- a/modules/mono/godotsharp_dirs.cpp
+++ b/modules/mono/godotsharp_dirs.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -99,7 +99,6 @@ public:
String sln_filepath;
String csproj_filepath;
- String data_mono_bin_dir;
String data_editor_tools_dir;
String data_editor_prebuilt_api_dir;
#endif
@@ -107,6 +106,10 @@ public:
String data_mono_etc_dir;
String data_mono_lib_dir;
+#ifdef WINDOWS_ENABLED
+ String data_mono_bin_dir;
+#endif
+
private:
_GodotSharpDirs() {
res_data_dir = "res://.mono";
@@ -146,10 +149,13 @@ private:
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 WINDOWS_ENABLED
+ data_mono_bin_dir = data_mono_root_dir.plus_file("bin");
+#endif
+
#ifdef OSX_ENABLED
if (!DirAccess::exists(data_editor_tools_dir)) {
data_editor_tools_dir = exe_dir.plus_file("../Frameworks/GodotSharp/Tools");
@@ -160,7 +166,6 @@ private:
}
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");
}
@@ -178,6 +183,10 @@ private:
data_mono_etc_dir = data_mono_root_dir.plus_file("etc");
data_mono_lib_dir = data_mono_root_dir.plus_file("lib");
+#ifdef WINDOWS_ENABLED
+ data_mono_bin_dir = data_mono_root_dir.plus_file("bin");
+#endif
+
#ifdef OSX_ENABLED
if (!DirAccess::exists(data_mono_root_dir)) {
data_mono_etc_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/etc");
@@ -251,10 +260,6 @@ 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;
}
@@ -272,4 +277,10 @@ String get_data_mono_lib_dir() {
return _GodotSharpDirs::get_singleton().data_mono_lib_dir;
}
+#ifdef WINDOWS_ENABLED
+String get_data_mono_bin_dir() {
+ return _GodotSharpDirs::get_singleton().data_mono_bin_dir;
+}
+#endif
+
} // namespace GodotSharpDirs
diff --git a/modules/mono/godotsharp_dirs.h b/modules/mono/godotsharp_dirs.h
index 35b564be30..556df959e2 100644
--- a/modules/mono/godotsharp_dirs.h
+++ b/modules/mono/godotsharp_dirs.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -53,7 +53,6 @@ String get_build_logs_dir();
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
@@ -61,6 +60,10 @@ String get_data_editor_prebuilt_api_dir();
String get_data_mono_etc_dir();
String get_data_mono_lib_dir();
+#ifdef WINDOWS_ENABLED
+String get_data_mono_bin_dir();
+#endif
+
} // namespace GodotSharpDirs
#endif // GODOTSHARP_DIRS_H
diff --git a/modules/mono/mono_gc_handle.cpp b/modules/mono/mono_gc_handle.cpp
index f695bddfeb..a9e2136a19 100644
--- a/modules/mono/mono_gc_handle.cpp
+++ b/modules/mono/mono_gc_handle.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -65,7 +65,7 @@ Ref<MonoGCHandle> MonoGCHandle::create_weak(MonoObject *p_object) {
void MonoGCHandle::release() {
#ifdef DEBUG_ENABLED
- CRASH_COND(GDMono::get_singleton() == NULL);
+ CRASH_COND(!released && GDMono::get_singleton() == NULL);
#endif
if (!released && GDMono::get_singleton()->is_runtime_initialized()) {
diff --git a/modules/mono/mono_gc_handle.h b/modules/mono/mono_gc_handle.h
index e5aa04e2b8..63b61aff18 100644
--- a/modules/mono/mono_gc_handle.h
+++ b/modules/mono/mono_gc_handle.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index a80155bd89..bfb6c13224 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,10 +30,12 @@
#include "gd_mono.h"
+#include <mono/metadata/environment.h>
#include <mono/metadata/exception.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/mono-gc.h>
+#include <mono/metadata/profiler.h>
#include "core/os/dir_access.h"
#include "core/os/file_access.h"
@@ -54,16 +56,9 @@
#include "main/main.h"
#endif
-#ifdef MONO_PRINT_HANDLER_ENABLED
-void gdmono_MonoPrintCallback(const char *string, mono_bool is_stdout) {
-
- if (is_stdout) {
- OS::get_singleton()->print(string);
- } else {
- OS::get_singleton()->printerr(string);
- }
-}
-#endif
+#define OUT_OF_SYNC_ERR_MESSAGE(m_assembly_name) "The assembly '" m_assembly_name "' is out of sync. " \
+ "This error is expected if you just upgraded to a newer Godot version. " \
+ "Building the project will update the assembly to the correct version."
GDMono *GDMono::singleton = NULL;
@@ -90,6 +85,14 @@ void setup_runtime_main_args() {
mono_runtime_set_main_args(main_args.size(), main_args.ptrw());
}
+void gdmono_profiler_init() {
+ String profiler_args = GLOBAL_DEF("mono/profiler/args", "log:calls,alloc,sample,output=output.mlpd");
+ bool profiler_enabled = GLOBAL_DEF("mono/profiler/enabled", false);
+ if (profiler_enabled) {
+ mono_profiler_load(profiler_args.utf8());
+ }
+}
+
#ifdef DEBUG_ENABLED
static bool _wait_for_debugger_msecs(uint32_t p_msecs) {
@@ -102,7 +105,7 @@ static bool _wait_for_debugger_msecs(uint32_t p_msecs) {
OS::get_singleton()->delay_usec((p_msecs < 25 ? p_msecs : 25) * 1000);
- int tdiff = OS::get_singleton()->get_ticks_msec() - last_tick;
+ uint32_t tdiff = OS::get_singleton()->get_ticks_msec() - last_tick;
if (tdiff > p_msecs) {
p_msecs = 0;
@@ -130,9 +133,14 @@ void gdmono_debug_init() {
}
#endif
- CharString da_args = String("--debugger-agent=transport=dt_socket,address=127.0.0.1:" + itos(da_port) +
- ",embedding=1,server=y,suspend=" + (da_suspend ? "y,timeout=" + itos(da_timeout) : "n"))
- .utf8();
+ CharString da_args = OS::get_singleton()->get_environment("GODOT_MONO_DEBUGGER_AGENT").utf8();
+
+ if (da_args.length() == 0) {
+ da_args = String("--debugger-agent=transport=dt_socket,address=127.0.0.1:" + itos(da_port) +
+ ",embedding=1,server=y,suspend=" + (da_suspend ? "y,timeout=" + itos(da_timeout) : "n"))
+ .utf8();
+ }
+
// --debugger-agent=help
const char *options[] = {
"--soft-breakpoints",
@@ -145,6 +153,50 @@ void gdmono_debug_init() {
} // namespace
+void GDMono::add_mono_shared_libs_dir_to_path() {
+ // By default Mono seems to search shared libraries in the following directories:
+ // Current working directory, @executable_path@ and PATH
+ // The parent directory of the image file (assembly where the dllimport method is declared)
+ // @executable_path@/../lib
+ // @executable_path@/../Libraries (__MACH__ only)
+
+ // This does not work when embedding Mono unless we use the same directory structure.
+ // To fix this we append the directory containing our shared libraries to PATH.
+
+#if defined(WINDOWS_ENABLED) || defined(UNIX_ENABLED)
+ String path_var("PATH");
+ String path_value = OS::get_singleton()->get_environment(path_var);
+
+#ifdef WINDOWS_ENABLED
+ path_value += ';';
+
+ String bundled_bin_dir = GodotSharpDirs::get_data_mono_bin_dir();
+#ifdef TOOLS_ENABLED
+ if (DirAccess::exists(bundled_bin_dir)) {
+ path_value += bundled_bin_dir;
+ } else {
+ path_value += mono_reg_info.bin_dir;
+ }
+#else
+ if (DirAccess::exists(bundled_bin_dir))
+ path_value += bundled_bin_dir;
+#endif // TOOLS_ENABLED
+
+#else
+ path_value += ':';
+
+ String bundled_lib_dir = GodotSharpDirs::get_data_mono_lib_dir();
+ if (DirAccess::exists(bundled_lib_dir)) {
+ path_value += bundled_lib_dir;
+ } else {
+ // TODO: Do we need to add the lib dir when using the system installed Mono on Unix platforms?
+ }
+#endif // WINDOWS_ENABLED
+
+ OS::get_singleton()->set_environment(path_var, path_value);
+#endif // WINDOWS_ENABLED || UNIX_ENABLED
+}
+
void GDMono::initialize() {
ERR_FAIL_NULL(Engine::get_singleton());
@@ -157,16 +209,11 @@ void GDMono::initialize() {
GDMonoLog::get_singleton()->initialize();
-#ifdef MONO_PRINT_HANDLER_ENABLED
- mono_trace_set_print_handler(gdmono_MonoPrintCallback);
- mono_trace_set_printerr_handler(gdmono_MonoPrintCallback);
-#endif
-
String assembly_rootdir;
String config_dir;
#ifdef TOOLS_ENABLED
-#ifdef WINDOWS_ENABLED
+#if defined(WINDOWS_ENABLED)
mono_reg_info = MonoRegUtils::find_mono();
if (mono_reg_info.assembly_dir.length() && DirAccess::exists(mono_reg_info.assembly_dir)) {
@@ -176,7 +223,7 @@ void GDMono::initialize() {
if (mono_reg_info.config_dir.length() && DirAccess::exists(mono_reg_info.config_dir)) {
config_dir = mono_reg_info.config_dir;
}
-#elif OSX_ENABLED
+#elif defined(OSX_ENABLED)
const char *c_assembly_rootdir = mono_assembly_getrootdir();
const char *c_config_dir = mono_get_config_dir();
@@ -208,18 +255,32 @@ void GDMono::initialize() {
assembly_rootdir = bundled_assembly_rootdir;
config_dir = bundled_config_dir;
}
+
+#ifdef WINDOWS_ENABLED
+ if (assembly_rootdir.empty() || config_dir.empty()) {
+ // Assertion: if they are not set, then they weren't found in the registry
+ CRASH_COND(mono_reg_info.assembly_dir.length() > 0 || mono_reg_info.config_dir.length() > 0);
+
+ ERR_PRINT("Cannot find Mono in the registry");
+ }
+#endif // WINDOWS_ENABLED
+
#else
// These are always the directories in export templates
assembly_rootdir = bundled_assembly_rootdir;
config_dir = bundled_config_dir;
-#endif
+#endif // TOOLS_ENABLED
// 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);
+ add_mono_shared_libs_dir_to_path();
+
GDMonoAssembly::initialize();
+ gdmono_profiler_init();
+
#ifdef DEBUG_ENABLED
gdmono_debug_init();
#endif
@@ -228,6 +289,29 @@ void GDMono::initialize() {
mono_install_unhandled_exception_hook(&unhandled_exception_hook, NULL);
+#ifndef TOOLS_ENABLED
+ if (!DirAccess::exists("res://.mono")) {
+ // 'res://.mono/' is missing so there is nothing to load. We don't need to initialize mono, but
+ // we still do so unless mscorlib is missing (which is the case for projects that don't use C#).
+
+ String mscorlib_fname("mscorlib.dll");
+
+ Vector<String> search_dirs;
+ GDMonoAssembly::fill_search_dirs(search_dirs);
+
+ bool found = false;
+ for (int i = 0; i < search_dirs.size(); i++) {
+ if (FileAccess::exists(search_dirs[i].plus_file(mscorlib_fname))) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return; // mscorlib is missing, do not initialize mono
+ }
+#endif
+
root_domain = mono_jit_init_version("GodotEngine.RootDomain", "v4.0.30319");
ERR_EXPLAIN("Mono: Failed to initialize runtime");
@@ -285,15 +369,15 @@ void GDMono::initialize() {
// metadata, so we invalidate the version in the metadata and unload the script domain.
if (core_api_assembly_out_of_sync) {
- ERR_PRINT("The loaded Core API assembly is out of sync");
+ ERR_PRINT(OUT_OF_SYNC_ERR_MESSAGE(CORE_API_ASSEMBLY_NAME));
metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true);
} else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) {
- ERR_PRINT("The loaded Core API assembly is in sync, but the cache update failed");
+ ERR_PRINT("The loaded assembly '" CORE_API_ASSEMBLY_NAME "' is in sync, but the cache update failed");
metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true);
}
if (editor_api_assembly_out_of_sync) {
- ERR_PRINT("The loaded Editor API assembly is out of sync");
+ ERR_PRINT(OUT_OF_SYNC_ERR_MESSAGE(EDITOR_API_ASSEMBLY_NAME));
metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true);
}
@@ -322,7 +406,7 @@ namespace GodotSharpBindings {
uint64_t get_core_api_hash();
#ifdef TOOLS_ENABLED
uint64_t get_editor_api_hash();
-#endif // TOOLS_ENABLED
+#endif
uint32_t get_bindings_version();
void register_generated_icalls();
@@ -339,29 +423,20 @@ void GDMono::_register_internal_calls() {
#endif
}
-#ifdef DEBUG_METHODS_ENABLED
void GDMono::_initialize_and_check_api_hashes() {
- api_core_hash = ClassDB::get_api_hash(ClassDB::API_CORE);
-
#ifdef MONO_GLUE_ENABLED
- if (api_core_hash != GodotSharpBindings::get_core_api_hash()) {
+ if (get_api_core_hash() != GodotSharpBindings::get_core_api_hash()) {
ERR_PRINT("Mono: Core API hash mismatch!");
}
-#endif
#ifdef TOOLS_ENABLED
- api_editor_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR);
-
-#ifdef MONO_GLUE_ENABLED
- if (api_editor_hash != GodotSharpBindings::get_editor_api_hash()) {
+ if (get_api_editor_hash() != GodotSharpBindings::get_editor_api_hash()) {
ERR_PRINT("Mono: Editor API hash mismatch!");
}
-#endif
-
#endif // TOOLS_ENABLED
+#endif // MONO_GLUE_ENABLED
}
-#endif // DEBUG_METHODS_ENABLED
void GDMono::add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly) {
@@ -513,6 +588,8 @@ bool GDMono::_load_core_api_assembly() {
CS_GLUE_VERSION != api_assembly_ver.cs_glue_version;
if (!core_api_assembly_out_of_sync) {
GDMonoUtils::update_godot_api_cache();
+
+ _install_trace_listener();
}
#else
GDMonoUtils::update_godot_api_cache();
@@ -616,6 +693,23 @@ bool GDMono::_load_api_assemblies() {
return true;
}
+void GDMono::_install_trace_listener() {
+
+#ifdef DEBUG_ENABLED
+ // Install the trace listener now before the project assembly is loaded
+ typedef void (*DebuggingUtils_InstallTraceListener)(MonoObject **);
+ MonoException *exc = NULL;
+ GDMonoClass *debug_utils = core_api_assembly->get_class(BINDINGS_NAMESPACE, "DebuggingUtils");
+ DebuggingUtils_InstallTraceListener install_func =
+ (DebuggingUtils_InstallTraceListener)debug_utils->get_method_thunk("InstallTraceListener");
+ install_func((MonoObject **)&exc);
+ if (exc) {
+ ERR_PRINT("Failed to install System.Diagnostics.Trace listener");
+ GDMonoUtils::debug_print_unhandled_exception(exc);
+ }
+#endif
+}
+
#ifdef TOOLS_ENABLED
String GDMono::_get_api_assembly_metadata_path() {
@@ -705,8 +799,6 @@ Error GDMono::_unload_scripts_domain() {
if (mono_domain_get() != root_domain)
mono_domain_set(root_domain, true);
- mono_gc_collect(mono_gc_max_generation());
-
finalizing_scripts_domain = true;
if (!mono_domain_finalize(scripts_domain, 2000)) {
@@ -726,7 +818,9 @@ Error GDMono::_unload_scripts_domain() {
#endif
core_api_assembly_out_of_sync = false;
+#ifdef TOOLS_ENABLED
editor_api_assembly_out_of_sync = false;
+#endif
MonoDomain *domain = scripts_domain;
scripts_domain = NULL;
@@ -759,7 +853,7 @@ Error GDMono::_load_tools_domain() {
}
#endif
-#ifdef TOOLS_ENABLED
+#ifdef GD_MONO_HOT_RELOAD
Error GDMono::reload_scripts_domain() {
ERR_FAIL_COND_V(!runtime_initialized, ERR_BUG);
@@ -772,6 +866,8 @@ Error GDMono::reload_scripts_domain() {
}
}
+ CSharpLanguage::get_singleton()->_uninitialize_script_bindings();
+
Error err = _load_scripts_domain();
if (err != OK) {
ERR_PRINT("Mono: Failed to load scripts domain");
@@ -780,14 +876,18 @@ Error GDMono::reload_scripts_domain() {
#ifdef MONO_GLUE_ENABLED
if (!_load_api_assemblies()) {
- 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
// metadata, so we invalidate the version in the metadata and unload the script domain.
if (core_api_assembly_out_of_sync) {
- ERR_PRINT("The loaded Core API assembly is out of sync");
+ ERR_PRINT(OUT_OF_SYNC_ERR_MESSAGE(CORE_API_ASSEMBLY_NAME));
metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true);
} else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) {
ERR_PRINT("The loaded Core API assembly is in sync, but the cache update failed");
@@ -795,16 +895,20 @@ Error GDMono::reload_scripts_domain() {
}
if (editor_api_assembly_out_of_sync) {
- ERR_PRINT("The loaded Editor API assembly is out of sync");
+ ERR_PRINT(OUT_OF_SYNC_ERR_MESSAGE(EDITOR_API_ASSEMBLY_NAME));
metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true);
}
- Error err = _unload_scripts_domain();
+ err = _unload_scripts_domain();
if (err != OK) {
WARN_PRINT("Mono: Failed to unload scripts domain");
}
return ERR_CANT_RESOLVE;
+#else
+ ERR_PRINT("The loaded API assembly is invalid");
+ CRASH_NOW();
+#endif
} else {
return ERR_CANT_OPEN;
}
@@ -832,14 +936,20 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
if (mono_domain_get() == p_domain)
mono_domain_set(root_domain, true);
- mono_gc_collect(mono_gc_max_generation());
if (!mono_domain_finalize(p_domain, 2000)) {
ERR_PRINT("Mono: Domain finalization timeout");
}
+
mono_gc_collect(mono_gc_max_generation());
_domain_assemblies_cleanup(mono_domain_get_id(p_domain));
+#ifdef TOOLS_ENABLED
+ if (p_domain == tools_domain) {
+ editor_tools_assembly = NULL;
+ }
+#endif
+
MonoException *exc = NULL;
mono_domain_try_unload(p_domain, (MonoObject **)&exc);
@@ -899,8 +1009,10 @@ void GDMono::unhandled_exception_hook(MonoObject *p_exc, void *) {
if (ScriptDebugger::get_singleton())
ScriptDebugger::get_singleton()->idle_poll();
#endif
- abort();
- _UNREACHABLE_();
+
+ exit(mono_environment_exitcode_get());
+
+ GD_UNREACHABLE();
}
GDMono::GDMono() {
@@ -919,7 +1031,9 @@ GDMono::GDMono() {
#endif
core_api_assembly_out_of_sync = false;
+#ifdef TOOLS_ENABLED
editor_api_assembly_out_of_sync = false;
+#endif
corlib_assembly = NULL;
core_api_assembly = NULL;
@@ -929,23 +1043,29 @@ GDMono::GDMono() {
editor_tools_assembly = NULL;
#endif
-#ifdef DEBUG_METHODS_ENABLED
api_core_hash = 0;
#ifdef TOOLS_ENABLED
api_editor_hash = 0;
#endif
-#endif
}
GDMono::~GDMono() {
if (is_runtime_initialized()) {
- if (scripts_domain) {
+#ifdef TOOLS_ENABLED
+ if (tools_domain) {
+ Error err = finalize_and_unload_domain(tools_domain);
+ if (err != OK) {
+ ERR_PRINT("Mono: Failed to unload tools domain");
+ }
+ }
+#endif
+ if (scripts_domain) {
Error err = _unload_scripts_domain();
if (err != OK) {
- WARN_PRINT("Mono: Failed to unload scripts domain");
+ ERR_PRINT("Mono: Failed to unload scripts domain");
}
}
@@ -966,6 +1086,8 @@ GDMono::~GDMono() {
mono_jit_cleanup(root_domain);
+ print_verbose("Mono: Finalized");
+
runtime_initialized = false;
}
@@ -1057,17 +1179,9 @@ void _GodotSharp::_bind_methods() {
_GodotSharp::_GodotSharp() {
singleton = this;
- queue_empty = true;
-#ifndef NO_THREADS
- queue_mutex = Mutex::create();
-#endif
}
_GodotSharp::~_GodotSharp() {
singleton = NULL;
-
- if (queue_mutex) {
- memdelete(queue_mutex);
- }
}
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index fd9551b6de..216c96a612 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -95,7 +95,9 @@ class GDMono {
#endif
bool core_api_assembly_out_of_sync;
+#ifdef TOOLS_ENABLED
bool editor_api_assembly_out_of_sync;
+#endif
GDMonoAssembly *corlib_assembly;
GDMonoAssembly *core_api_assembly;
@@ -123,6 +125,8 @@ class GDMono {
String _get_api_assembly_metadata_path();
#endif
+ void _install_trace_listener();
+
void _register_internal_calls();
Error _load_scripts_domain();
@@ -132,13 +136,11 @@ class GDMono {
Error _load_tools_domain();
#endif
-#ifdef DEBUG_METHODS_ENABLED
uint64_t api_core_hash;
#ifdef TOOLS_ENABLED
uint64_t api_editor_hash;
#endif
void _initialize_and_check_api_hashes();
-#endif
GDMonoLog *gdmono_log;
@@ -146,15 +148,23 @@ class GDMono {
MonoRegInfo mono_reg_info;
#endif
+ void add_mono_shared_libs_dir_to_path();
+
protected:
static GDMono *singleton;
public:
-#ifdef DEBUG_METHODS_ENABLED
- uint64_t get_api_core_hash() { return api_core_hash; }
+ uint64_t get_api_core_hash() {
+ if (api_core_hash == 0)
+ api_core_hash = ClassDB::get_api_hash(ClassDB::API_CORE);
+ return api_core_hash;
+ }
#ifdef TOOLS_ENABLED
- uint64_t get_api_editor_hash() { return api_editor_hash; }
-#endif
+ uint64_t get_api_editor_hash() {
+ if (api_editor_hash == 0)
+ api_editor_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR);
+ return api_editor_hash;
+ }
#endif
#ifdef TOOLS_ENABLED
@@ -193,7 +203,7 @@ public:
GDMonoClass *get_class(MonoClass *p_raw_class);
-#ifdef TOOLS_ENABLED
+#ifdef GD_MONO_HOT_RELOAD
Error reload_scripts_domain();
#endif
@@ -266,12 +276,6 @@ class _GodotSharp : public Object {
List<NodePath *> np_delete_queue;
List<RID *> rid_delete_queue;
- bool queue_empty;
-
-#ifndef NO_THREADS
- Mutex *queue_mutex;
-#endif
-
protected:
static _GodotSharp *singleton;
static void _bind_methods();
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
index 72b0204672..8fec28b186 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -50,7 +50,7 @@ void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const Strin
const char *rootdir = mono_assembly_getrootdir();
if (rootdir) {
- String framework_dir = String(rootdir).plus_file("mono").plus_file("4.5");
+ String framework_dir = String::utf8(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"));
}
@@ -277,6 +277,7 @@ Error GDMonoAssembly::load(bool p_refonly) {
ERR_FAIL_NULL_V(image, ERR_FILE_CANT_OPEN);
#ifdef DEBUG_ENABLED
+ Vector<uint8_t> pdb_data;
String pdb_path(path + ".pdb");
if (!FileAccess::exists(pdb_path)) {
@@ -286,8 +287,9 @@ Error GDMonoAssembly::load(bool p_refonly) {
goto no_pdb;
}
- pdb_data.clear();
pdb_data = FileAccess::get_file_as_array(pdb_path);
+
+ // mono_debug_close_image doesn't seem to be needed
mono_debug_open_image_from_memory(image, &pdb_data[0], pdb_data.size());
no_pdb:
@@ -306,6 +308,9 @@ no_pdb:
ERR_FAIL_COND_V(status != MONO_IMAGE_OK || assembly == NULL, ERR_FILE_CANT_OPEN);
+ // Decrement refcount which was previously incremented by mono_image_open_from_data_with_name
+ mono_image_close(image);
+
loaded = true;
modified_time = last_modified_time;
@@ -321,8 +326,6 @@ Error GDMonoAssembly::wrapper_for_image(MonoImage *p_image) {
image = p_image;
- mono_image_addref(image);
-
loaded = true;
return OK;
@@ -332,13 +335,6 @@ void GDMonoAssembly::unload() {
ERR_FAIL_COND(!loaded);
-#ifdef DEBUG_ENABLED
- if (pdb_data.size()) {
- mono_debug_close_image(image);
- pdb_data.clear();
- }
-#endif
-
for (Map<MonoClass *, GDMonoClass *>::Element *E = cached_raw.front(); E; E = E->next()) {
memdelete(E->value());
}
@@ -346,8 +342,6 @@ void GDMonoAssembly::unload() {
cached_classes.clear();
cached_raw.clear();
- mono_image_close(image);
-
assembly = NULL;
image = NULL;
loaded = false;
diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h
index 2af40ec901..32432af37d 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.h
+++ b/modules/mono/mono_gd/gd_mono_assembly.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -84,10 +84,6 @@ class GDMonoAssembly {
bool gdobject_class_cache_updated;
Map<StringName, GDMonoClass *> gdobject_class_cache;
-#ifdef DEBUG_ENABLED
- Vector<uint8_t> pdb_data;
-#endif
-
static bool no_search;
static bool in_preload;
static Vector<String> search_dirs;
diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp
index c55f9160bd..4342f46109 100644
--- a/modules/mono/mono_gd/gd_mono_class.cpp
+++ b/modules/mono/mono_gd/gd_mono_class.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -55,12 +55,21 @@ String GDMonoClass::get_full_name() const {
}
MonoType *GDMonoClass::get_mono_type() {
- // Care, you cannot compare MonoType pointers
+ // Careful, you cannot compare two MonoType*.
+ // There is mono_metadata_type_equal, how is this different from comparing two MonoClass*?
return get_mono_type(mono_class);
}
-bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const {
+uint32_t GDMonoClass::get_flags() const {
+ return mono_class_get_flags(mono_class);
+}
+
+bool GDMonoClass::is_static() const {
+ uint32_t static_class_flags = MONO_TYPE_ATTR_ABSTRACT | MONO_TYPE_ATTR_SEALED;
+ return (get_flags() & static_class_flags) == static_class_flags;
+}
+bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const {
return mono_class_is_assignable_from(mono_class, p_from->mono_class);
}
@@ -252,6 +261,11 @@ bool GDMonoClass::has_fetched_method_unknown_params(const StringName &p_name) {
return get_fetched_method_unknown_params(p_name) != NULL;
}
+bool GDMonoClass::implements_interface(GDMonoClass *p_interface) {
+
+ return mono_class_implements_interface(mono_class, p_interface->get_mono_ptr());
+}
+
GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, int p_params_count) {
MethodKey key = MethodKey(p_name, p_params_count);
diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h
index 689001f494..249422b844 100644
--- a/modules/mono/mono_gd/gd_mono_class.h
+++ b/modules/mono/mono_gd/gd_mono_class.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -109,6 +109,9 @@ public:
String get_full_name() const;
MonoType *get_mono_type();
+ uint32_t get_flags() const;
+ bool is_static() const;
+
bool is_assignable_from(GDMonoClass *p_from) const;
_FORCE_INLINE_ StringName get_namespace() const { return namespace_name; }
@@ -132,6 +135,8 @@ public:
void fetch_attributes();
void fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base);
+ bool implements_interface(GDMonoClass *p_interface);
+
GDMonoMethod *get_method(const StringName &p_name, int p_params_count = 0);
GDMonoMethod *get_method(MonoMethod *p_raw_method);
GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name);
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
index f09e93e662..9779797d1a 100644
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ b/modules/mono/mono_gd/gd_mono_field.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -49,7 +49,7 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
#define SET_FROM_ARRAY(m_type) \
{ \
MonoArray *managed = GDMonoMarshal::m_type##_to_mono_array(p_value.operator ::m_type()); \
- mono_field_set_value(p_object, mono_field, &managed); \
+ mono_field_set_value(p_object, mono_field, managed); \
}
switch (type.type_encoding) {
@@ -313,6 +313,18 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
break;
}
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
+
ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + type_class->get_name());
ERR_FAIL();
} break;
@@ -422,8 +434,8 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
MonoException *exc = NULL;
- GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
- MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
+ MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_dict) {
@@ -434,8 +446,8 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
exc = NULL;
- GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
- MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
+ MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_array) {
@@ -443,6 +455,18 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
mono_field_set_value(p_object, mono_field, managed);
break;
}
+
+ if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
+
+ if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
} break;
default: {
@@ -505,20 +529,20 @@ bool GDMonoField::is_static() {
return mono_field_get_flags(mono_field) & MONO_FIELD_ATTR_STATIC;
}
-GDMonoClassMember::Visibility GDMonoField::get_visibility() {
+IMonoClassMember::Visibility GDMonoField::get_visibility() {
switch (mono_field_get_flags(mono_field) & MONO_FIELD_ATTR_FIELD_ACCESS_MASK) {
case MONO_FIELD_ATTR_PRIVATE:
- return GDMonoClassMember::PRIVATE;
+ return IMonoClassMember::PRIVATE;
case MONO_FIELD_ATTR_FAM_AND_ASSEM:
- return GDMonoClassMember::PROTECTED_AND_INTERNAL;
+ return IMonoClassMember::PROTECTED_AND_INTERNAL;
case MONO_FIELD_ATTR_ASSEMBLY:
- return GDMonoClassMember::INTERNAL;
+ return IMonoClassMember::INTERNAL;
case MONO_FIELD_ATTR_FAMILY:
- return GDMonoClassMember::PROTECTED;
+ return IMonoClassMember::PROTECTED;
case MONO_FIELD_ATTR_PUBLIC:
- return GDMonoClassMember::PUBLIC;
+ return IMonoClassMember::PUBLIC;
default:
- ERR_FAIL_V(GDMonoClassMember::PRIVATE);
+ ERR_FAIL_V(IMonoClassMember::PRIVATE);
}
}
diff --git a/modules/mono/mono_gd/gd_mono_field.h b/modules/mono/mono_gd/gd_mono_field.h
index a6b368c4d6..e348583370 100644
--- a/modules/mono/mono_gd/gd_mono_field.h
+++ b/modules/mono/mono_gd/gd_mono_field.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,10 +32,10 @@
#define GDMONOFIELD_H
#include "gd_mono.h"
-#include "gd_mono_class_member.h"
#include "gd_mono_header.h"
+#include "i_mono_class_member.h"
-class GDMonoField : public GDMonoClassMember {
+class GDMonoField : public IMonoClassMember {
GDMonoClass *owner;
MonoClassField *mono_field;
@@ -47,15 +47,15 @@ class GDMonoField : public GDMonoClassMember {
MonoCustomAttrInfo *attributes;
public:
- virtual MemberType get_member_type() { return MEMBER_TYPE_FIELD; }
+ virtual MemberType get_member_type() GD_FINAL { return MEMBER_TYPE_FIELD; }
- virtual StringName get_name() { return name; }
+ virtual StringName get_name() GD_FINAL { return name; }
- virtual bool is_static();
- virtual Visibility get_visibility();
+ virtual bool is_static() GD_FINAL;
+ virtual Visibility get_visibility() GD_FINAL;
- virtual bool has_attribute(GDMonoClass *p_attr_class);
- virtual MonoObject *get_attribute(GDMonoClass *p_attr_class);
+ virtual bool has_attribute(GDMonoClass *p_attr_class) GD_FINAL;
+ virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) GD_FINAL;
void fetch_attributes();
_FORCE_INLINE_ ManagedType get_type() const { return type; }
diff --git a/modules/mono/mono_gd/gd_mono_header.h b/modules/mono/mono_gd/gd_mono_header.h
index 51d0c9b356..d7962eac8b 100644
--- a/modules/mono/mono_gd/gd_mono_header.h
+++ b/modules/mono/mono_gd/gd_mono_header.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,24 +35,12 @@
class GDMonoAssembly;
class GDMonoClass;
-class GDMonoClassMember;
class GDMonoField;
-class GDMonoProperty;
class GDMonoMethod;
+class GDMonoProperty;
-struct ManagedType {
- int type_encoding;
- GDMonoClass *type_class;
-
- ManagedType() :
- type_encoding(0),
- type_class(NULL) {
- }
+class IMonoClassMember;
- ManagedType(int p_type_encoding, GDMonoClass *p_type_class) :
- type_encoding(p_type_encoding),
- type_class(p_type_class) {
- }
-};
+#include "managed_type.h"
#endif // GD_MONO_HEADER_H
diff --git a/modules/mono/mono_gd/gd_mono_internals.cpp b/modules/mono/mono_gd/gd_mono_internals.cpp
index 505c030ca1..63bcfe053c 100644
--- a/modules/mono/mono_gd/gd_mono_internals.cpp
+++ b/modules/mono/mono_gd/gd_mono_internals.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,6 +34,8 @@
#include "../mono_gc_handle.h"
#include "../utils/macros.h"
#include "../utils/thread_local.h"
+#include "gd_mono_class.h"
+#include "gd_mono_marshal.h"
#include "gd_mono_utils.h"
#include <mono/metadata/exception.h>
@@ -55,10 +57,48 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
CRASH_COND(!klass);
- Ref<MonoGCHandle> gchandle = ref ? MonoGCHandle::create_weak(managed) :
- MonoGCHandle::create_strong(managed);
+ GDMonoClass *native = GDMonoUtils::get_class_native_base(klass);
- Ref<CSharpScript> script = CSharpScript::create_for_managed_type(klass);
+ CRASH_COND(native == NULL);
+
+ if (native == klass) {
+ // If it's just a wrapper Godot class and not a custom inheriting class, then attach a
+ // script binding instead. One of the advantages of this is that if a script is attached
+ // later and it's not a C# script, then the managed object won't have to be disposed.
+ // Another reason for doing this is that this instance could outlive CSharpLanguage, which would
+ // be problematic when using a script. See: https://github.com/godotengine/godot/issues/25621
+
+ CSharpScriptBinding script_binding;
+
+ script_binding.inited = true;
+ script_binding.type_name = NATIVE_GDMONOCLASS_NAME(klass);
+ script_binding.wrapper_class = klass;
+ script_binding.gchandle = MonoGCHandle::create_strong(managed);
+
+ Reference *kref = Object::cast_to<Reference>(unmanaged);
+ if (kref) {
+ // Unsafe refcount increment. The managed instance also counts as a reference.
+ // This way if the unmanaged world has no references to our owner
+ // but the managed instance is alive, the refcount will be 1 instead of 0.
+ // See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr)
+
+ kref->reference();
+ }
+
+ // The object was just created, no script instance binding should have been attached
+ CRASH_COND(unmanaged->has_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()));
+
+ void *data = (void *)CSharpLanguage::get_singleton()->insert_script_binding(unmanaged, script_binding);
+
+ // Should be thread safe because the object was just created and nothing else should be referencing it
+ unmanaged->set_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index(), data);
+
+ return;
+ }
+
+ Ref<MonoGCHandle> gchandle = ref ? MonoGCHandle::create_weak(managed) : MonoGCHandle::create_strong(managed);
+
+ Ref<CSharpScript> script = CSharpScript::create_for_managed_type(klass, native);
CRASH_COND(script.is_null());
@@ -71,8 +111,9 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
void unhandled_exception(MonoException *p_exc) {
mono_unhandled_exception((MonoObject *)p_exc); // prints the exception as well
- abort();
- _UNREACHABLE_();
+ // Too bad 'mono_invoke_unhandled_exception_hook' is not exposed to embedders
+ GDMono::unhandled_exception_hook((MonoObject *)p_exc, NULL);
+ GD_UNREACHABLE();
}
} // namespace GDMonoInternals
diff --git a/modules/mono/mono_gd/gd_mono_internals.h b/modules/mono/mono_gd/gd_mono_internals.h
index 50cadcedf6..2d77bde27c 100644
--- a/modules/mono/mono_gd/gd_mono_internals.h
+++ b/modules/mono/mono_gd/gd_mono_internals.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -45,7 +45,7 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged);
* Do not call this function directly.
* Use GDMonoUtils::debug_unhandled_exception(MonoException *) instead.
*/
-_NO_RETURN_ void unhandled_exception(MonoException *p_exc);
+GD_NORETURN void unhandled_exception(MonoException *p_exc);
} // namespace GDMonoInternals
diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp
index b7bb2cb2d6..087a7a2e5c 100644
--- a/modules/mono/mono_gd/gd_mono_log.cpp
+++ b/modules/mono/mono_gd/gd_mono_log.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -52,7 +52,7 @@ static int log_level_get_id(const char *p_log_level) {
return -1;
}
-void gdmono_MonoLogCallback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) {
+static void mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) {
FileAccess *f = GDMonoLog::get_singleton()->get_log_file();
@@ -72,8 +72,11 @@ void gdmono_MonoLogCallback(const char *log_domain, const char *log_level, const
if (fatal) {
ERR_PRINTS("Mono: FATAL ERROR, ABORTING! Logfile: " + GDMonoLog::get_singleton()->get_log_file_path() + "\n");
- // If we were to abort without flushing, the log wouldn't get written.
+ // Make sure to flush before aborting
f->flush();
+ f->close();
+ memdelete(f);
+
abort();
}
}
@@ -93,17 +96,9 @@ bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) {
return true;
}
-void GDMonoLog::_open_log_file(const String &p_file_path) {
-
- log_file = FileAccess::open(p_file_path, FileAccess::WRITE);
-
- ERR_EXPLAIN("Failed to create log file");
- ERR_FAIL_COND(!log_file);
-}
-
void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) {
- static const uint64_t MAX_SECS = 5 * 86400;
+ static const uint64_t MAX_SECS = 5 * 86400; // 5 days
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
ERR_FAIL_COND(!da);
@@ -120,10 +115,9 @@ void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) {
if (!current.ends_with(".txt"))
continue;
- String name = current.get_basename();
- uint64_t unixtime = (uint64_t)name.to_int64();
+ uint64_t modified_time = FileAccess::get_modified_time(da->get_current_dir().plus_file(current));
- if (OS::get_singleton()->get_unix_time() - unixtime > MAX_SECS) {
+ if (OS::get_singleton()->get_unix_time() - modified_time > MAX_SECS) {
da->remove(current);
}
}
@@ -131,29 +125,71 @@ void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) {
da->list_dir_end();
}
+static String format(const char *p_fmt, ...) {
+ va_list args;
+
+ va_start(args, p_fmt);
+ int len = vsnprintf(NULL, 0, p_fmt, args);
+ va_end(args);
+
+ len += 1; // for the trailing '/0'
+
+ char *buffer(memnew_arr(char, len));
+
+ va_start(args, p_fmt);
+ vsnprintf(buffer, len, p_fmt, args);
+ va_end(args);
+
+ String res(buffer);
+ memdelete_arr(buffer);
+
+ return res;
+}
+
void GDMonoLog::initialize() {
+ CharString log_level = OS::get_singleton()->get_environment("GODOT_MONO_LOG_LEVEL").utf8();
+
+ if (log_level.length() != 0 && log_level_get_id(log_level.get_data()) == -1) {
+ ERR_PRINTS(String() + "Mono: Ignoring invalid log level (GODOT_MONO_LOG_LEVEL): " + log_level.get_data());
+ log_level = CharString();
+ }
+
+ if (log_level.length() == 0) {
#ifdef DEBUG_ENABLED
- const char *log_level = "debug";
+ log_level = String("info").utf8();
#else
- const char *log_level = "warning";
+ log_level = String("warning").utf8();
#endif
+ }
String logs_dir = GodotSharpDirs::get_mono_logs_dir();
if (_try_create_logs_dir(logs_dir)) {
_delete_old_log_files(logs_dir);
- log_file_path = logs_dir.plus_file(String::num_int64(OS::get_singleton()->get_unix_time()) + ".txt");
- _open_log_file(log_file_path);
+ OS::Date date_now = OS::get_singleton()->get_date();
+ OS::Time time_now = OS::get_singleton()->get_time();
+ int pid = OS::get_singleton()->get_process_id();
+
+ String log_file_name = format("%d_%02d_%02d %02d.%02d.%02d (%d).txt",
+ date_now.year, date_now.month, date_now.day,
+ time_now.hour, time_now.min, time_now.sec, pid);
+
+ log_file_path = logs_dir.plus_file(log_file_name);
+
+ log_file = FileAccess::open(log_file_path, FileAccess::WRITE);
+ if (!log_file) {
+ ERR_PRINT("Mono: Cannot create log file");
+ }
}
- mono_trace_set_level_string(log_level);
- log_level_id = log_level_get_id(log_level);
+ mono_trace_set_level_string(log_level.get_data());
+ log_level_id = log_level_get_id(log_level.get_data());
if (log_file) {
- print_verbose("Mono: Logfile is " + log_file_path);
- mono_trace_set_log_handler(gdmono_MonoLogCallback, this);
+ OS::get_singleton()->print("Mono: Logfile is: %s\n", log_file_path.utf8().get_data());
+ mono_trace_set_log_handler(mono_log_callback, this);
} else {
OS::get_singleton()->printerr("Mono: No log file, using default log handler\n");
}
diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h
index 3b4ff07b7b..91d0557aa3 100644
--- a/modules/mono/mono_gd/gd_mono_log.h
+++ b/modules/mono/mono_gd/gd_mono_log.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -41,7 +41,6 @@ class GDMonoLog {
String log_file_path;
bool _try_create_logs_dir(const String &p_logs_dir);
- void _open_log_file(const String &p_file_path);
void _delete_old_log_files(const String &p_logs_dir);
static GDMonoLog *singleton;
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index 3f0a5d6e50..de4f3650bd 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,7 +35,7 @@
namespace GDMonoMarshal {
-Variant::Type managed_to_variant_type(const ManagedType &p_type) {
+Variant::Type managed_to_variant_type(const ManagedType &p_type, ExportInfo *r_export_info) {
switch (p_type.type_encoding) {
case MONO_TYPE_BOOLEAN:
return Variant::BOOL;
@@ -68,39 +68,39 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
} break;
case MONO_TYPE_VALUETYPE: {
- GDMonoClass *tclass = p_type.type_class;
+ GDMonoClass *vtclass = p_type.type_class;
- if (tclass == CACHED_CLASS(Vector2))
+ if (vtclass == CACHED_CLASS(Vector2))
return Variant::VECTOR2;
- if (tclass == CACHED_CLASS(Rect2))
+ if (vtclass == CACHED_CLASS(Rect2))
return Variant::RECT2;
- if (tclass == CACHED_CLASS(Transform2D))
+ if (vtclass == CACHED_CLASS(Transform2D))
return Variant::TRANSFORM2D;
- if (tclass == CACHED_CLASS(Vector3))
+ if (vtclass == CACHED_CLASS(Vector3))
return Variant::VECTOR3;
- if (tclass == CACHED_CLASS(Basis))
+ if (vtclass == CACHED_CLASS(Basis))
return Variant::BASIS;
- if (tclass == CACHED_CLASS(Quat))
+ if (vtclass == CACHED_CLASS(Quat))
return Variant::QUAT;
- if (tclass == CACHED_CLASS(Transform))
+ if (vtclass == CACHED_CLASS(Transform))
return Variant::TRANSFORM;
- if (tclass == CACHED_CLASS(AABB))
+ if (vtclass == CACHED_CLASS(AABB))
return Variant::AABB;
- if (tclass == CACHED_CLASS(Color))
+ if (vtclass == CACHED_CLASS(Color))
return Variant::COLOR;
- if (tclass == CACHED_CLASS(Plane))
+ if (vtclass == CACHED_CLASS(Plane))
return Variant::PLANE;
- if (mono_class_is_enum(tclass->get_mono_ptr()))
+ if (mono_class_is_enum(vtclass->get_mono_ptr()))
return Variant::INT;
} break;
@@ -156,26 +156,66 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
if (CACHED_CLASS(Array) == type_class) {
return Variant::ARRAY;
}
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ return Variant::DICTIONARY;
+ }
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ return Variant::ARRAY;
+ }
} break;
case MONO_TYPE_GENERICINST: {
MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type());
MonoException *exc = NULL;
- GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
- MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
+ MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_dict) {
+ if (r_export_info) {
+ MonoReflectionType *key_reftype;
+ MonoReflectionType *value_reftype;
+
+ exc = NULL;
+ invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes),
+ reftype, &key_reftype, &value_reftype, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+ r_export_info->dictionary.key_type = managed_to_variant_type(ManagedType::from_reftype(key_reftype));
+ r_export_info->dictionary.value_type = managed_to_variant_type(ManagedType::from_reftype(value_reftype));
+ }
+
return Variant::DICTIONARY;
}
exc = NULL;
- GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
- MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
+ MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_array) {
+ if (r_export_info) {
+ MonoReflectionType *elem_reftype;
+
+ exc = NULL;
+ invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType),
+ reftype, &elem_reftype, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+ r_export_info->array.element_type = managed_to_variant_type(ManagedType::from_reftype(elem_reftype));
+ }
+
+ return Variant::ARRAY;
+ }
+
+ if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ return Variant::DICTIONARY;
+ }
+
+ if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
return Variant::ARRAY;
}
} break;
@@ -216,7 +256,7 @@ String mono_to_utf16_string(MonoString *p_mono_string) {
ret.set(len, 0);
CharType *src = (CharType *)mono_string_chars(p_mono_string);
- CharType *dst = &(ret.operator[](0));
+ CharType *dst = ret.ptrw();
for (int i = 0; i < len; i++) {
dst[i] = src[i];
@@ -294,60 +334,60 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
} break;
case MONO_TYPE_VALUETYPE: {
- GDMonoClass *tclass = p_type.type_class;
+ GDMonoClass *vtclass = p_type.type_class;
- if (tclass == CACHED_CLASS(Vector2)) {
+ if (vtclass == CACHED_CLASS(Vector2)) {
GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var->operator ::Vector2());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from);
}
- if (tclass == CACHED_CLASS(Rect2)) {
+ if (vtclass == CACHED_CLASS(Rect2)) {
GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var->operator ::Rect2());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from);
}
- if (tclass == CACHED_CLASS(Transform2D)) {
+ if (vtclass == CACHED_CLASS(Transform2D)) {
GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var->operator ::Transform2D());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from);
}
- if (tclass == CACHED_CLASS(Vector3)) {
+ if (vtclass == CACHED_CLASS(Vector3)) {
GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var->operator ::Vector3());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from);
}
- if (tclass == CACHED_CLASS(Basis)) {
+ if (vtclass == CACHED_CLASS(Basis)) {
GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var->operator ::Basis());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from);
}
- if (tclass == CACHED_CLASS(Quat)) {
+ if (vtclass == CACHED_CLASS(Quat)) {
GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var->operator ::Quat());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from);
}
- if (tclass == CACHED_CLASS(Transform)) {
+ if (vtclass == CACHED_CLASS(Transform)) {
GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var->operator ::Transform());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from);
}
- if (tclass == CACHED_CLASS(AABB)) {
+ if (vtclass == CACHED_CLASS(AABB)) {
GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var->operator ::AABB());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from);
}
- if (tclass == CACHED_CLASS(Color)) {
+ if (vtclass == CACHED_CLASS(Color)) {
GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var->operator ::Color());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from);
}
- if (tclass == CACHED_CLASS(Plane)) {
+ if (vtclass == CACHED_CLASS(Plane)) {
GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var->operator ::Plane());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from);
}
- if (mono_class_is_enum(tclass->get_mono_ptr())) {
- MonoType *enum_basetype = mono_class_enum_basetype(tclass->get_mono_ptr());
+ if (mono_class_is_enum(vtclass->get_mono_ptr())) {
+ MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr());
MonoClass *enum_baseclass = mono_class_from_mono_type(enum_basetype);
switch (mono_type_get_type(enum_basetype)) {
case MONO_TYPE_BOOLEAN: {
@@ -453,6 +493,14 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
if (CACHED_CLASS(Array) == type_class) {
return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
}
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
+ }
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
+ }
} break;
case MONO_TYPE_OBJECT: {
// Variant
@@ -548,8 +596,8 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type());
MonoException *exc = NULL;
- GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
- MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
+ MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_dict) {
@@ -557,13 +605,21 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
}
exc = NULL;
- GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
- MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
+ MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_array) {
return GDMonoUtils::create_managed_from(p_var->operator Array(), p_type.type_class);
}
+
+ if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
+ }
+
+ if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
+ }
} break;
} break;
}
@@ -577,15 +633,9 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
if (!p_obj)
return Variant();
- GDMonoClass *tclass = GDMono::get_singleton()->get_class(mono_object_get_class(p_obj));
- ERR_FAIL_COND_V(!tclass, Variant());
-
- MonoType *raw_type = tclass->get_mono_type();
-
- ManagedType type;
+ ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj));
- type.type_encoding = mono_type_get_type(raw_type);
- type.type_class = tclass;
+ ERR_FAIL_COND_V(!type.type_class, Variant());
switch (type.type_encoding) {
case MONO_TYPE_BOOLEAN:
@@ -624,39 +674,39 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
} break;
case MONO_TYPE_VALUETYPE: {
- GDMonoClass *tclass = type.type_class;
+ GDMonoClass *vtclass = type.type_class;
- if (tclass == CACHED_CLASS(Vector2))
+ if (vtclass == CACHED_CLASS(Vector2))
return MARSHALLED_IN(Vector2, (GDMonoMarshal::M_Vector2 *)mono_object_unbox(p_obj));
- if (tclass == CACHED_CLASS(Rect2))
+ if (vtclass == CACHED_CLASS(Rect2))
return MARSHALLED_IN(Rect2, (GDMonoMarshal::M_Rect2 *)mono_object_unbox(p_obj));
- if (tclass == CACHED_CLASS(Transform2D))
+ if (vtclass == CACHED_CLASS(Transform2D))
return MARSHALLED_IN(Transform2D, (GDMonoMarshal::M_Transform2D *)mono_object_unbox(p_obj));
- if (tclass == CACHED_CLASS(Vector3))
+ if (vtclass == CACHED_CLASS(Vector3))
return MARSHALLED_IN(Vector3, (GDMonoMarshal::M_Vector3 *)mono_object_unbox(p_obj));
- if (tclass == CACHED_CLASS(Basis))
+ if (vtclass == CACHED_CLASS(Basis))
return MARSHALLED_IN(Basis, (GDMonoMarshal::M_Basis *)mono_object_unbox(p_obj));
- if (tclass == CACHED_CLASS(Quat))
+ if (vtclass == CACHED_CLASS(Quat))
return MARSHALLED_IN(Quat, (GDMonoMarshal::M_Quat *)mono_object_unbox(p_obj));
- if (tclass == CACHED_CLASS(Transform))
+ if (vtclass == CACHED_CLASS(Transform))
return MARSHALLED_IN(Transform, (GDMonoMarshal::M_Transform *)mono_object_unbox(p_obj));
- if (tclass == CACHED_CLASS(AABB))
+ if (vtclass == CACHED_CLASS(AABB))
return MARSHALLED_IN(AABB, (GDMonoMarshal::M_AABB *)mono_object_unbox(p_obj));
- if (tclass == CACHED_CLASS(Color))
+ if (vtclass == CACHED_CLASS(Color))
return MARSHALLED_IN(Color, (GDMonoMarshal::M_Color *)mono_object_unbox(p_obj));
- if (tclass == CACHED_CLASS(Plane))
+ if (vtclass == CACHED_CLASS(Plane))
return MARSHALLED_IN(Plane, (GDMonoMarshal::M_Plane *)mono_object_unbox(p_obj));
- if (mono_class_is_enum(tclass->get_mono_ptr()))
+ if (mono_class_is_enum(vtclass->get_mono_ptr()))
return unbox<int32_t>(p_obj);
} break;
@@ -698,7 +748,11 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
// GodotObject
if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
Object *ptr = unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_obj));
- return ptr ? Variant(ptr) : Variant();
+ if (ptr != NULL) {
+ Reference *ref = Object::cast_to<Reference>(ptr);
+ return ref ? Variant(Ref<Reference>(ref)) : Variant(ptr);
+ }
+ return Variant();
}
if (CACHED_CLASS(NodePath) == type_class) {
@@ -713,17 +767,33 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
if (CACHED_CLASS(Array) == type_class) {
MonoException *exc = NULL;
- Array *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Array, GetPtr), p_obj, (MonoObject **)&exc);
+ Array *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Array, GetPtr), p_obj, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
return ptr ? Variant(*ptr) : Variant();
}
if (CACHED_CLASS(Dictionary) == type_class) {
MonoException *exc = NULL;
- Dictionary *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Dictionary, GetPtr), p_obj, (MonoObject **)&exc);
+ Dictionary *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Dictionary, GetPtr), p_obj, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
return ptr ? Variant(*ptr) : Variant();
}
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ Dictionary dict;
+ MonoException *exc = NULL;
+ invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary), p_obj, &dict, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return dict;
+ }
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ Array array;
+ MonoException *exc = NULL;
+ invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray), p_obj, &array, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return array;
+ }
} break;
case MONO_TYPE_GENERICINST: {
@@ -731,12 +801,12 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
MonoException *exc = NULL;
- GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
- MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
+ MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_dict) {
- MonoException *exc = NULL;
+ exc = NULL;
MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
return *unbox<Dictionary *>(ret);
@@ -744,16 +814,32 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
exc = NULL;
- GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
- MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
+ MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_array) {
- MonoException *exc = NULL;
+ exc = NULL;
MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
return *unbox<Array *>(ret);
}
+
+ if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ Dictionary dict;
+ exc = NULL;
+ invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary), p_obj, &dict, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return dict;
+ }
+
+ if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ Array array;
+ exc = NULL;
+ invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray), p_obj, &array, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return array;
+ }
} break;
}
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
index 4002f2a225..4a73f9e3e6 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,6 +32,7 @@
#define GDMONOMARSHAL_H
#include "core/variant.h"
+
#include "gd_mono.h"
#include "gd_mono_utils.h"
@@ -56,7 +57,25 @@ T unbox(MonoObject *p_obj) {
#define BOX_PTR(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(IntPtr), x)
#define BOX_ENUM(m_enum_class, x) mono_value_box(mono_domain_get(), m_enum_class, &x)
-Variant::Type managed_to_variant_type(const ManagedType &p_type);
+// FIXME: Made this struct in a hurry. It could be done differently.
+struct ExportInfo {
+ struct ArrayInfo {
+ Variant::Type element_type;
+
+ ArrayInfo() :
+ element_type(Variant::NIL) {}
+ } array;
+ struct DictionaryInfo {
+ Variant::Type key_type;
+ Variant::Type value_type;
+
+ DictionaryInfo() :
+ key_type(Variant::NIL),
+ value_type(Variant::NIL) {}
+ } dictionary;
+};
+
+Variant::Type managed_to_variant_type(const ManagedType &p_type, ExportInfo *r_export_info = NULL);
// String
@@ -206,9 +225,10 @@ enum {
// In the future we may force this if we want to ref return these structs
#ifdef GD_MONO_FORCE_INTEROP_STRUCT_COPY
-// Sometimes clang-format can be an ass
-GD_STATIC_ASSERT(MATCHES_Vector2 &&MATCHES_Rect2 &&MATCHES_Transform2D &&MATCHES_Vector3 &&
- MATCHES_Basis &&MATCHES_Quat &&MATCHES_Transform &&MATCHES_AABB &&MATCHES_Color &&MATCHES_Plane);
+/* clang-format off */
+GD_STATIC_ASSERT(MATCHES_Vector2 && MATCHES_Rect2 && MATCHES_Transform2D && MATCHES_Vector3 &&
+ MATCHES_Basis && MATCHES_Quat && MATCHES_Transform && MATCHES_AABB && MATCHES_Color &&MATCHES_Plane);
+/* clang-format on */
#endif
} // namespace InteropLayout
diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp
index 6ef6e97f5a..7f11e4671d 100644
--- a/modules/mono/mono_gd/gd_mono_method.cpp
+++ b/modules/mono/mono_gd/gd_mono_method.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -78,20 +78,20 @@ bool GDMonoMethod::is_static() {
return mono_method_get_flags(mono_method, NULL) & MONO_METHOD_ATTR_STATIC;
}
-GDMonoClassMember::Visibility GDMonoMethod::get_visibility() {
+IMonoClassMember::Visibility GDMonoMethod::get_visibility() {
switch (mono_method_get_flags(mono_method, NULL) & MONO_METHOD_ATTR_ACCESS_MASK) {
case MONO_METHOD_ATTR_PRIVATE:
- return GDMonoClassMember::PRIVATE;
+ return IMonoClassMember::PRIVATE;
case MONO_METHOD_ATTR_FAM_AND_ASSEM:
- return GDMonoClassMember::PROTECTED_AND_INTERNAL;
+ return IMonoClassMember::PROTECTED_AND_INTERNAL;
case MONO_METHOD_ATTR_ASSEM:
- return GDMonoClassMember::INTERNAL;
+ return IMonoClassMember::INTERNAL;
case MONO_METHOD_ATTR_FAMILY:
- return GDMonoClassMember::PROTECTED;
+ return IMonoClassMember::PROTECTED;
case MONO_METHOD_ATTR_PUBLIC:
- return GDMonoClassMember::PUBLIC;
+ return IMonoClassMember::PUBLIC;
default:
- ERR_FAIL_V(GDMonoClassMember::PRIVATE);
+ ERR_FAIL_V(IMonoClassMember::PRIVATE);
}
}
diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h
index 6c3ae5fce0..f74cef438d 100644
--- a/modules/mono/mono_gd/gd_mono_method.h
+++ b/modules/mono/mono_gd/gd_mono_method.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,10 +32,10 @@
#define GD_MONO_METHOD_H
#include "gd_mono.h"
-#include "gd_mono_class_member.h"
#include "gd_mono_header.h"
+#include "i_mono_class_member.h"
-class GDMonoMethod : public GDMonoClassMember {
+class GDMonoMethod : public IMonoClassMember {
StringName name;
@@ -57,17 +57,17 @@ class GDMonoMethod : public GDMonoClassMember {
MonoMethod *mono_method;
public:
- virtual MemberType get_member_type() { return MEMBER_TYPE_METHOD; }
+ virtual MemberType get_member_type() GD_FINAL { return MEMBER_TYPE_METHOD; }
- virtual StringName get_name() { return name; }
+ virtual StringName get_name() GD_FINAL { return name; }
- virtual bool is_static();
+ virtual bool is_static() GD_FINAL;
- virtual Visibility get_visibility();
+ virtual Visibility get_visibility() GD_FINAL;
- virtual bool has_attribute(GDMonoClass *p_attr_class);
- virtual MonoObject *get_attribute(GDMonoClass *p_attr_class);
- virtual void fetch_attributes();
+ virtual bool has_attribute(GDMonoClass *p_attr_class) GD_FINAL;
+ virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) GD_FINAL;
+ void fetch_attributes();
_FORCE_INLINE_ int get_parameters_count() { return params_count; }
_FORCE_INLINE_ ManagedType get_return_type() { return return_type; }
diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp
index ce66e0c8db..5842e26241 100644
--- a/modules/mono/mono_gd/gd_mono_property.cpp
+++ b/modules/mono/mono_gd/gd_mono_property.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "gd_mono_property.h"
#include "gd_mono_class.h"
@@ -79,24 +80,24 @@ bool GDMonoProperty::is_static() {
return mono_method_get_flags(prop_method, NULL) & MONO_METHOD_ATTR_STATIC;
}
-GDMonoClassMember::Visibility GDMonoProperty::get_visibility() {
+IMonoClassMember::Visibility GDMonoProperty::get_visibility() {
MonoMethod *prop_method = mono_property_get_get_method(mono_property);
if (prop_method == NULL)
prop_method = mono_property_get_set_method(mono_property);
switch (mono_method_get_flags(prop_method, NULL) & MONO_METHOD_ATTR_ACCESS_MASK) {
case MONO_METHOD_ATTR_PRIVATE:
- return GDMonoClassMember::PRIVATE;
+ return IMonoClassMember::PRIVATE;
case MONO_METHOD_ATTR_FAM_AND_ASSEM:
- return GDMonoClassMember::PROTECTED_AND_INTERNAL;
+ return IMonoClassMember::PROTECTED_AND_INTERNAL;
case MONO_METHOD_ATTR_ASSEM:
- return GDMonoClassMember::INTERNAL;
+ return IMonoClassMember::INTERNAL;
case MONO_METHOD_ATTR_FAMILY:
- return GDMonoClassMember::PROTECTED;
+ return IMonoClassMember::PROTECTED;
case MONO_METHOD_ATTR_PUBLIC:
- return GDMonoClassMember::PUBLIC;
+ return IMonoClassMember::PUBLIC;
default:
- ERR_FAIL_V(GDMonoClassMember::PRIVATE);
+ ERR_FAIL_V(IMonoClassMember::PRIVATE);
}
}
diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h
index b3f1e2114a..2700c460b0 100644
--- a/modules/mono/mono_gd/gd_mono_property.h
+++ b/modules/mono/mono_gd/gd_mono_property.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,14 +27,15 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef GD_MONO_PROPERTY_H
#define GD_MONO_PROPERTY_H
#include "gd_mono.h"
-#include "gd_mono_class_member.h"
#include "gd_mono_header.h"
+#include "i_mono_class_member.h"
-class GDMonoProperty : public GDMonoClassMember {
+class GDMonoProperty : public IMonoClassMember {
GDMonoClass *owner;
MonoProperty *mono_property;
@@ -46,15 +47,15 @@ class GDMonoProperty : public GDMonoClassMember {
MonoCustomAttrInfo *attributes;
public:
- virtual MemberType get_member_type() { return MEMBER_TYPE_PROPERTY; }
+ virtual MemberType get_member_type() GD_FINAL { return MEMBER_TYPE_PROPERTY; }
- virtual StringName get_name() { return name; }
+ virtual StringName get_name() GD_FINAL { return name; }
- virtual bool is_static();
- virtual Visibility get_visibility();
+ virtual bool is_static() GD_FINAL;
+ virtual Visibility get_visibility() GD_FINAL;
- virtual bool has_attribute(GDMonoClass *p_attr_class);
- virtual MonoObject *get_attribute(GDMonoClass *p_attr_class);
+ virtual bool has_attribute(GDMonoClass *p_attr_class) GD_FINAL;
+ virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) GD_FINAL;
void fetch_attributes();
bool has_getter();
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index 211987d242..bcf5712d16 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -39,6 +39,7 @@
#include "../csharp_script.h"
#include "../utils/macros.h"
+#include "../utils/mutex_utils.h"
#include "gd_mono.h"
#include "gd_mono_class.h"
#include "gd_mono_marshal.h"
@@ -62,6 +63,7 @@ MonoCache mono_cache;
#define CACHE_FIELD_AND_CHECK(m_class, m_field, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.field_##m_class##_##m_field, m_val)
#define CACHE_METHOD_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.method_##m_class##_##m_method, m_val)
#define CACHE_METHOD_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method, m_val)
+#define CACHE_PROPERTY_AND_CHECK(m_class, m_property, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.property_##m_class##_##m_property, m_val)
void MonoCache::clear_members() {
@@ -80,6 +82,9 @@ void MonoCache::clear_members() {
class_String = NULL;
class_IntPtr = NULL;
+ class_System_Collections_IEnumerable = NULL;
+ class_System_Collections_IDictionary = NULL;
+
#ifdef DEBUG_ENABLED
class_System_Diagnostics_StackTrace = NULL;
methodthunk_System_Diagnostics_StackTrace_GetFrames = NULL;
@@ -142,12 +147,17 @@ void MonoCache::clear_members() {
methodthunk_GodotObject_Dispose = NULL;
methodthunk_Array_GetPtr = NULL;
methodthunk_Dictionary_GetPtr = NULL;
- methodthunk_MarshalUtils_IsArrayGenericType = NULL;
- methodthunk_MarshalUtils_IsDictionaryGenericType = NULL;
methodthunk_SignalAwaiter_SignalCallback = NULL;
methodthunk_SignalAwaiter_FailureCallback = NULL;
methodthunk_GodotTaskScheduler_Activate = NULL;
+ methodthunk_MarshalUtils_TypeIsGenericArray = NULL;
+ methodthunk_MarshalUtils_TypeIsGenericDictionary = NULL;
+ methodthunk_MarshalUtils_ArrayGetElementType = NULL;
+ methodthunk_MarshalUtils_DictionaryGetKeyValueTypes = NULL;
+ methodthunk_MarshalUtils_EnumerableToArray = NULL;
+ methodthunk_MarshalUtils_IDictionaryToDictionary = NULL;
+
task_scheduler_handle = Ref<MonoGCHandle>();
}
@@ -177,6 +187,9 @@ void update_corlib_cache() {
CACHE_CLASS_AND_CHECK(String, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_string_class()));
CACHE_CLASS_AND_CHECK(IntPtr, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_intptr_class()));
+ CACHE_CLASS_AND_CHECK(System_Collections_IEnumerable, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IEnumerable"));
+ CACHE_CLASS_AND_CHECK(System_Collections_IDictionary, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IDictionary"));
+
#ifdef DEBUG_ENABLED
CACHE_CLASS_AND_CHECK(System_Diagnostics_StackTrace, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Diagnostics", "StackTrace"));
CACHE_METHOD_THUNK_AND_CHECK(System_Diagnostics_StackTrace, GetFrames, (StackTrace_GetFrames)CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_thunk("GetFrames"));
@@ -241,12 +254,17 @@ void update_godot_api_cache() {
CACHE_METHOD_THUNK_AND_CHECK(GodotObject, Dispose, (GodotObject_Dispose)CACHED_CLASS(GodotObject)->get_method_thunk("Dispose", 0));
CACHE_METHOD_THUNK_AND_CHECK(Array, GetPtr, (Array_GetPtr)GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Array)->get_method_thunk("GetPtr", 0));
CACHE_METHOD_THUNK_AND_CHECK(Dictionary, GetPtr, (Dictionary_GetPtr)GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary)->get_method_thunk("GetPtr", 0));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsArrayGenericType, (IsArrayGenericType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IsArrayGenericType", 1));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsDictionaryGenericType, (IsDictionaryGenericType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IsDictionaryGenericType", 1));
CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, (SignalAwaiter_SignalCallback)GODOT_API_CLASS(SignalAwaiter)->get_method_thunk("SignalCallback", 1));
CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, (SignalAwaiter_FailureCallback)GODOT_API_CLASS(SignalAwaiter)->get_method_thunk("FailureCallback", 0));
CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method_thunk("Activate", 0));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericArray, (TypeIsGenericArray)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("TypeIsGenericArray", 1));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericDictionary, (TypeIsGenericDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("TypeIsGenericDictionary", 1));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, (ArrayGetElementType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("ArrayGetElementType", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, (DictionaryGetKeyValueTypes)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("DictionaryGetKeyValueTypes", 3));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, EnumerableToArray, (EnumerableToArray)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("EnumerableToArray", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IDictionaryToDictionary, (IDictionaryToDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IDictionaryToDictionary", 2));
+
#ifdef DEBUG_ENABLED
CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, (DebugUtils_StackFrameInfo)GODOT_API_CLASS(DebuggingUtils)->get_method_thunk("GetStackFrameInfo", 4));
#endif
@@ -265,61 +283,72 @@ void clear_cache() {
}
MonoObject *unmanaged_get_managed(Object *unmanaged) {
- if (unmanaged) {
- if (unmanaged->get_script_instance()) {
- CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(unmanaged->get_script_instance());
- if (cs_instance) {
- return cs_instance->get_mono_object();
- }
+ if (!unmanaged)
+ return NULL;
+
+ if (unmanaged->get_script_instance()) {
+ CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(unmanaged->get_script_instance());
+
+ if (cs_instance) {
+ return cs_instance->get_mono_object();
}
+ }
+
+ // If the owner does not have a CSharpInstance...
+
+ void *data = unmanaged->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
+
+ ERR_FAIL_NULL_V(data, NULL);
+
+ CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->value();
- // If the owner does not have a CSharpInstance...
+ if (!script_binding.inited) {
+ SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->get_language_bind_mutex());
- void *data = unmanaged->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
+ if (!script_binding.inited) { // Other thread may have set it up
+ // Already had a binding that needs to be setup
+ CSharpLanguage::get_singleton()->setup_csharp_script_binding(script_binding, unmanaged);
- if (data) {
- CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->value();
+ ERR_FAIL_COND_V(!script_binding.inited, NULL);
+ }
+ }
- Ref<MonoGCHandle> &gchandle = script_binding.gchandle;
- ERR_FAIL_COND_V(gchandle.is_null(), NULL);
+ Ref<MonoGCHandle> &gchandle = script_binding.gchandle;
+ ERR_FAIL_COND_V(gchandle.is_null(), NULL);
- MonoObject *target = gchandle->get_target();
+ MonoObject *target = gchandle->get_target();
- if (target)
- return target;
+ if (target)
+ return target;
- CSharpLanguage::get_singleton()->release_script_gchandle(gchandle);
+ CSharpLanguage::get_singleton()->release_script_gchandle(gchandle);
- // Create a new one
+ // Create a new one
#ifdef DEBUG_ENABLED
- CRASH_COND(script_binding.type_name == StringName());
- CRASH_COND(script_binding.wrapper_class == NULL);
+ CRASH_COND(script_binding.type_name == StringName());
+ CRASH_COND(script_binding.wrapper_class == NULL);
#endif
- MonoObject *mono_object = GDMonoUtils::create_managed_for_godot_object(script_binding.wrapper_class, script_binding.type_name, unmanaged);
- ERR_FAIL_NULL_V(mono_object, NULL);
-
- gchandle->set_handle(MonoGCHandle::new_strong_handle(mono_object), MonoGCHandle::STRONG_HANDLE);
+ MonoObject *mono_object = GDMonoUtils::create_managed_for_godot_object(script_binding.wrapper_class, script_binding.type_name, unmanaged);
+ ERR_FAIL_NULL_V(mono_object, NULL);
- // Tie managed to unmanaged
- Reference *ref = Object::cast_to<Reference>(unmanaged);
+ gchandle->set_handle(MonoGCHandle::new_strong_handle(mono_object), MonoGCHandle::STRONG_HANDLE);
- if (ref) {
- // Unsafe refcount increment. The managed instance also counts as a reference.
- // This way if the unmanaged world has no references to our owner
- // but the managed instance is alive, the refcount will be 1 instead of 0.
- // See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr)
+ // Tie managed to unmanaged
+ Reference *ref = Object::cast_to<Reference>(unmanaged);
- ref->reference();
- }
+ if (ref) {
+ // Unsafe refcount increment. The managed instance also counts as a reference.
+ // This way if the unmanaged world has no references to our owner
+ // but the managed instance is alive, the refcount will be 1 instead of 0.
+ // See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr)
- return mono_object;
- }
+ ref->reference();
}
- return NULL;
+ return mono_object;
}
void set_main_thread(MonoThread *p_thread) {
@@ -362,6 +391,11 @@ GDMonoClass *type_get_proxy_class(const StringName &p_type) {
GDMonoClass *klass = GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, class_name);
+ if (klass && klass->is_static()) {
+ // A static class means this is a Godot singleton class. If an instance is needed we use Godot.Object.
+ return mono_cache.class_GodotObject;
+ }
+
#ifdef TOOLS_ENABLED
if (!klass) {
return GDMono::get_singleton()->get_editor_api_assembly()->get_class(BINDINGS_NAMESPACE, class_name);
@@ -565,7 +599,7 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) {
if (unexpected_exc) {
GDMonoInternals::unhandled_exception(unexpected_exc);
- _UNREACHABLE_();
+ GD_UNREACHABLE();
}
Vector<ScriptLanguage::StackInfo> _si;
@@ -598,13 +632,8 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) {
}
void debug_unhandled_exception(MonoException *p_exc) {
-#ifdef DEBUG_ENABLED
- GDMonoUtils::debug_send_unhandled_exception_error(p_exc);
- if (ScriptDebugger::get_singleton())
- ScriptDebugger::get_singleton()->idle_poll();
-#endif
GDMonoInternals::unhandled_exception(p_exc); // prints the exception as well
- _UNREACHABLE_();
+ GD_UNREACHABLE();
}
void print_unhandled_exception(MonoException *p_exc) {
@@ -615,7 +644,7 @@ void set_pending_exception(MonoException *p_exc) {
#ifdef HAS_PENDING_EXCEPTIONS
if (get_runtime_invoke_count() == 0) {
debug_unhandled_exception(p_exc);
- _UNREACHABLE_();
+ GD_UNREACHABLE();
}
if (!mono_runtime_set_pending_exception(p_exc, false)) {
@@ -624,7 +653,7 @@ void set_pending_exception(MonoException *p_exc) {
}
#else
debug_unhandled_exception(p_exc);
- _UNREACHABLE_();
+ GD_UNREACHABLE();
#endif
}
@@ -695,7 +724,7 @@ uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool &
}
void dispose(MonoObject *p_mono_object, MonoException **r_exc) {
- invoke_method_thunk(CACHED_METHOD_THUNK(GodotObject, Dispose), p_mono_object, (MonoObject **)r_exc);
+ invoke_method_thunk(CACHED_METHOD_THUNK(GodotObject, Dispose), p_mono_object, r_exc);
}
} // namespace GDMonoUtils
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index 170df32991..87610e286c 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -44,23 +44,26 @@
#define UNLIKELY_UNHANDLED_EXCEPTION(m_exc) \
if (unlikely(m_exc != NULL)) { \
GDMonoUtils::debug_unhandled_exception(m_exc); \
- _UNREACHABLE_(); \
+ GD_UNREACHABLE(); \
}
namespace GDMonoUtils {
-typedef void (*GodotObject_Dispose)(MonoObject *, MonoObject **);
-typedef Array *(*Array_GetPtr)(MonoObject *, MonoObject **);
-typedef Dictionary *(*Dictionary_GetPtr)(MonoObject *, MonoObject **);
-typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray *, MonoObject **);
-typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoObject **);
-typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoObject **);
-typedef MonoArray *(*StackTrace_GetFrames)(MonoObject *, MonoObject **);
-typedef MonoBoolean (*IsArrayGenericType)(MonoObject *, MonoObject **);
-typedef MonoBoolean (*IsDictionaryGenericType)(MonoObject *, MonoObject **);
-typedef MonoBoolean (*IsArrayGenericType)(MonoObject *, MonoObject **);
-typedef MonoBoolean (*IsDictionaryGenericType)(MonoObject *, MonoObject **);
-typedef void (*DebugUtils_StackFrameInfo)(MonoObject *, MonoString **, int *, MonoString **, MonoObject **);
+typedef void (*GodotObject_Dispose)(MonoObject *, MonoException **);
+typedef Array *(*Array_GetPtr)(MonoObject *, MonoException **);
+typedef Dictionary *(*Dictionary_GetPtr)(MonoObject *, MonoException **);
+typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray *, MonoException **);
+typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoException **);
+typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoException **);
+typedef MonoArray *(*StackTrace_GetFrames)(MonoObject *, MonoException **);
+typedef void (*DebugUtils_StackFrameInfo)(MonoObject *, MonoString **, int *, MonoString **, MonoException **);
+
+typedef MonoBoolean (*TypeIsGenericArray)(MonoReflectionType *, MonoException **);
+typedef MonoBoolean (*TypeIsGenericDictionary)(MonoReflectionType *, MonoException **);
+typedef MonoBoolean (*ArrayGetElementType)(MonoReflectionType *, MonoReflectionType **, MonoException **);
+typedef MonoBoolean (*DictionaryGetKeyValueTypes)(MonoReflectionType *, MonoReflectionType **, MonoReflectionType **, MonoException **);
+typedef void (*EnumerableToArray)(MonoObject *, Array *, MonoException **);
+typedef void (*IDictionaryToDictionary)(MonoObject *, Dictionary *, MonoException **);
struct MonoCache {
@@ -83,6 +86,9 @@ struct MonoCache {
GDMonoClass *class_String;
GDMonoClass *class_IntPtr;
+ GDMonoClass *class_System_Collections_IEnumerable;
+ GDMonoClass *class_System_Collections_IDictionary;
+
#ifdef DEBUG_ENABLED
GDMonoClass *class_System_Diagnostics_StackTrace;
StackTrace_GetFrames methodthunk_System_Diagnostics_StackTrace_GetFrames;
@@ -146,12 +152,17 @@ struct MonoCache {
GodotObject_Dispose methodthunk_GodotObject_Dispose;
Array_GetPtr methodthunk_Array_GetPtr;
Dictionary_GetPtr methodthunk_Dictionary_GetPtr;
- IsArrayGenericType methodthunk_MarshalUtils_IsArrayGenericType;
- IsDictionaryGenericType methodthunk_MarshalUtils_IsDictionaryGenericType;
SignalAwaiter_SignalCallback methodthunk_SignalAwaiter_SignalCallback;
SignalAwaiter_FailureCallback methodthunk_SignalAwaiter_FailureCallback;
GodotTaskScheduler_Activate methodthunk_GodotTaskScheduler_Activate;
+ TypeIsGenericArray methodthunk_MarshalUtils_TypeIsGenericArray;
+ TypeIsGenericDictionary methodthunk_MarshalUtils_TypeIsGenericDictionary;
+ ArrayGetElementType methodthunk_MarshalUtils_ArrayGetElementType;
+ DictionaryGetKeyValueTypes methodthunk_MarshalUtils_DictionaryGetKeyValueTypes;
+ EnumerableToArray methodthunk_MarshalUtils_EnumerableToArray;
+ IDictionaryToDictionary methodthunk_MarshalUtils_IDictionaryToDictionary;
+
Ref<MonoGCHandle> task_scheduler_handle;
bool corlib_cache_updated;
@@ -214,7 +225,7 @@ void set_exception_message(MonoException *p_exc, String message);
void debug_print_unhandled_exception(MonoException *p_exc);
void debug_send_unhandled_exception_error(MonoException *p_exc);
-_NO_RETURN_ void debug_unhandled_exception(MonoException *p_exc);
+GD_NORETURN void debug_unhandled_exception(MonoException *p_exc);
void print_unhandled_exception(MonoException *p_exc);
/**
@@ -255,6 +266,7 @@ void dispose(MonoObject *p_mono_object, MonoException **r_exc);
#define CACHED_FIELD(m_class, m_field) (GDMonoUtils::mono_cache.field_##m_class##_##m_field)
#define CACHED_METHOD(m_class, m_method) (GDMonoUtils::mono_cache.method_##m_class##_##m_method)
#define CACHED_METHOD_THUNK(m_class, m_method) (GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method)
+#define CACHED_PROPERTY(m_class, m_property) (GDMonoUtils::mono_cache.property_##m_class##_##m_property)
#ifdef REAL_T_IS_DOUBLE
#define REAL_T_MONOCLASS CACHED_CLASS_RAW(double)
diff --git a/modules/mono/mono_gd/gd_mono_class_member.h b/modules/mono/mono_gd/i_mono_class_member.h
index 008ea0e416..553d9edc72 100644
--- a/modules/mono/mono_gd/gd_mono_class_member.h
+++ b/modules/mono/mono_gd/i_mono_class_member.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* gd_mono_class_member.h */
+/* i_mono_class_member.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,14 +27,15 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef GD_MONO_CLASS_MEMBER_H
-#define GD_MONO_CLASS_MEMBER_H
+
+#ifndef I_MONO_CLASS_MEMBER_H
+#define I_MONO_CLASS_MEMBER_H
#include "gd_mono_header.h"
#include <mono/metadata/object.h>
-class GDMonoClassMember {
+class IMonoClassMember {
public:
enum Visibility {
PRIVATE,
@@ -50,7 +51,7 @@ public:
MEMBER_TYPE_METHOD
};
- virtual ~GDMonoClassMember() {}
+ virtual ~IMonoClassMember() {}
virtual MemberType get_member_type() = 0;
@@ -64,4 +65,4 @@ public:
virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) = 0;
};
-#endif // GD_MONO_CLASS_MEMBER_H
+#endif // I_MONO_CLASS_MEMBER_H
diff --git a/modules/mono/mono_gd/managed_type.cpp b/modules/mono/mono_gd/managed_type.cpp
new file mode 100644
index 0000000000..9f736b71cd
--- /dev/null
+++ b/modules/mono/mono_gd/managed_type.cpp
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* managed_type.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "managed_type.h"
+
+#include "gd_mono.h"
+#include "gd_mono_class.h"
+
+ManagedType ManagedType::from_class(GDMonoClass *p_class) {
+ return ManagedType(mono_type_get_type(p_class->get_mono_type()), p_class);
+}
+
+ManagedType ManagedType::from_class(MonoClass *p_mono_class) {
+ GDMonoClass *tclass = GDMono::get_singleton()->get_class(p_mono_class);
+ ERR_FAIL_COND_V(!tclass, ManagedType());
+
+ return ManagedType(mono_type_get_type(tclass->get_mono_type()), tclass);
+}
+
+ManagedType ManagedType::from_type(MonoType *p_mono_type) {
+ MonoClass *mono_class = mono_class_from_mono_type(p_mono_type);
+ GDMonoClass *tclass = GDMono::get_singleton()->get_class(mono_class);
+ ERR_FAIL_COND_V(!tclass, ManagedType());
+
+ return ManagedType(mono_type_get_type(p_mono_type), tclass);
+}
+
+ManagedType ManagedType::from_reftype(MonoReflectionType *p_mono_reftype) {
+ MonoType *mono_type = mono_reflection_type_get_type(p_mono_reftype);
+ return from_type(mono_type);
+}
diff --git a/modules/mono/mono_gd/managed_type.h b/modules/mono/mono_gd/managed_type.h
new file mode 100644
index 0000000000..a537e56aea
--- /dev/null
+++ b/modules/mono/mono_gd/managed_type.h
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* managed_type.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef MANAGED_TYPE_H
+#define MANAGED_TYPE_H
+
+#include <mono/metadata/object.h>
+
+#include "gd_mono_header.h"
+
+struct ManagedType {
+ int type_encoding;
+ GDMonoClass *type_class;
+
+ static ManagedType from_class(GDMonoClass *p_class);
+ static ManagedType from_class(MonoClass *p_mono_class);
+ static ManagedType from_type(MonoType *p_mono_type);
+ static ManagedType from_reftype(MonoReflectionType *p_mono_reftype);
+
+ ManagedType() :
+ type_encoding(0),
+ type_class(NULL) {
+ }
+
+ ManagedType(int p_type_encoding, GDMonoClass *p_type_class) :
+ type_encoding(p_type_encoding),
+ type_class(p_type_class) {
+ }
+};
+
+#endif // MANAGED_TYPE_H
diff --git a/modules/mono/register_types.cpp b/modules/mono/register_types.cpp
index f6cb143e8e..3607b6f8b3 100644
--- a/modules/mono/register_types.cpp
+++ b/modules/mono/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,8 +35,8 @@
#include "csharp_script.h"
CSharpLanguage *script_language_cs = NULL;
-ResourceFormatLoaderCSharpScript *resource_loader_cs = NULL;
-ResourceFormatSaverCSharpScript *resource_saver_cs = NULL;
+Ref<ResourceFormatLoaderCSharpScript> resource_loader_cs;
+Ref<ResourceFormatSaverCSharpScript> resource_saver_cs;
_GodotSharp *_godotsharp = NULL;
@@ -52,9 +52,10 @@ void register_mono_types() {
script_language_cs->set_language_index(ScriptServer::get_language_count());
ScriptServer::register_language(script_language_cs);
- resource_loader_cs = memnew(ResourceFormatLoaderCSharpScript);
+ resource_loader_cs.instance();
ResourceLoader::add_resource_format_loader(resource_loader_cs);
- resource_saver_cs = memnew(ResourceFormatSaverCSharpScript);
+
+ resource_saver_cs.instance();
ResourceSaver::add_resource_format_saver(resource_saver_cs);
}
@@ -63,10 +64,12 @@ void unregister_mono_types() {
if (script_language_cs)
memdelete(script_language_cs);
- if (resource_loader_cs)
- memdelete(resource_loader_cs);
- if (resource_saver_cs)
- memdelete(resource_saver_cs);
+
+ ResourceLoader::remove_resource_format_loader(resource_loader_cs);
+ resource_loader_cs.unref();
+
+ ResourceSaver::remove_resource_format_saver(resource_saver_cs);
+ resource_saver_cs.unref();
if (_godotsharp)
memdelete(_godotsharp);
diff --git a/modules/mono/register_types.h b/modules/mono/register_types.h
index ab8a7d6463..0601e9a382 100644
--- a/modules/mono/register_types.h
+++ b/modules/mono/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp
index c6748309f3..5d37e8212f 100644
--- a/modules/mono/signal_awaiter_utils.cpp
+++ b/modules/mono/signal_awaiter_utils.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -100,7 +100,7 @@ Variant SignalAwaiterHandle::_signal_callback(const Variant **p_args, int p_argc
MonoException *exc = NULL;
GD_MONO_BEGIN_RUNTIME_INVOKE;
- invoke_method_thunk(CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback), get_target(), signal_args, (MonoObject **)&exc);
+ invoke_method_thunk(CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback), get_target(), signal_args, &exc);
GD_MONO_END_RUNTIME_INVOKE;
if (exc) {
@@ -132,7 +132,7 @@ SignalAwaiterHandle::~SignalAwaiterHandle() {
if (awaiter) {
MonoException *exc = NULL;
GD_MONO_BEGIN_RUNTIME_INVOKE;
- invoke_method_thunk(CACHED_METHOD_THUNK(SignalAwaiter, FailureCallback), awaiter, (MonoObject **)&exc);
+ invoke_method_thunk(CACHED_METHOD_THUNK(SignalAwaiter, FailureCallback), awaiter, &exc);
GD_MONO_END_RUNTIME_INVOKE;
if (exc) {
diff --git a/modules/mono/signal_awaiter_utils.h b/modules/mono/signal_awaiter_utils.h
index 4ec860537b..098008ded7 100644
--- a/modules/mono/signal_awaiter_utils.h
+++ b/modules/mono/signal_awaiter_utils.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/utils/macros.h b/modules/mono/utils/macros.h
index c801fb2f33..e44f254e1c 100644
--- a/modules/mono/utils/macros.h
+++ b/modules/mono/utils/macros.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* util_macros.h */
+/* macros.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,39 +31,53 @@
#ifndef UTIL_MACROS_H
#define UTIL_MACROS_H
-#define _GD_VARNAME_CONCAT_B(m_ignore, m_name) m_name
-#define _GD_VARNAME_CONCAT_A(m_a, m_b, m_c) _GD_VARNAME_CONCAT_B(hello there, m_a##m_b##m_c)
-#define _GD_VARNAME_CONCAT(m_a, m_b, m_c) _GD_VARNAME_CONCAT_A(m_a, m_b, m_c)
-#define GD_UNIQUE_NAME(m_name) _GD_VARNAME_CONCAT(m_name, _, __COUNTER__)
+#define _GD_VARNAME_CONCAT_B_(m_ignore, m_name) m_name
+#define _GD_VARNAME_CONCAT_A_(m_a, m_b, m_c) _GD_VARNAME_CONCAT_B_(hello there, m_a##m_b##m_c)
+#define _GD_VARNAME_CONCAT_(m_a, m_b, m_c) _GD_VARNAME_CONCAT_A_(m_a, m_b, m_c)
+#define GD_UNIQUE_NAME(m_name) _GD_VARNAME_CONCAT_(m_name, _, __COUNTER__)
-// noreturn
+// static assert
+// TODO: Get rid of this macro once we upgrade to C++11
-#if __cpp_static_assert
+#ifdef __cpp_static_assert
#define GD_STATIC_ASSERT(m_cond) static_assert((m_cond), "Condition '" #m_cond "' failed")
#else
#define GD_STATIC_ASSERT(m_cond) typedef int GD_UNIQUE_NAME(godot_static_assert)[((m_cond) ? 1 : -1)]
#endif
-#undef _NO_RETURN_
+// final
+// TODO: Get rid of this macro once we upgrade to C++11
+
+#if (__cplusplus >= 201103L)
+#define GD_FINAL final
+#else
+#define GD_FINAL
+#endif
+
+// noreturn
+// TODO: Get rid of this macro once we upgrade to C++11
-#ifdef __GNUC__
-#define _NO_RETURN_ __attribute__((noreturn))
-#elif _MSC_VER
-#define _NO_RETURN_ __declspec(noreturn)
+#if (__cplusplus >= 201103L)
+#define GD_NORETURN [[noreturn]]
+#elif defined(__GNUC__)
+#define GD_NORETURN __attribute__((noreturn))
+#elif defined(_MSC_VER)
+#define GD_NORETURN __declspec(noreturn)
#else
-#error Platform or compiler not supported
+#define GD_NORETURN
+#pragma message "Macro GD_NORETURN will have no effect"
#endif
// unreachable
#if defined(_MSC_VER)
-#define _UNREACHABLE_() __assume(0)
+#define GD_UNREACHABLE() __assume(0)
#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
-#define _UNREACHABLE_() __builtin_unreachable()
+#define GD_UNREACHABLE() __builtin_unreachable()
#else
-#define _UNREACHABLE_() \
- CRASH_NOW(); \
- do { \
+#define GD_UNREACHABLE() \
+ CRASH_NOW(); \
+ do { \
} while (true);
#endif
diff --git a/modules/mono/utils/mono_reg_utils.cpp b/modules/mono/utils/mono_reg_utils.cpp
index 6bb6efa92a..98aeadc8c8 100644
--- a/modules/mono/utils/mono_reg_utils.cpp
+++ b/modules/mono/utils/mono_reg_utils.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "mono_reg_utils.h"
+#include "core/os/dir_access.h"
#ifdef WINDOWS_ENABLED
@@ -158,8 +159,6 @@ MonoRegInfo find_mono() {
if (_find_mono_in_reg_old("Software\\Novell\\Mono", info) == ERROR_SUCCESS)
return info;
- ERR_PRINT("Cannot find mono in the registry");
-
return MonoRegInfo();
}
@@ -202,6 +201,13 @@ String find_msbuild_tools_path() {
val += "\\";
}
+ // Since VS2019, the directory is simply named "Current"
+ String msbuild_dir = val + "MSBuild\\Current\\Bin";
+ if (DirAccess::exists(msbuild_dir)) {
+ return msbuild_dir;
+ }
+
+ // Directory name "15.0" is used in VS 2017
return val + "MSBuild\\15.0\\Bin";
}
}
diff --git a/modules/mono/utils/mono_reg_utils.h b/modules/mono/utils/mono_reg_utils.h
index 26f7e2d3c2..25446a4992 100644
--- a/modules/mono/utils/mono_reg_utils.h
+++ b/modules/mono/utils/mono_reg_utils.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/utils/mutex_utils.h b/modules/mono/utils/mutex_utils.h
index 07d659b6eb..b8be033cba 100644
--- a/modules/mono/utils/mutex_utils.h
+++ b/modules/mono/utils/mutex_utils.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/utils/osx_utils.cpp b/modules/mono/utils/osx_utils.cpp
index f520706a0c..f1362be249 100644
--- a/modules/mono/utils/osx_utils.cpp
+++ b/modules/mono/utils/osx_utils.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,10 +30,10 @@
#include "osx_utils.h"
-#include "core/print_string.h"
-
#ifdef OSX_ENABLED
+#include "core/print_string.h"
+
#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
diff --git a/modules/mono/utils/osx_utils.h b/modules/mono/utils/osx_utils.h
index 68479b4f44..cc72233058 100644
--- a/modules/mono/utils/osx_utils.h
+++ b/modules/mono/utils/osx_utils.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,6 +31,7 @@
#include "core/ustring.h"
#ifndef OSX_UTILS_H
+#define OSX_UTILS_H
#ifdef OSX_ENABLED
diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp
index e663ee3c4a..6e431f51e7 100644
--- a/modules/mono/utils/path_utils.cpp
+++ b/modules/mono/utils/path_utils.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -59,7 +59,7 @@ String path_which(const String &p_name) {
#ifdef WINDOWS_ENABLED
for (int j = 0; j < exts.size(); j++) {
- String p2 = p + exts[j];
+ String p2 = p + exts[j].to_lower(); // lowercase to reduce risk of case mismatch warning
if (FileAccess::exists(p2))
return p2;
diff --git a/modules/mono/utils/path_utils.h b/modules/mono/utils/path_utils.h
index 3c7b36c0d4..69edf4deb7 100644
--- a/modules/mono/utils/path_utils.h
+++ b/modules/mono/utils/path_utils.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp
index 6900866725..c390f8b9c2 100644
--- a/modules/mono/utils/string_utils.cpp
+++ b/modules/mono/utils/string_utils.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/utils/string_utils.h b/modules/mono/utils/string_utils.h
index ee803bd720..61765ccfd8 100644
--- a/modules/mono/utils/string_utils.h
+++ b/modules/mono/utils/string_utils.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/utils/thread_local.cpp b/modules/mono/utils/thread_local.cpp
index a0e28fca5f..13179bf408 100644
--- a/modules/mono/utils/thread_local.cpp
+++ b/modules/mono/utils/thread_local.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/utils/thread_local.h b/modules/mono/utils/thread_local.h
index d7d98c47e2..488cc2619a 100644
--- a/modules/mono/utils/thread_local.h
+++ b/modules/mono/utils/thread_local.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -39,7 +39,7 @@
#error Platform or compiler not supported
#endif
-#ifdef __GNUC__
+#if defined(__GNUC__)
#ifdef HAVE_GCC___THREAD
#define _THREAD_LOCAL_(m_t) __thread m_t
@@ -47,7 +47,7 @@
#define USE_CUSTOM_THREAD_LOCAL
#endif
-#elif _MSC_VER
+#elif defined(_MSC_VER)
#ifdef HAVE_DECLSPEC_THREAD
#define _THREAD_LOCAL_(m_t) __declspec(thread) m_t