mirror of
https://github.com/godotengine/godot.git
synced 2024-11-22 04:06:14 +00:00
Added mono module
This commit is contained in:
parent
29b44801b2
commit
e36fb95c50
120
modules/mono/SCsub
Normal file
120
modules/mono/SCsub
Normal file
@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import('env')
|
||||
|
||||
|
||||
def make_cs_files_header(src, dst):
|
||||
with open(dst, 'wb') as header:
|
||||
header.write('/* This is an automatically generated file; DO NOT EDIT! OK THX */\n')
|
||||
header.write('#ifndef _CS_FILES_DATA_H\n')
|
||||
header.write('#define _CS_FILES_DATA_H\n\n')
|
||||
header.write('#include "map.h"\n')
|
||||
header.write('#include "ustring.h"\n')
|
||||
inserted_files = ''
|
||||
import os
|
||||
for file in os.listdir(src):
|
||||
if file.endswith('.cs'):
|
||||
with open(os.path.join(src, file), 'rb') as f:
|
||||
buf = f.read()
|
||||
decomp_size = len(buf)
|
||||
import zlib
|
||||
buf = zlib.compress(buf)
|
||||
name = os.path.splitext(file)[0]
|
||||
header.write('\nstatic 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(str(ord(buf[buf_idx])))
|
||||
inserted_files += '\tr_files.insert(\"' + file + '\", ' \
|
||||
'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('#endif // _CS_FILES_DATA_H')
|
||||
|
||||
|
||||
env.add_source_files(env.modules_sources, '*.cpp')
|
||||
env.add_source_files(env.modules_sources, 'mono_gd/*.cpp')
|
||||
env.add_source_files(env.modules_sources, 'utils/*.cpp')
|
||||
|
||||
if env['tools']:
|
||||
env.add_source_files(env.modules_sources, 'editor/*.cpp')
|
||||
make_cs_files_header('glue/cs_files', 'glue/cs_compressed.gen.h')
|
||||
|
||||
vars = Variables()
|
||||
vars.Add(BoolVariable('mono_glue', 'Build with the mono glue sources', True))
|
||||
vars.Update(env)
|
||||
|
||||
# Glue sources
|
||||
if env['mono_glue']:
|
||||
env.add_source_files(env.modules_sources, 'glue/*.cpp')
|
||||
else:
|
||||
env.Append(CPPDEFINES = [ 'MONO_GLUE_DISABLED' ])
|
||||
|
||||
if ARGUMENTS.get('yolo_copy', False):
|
||||
env.Append(CPPDEFINES = [ 'YOLO_COPY' ])
|
||||
|
||||
# Build GodotSharpTools solution
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import mono_reg_utils as monoreg
|
||||
|
||||
|
||||
def mono_build_solution(source, target, env):
|
||||
if os.name == 'nt':
|
||||
msbuild_tools_path = monoreg.find_msbuild_tools_path_reg()
|
||||
if not msbuild_tools_path:
|
||||
raise RuntimeError('Cannot find MSBuild Tools Path in the registry')
|
||||
msbuild_path = os.path.join(msbuild_tools_path, 'MSBuild.exe')
|
||||
else:
|
||||
msbuild_path = 'msbuild'
|
||||
|
||||
output_path = os.path.abspath(os.path.join(str(target[0]), os.pardir))
|
||||
|
||||
msbuild_args = [
|
||||
msbuild_path,
|
||||
os.path.abspath(str(source[0])),
|
||||
'/p:Configuration=Release',
|
||||
'/p:OutputPath=' + output_path
|
||||
]
|
||||
|
||||
msbuild_env = os.environ.copy()
|
||||
|
||||
# Needed when running from Developer Command Prompt for VS
|
||||
if 'PLATFORM' in msbuild_env:
|
||||
del msbuild_env['PLATFORM']
|
||||
|
||||
msbuild_alt_paths = [ 'xbuild' ]
|
||||
|
||||
while True:
|
||||
try:
|
||||
subprocess.check_call(msbuild_args, env = msbuild_env)
|
||||
break
|
||||
except subprocess.CalledProcessError:
|
||||
raise RuntimeError('GodotSharpTools build failed')
|
||||
except OSError:
|
||||
if os.name != 'nt':
|
||||
if not msbuild_alt_paths:
|
||||
raise RuntimeError('Could not find commands msbuild or xbuild')
|
||||
# Try xbuild
|
||||
msbuild_args[0] = msbuild_alt_paths.pop(0)
|
||||
else:
|
||||
raise RuntimeError('Could not find command MSBuild.exe')
|
||||
|
||||
|
||||
mono_sln_builder = Builder(action = mono_build_solution)
|
||||
env.Append(BUILDERS = { 'MonoBuildSolution' : mono_sln_builder })
|
||||
env.MonoBuildSolution(
|
||||
os.path.join(Dir('#bin').abspath, 'GodotSharpTools.dll'),
|
||||
'editor/GodotSharpTools/GodotSharpTools.sln'
|
||||
)
|
143
modules/mono/config.py
Normal file
143
modules/mono/config.py
Normal file
@ -0,0 +1,143 @@
|
||||
|
||||
import imp
|
||||
import os
|
||||
import sys
|
||||
from shutil import copyfile
|
||||
|
||||
from SCons.Script import BoolVariable, Environment, Variables
|
||||
|
||||
|
||||
monoreg = imp.load_source('mono_reg_utils', 'modules/mono/mono_reg_utils.py')
|
||||
|
||||
|
||||
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 None
|
||||
|
||||
|
||||
def can_build(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
|
||||
|
||||
envvars = Variables()
|
||||
envvars.Add(BoolVariable('mono_static', 'Statically link mono', False))
|
||||
envvars.Update(env)
|
||||
|
||||
mono_static = env['mono_static']
|
||||
|
||||
mono_lib_names = ['mono-2.0-sgen', 'monosgen-2.0']
|
||||
|
||||
if env['platform'] == 'windows':
|
||||
if mono_static:
|
||||
raise RuntimeError('mono-static: Not supported on Windows')
|
||||
|
||||
if env['bits'] == '32':
|
||||
if os.getenv('MONO32_PREFIX'):
|
||||
mono_root = os.getenv('MONO32_PREFIX')
|
||||
elif os.name == 'nt':
|
||||
mono_root = monoreg.find_mono_root_dir()
|
||||
else:
|
||||
if os.getenv('MONO64_PREFIX'):
|
||||
mono_root = os.getenv('MONO64_PREFIX')
|
||||
elif os.name == 'nt':
|
||||
mono_root = monoreg.find_mono_root_dir()
|
||||
|
||||
if mono_root is None:
|
||||
raise RuntimeError('Mono installation directory not found')
|
||||
|
||||
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_name = find_file_in_dir(mono_lib_path, mono_lib_names, extension='.lib')
|
||||
|
||||
if mono_lib_name is None:
|
||||
raise RuntimeError('Could not find mono library in: ' + mono_lib_path)
|
||||
|
||||
if os.getenv('VCINSTALLDIR'):
|
||||
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')
|
||||
|
||||
mono_dll_src = os.path.join(mono_bin_path, mono_dll_name + '.dll')
|
||||
mono_dll_dst = os.path.join('bin', mono_dll_name + '.dll')
|
||||
copy_mono_dll = True
|
||||
|
||||
if not os.path.isdir('bin'):
|
||||
os.mkdir('bin')
|
||||
elif os.path.exists(mono_dll_dst):
|
||||
copy_mono_dll = False
|
||||
|
||||
if copy_mono_dll:
|
||||
copyfile(mono_dll_src, mono_dll_dst)
|
||||
else:
|
||||
mono_root = None
|
||||
|
||||
if env['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 mono_root is not None:
|
||||
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 mono_lib is None:
|
||||
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])
|
||||
elif sys.platform == "linux" or sys.platform == "linux2":
|
||||
env.Append(LINKFLAGS=['-Wl,-whole-archive', mono_lib_file, '-Wl,-no-whole-archive'])
|
||||
else:
|
||||
raise RuntimeError('mono-static: Not supported on this platform')
|
||||
else:
|
||||
env.Append(LIBS=[mono_lib])
|
||||
|
||||
env.Append(LIBS=['m', 'rt', 'dl', 'pthread'])
|
||||
else:
|
||||
if mono_static:
|
||||
raise RuntimeError('mono-static: Not supported with pkg-config. Specify a mono prefix manually')
|
||||
|
||||
env.ParseConfig('pkg-config mono-2 --cflags --libs')
|
||||
|
||||
env.Append(LINKFLAGS='-rdynamic')
|
||||
|
||||
|
||||
def get_doc_classes():
|
||||
return ["@C#", "CSharpScript", "GodotSharp"]
|
||||
|
||||
|
||||
def get_doc_path():
|
||||
return "doc_classes"
|
1853
modules/mono/csharp_script.cpp
Normal file
1853
modules/mono/csharp_script.cpp
Normal file
File diff suppressed because it is too large
Load Diff
338
modules/mono/csharp_script.h
Normal file
338
modules/mono/csharp_script.h
Normal file
@ -0,0 +1,338 @@
|
||||
/*************************************************************************/
|
||||
/* csharp_script.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 CSHARP_SCRIPT_H
|
||||
#define CSHARP_SCRIPT_H
|
||||
|
||||
#include "io/resource_loader.h"
|
||||
#include "io/resource_saver.h"
|
||||
#include "script_language.h"
|
||||
#include "self_list.h"
|
||||
|
||||
#include "mono_gc_handle.h"
|
||||
#include "mono_gd/gd_mono.h"
|
||||
#include "mono_gd/gd_mono_header.h"
|
||||
#include "mono_gd/gd_mono_internals.h"
|
||||
|
||||
class CSharpScript;
|
||||
class CSharpInstance;
|
||||
class CSharpLanguage;
|
||||
|
||||
#ifdef NO_SAFE_CAST
|
||||
template <typename TScriptInstance, typename TScriptLanguage>
|
||||
TScriptInstance *cast_script_instance(ScriptInstance *p_inst) {
|
||||
return p_inst->get_language() == TScriptLanguage::get_singleton() ? static_cast<TScriptInstance *>(p_inst) : NULL;
|
||||
}
|
||||
#else
|
||||
template <typename TScriptInstance, typename TScriptLanguage>
|
||||
TScriptInstance *cast_script_instance(ScriptInstance *p_inst) {
|
||||
return dynamic_cast<TScriptInstance *>(p_inst);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define CAST_CSHARP_INSTANCE(m_inst) (cast_script_instance<CSharpInstance, CSharpLanguage>(m_inst))
|
||||
|
||||
class CSharpScript : public Script {
|
||||
|
||||
GDCLASS(CSharpScript, Script)
|
||||
|
||||
friend class CSharpInstance;
|
||||
friend class CSharpLanguage;
|
||||
friend class CSharpScriptDepSort;
|
||||
|
||||
bool tool;
|
||||
bool valid;
|
||||
|
||||
bool builtin;
|
||||
|
||||
GDMonoClass *base;
|
||||
GDMonoClass *native;
|
||||
GDMonoClass *script_class;
|
||||
|
||||
Ref<CSharpScript> base_cache; // TODO what's this for?
|
||||
|
||||
Set<Object *> instances;
|
||||
|
||||
String source;
|
||||
StringName name;
|
||||
|
||||
SelfList<CSharpScript> script_list;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
List<PropertyInfo> exported_members_cache; // members_cache
|
||||
Map<StringName, Variant> exported_members_defval_cache; // member_default_values_cache
|
||||
Set<PlaceHolderScriptInstance *> placeholders;
|
||||
bool source_changed_cache;
|
||||
bool exports_invalidated;
|
||||
|
||||
void _update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames);
|
||||
virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
Map<ObjectID, List<Pair<StringName, Variant> > > pending_reload_state;
|
||||
#endif
|
||||
|
||||
Map<StringName, PropertyInfo> member_info;
|
||||
|
||||
void _clear();
|
||||
|
||||
bool _update_exports();
|
||||
CSharpInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error);
|
||||
Variant _new(const Variant **p_args, int p_argcount, Variant::CallError &r_error);
|
||||
|
||||
// Do not use unless you know what you are doing
|
||||
friend void GDMonoInternals::tie_managed_to_unmanaged(MonoObject *, Object *);
|
||||
static Ref<CSharpScript> create_for_managed_type(GDMonoClass *p_class);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error);
|
||||
virtual void _resource_path_changed();
|
||||
|
||||
public:
|
||||
virtual bool can_instance() const;
|
||||
virtual StringName get_instance_base_type() const;
|
||||
virtual ScriptInstance *instance_create(Object *p_this);
|
||||
virtual bool instance_has(const Object *p_this) const;
|
||||
|
||||
virtual bool has_source_code() const;
|
||||
virtual String get_source_code() const;
|
||||
virtual void set_source_code(const String &p_code);
|
||||
|
||||
virtual Error reload(bool p_keep_state = false);
|
||||
|
||||
/* TODO */ virtual bool has_script_signal(const StringName &p_signal) const { return false; }
|
||||
/* TODO */ 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 void get_script_property_list(List<PropertyInfo> *p_list) const;
|
||||
virtual void update_exports();
|
||||
|
||||
virtual bool is_tool() const { return tool; }
|
||||
virtual Ref<Script> get_base_script() const;
|
||||
virtual String get_node_type() const;
|
||||
virtual ScriptLanguage *get_language() const;
|
||||
|
||||
/* TODO */ virtual void get_script_method_list(List<MethodInfo> *p_list) const {}
|
||||
bool has_method(const StringName &p_method) const;
|
||||
/* TODO */ MethodInfo get_method_info(const StringName &p_method) const { return MethodInfo(); }
|
||||
|
||||
virtual int get_member_line(const StringName &p_member) const;
|
||||
|
||||
Error load_source_code(const String &p_path);
|
||||
|
||||
StringName get_script_name() const;
|
||||
|
||||
CSharpScript();
|
||||
~CSharpScript();
|
||||
};
|
||||
|
||||
class CSharpInstance : public ScriptInstance {
|
||||
|
||||
friend class CSharpScript;
|
||||
friend class CSharpLanguage;
|
||||
Object *owner;
|
||||
Ref<CSharpScript> script;
|
||||
Ref<MonoGCHandle> gchandle;
|
||||
bool base_ref;
|
||||
bool ref_dying;
|
||||
|
||||
void _ml_call_reversed(GDMonoClass *klass, const StringName &p_method, const Variant **p_args, int p_argcount);
|
||||
|
||||
void _reference_owner_unsafe();
|
||||
void _unreference_owner_unsafe();
|
||||
|
||||
// Do not use unless you know what you are doing
|
||||
friend void GDMonoInternals::tie_managed_to_unmanaged(MonoObject *, Object *);
|
||||
static CSharpInstance *create_for_managed_type(Object *p_owner, CSharpScript *p_script, const Ref<MonoGCHandle> &p_gchandle);
|
||||
|
||||
public:
|
||||
MonoObject *get_mono_object() const;
|
||||
|
||||
virtual bool set(const StringName &p_name, const Variant &p_value);
|
||||
virtual bool get(const StringName &p_name, Variant &r_ret) const;
|
||||
virtual void get_property_list(List<PropertyInfo> *p_properties) const;
|
||||
virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid) const;
|
||||
|
||||
/* TODO */ virtual void get_method_list(List<MethodInfo> *p_list) const {}
|
||||
virtual bool has_method(const StringName &p_method) const;
|
||||
virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error);
|
||||
virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount);
|
||||
virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount);
|
||||
|
||||
void mono_object_disposed();
|
||||
|
||||
void refcount_incremented();
|
||||
bool refcount_decremented();
|
||||
|
||||
RPCMode get_rpc_mode(const StringName &p_method) const;
|
||||
RPCMode get_rset_mode(const StringName &p_variable) const;
|
||||
|
||||
virtual void notification(int p_notification);
|
||||
|
||||
virtual Ref<Script> get_script() const;
|
||||
|
||||
virtual ScriptLanguage *get_language();
|
||||
|
||||
CSharpInstance();
|
||||
~CSharpInstance();
|
||||
};
|
||||
|
||||
class CSharpLanguage : public ScriptLanguage {
|
||||
|
||||
friend class CSharpScript;
|
||||
friend class CSharpInstance;
|
||||
|
||||
static CSharpLanguage *singleton;
|
||||
|
||||
GDMono *gdmono;
|
||||
SelfList<CSharpScript>::List script_list;
|
||||
|
||||
Mutex *lock;
|
||||
Mutex *script_bind_lock;
|
||||
|
||||
Map<Ref<CSharpScript>, Map<ObjectID, List<Pair<StringName, Variant> > > > to_reload;
|
||||
|
||||
Map<Object *, Ref<MonoGCHandle> > gchandle_bindings;
|
||||
|
||||
struct StringNameCache {
|
||||
|
||||
StringName _awaited_signal_callback;
|
||||
StringName _set;
|
||||
StringName _get;
|
||||
StringName _notification;
|
||||
StringName dotctor; // .ctor
|
||||
|
||||
StringNameCache();
|
||||
};
|
||||
|
||||
StringNameCache string_names;
|
||||
|
||||
int lang_idx;
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ int get_language_index() { return lang_idx; }
|
||||
void set_language_index(int p_idx);
|
||||
|
||||
_FORCE_INLINE_ static CSharpLanguage *get_singleton() { return singleton; }
|
||||
|
||||
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
|
||||
void reload_assemblies_if_needed(bool p_soft_reload);
|
||||
#endif
|
||||
|
||||
virtual String get_name() const;
|
||||
|
||||
/* LANGUAGE FUNCTIONS */
|
||||
virtual String get_type() const;
|
||||
virtual String get_extension() const;
|
||||
virtual Error execute_file(const String &p_path);
|
||||
virtual void init();
|
||||
virtual void finish();
|
||||
|
||||
/* EDITOR FUNCTIONS */
|
||||
virtual void get_reserved_words(List<String> *p_words) const;
|
||||
virtual void get_comment_delimiters(List<String> *p_delimiters) const;
|
||||
virtual void get_string_delimiters(List<String> *p_delimiters) const;
|
||||
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const;
|
||||
/* TODO */ virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const { return true; }
|
||||
virtual Script *create_script() const;
|
||||
virtual bool has_named_classes() const;
|
||||
/* TODO? */ virtual int find_function(const String &p_function, const String &p_code) const { return -1; }
|
||||
virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const;
|
||||
/* TODO? */ Error complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, String &r_call_hint) { return ERR_UNAVAILABLE; }
|
||||
/* TODO? */ virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const {}
|
||||
/* TODO */ virtual void add_global_constant(const StringName &p_variable, const Variant &p_value) {}
|
||||
|
||||
/* DEBUGGER FUNCTIONS */
|
||||
/* TODO */ virtual String debug_get_error() const { return ""; }
|
||||
/* TODO */ virtual int debug_get_stack_level_count() const { return 1; }
|
||||
/* TODO */ virtual int debug_get_stack_level_line(int p_level) const { return 1; }
|
||||
/* TODO */ virtual String debug_get_stack_level_function(int p_level) const { return ""; }
|
||||
/* TODO */ virtual String debug_get_stack_level_source(int p_level) const { return ""; }
|
||||
/* TODO */ virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {}
|
||||
/* TODO */ virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {}
|
||||
/* TODO */ virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {}
|
||||
/* TODO */ virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) { return ""; }
|
||||
/* TODO */ virtual Vector<StackInfo> debug_get_current_stack_info() { return Vector<StackInfo>(); }
|
||||
|
||||
/* PROFILING FUNCTIONS */
|
||||
/* TODO */ virtual void profiling_start() {}
|
||||
/* TODO */ virtual void profiling_stop() {}
|
||||
/* TODO */ virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) { return 0; }
|
||||
/* TODO */ virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) { return 0; }
|
||||
|
||||
virtual void frame();
|
||||
|
||||
/* TODO? */ virtual void get_public_functions(List<MethodInfo> *p_functions) const {}
|
||||
/* TODO? */ virtual void get_public_constants(List<Pair<String, Variant> > *p_constants) const {}
|
||||
|
||||
virtual void reload_all_scripts();
|
||||
virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload);
|
||||
|
||||
/* LOADER FUNCTIONS */
|
||||
virtual void get_recognized_extensions(List<String> *p_extensions) const;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
virtual Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col);
|
||||
virtual bool overrides_external_editor();
|
||||
#endif
|
||||
|
||||
/* THREAD ATTACHING */
|
||||
virtual void thread_enter();
|
||||
virtual void thread_exit();
|
||||
|
||||
// Don't use these. I'm watching you
|
||||
virtual void *alloc_instance_binding_data(Object *p_object);
|
||||
virtual void free_instance_binding_data(void *p_data);
|
||||
|
||||
CSharpLanguage();
|
||||
~CSharpLanguage();
|
||||
};
|
||||
|
||||
class ResourceFormatLoaderCSharpScript : public 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;
|
||||
virtual bool handles_type(const String &p_type) const;
|
||||
virtual String get_resource_type(const String &p_path) const;
|
||||
};
|
||||
|
||||
class ResourceFormatSaverCSharpScript : public 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;
|
||||
virtual bool recognize(const RES &p_resource) const;
|
||||
};
|
||||
|
||||
#endif // CSHARP_SCRIPT_H
|
15
modules/mono/doc_classes/@C#.xml
Normal file
15
modules/mono/doc_classes/@C#.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="@C#" category="Core" version="3.0.alpha.custom_build">
|
||||
<brief_description>
|
||||
</brief_description>
|
||||
<description>
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<demos>
|
||||
</demos>
|
||||
<methods>
|
||||
</methods>
|
||||
<constants>
|
||||
</constants>
|
||||
</class>
|
21
modules/mono/doc_classes/CSharpScript.xml
Normal file
21
modules/mono/doc_classes/CSharpScript.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="CSharpScript" inherits="Script" category="Core" version="3.0.alpha.custom_build">
|
||||
<brief_description>
|
||||
</brief_description>
|
||||
<description>
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<demos>
|
||||
</demos>
|
||||
<methods>
|
||||
<method name="new" qualifiers="vararg">
|
||||
<return type="Object">
|
||||
</return>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<constants>
|
||||
</constants>
|
||||
</class>
|
43
modules/mono/doc_classes/GodotSharp.xml
Normal file
43
modules/mono/doc_classes/GodotSharp.xml
Normal file
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="GodotSharp" inherits="Object" category="Core" version="3.0.alpha.custom_build">
|
||||
<brief_description>
|
||||
</brief_description>
|
||||
<description>
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<demos>
|
||||
</demos>
|
||||
<methods>
|
||||
<method name="attach_thread">
|
||||
<return type="void">
|
||||
</return>
|
||||
<description>
|
||||
Attaches the current thread to the mono runtime.
|
||||
</description>
|
||||
</method>
|
||||
<method name="detach_thread">
|
||||
<return type="void">
|
||||
</return>
|
||||
<description>
|
||||
Detaches the current thread from the mono runtime.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_domain_loaded">
|
||||
<return type="bool">
|
||||
</return>
|
||||
<description>
|
||||
Returns whether the scripts domain is loaded.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_finalizing_domain">
|
||||
<return type="bool">
|
||||
</return>
|
||||
<description>
|
||||
Returns whether the scripts domain is being finalized.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<constants>
|
||||
</constants>
|
||||
</class>
|
335
modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs
Normal file
335
modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs
Normal file
@ -0,0 +1,335 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Security;
|
||||
using Microsoft.Build.Framework;
|
||||
|
||||
namespace GodotSharpTools.Build
|
||||
{
|
||||
public class BuildInstance : IDisposable
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_BuildInstance_ExitCallback(string solution, string config, int exitCode);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static string godot_icall_BuildInstance_get_MSBuildPath();
|
||||
|
||||
private static string MSBuildPath
|
||||
{
|
||||
get { return godot_icall_BuildInstance_get_MSBuildPath(); }
|
||||
}
|
||||
|
||||
private string solution;
|
||||
private string config;
|
||||
|
||||
private Process process;
|
||||
|
||||
private int exitCode;
|
||||
public int ExitCode { get { return exitCode; } }
|
||||
|
||||
public bool IsRunning { get { return process != null && !process.HasExited; } }
|
||||
|
||||
public BuildInstance(string solution, string config)
|
||||
{
|
||||
this.solution = solution;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public bool Build(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties = null)
|
||||
{
|
||||
string compilerArgs = BuildArguments(loggerAssemblyPath, loggerOutputDir, customProperties);
|
||||
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo(MSBuildPath, compilerArgs);
|
||||
|
||||
// No console output, thanks
|
||||
startInfo.RedirectStandardOutput = true;
|
||||
startInfo.RedirectStandardError = true;
|
||||
startInfo.UseShellExecute = false;
|
||||
|
||||
// Needed when running from Developer Command Prompt for VS
|
||||
RemovePlatformVariable(startInfo.EnvironmentVariables);
|
||||
|
||||
using (Process process = new Process())
|
||||
{
|
||||
process.StartInfo = startInfo;
|
||||
|
||||
process.Start();
|
||||
|
||||
process.BeginOutputReadLine();
|
||||
process.BeginErrorReadLine();
|
||||
|
||||
process.WaitForExit();
|
||||
|
||||
exitCode = process.ExitCode;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool BuildAsync(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties = null)
|
||||
{
|
||||
if (process != null)
|
||||
throw new InvalidOperationException("Already in use");
|
||||
|
||||
string compilerArgs = BuildArguments(loggerAssemblyPath, loggerOutputDir, customProperties);
|
||||
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo("msbuild", compilerArgs);
|
||||
|
||||
// No console output, thanks
|
||||
startInfo.RedirectStandardOutput = true;
|
||||
startInfo.RedirectStandardError = true;
|
||||
startInfo.UseShellExecute = false;
|
||||
|
||||
// Needed when running from Developer Command Prompt for VS
|
||||
RemovePlatformVariable(startInfo.EnvironmentVariables);
|
||||
|
||||
process = new Process();
|
||||
process.StartInfo = startInfo;
|
||||
process.EnableRaisingEvents = true;
|
||||
process.Exited += new EventHandler(BuildProcess_Exited);
|
||||
|
||||
process.Start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private string BuildArguments(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties)
|
||||
{
|
||||
string arguments = string.Format("{0} /v:normal /t:Build /p:{1} /l:{2},{3};{4}",
|
||||
solution,
|
||||
"Configuration=" + config,
|
||||
typeof(GodotBuildLogger).FullName,
|
||||
loggerAssemblyPath,
|
||||
loggerOutputDir
|
||||
);
|
||||
|
||||
if (customProperties != null)
|
||||
{
|
||||
foreach (string customProperty in customProperties)
|
||||
{
|
||||
arguments += " /p:" + customProperty;
|
||||
}
|
||||
}
|
||||
|
||||
return arguments;
|
||||
}
|
||||
|
||||
private void RemovePlatformVariable(StringDictionary environmentVariables)
|
||||
{
|
||||
// EnvironmentVariables is case sensitive? Seriously?
|
||||
|
||||
List<string> platformEnvironmentVariables = new List<string>();
|
||||
|
||||
foreach (string env in environmentVariables.Keys)
|
||||
{
|
||||
if (env.ToUpper() == "PLATFORM")
|
||||
platformEnvironmentVariables.Add(env);
|
||||
}
|
||||
|
||||
foreach (string env in platformEnvironmentVariables)
|
||||
environmentVariables.Remove(env);
|
||||
}
|
||||
|
||||
private void BuildProcess_Exited(object sender, System.EventArgs e)
|
||||
{
|
||||
exitCode = process.ExitCode;
|
||||
|
||||
godot_icall_BuildInstance_ExitCallback(solution, config, exitCode);
|
||||
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (process != null)
|
||||
{
|
||||
process.Dispose();
|
||||
process = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class GodotBuildLogger : ILogger
|
||||
{
|
||||
public string Parameters { get; set; }
|
||||
public LoggerVerbosity Verbosity { get; set; }
|
||||
|
||||
public void Initialize(IEventSource eventSource)
|
||||
{
|
||||
if (null == Parameters)
|
||||
throw new LoggerException("Log directory was not set.");
|
||||
|
||||
string[] parameters = Parameters.Split(';');
|
||||
|
||||
string logDir = parameters[0];
|
||||
|
||||
if (String.IsNullOrEmpty(logDir))
|
||||
throw new LoggerException("Log directory was not set.");
|
||||
|
||||
if (parameters.Length > 1)
|
||||
throw new LoggerException("Too many parameters passed.");
|
||||
|
||||
string logFile = Path.Combine(logDir, "msbuild_log.txt");
|
||||
string issuesFile = Path.Combine(logDir, "msbuild_issues.csv");
|
||||
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(logDir))
|
||||
Directory.CreateDirectory(logDir);
|
||||
|
||||
this.logStreamWriter = new StreamWriter(logFile);
|
||||
this.issuesStreamWriter = new StreamWriter(issuesFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if
|
||||
(
|
||||
ex is UnauthorizedAccessException
|
||||
|| ex is ArgumentNullException
|
||||
|| ex is PathTooLongException
|
||||
|| ex is DirectoryNotFoundException
|
||||
|| ex is NotSupportedException
|
||||
|| ex is ArgumentException
|
||||
|| ex is SecurityException
|
||||
|| ex is IOException
|
||||
)
|
||||
{
|
||||
throw new LoggerException("Failed to create log file: " + ex.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unexpected failure
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
eventSource.ProjectStarted += new ProjectStartedEventHandler(eventSource_ProjectStarted);
|
||||
eventSource.TaskStarted += new TaskStartedEventHandler(eventSource_TaskStarted);
|
||||
eventSource.MessageRaised += new BuildMessageEventHandler(eventSource_MessageRaised);
|
||||
eventSource.WarningRaised += new BuildWarningEventHandler(eventSource_WarningRaised);
|
||||
eventSource.ErrorRaised += new BuildErrorEventHandler(eventSource_ErrorRaised);
|
||||
eventSource.ProjectFinished += new ProjectFinishedEventHandler(eventSource_ProjectFinished);
|
||||
}
|
||||
|
||||
void eventSource_ErrorRaised(object sender, BuildErrorEventArgs e)
|
||||
{
|
||||
string line = String.Format("{0}({1},{2}): error {3}: {4}", e.File, e.LineNumber, e.ColumnNumber, e.Code, e.Message);
|
||||
|
||||
if (e.ProjectFile.Length > 0)
|
||||
line += string.Format(" [{0}]", e.ProjectFile);
|
||||
|
||||
WriteLine(line);
|
||||
|
||||
string errorLine = String.Format(@"error,{0},{1},{2},{3},{4},{5}",
|
||||
e.File.CsvEscape(), e.LineNumber, e.ColumnNumber,
|
||||
e.Code.CsvEscape(), e.Message.CsvEscape(), e.ProjectFile.CsvEscape());
|
||||
issuesStreamWriter.WriteLine(errorLine);
|
||||
}
|
||||
|
||||
void eventSource_WarningRaised(object sender, BuildWarningEventArgs e)
|
||||
{
|
||||
string line = String.Format("{0}({1},{2}): warning {3}: {4}", e.File, e.LineNumber, e.ColumnNumber, e.Code, e.Message, e.ProjectFile);
|
||||
|
||||
if (e.ProjectFile != null && e.ProjectFile.Length > 0)
|
||||
line += string.Format(" [{0}]", e.ProjectFile);
|
||||
|
||||
WriteLine(line);
|
||||
|
||||
string warningLine = String.Format(@"warning,{0},{1},{2},{3},{4},{5}",
|
||||
e.File.CsvEscape(), e.LineNumber, e.ColumnNumber,
|
||||
e.Code.CsvEscape(), e.Message.CsvEscape(), e.ProjectFile != null ? e.ProjectFile.CsvEscape() : string.Empty);
|
||||
issuesStreamWriter.WriteLine(warningLine);
|
||||
}
|
||||
|
||||
void eventSource_MessageRaised(object sender, BuildMessageEventArgs e)
|
||||
{
|
||||
// BuildMessageEventArgs adds Importance to BuildEventArgs
|
||||
// Let's take account of the verbosity setting we've been passed in deciding whether to log the message
|
||||
if ((e.Importance == MessageImportance.High && IsVerbosityAtLeast(LoggerVerbosity.Minimal))
|
||||
|| (e.Importance == MessageImportance.Normal && IsVerbosityAtLeast(LoggerVerbosity.Normal))
|
||||
|| (e.Importance == MessageImportance.Low && IsVerbosityAtLeast(LoggerVerbosity.Detailed))
|
||||
)
|
||||
{
|
||||
WriteLineWithSenderAndMessage(String.Empty, e);
|
||||
}
|
||||
}
|
||||
|
||||
void eventSource_TaskStarted(object sender, TaskStartedEventArgs e)
|
||||
{
|
||||
// TaskStartedEventArgs adds ProjectFile, TaskFile, TaskName
|
||||
// To keep this log clean, this logger will ignore these events.
|
||||
}
|
||||
|
||||
void eventSource_ProjectStarted(object sender, ProjectStartedEventArgs e)
|
||||
{
|
||||
WriteLine(e.Message);
|
||||
indent++;
|
||||
}
|
||||
|
||||
void eventSource_ProjectFinished(object sender, ProjectFinishedEventArgs e)
|
||||
{
|
||||
indent--;
|
||||
WriteLine(e.Message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a line to the log, adding the SenderName
|
||||
/// </summary>
|
||||
private void WriteLineWithSender(string line, BuildEventArgs e)
|
||||
{
|
||||
if (0 == String.Compare(e.SenderName, "MSBuild", true /*ignore case*/))
|
||||
{
|
||||
// Well, if the sender name is MSBuild, let's leave it out for prettiness
|
||||
WriteLine(line);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLine(e.SenderName + ": " + line);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a line to the log, adding the SenderName and Message
|
||||
/// (these parameters are on all MSBuild event argument objects)
|
||||
/// </summary>
|
||||
private void WriteLineWithSenderAndMessage(string line, BuildEventArgs e)
|
||||
{
|
||||
if (0 == String.Compare(e.SenderName, "MSBuild", true /*ignore case*/))
|
||||
{
|
||||
// Well, if the sender name is MSBuild, let's leave it out for prettiness
|
||||
WriteLine(line + e.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLine(e.SenderName + ": " + line + e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteLine(string line)
|
||||
{
|
||||
for (int i = indent; i > 0; i--)
|
||||
{
|
||||
logStreamWriter.Write("\t");
|
||||
}
|
||||
logStreamWriter.WriteLine(line);
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
logStreamWriter.Close();
|
||||
issuesStreamWriter.Close();
|
||||
}
|
||||
|
||||
public bool IsVerbosityAtLeast(LoggerVerbosity checkVerbosity)
|
||||
{
|
||||
return this.Verbosity >= checkVerbosity;
|
||||
}
|
||||
|
||||
private StreamWriter logStreamWriter;
|
||||
private StreamWriter issuesStreamWriter;
|
||||
private int indent;
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace GodotSharpTools.Editor
|
||||
{
|
||||
public class MonoDevelopInstance
|
||||
{
|
||||
private Process process;
|
||||
private string solutionFile;
|
||||
|
||||
public void Execute(string[] files)
|
||||
{
|
||||
bool newWindow = process == null || process.HasExited;
|
||||
|
||||
List<string> args = new List<string>();
|
||||
|
||||
args.Add("--ipc-tcp");
|
||||
|
||||
if (newWindow)
|
||||
args.Add("\"" + Path.GetFullPath(solutionFile) + "\"");
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
int semicolonIndex = file.IndexOf(';');
|
||||
|
||||
string filePath = semicolonIndex < 0 ? file : file.Substring(0, semicolonIndex);
|
||||
string cursor = semicolonIndex < 0 ? string.Empty : file.Substring(semicolonIndex);
|
||||
|
||||
args.Add("\"" + Path.GetFullPath(filePath.NormalizePath()) + cursor + "\"");
|
||||
}
|
||||
|
||||
if (newWindow)
|
||||
{
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo(MonoDevelopFile, string.Join(" ", args));
|
||||
process = Process.Start(startInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
Process.Start(MonoDevelopFile, string.Join(" ", args));
|
||||
}
|
||||
}
|
||||
|
||||
public MonoDevelopInstance(string solutionFile)
|
||||
{
|
||||
this.solutionFile = solutionFile;
|
||||
}
|
||||
|
||||
private static string MonoDevelopFile
|
||||
{
|
||||
get
|
||||
{
|
||||
return "monodevelop";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
45
modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj
Normal file
45
modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj
Normal file
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>GodotSharpTools</RootNamespace>
|
||||
<AssemblyName>GodotSharpTools</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="Microsoft.Build" />
|
||||
<Reference Include="Microsoft.Build.Framework" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="StringExtensions.cs" />
|
||||
<Compile Include="Build\BuildSystem.cs" />
|
||||
<Compile Include="Editor\MonoDevelopInstance.cs" />
|
||||
<Compile Include="Project\ProjectExtensions.cs" />
|
||||
<Compile Include="Project\ProjectGenerator.cs" />
|
||||
<Compile Include="Project\ProjectUtils.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
17
modules/mono/editor/GodotSharpTools/GodotSharpTools.sln
Normal file
17
modules/mono/editor/GodotSharpTools/GodotSharpTools.sln
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2012
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotSharpTools", "GodotSharpTools.csproj", "{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -0,0 +1,14 @@
|
||||
<Properties StartupItem="GodotSharpTools.csproj">
|
||||
<MonoDevelop.Ide.Workspace ActiveConfiguration="Debug" />
|
||||
<MonoDevelop.Ide.Workbench ActiveDocument="Build/BuildSystem.cs">
|
||||
<Files>
|
||||
<File FileName="Build/ProjectExtensions.cs" Line="1" Column="1" />
|
||||
<File FileName="Build/ProjectGenerator.cs" Line="1" Column="1" />
|
||||
<File FileName="Build/BuildSystem.cs" Line="37" Column="14" />
|
||||
</Files>
|
||||
</MonoDevelop.Ide.Workbench>
|
||||
<MonoDevelop.Ide.DebuggingService.Breakpoints>
|
||||
<BreakpointStore />
|
||||
</MonoDevelop.Ide.DebuggingService.Breakpoints>
|
||||
<MonoDevelop.Ide.DebuggingService.PinnedWatches />
|
||||
</Properties>
|
@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using Microsoft.Build.Construction;
|
||||
|
||||
namespace GodotSharpTools.Project
|
||||
{
|
||||
public static class ProjectExtensions
|
||||
{
|
||||
public static bool HasItem(this ProjectRootElement root, string itemType, string include)
|
||||
{
|
||||
string includeNormalized = include.NormalizePath();
|
||||
|
||||
foreach (var itemGroup in root.ItemGroups)
|
||||
{
|
||||
if (itemGroup.Condition.Length != 0)
|
||||
continue;
|
||||
|
||||
foreach (var item in itemGroup.Items)
|
||||
{
|
||||
if (item.ItemType == itemType)
|
||||
{
|
||||
if (item.Include.NormalizePath() == includeNormalized)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void AddItemChecked(this ProjectRootElement root, string itemType, string include)
|
||||
{
|
||||
if (!root.HasItem(itemType, include))
|
||||
{
|
||||
root.AddItem(itemType, include);
|
||||
}
|
||||
}
|
||||
|
||||
public static Guid GetGuid(this ProjectRootElement root)
|
||||
{
|
||||
foreach (var property in root.Properties)
|
||||
{
|
||||
if (property.Name == "ProjectGuid")
|
||||
return Guid.Parse(property.Value);
|
||||
}
|
||||
|
||||
return Guid.Empty;
|
||||
}
|
||||
}
|
||||
}
|
216
modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs
Normal file
216
modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs
Normal file
@ -0,0 +1,216 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Construction;
|
||||
|
||||
namespace GodotSharpTools.Project
|
||||
{
|
||||
public static class ProjectGenerator
|
||||
{
|
||||
public static string GenCoreApiProject(string dir, string[] compileItems)
|
||||
{
|
||||
string path = Path.Combine(dir, CoreApiProject + ".csproj");
|
||||
|
||||
ProjectPropertyGroupElement mainGroup;
|
||||
var root = CreateLibraryProject(CoreApiProject, out mainGroup);
|
||||
|
||||
mainGroup.AddProperty("DocumentationFile", Path.Combine("$(OutputPath)", "$(AssemblyName).xml"));
|
||||
mainGroup.SetProperty("RootNamespace", "Godot");
|
||||
|
||||
GenAssemblyInfoFile(root, dir, CoreApiProject,
|
||||
new string[] { "[assembly: InternalsVisibleTo(\"" + EditorApiProject + "\")]" },
|
||||
new string[] { "System.Runtime.CompilerServices" });
|
||||
|
||||
foreach (var item in compileItems)
|
||||
{
|
||||
root.AddItem("Compile", item.RelativeToPath(dir).Replace("/", "\\"));
|
||||
}
|
||||
|
||||
root.Save(path);
|
||||
|
||||
return root.GetGuid().ToString().ToUpper();
|
||||
}
|
||||
|
||||
public static string GenEditorApiProject(string dir, string coreApiHintPath, string[] compileItems)
|
||||
{
|
||||
string path = Path.Combine(dir, EditorApiProject + ".csproj");
|
||||
|
||||
ProjectPropertyGroupElement mainGroup;
|
||||
var root = CreateLibraryProject(EditorApiProject, out mainGroup);
|
||||
|
||||
mainGroup.AddProperty("DocumentationFile", Path.Combine("$(OutputPath)", "$(AssemblyName).xml"));
|
||||
mainGroup.SetProperty("RootNamespace", "Godot");
|
||||
|
||||
GenAssemblyInfoFile(root, dir, EditorApiProject);
|
||||
|
||||
foreach (var item in compileItems)
|
||||
{
|
||||
root.AddItem("Compile", item.RelativeToPath(dir).Replace("/", "\\"));
|
||||
}
|
||||
|
||||
var coreApiRef = root.AddItem("Reference", CoreApiProject);
|
||||
coreApiRef.AddMetadata("HintPath", coreApiHintPath);
|
||||
coreApiRef.AddMetadata("Private", "False");
|
||||
|
||||
root.Save(path);
|
||||
|
||||
return root.GetGuid().ToString().ToUpper();
|
||||
}
|
||||
|
||||
public static string GenGameProject(string dir, string name, string[] compileItems)
|
||||
{
|
||||
string path = Path.Combine(dir, name + ".csproj");
|
||||
|
||||
ProjectPropertyGroupElement mainGroup;
|
||||
var root = CreateLibraryProject(name, out mainGroup);
|
||||
|
||||
mainGroup.SetProperty("OutputPath", Path.Combine(".mono", "temp", "bin", "$(Configuration)"));
|
||||
mainGroup.SetProperty("BaseIntermediateOutputPath", Path.Combine(".mono", "temp", "obj"));
|
||||
mainGroup.SetProperty("IntermediateOutputPath", Path.Combine("$(BaseIntermediateOutputPath)", "$(Configuration)"));
|
||||
|
||||
var toolsGroup = root.AddPropertyGroup();
|
||||
toolsGroup.Condition = " '$(Configuration)|$(Platform)' == 'Tools|AnyCPU' ";
|
||||
toolsGroup.AddProperty("DebugSymbols", "true");
|
||||
toolsGroup.AddProperty("DebugType", "full");
|
||||
toolsGroup.AddProperty("Optimize", "false");
|
||||
toolsGroup.AddProperty("DefineConstants", "DEBUG;TOOLS;");
|
||||
toolsGroup.AddProperty("ErrorReport", "prompt");
|
||||
toolsGroup.AddProperty("WarningLevel", "4");
|
||||
toolsGroup.AddProperty("ConsolePause", "false");
|
||||
|
||||
var coreApiRef = root.AddItem("Reference", CoreApiProject);
|
||||
coreApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", CoreApiProject + ".dll"));
|
||||
coreApiRef.AddMetadata("Private", "False");
|
||||
|
||||
var editorApiRef = root.AddItem("Reference", EditorApiProject);
|
||||
editorApiRef.Condition = " '$(Configuration)' == 'Tools' ";
|
||||
editorApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", EditorApiProject + ".dll"));
|
||||
editorApiRef.AddMetadata("Private", "False");
|
||||
|
||||
GenAssemblyInfoFile(root, dir, name);
|
||||
|
||||
foreach (var item in compileItems)
|
||||
{
|
||||
root.AddItem("Compile", item.RelativeToPath(dir).Replace("/", "\\"));
|
||||
}
|
||||
|
||||
root.Save(path);
|
||||
|
||||
return root.GetGuid().ToString().ToUpper();
|
||||
}
|
||||
|
||||
public static void GenAssemblyInfoFile(ProjectRootElement root, string dir, string name, string[] assemblyLines = null, string[] usingDirectives = null)
|
||||
{
|
||||
|
||||
string propertiesDir = Path.Combine(dir, "Properties");
|
||||
if (!Directory.Exists(propertiesDir))
|
||||
Directory.CreateDirectory(propertiesDir);
|
||||
|
||||
string usingDirectivesText = string.Empty;
|
||||
|
||||
if (usingDirectives != null)
|
||||
{
|
||||
foreach (var usingDirective in usingDirectives)
|
||||
usingDirectivesText += "\nusing " + usingDirective + ";";
|
||||
}
|
||||
|
||||
string assemblyLinesText = string.Empty;
|
||||
|
||||
if (assemblyLines != null)
|
||||
{
|
||||
foreach (var assemblyLine in assemblyLines)
|
||||
assemblyLinesText += string.Join("\n", assemblyLines) + "\n";
|
||||
}
|
||||
|
||||
string content = string.Format(assemblyInfoTemplate, usingDirectivesText, name, assemblyLinesText);
|
||||
|
||||
string assemblyInfoFile = Path.Combine(propertiesDir, "AssemblyInfo.cs");
|
||||
|
||||
File.WriteAllText(assemblyInfoFile, content);
|
||||
|
||||
root.AddItem("Compile", assemblyInfoFile.RelativeToPath(dir).Replace("/", "\\"));
|
||||
}
|
||||
|
||||
public static ProjectRootElement CreateLibraryProject(string name, out ProjectPropertyGroupElement mainGroup)
|
||||
{
|
||||
var root = ProjectRootElement.Create();
|
||||
root.DefaultTargets = "Build";
|
||||
|
||||
mainGroup = root.AddPropertyGroup();
|
||||
mainGroup.AddProperty("Configuration", "Debug").Condition = " '$(Configuration)' == '' ";
|
||||
mainGroup.AddProperty("Platform", "AnyCPU").Condition = " '$(Platform)' == '' ";
|
||||
mainGroup.AddProperty("ProjectGuid", "{" + Guid.NewGuid().ToString().ToUpper() + "}");
|
||||
mainGroup.AddProperty("OutputType", "Library");
|
||||
mainGroup.AddProperty("OutputPath", Path.Combine("bin", "$(Configuration)"));
|
||||
mainGroup.AddProperty("RootNamespace", name);
|
||||
mainGroup.AddProperty("AssemblyName", name);
|
||||
mainGroup.AddProperty("TargetFrameworkVersion", "v4.5");
|
||||
|
||||
var debugGroup = root.AddPropertyGroup();
|
||||
debugGroup.Condition = " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ";
|
||||
debugGroup.AddProperty("DebugSymbols", "true");
|
||||
debugGroup.AddProperty("DebugType", "full");
|
||||
debugGroup.AddProperty("Optimize", "false");
|
||||
debugGroup.AddProperty("DefineConstants", "DEBUG;");
|
||||
debugGroup.AddProperty("ErrorReport", "prompt");
|
||||
debugGroup.AddProperty("WarningLevel", "4");
|
||||
debugGroup.AddProperty("ConsolePause", "false");
|
||||
|
||||
var releaseGroup = root.AddPropertyGroup();
|
||||
releaseGroup.Condition = " '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ";
|
||||
releaseGroup.AddProperty("DebugType", "full");
|
||||
releaseGroup.AddProperty("Optimize", "true");
|
||||
releaseGroup.AddProperty("ErrorReport", "prompt");
|
||||
releaseGroup.AddProperty("WarningLevel", "4");
|
||||
releaseGroup.AddProperty("ConsolePause", "false");
|
||||
|
||||
// References
|
||||
var referenceGroup = root.AddItemGroup();
|
||||
referenceGroup.AddItem("Reference", "System");
|
||||
|
||||
root.AddImport(Path.Combine("$(MSBuildBinPath)", "Microsoft.CSharp.targets").Replace("/", "\\"));
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
private static void AddItems(ProjectRootElement elem, string groupName, params string[] items)
|
||||
{
|
||||
var group = elem.AddItemGroup();
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
group.AddItem(groupName, item);
|
||||
}
|
||||
}
|
||||
|
||||
public const string CoreApiProject = "GodotSharp";
|
||||
public const string EditorApiProject = "GodotSharpEditor";
|
||||
|
||||
private const string assemblyInfoTemplate =
|
||||
@"using System.Reflection;{0}
|
||||
|
||||
// Information about this assembly is defined by the following attributes.
|
||||
// Change them to the values specific to your project.
|
||||
|
||||
[assembly: AssemblyTitle(""{1}"")]
|
||||
[assembly: AssemblyDescription("""")]
|
||||
[assembly: AssemblyConfiguration("""")]
|
||||
[assembly: AssemblyCompany("""")]
|
||||
[assembly: AssemblyProduct("""")]
|
||||
[assembly: AssemblyCopyright("""")]
|
||||
[assembly: AssemblyTrademark("""")]
|
||||
[assembly: AssemblyCulture("""")]
|
||||
|
||||
// The assembly version has the format ""{{Major}}.{{Minor}}.{{Build}}.{{Revision}}"".
|
||||
// The form ""{{Major}}.{{Minor}}.*"" will automatically update the build and revision,
|
||||
// and ""{{Major}}.{{Minor}}.{{Build}}.*"" will update just the revision.
|
||||
|
||||
[assembly: AssemblyVersion(""1.0.*"")]
|
||||
|
||||
// The following attributes are used to specify the signing key for the assembly,
|
||||
// if desired. See the Mono documentation for more information about signing.
|
||||
|
||||
//[assembly: AssemblyDelaySign(false)]
|
||||
//[assembly: AssemblyKeyFile("""")]
|
||||
{2}";
|
||||
}
|
||||
}
|
17
modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs
Normal file
17
modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Construction;
|
||||
|
||||
namespace GodotSharpTools.Project
|
||||
{
|
||||
public static class ProjectUtils
|
||||
{
|
||||
public static void AddItemToProjectChecked(string projectPath, string itemType, string include)
|
||||
{
|
||||
var dir = Directory.GetParent(projectPath).FullName;
|
||||
var root = ProjectRootElement.Open(projectPath);
|
||||
root.AddItemChecked(itemType, include.RelativeToPath(dir).Replace("/", "\\"));
|
||||
root.Save();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// Information about this assembly is defined by the following attributes.
|
||||
// Change them to the values specific to your project.
|
||||
|
||||
[assembly: AssemblyTitle("GodotSharpTools")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("")]
|
||||
[assembly: AssemblyCopyright("ignacio")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
|
||||
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
|
||||
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
// The following attributes are used to specify the signing key for the assembly,
|
||||
// if desired. See the Mono documentation for more information about signing.
|
||||
|
||||
//[assembly: AssemblyDelaySign(false)]
|
||||
//[assembly: AssemblyKeyFile("")]
|
||||
|
52
modules/mono/editor/GodotSharpTools/StringExtensions.cs
Normal file
52
modules/mono/editor/GodotSharpTools/StringExtensions.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace GodotSharpTools
|
||||
{
|
||||
public static class StringExtensions
|
||||
{
|
||||
public static string RelativeToPath(this string path, string dir)
|
||||
{
|
||||
// Make sure the directory ends with a path separator
|
||||
dir = Path.Combine(dir, " ").TrimEnd();
|
||||
|
||||
if (Path.DirectorySeparatorChar == '\\')
|
||||
dir = dir.Replace("/", "\\") + "\\";
|
||||
|
||||
Uri fullPath = new Uri(Path.GetFullPath(path), UriKind.Absolute);
|
||||
Uri relRoot = new Uri(Path.GetFullPath(dir), UriKind.Absolute);
|
||||
|
||||
return relRoot.MakeRelativeUri(fullPath).ToString();
|
||||
}
|
||||
|
||||
public static string NormalizePath(this string path)
|
||||
{
|
||||
bool rooted = path.IsAbsolutePath();
|
||||
|
||||
path = path.Replace('\\', '/');
|
||||
|
||||
string[] parts = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
path = string.Join(Path.DirectorySeparatorChar.ToString(), parts).Trim();
|
||||
|
||||
return rooted ? Path.DirectorySeparatorChar.ToString() + path : path;
|
||||
}
|
||||
|
||||
private static readonly string driveRoot = Path.GetPathRoot(Environment.CurrentDirectory);
|
||||
|
||||
public static bool IsAbsolutePath(this string path)
|
||||
{
|
||||
return path.StartsWith("/") || path.StartsWith("\\") || path.StartsWith(driveRoot);
|
||||
}
|
||||
|
||||
public static string CsvEscape(this string value, char delimiter = ',')
|
||||
{
|
||||
bool hasSpecialChar = value.IndexOfAny(new char[] { '\"', '\n', '\r', delimiter }) != -1;
|
||||
|
||||
if (hasSpecialChar)
|
||||
return "\"" + value.Replace("\"", "\"\"") + "\"";
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
2151
modules/mono/editor/bindings_generator.cpp
Normal file
2151
modules/mono/editor/bindings_generator.cpp
Normal file
File diff suppressed because it is too large
Load Diff
429
modules/mono/editor/bindings_generator.h
Normal file
429
modules/mono/editor/bindings_generator.h
Normal file
@ -0,0 +1,429 @@
|
||||
/*************************************************************************/
|
||||
/* bindings_generator.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 BINDINGS_GENERATOR_H
|
||||
#define BINDINGS_GENERATOR_H
|
||||
|
||||
#include "class_db.h"
|
||||
#include "editor/doc/doc_data.h"
|
||||
#include "editor/editor_help.h"
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
|
||||
#include "ustring.h"
|
||||
|
||||
class BindingsGenerator {
|
||||
struct ArgumentInterface {
|
||||
enum DefaultParamMode {
|
||||
CONSTANT,
|
||||
NULLABLE_VAL,
|
||||
NULLABLE_REF
|
||||
};
|
||||
|
||||
String type;
|
||||
String name;
|
||||
String default_argument;
|
||||
DefaultParamMode def_param_mode;
|
||||
|
||||
ArgumentInterface() {
|
||||
def_param_mode = CONSTANT;
|
||||
}
|
||||
};
|
||||
|
||||
struct MethodInterface {
|
||||
String name;
|
||||
|
||||
/**
|
||||
* Name of the C# method
|
||||
*/
|
||||
String proxy_name;
|
||||
|
||||
/**
|
||||
* [TypeInterface::name] of the return type
|
||||
*/
|
||||
String return_type;
|
||||
|
||||
/**
|
||||
* Determines if the method has a variable number of arguments (VarArg)
|
||||
*/
|
||||
bool is_vararg;
|
||||
|
||||
/**
|
||||
* Virtual methods ("virtual" as defined by the Godot API) are methods that by default do nothing,
|
||||
* but can be overridden by the user to add custom functionality.
|
||||
* e.g.: _ready, _process, etc.
|
||||
*/
|
||||
bool is_virtual;
|
||||
|
||||
/**
|
||||
* Determines if the call should fallback to Godot's object.Call(string, params) in C#.
|
||||
*/
|
||||
bool requires_object_call;
|
||||
|
||||
/**
|
||||
* Determines if the method visibility is `internal` (visible only to files in the same assembly).
|
||||
* Currently, we only use this for methods that are not meant to be exposed,
|
||||
* but are required by properties as getters or setters.
|
||||
* Methods that are not meant to be exposed are those that begin with underscore and are not virtual.
|
||||
*/
|
||||
bool is_internal;
|
||||
|
||||
List<ArgumentInterface> arguments;
|
||||
|
||||
const DocData::MethodDoc *method_doc;
|
||||
|
||||
void add_argument(const ArgumentInterface &argument) {
|
||||
arguments.push_back(argument);
|
||||
}
|
||||
|
||||
MethodInterface() {
|
||||
return_type = "void";
|
||||
is_vararg = false;
|
||||
is_virtual = false;
|
||||
requires_object_call = false;
|
||||
is_internal = false;
|
||||
method_doc = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
struct TypeInterface {
|
||||
/**
|
||||
* Identifier name for this type.
|
||||
* Also used to format [c_out].
|
||||
*/
|
||||
String name;
|
||||
|
||||
/**
|
||||
* Identifier name of the base class.
|
||||
*/
|
||||
String base_name;
|
||||
|
||||
/**
|
||||
* Name of the C# class
|
||||
*/
|
||||
String proxy_name;
|
||||
|
||||
ClassDB::APIType api_type;
|
||||
|
||||
bool is_object_type;
|
||||
bool is_singleton;
|
||||
bool is_reference;
|
||||
|
||||
/**
|
||||
* Used only by Object-derived types.
|
||||
* Determines if this type is not virtual (incomplete).
|
||||
* e.g.: CanvasItem cannot be instantiated.
|
||||
*/
|
||||
bool is_instantiable;
|
||||
|
||||
/**
|
||||
* Used only by Object-derived types.
|
||||
* Determines if the C# class owns the native handle and must free it somehow when disposed.
|
||||
* e.g.: Reference types must notify when the C# instance is disposed, for proper refcounting.
|
||||
*/
|
||||
bool memory_own;
|
||||
|
||||
/**
|
||||
* Determines if the file must have a using directive for System.Collections.Generic
|
||||
* e.g.: When the generated class makes use of Dictionary
|
||||
*/
|
||||
bool requires_collections;
|
||||
|
||||
// !! The comments of the following fields make reference to other fields via square brackets, e.g.: [field_name]
|
||||
// !! When renaming those fields, make sure to rename their references in the comments
|
||||
|
||||
// --- C INTERFACE ---
|
||||
|
||||
static const char *DEFAULT_VARARG_C_IN;
|
||||
|
||||
/**
|
||||
* One or more statements that manipulate the parameter before being passed as argument of a ptrcall.
|
||||
* If the statement adds a local that must be passed as the argument instead of the parameter,
|
||||
* the name of that local must be specified with [c_arg_in].
|
||||
* For variadic methods, this field is required and, if empty, [DEFAULT_VARARG_C_IN] is used instead.
|
||||
* Formatting elements:
|
||||
* %0: [c_type] of the parameter
|
||||
* %1: name of the parameter
|
||||
*/
|
||||
String c_in;
|
||||
|
||||
/**
|
||||
* Determines the name of the variable that will be passed as argument to a ptrcall.
|
||||
* By default the value equals the name of the parameter,
|
||||
* this varies for types that require special manipulation via [c_in].
|
||||
* Formatting elements:
|
||||
* %0 or %s: name of the parameter
|
||||
*/
|
||||
String c_arg_in;
|
||||
|
||||
/**
|
||||
* One or more statements that determine how a variable of this type is returned from a function.
|
||||
* It must contain the return statement(s).
|
||||
* Formatting elements:
|
||||
* %0: [c_type_out] of the return type
|
||||
* %1: name of the variable to be returned
|
||||
* %2: [name] of the return type
|
||||
*/
|
||||
String c_out;
|
||||
|
||||
/**
|
||||
* The actual expected type, as seen (in most cases) in Variant copy constructors
|
||||
* Used for the type of the return variable and to format [c_in].
|
||||
* The value must be the following depending of the type:
|
||||
* Object-derived types: Object*
|
||||
* Other types: [name]
|
||||
* -- Exceptions --
|
||||
* VarArg (fictitious type to represent variable arguments): Array
|
||||
* float: double (because ptrcall only supports double)
|
||||
* int: int64_t (because ptrcall only supports int64_t and uint64_t)
|
||||
* Reference types override this for the type of the return variable: Ref<Reference>
|
||||
*/
|
||||
String c_type;
|
||||
|
||||
/**
|
||||
* Determines the type used for parameters in function signatures.
|
||||
*/
|
||||
String c_type_in;
|
||||
|
||||
/**
|
||||
* Determines the return type used for function signatures.
|
||||
* Also used to construct a default value to return in case of errors,
|
||||
* and to format [c_out].
|
||||
*/
|
||||
String c_type_out;
|
||||
|
||||
// --- C# INTERFACE ---
|
||||
|
||||
/**
|
||||
* An expression that overrides the way the parameter is passed to the internal call.
|
||||
* If empty, the parameter is passed as is.
|
||||
* Formatting elements:
|
||||
* %0 or %s: name of the parameter
|
||||
*/
|
||||
String cs_in;
|
||||
|
||||
/**
|
||||
* One or more statements that determine how a variable of this type is returned from a method.
|
||||
* It must contain the return statement(s).
|
||||
* Formatting elements:
|
||||
* %0 or %s: name of the variable to be returned
|
||||
*/
|
||||
String cs_out;
|
||||
|
||||
/**
|
||||
* Type used for method signatures, both for parameters and the return type.
|
||||
* Same as [proxy_name] except for variable arguments (VarArg).
|
||||
*/
|
||||
String cs_type;
|
||||
|
||||
/**
|
||||
* Type used for parameters of internal call methods.
|
||||
*/
|
||||
String im_type_in;
|
||||
|
||||
/**
|
||||
* Type used for the return type of internal call methods.
|
||||
* If [cs_out] is not empty and the method return type is not void,
|
||||
* it is also used for the type of the return variable.
|
||||
*/
|
||||
String im_type_out;
|
||||
|
||||
const DocData::ClassDoc *class_doc;
|
||||
|
||||
List<MethodInterface> methods;
|
||||
|
||||
const MethodInterface *find_method_by_name(const String &p_name) const {
|
||||
|
||||
for (const List<MethodInterface>::Element *E = methods.front(); E; E = E->next()) {
|
||||
if (E->get().name == p_name)
|
||||
return &E->get();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static TypeInterface create_value_type(const String &p_name) {
|
||||
TypeInterface itype;
|
||||
|
||||
itype.name = p_name;
|
||||
itype.proxy_name = p_name;
|
||||
|
||||
itype.c_type = itype.name;
|
||||
itype.c_type_in = "void*";
|
||||
itype.c_type_out = "MonoObject*";
|
||||
itype.cs_type = itype.proxy_name;
|
||||
itype.im_type_in = "ref " + itype.proxy_name;
|
||||
itype.im_type_out = itype.proxy_name;
|
||||
itype.class_doc = &EditorHelp::get_doc_data()->class_list[itype.proxy_name];
|
||||
|
||||
return itype;
|
||||
}
|
||||
|
||||
static TypeInterface create_object_type(const String &p_name, ClassDB::APIType p_api_type) {
|
||||
TypeInterface itype;
|
||||
|
||||
itype.name = p_name;
|
||||
itype.proxy_name = p_name.begins_with("_") ? p_name.substr(1, p_name.length()) : p_name;
|
||||
itype.api_type = p_api_type;
|
||||
itype.is_object_type = true;
|
||||
itype.class_doc = &EditorHelp::get_doc_data()->class_list[itype.proxy_name];
|
||||
|
||||
return itype;
|
||||
}
|
||||
|
||||
static void create_placeholder_type(TypeInterface &r_itype, const String &p_name) {
|
||||
r_itype.name = p_name;
|
||||
r_itype.proxy_name = p_name;
|
||||
|
||||
r_itype.c_type = r_itype.name;
|
||||
r_itype.c_type_in = "MonoObject*";
|
||||
r_itype.c_type_out = "MonoObject*";
|
||||
r_itype.cs_type = r_itype.proxy_name;
|
||||
r_itype.im_type_in = r_itype.proxy_name;
|
||||
r_itype.im_type_out = r_itype.proxy_name;
|
||||
}
|
||||
|
||||
TypeInterface() {
|
||||
|
||||
api_type = ClassDB::API_NONE;
|
||||
|
||||
is_object_type = false;
|
||||
is_singleton = false;
|
||||
is_reference = false;
|
||||
is_instantiable = false;
|
||||
|
||||
memory_own = false;
|
||||
requires_collections = false;
|
||||
|
||||
c_arg_in = "%s";
|
||||
|
||||
class_doc = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
struct InternalCall {
|
||||
String name;
|
||||
String im_type_out; // Return type for the C# method declaration. Also used as companion of [unique_siq]
|
||||
String im_sig; // Signature for the C# method declaration
|
||||
String unique_sig; // Unique signature to avoid duplicates in containers
|
||||
bool editor_only;
|
||||
|
||||
InternalCall() {}
|
||||
|
||||
InternalCall(const String &p_name, const String &p_im_type_out, const String &p_im_sig = String(), const String &p_unique_sig = String()) {
|
||||
name = p_name;
|
||||
im_type_out = p_im_type_out;
|
||||
im_sig = p_im_sig;
|
||||
unique_sig = p_unique_sig;
|
||||
editor_only = false;
|
||||
}
|
||||
|
||||
InternalCall(ClassDB::APIType api_type, const String &p_name, const String &p_im_type_out, const String &p_im_sig = String(), const String &p_unique_sig = String()) {
|
||||
name = p_name;
|
||||
im_type_out = p_im_type_out;
|
||||
im_sig = p_im_sig;
|
||||
unique_sig = p_unique_sig;
|
||||
editor_only = api_type == ClassDB::API_EDITOR;
|
||||
}
|
||||
|
||||
inline bool operator==(const InternalCall &p_a) const {
|
||||
return p_a.unique_sig == unique_sig;
|
||||
}
|
||||
};
|
||||
|
||||
static bool verbose_output;
|
||||
|
||||
Map<String, TypeInterface> placeholder_types;
|
||||
Map<String, TypeInterface> builtin_types;
|
||||
Map<String, TypeInterface> obj_types;
|
||||
|
||||
Map<String, String> extra_members;
|
||||
|
||||
List<InternalCall> method_icalls;
|
||||
Map<const MethodInterface *, const InternalCall *> method_icalls_map;
|
||||
|
||||
List<InternalCall> core_custom_icalls;
|
||||
List<InternalCall> editor_custom_icalls;
|
||||
|
||||
const List<InternalCall>::Element *find_icall_by_name(const String &p_name, const List<InternalCall> &p_list) {
|
||||
|
||||
const List<InternalCall>::Element *it = p_list.front();
|
||||
while (it) {
|
||||
if (it->get().name == p_name) return it;
|
||||
it = it->next();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline String get_unique_sig(const TypeInterface &p_type) {
|
||||
if (p_type.is_reference)
|
||||
return "Ref";
|
||||
else if (p_type.is_object_type)
|
||||
return "Obj";
|
||||
|
||||
return p_type.name;
|
||||
}
|
||||
|
||||
void _generate_header_icalls();
|
||||
void _generate_method_icalls(const TypeInterface &p_itype);
|
||||
|
||||
const TypeInterface *_get_type_by_name_or_null(const String &p_name);
|
||||
const TypeInterface *_get_type_by_name_or_placeholder(const String &p_name);
|
||||
|
||||
void _default_argument_from_variant(const Variant &p_var, ArgumentInterface &r_iarg);
|
||||
void _populate_builtin_type(TypeInterface &r_type, Variant::Type vtype);
|
||||
|
||||
void _populate_object_type_interfaces();
|
||||
void _populate_builtin_type_interfaces();
|
||||
|
||||
Error _generate_cs_type(const TypeInterface &itype, const String &p_output_file);
|
||||
|
||||
Error _save_file(const String &path, const List<String> &content);
|
||||
|
||||
BindingsGenerator();
|
||||
|
||||
BindingsGenerator(const BindingsGenerator &);
|
||||
BindingsGenerator &operator=(const BindingsGenerator &);
|
||||
|
||||
public:
|
||||
Error generate_cs_core_project(const String &p_output_dir, bool p_verbose_output = true);
|
||||
Error generate_cs_editor_project(const String &p_output_dir, const String &p_core_dll_path, bool p_verbose_output = true);
|
||||
Error generate_glue(const String &p_output_dir);
|
||||
|
||||
static BindingsGenerator &get_singleton() {
|
||||
static BindingsGenerator singleton;
|
||||
return singleton;
|
||||
}
|
||||
|
||||
static void handle_cmdline_args(const List<String> &p_cmdline_args);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // BINDINGS_GENERATOR_H
|
120
modules/mono/editor/csharp_project.cpp
Normal file
120
modules/mono/editor/csharp_project.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
/*************************************************************************/
|
||||
/* csharp_project.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "csharp_project.h"
|
||||
|
||||
#include "os/os.h"
|
||||
#include "project_settings.h"
|
||||
|
||||
#include "../mono_gd/gd_mono_class.h"
|
||||
#include "../mono_gd/gd_mono_marshal.h"
|
||||
|
||||
namespace CSharpProject {
|
||||
|
||||
String generate_core_api_project(const String &p_dir, const Vector<String> &p_files) {
|
||||
|
||||
_GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
|
||||
|
||||
GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectGenerator");
|
||||
|
||||
Variant dir = p_dir;
|
||||
Variant compile_items = p_files;
|
||||
const Variant *args[2] = { &dir, &compile_items };
|
||||
MonoObject *ex = NULL;
|
||||
MonoObject *ret = klass->get_method("GenCoreApiProject", 2)->invoke(NULL, args, &ex);
|
||||
|
||||
if (ex) {
|
||||
mono_print_unhandled_exception(ex);
|
||||
ERR_FAIL_V(String());
|
||||
}
|
||||
|
||||
return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : "";
|
||||
}
|
||||
|
||||
String generate_editor_api_project(const String &p_dir, const String &p_core_dll_path, const Vector<String> &p_files) {
|
||||
|
||||
_GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
|
||||
|
||||
GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectGenerator");
|
||||
|
||||
Variant dir = p_dir;
|
||||
Variant core_dll_path = p_core_dll_path;
|
||||
Variant compile_items = p_files;
|
||||
const Variant *args[3] = { &dir, &core_dll_path, &compile_items };
|
||||
MonoObject *ex = NULL;
|
||||
MonoObject *ret = klass->get_method("GenEditorApiProject", 3)->invoke(NULL, args, &ex);
|
||||
|
||||
if (ex) {
|
||||
mono_print_unhandled_exception(ex);
|
||||
ERR_FAIL_V(String());
|
||||
}
|
||||
|
||||
return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : "";
|
||||
}
|
||||
|
||||
String generate_game_project(const String &p_dir, const String &p_name, const Vector<String> &p_files) {
|
||||
|
||||
_GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
|
||||
|
||||
GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectGenerator");
|
||||
|
||||
Variant dir = p_dir;
|
||||
Variant name = p_name;
|
||||
Variant compile_items = p_files;
|
||||
const Variant *args[3] = { &dir, &name, &compile_items };
|
||||
MonoObject *ex = NULL;
|
||||
MonoObject *ret = klass->get_method("GenGameProject", 3)->invoke(NULL, args, &ex);
|
||||
|
||||
if (ex) {
|
||||
mono_print_unhandled_exception(ex);
|
||||
ERR_FAIL_V(String());
|
||||
}
|
||||
|
||||
return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : "";
|
||||
}
|
||||
|
||||
void add_item(const String &p_project_path, const String &p_item_type, const String &p_include) {
|
||||
|
||||
_GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
|
||||
|
||||
GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectUtils");
|
||||
|
||||
Variant project_path = p_project_path;
|
||||
Variant item_type = p_item_type;
|
||||
Variant include = p_include;
|
||||
const Variant *args[3] = { &project_path, &item_type, &include };
|
||||
MonoObject *ex = NULL;
|
||||
klass->get_method("AddItemToProjectChecked", 3)->invoke(NULL, args, &ex);
|
||||
|
||||
if (ex) {
|
||||
mono_print_unhandled_exception(ex);
|
||||
ERR_FAIL();
|
||||
}
|
||||
}
|
||||
} // CSharpProject
|
44
modules/mono/editor/csharp_project.h
Normal file
44
modules/mono/editor/csharp_project.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*************************************************************************/
|
||||
/* csharp_project.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 CSHARP_PROJECT_H
|
||||
#define CSHARP_PROJECT_H
|
||||
|
||||
#include "ustring.h"
|
||||
|
||||
namespace CSharpProject {
|
||||
|
||||
String generate_core_api_project(const String &p_dir, const Vector<String> &p_files = Vector<String>());
|
||||
String generate_editor_api_project(const String &p_dir, const String &p_core_dll_path, const Vector<String> &p_files = Vector<String>());
|
||||
String generate_game_project(const String &p_dir, const String &p_name, const Vector<String> &p_files = Vector<String>());
|
||||
|
||||
void add_item(const String &p_project_path, const String &p_item_type, const String &p_include);
|
||||
}
|
||||
|
||||
#endif // CSHARP_PROJECT_H
|
440
modules/mono/editor/godotsharp_builds.cpp
Normal file
440
modules/mono/editor/godotsharp_builds.cpp
Normal file
@ -0,0 +1,440 @@
|
||||
/*************************************************************************/
|
||||
/* godotsharp_builds.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "godotsharp_builds.h"
|
||||
|
||||
#include "../godotsharp_dirs.h"
|
||||
#include "../mono_gd/gd_mono_class.h"
|
||||
#include "../mono_gd/gd_mono_marshal.h"
|
||||
#include "../utils/path_utils.h"
|
||||
#include "bindings_generator.h"
|
||||
#include "godotsharp_editor.h"
|
||||
#include "main/main.h"
|
||||
|
||||
void godot_icall_BuildInstance_ExitCallback(MonoString *p_solution, MonoString *p_config, int p_exit_code) {
|
||||
|
||||
String solution = GDMonoMarshal::mono_string_to_godot(p_solution);
|
||||
String config = GDMonoMarshal::mono_string_to_godot(p_config);
|
||||
GodotSharpBuilds::get_singleton()->build_exit_callback(MonoBuildInfo(solution, config), p_exit_code);
|
||||
}
|
||||
|
||||
MonoString *godot_icall_BuildInstance_get_MSBuildPath() {
|
||||
|
||||
GodotSharpBuilds::BuildTool build_tool = GodotSharpBuilds::BuildTool(int(EditorSettings::get_singleton()->get("mono/builds/build_tool")));
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
switch (build_tool) {
|
||||
case GodotSharpBuilds::MSBUILD: {
|
||||
static String 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");
|
||||
}
|
||||
|
||||
OS::get_singleton()->print("Cannot find System's MSBuild. Trying with Mono's...\n");
|
||||
}
|
||||
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 msbuild ('mono/builds/build_tool'). Tried with path: " + msbuild_path);
|
||||
}
|
||||
|
||||
return GDMonoMarshal::mono_string_from_godot(msbuild_path);
|
||||
}
|
||||
case GodotSharpBuilds::XBUILD: {
|
||||
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 xbuild ('mono/builds/build_tool'). Tried with path: " + xbuild_path);
|
||||
}
|
||||
|
||||
return GDMonoMarshal::mono_string_from_godot(xbuild_path);
|
||||
}
|
||||
default:
|
||||
ERR_EXPLAIN("You don't deserve to live");
|
||||
CRASH_NOW();
|
||||
}
|
||||
#else
|
||||
static bool msbuild_found = path_which("msbuild").length();
|
||||
|
||||
if (build_tool != GodotSharpBuilds::XBUILD && !msbuild_found) {
|
||||
WARN_PRINT("Cannot find msbuild ('mono/builds/build_tool').");
|
||||
}
|
||||
|
||||
return GDMonoMarshal::mono_string_from_godot(build_tool != GodotSharpBuilds::XBUILD ? "msbuild" : "xbuild");
|
||||
#endif
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void GodotSharpBuilds::show_build_error_dialog(const String &p_message) {
|
||||
|
||||
GodotSharpEditor::get_singleton()->show_error_dialog(p_message, "Build error");
|
||||
MonoBottomPanel::get_singleton()->show_build_tab();
|
||||
}
|
||||
|
||||
bool GodotSharpBuilds::build_api_sln(const String &p_name, const String &p_api_sln_dir, const String &p_config) {
|
||||
|
||||
String api_sln_file = p_api_sln_dir.plus_file(p_name + ".sln");
|
||||
String api_assembly_dir = p_api_sln_dir.plus_file("bin").plus_file(p_config);
|
||||
String api_assembly_file = api_assembly_dir.plus_file(p_name + ".dll");
|
||||
|
||||
if (!FileAccess::exists(api_assembly_file)) {
|
||||
MonoBuildInfo api_build_info(api_sln_file, p_config);
|
||||
api_build_info.custom_props.push_back("NoWarn=1591"); // Ignore missing documentation warnings
|
||||
|
||||
if (!GodotSharpBuilds::get_singleton()->build(api_build_info)) {
|
||||
show_build_error_dialog("Failed to build " + p_name + " solution.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GodotSharpBuilds::copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name) {
|
||||
|
||||
String assembly_file = p_assembly_name + ".dll";
|
||||
String assembly_src = p_src_dir.plus_file(assembly_file);
|
||||
String assembly_dst = p_dst_dir.plus_file(assembly_file);
|
||||
|
||||
if (!FileAccess::exists(assembly_dst) || FileAccess::get_modified_time(assembly_src) > FileAccess::get_modified_time(assembly_dst)) {
|
||||
DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
|
||||
String xml_file = p_assembly_name + ".xml";
|
||||
if (da->copy(p_src_dir.plus_file(xml_file), p_dst_dir.plus_file(xml_file)) != OK)
|
||||
WARN_PRINTS("Failed to copy " + xml_file);
|
||||
|
||||
String pdb_file = p_assembly_name + ".pdb";
|
||||
if (da->copy(p_src_dir.plus_file(pdb_file), p_dst_dir.plus_file(pdb_file)) != OK)
|
||||
WARN_PRINTS("Failed to copy " + pdb_file);
|
||||
|
||||
Error err = da->copy(assembly_src, assembly_dst);
|
||||
|
||||
memdelete(da);
|
||||
|
||||
if (err != OK) {
|
||||
show_build_error_dialog("Failed to copy " API_ASSEMBLY_NAME ".dll");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GodotSharpBuilds::make_api_sln(GodotSharpBuilds::APIType p_api_type) {
|
||||
|
||||
String api_name = p_api_type == API_CORE ? API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME;
|
||||
String api_build_config = "Release";
|
||||
|
||||
EditorProgress pr("mono_build_release_" + api_name, "Building " + api_name + " solution...", 4);
|
||||
|
||||
pr.step("Generating " + api_name + " solution");
|
||||
|
||||
uint64_t core_hash = GDMono::get_singleton()->get_api_core_hash();
|
||||
uint64_t editor_hash = GDMono::get_singleton()->get_api_editor_hash();
|
||||
|
||||
String core_api_sln_dir = GodotSharpDirs::get_mono_solutions_dir().plus_file(API_ASSEMBLY_NAME "_" + itos(core_hash));
|
||||
String editor_api_sln_dir = GodotSharpDirs::get_mono_solutions_dir().plus_file(EDITOR_API_ASSEMBLY_NAME "_" + itos(editor_hash));
|
||||
|
||||
String api_sln_dir = p_api_type == API_CORE ? core_api_sln_dir : editor_api_sln_dir;
|
||||
String api_sln_file = api_sln_dir.plus_file(api_name + ".sln");
|
||||
|
||||
if (!DirAccess::exists(api_sln_dir) || !FileAccess::exists(api_sln_file)) {
|
||||
String core_api_assembly;
|
||||
|
||||
if (p_api_type == API_EDITOR) {
|
||||
core_api_assembly = core_api_sln_dir.plus_file("bin")
|
||||
.plus_file(api_build_config)
|
||||
.plus_file(API_ASSEMBLY_NAME ".dll");
|
||||
}
|
||||
|
||||
#ifndef DEBUG_METHODS_ENABLED
|
||||
#error "How am I supposed to generate the bindings?"
|
||||
#endif
|
||||
|
||||
BindingsGenerator &gen = BindingsGenerator::get_singleton();
|
||||
bool gen_verbose = OS::get_singleton()->is_stdout_verbose();
|
||||
|
||||
Error err = p_api_type == API_CORE ?
|
||||
gen.generate_cs_core_project(api_sln_dir, gen_verbose) :
|
||||
gen.generate_cs_editor_project(api_sln_dir, core_api_assembly, gen_verbose);
|
||||
|
||||
if (err != OK) {
|
||||
show_build_error_dialog("Failed to generate " + api_name + " solution. Error: " + itos(err));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
pr.step("Building " + api_name + " solution");
|
||||
|
||||
if (!GodotSharpBuilds::build_api_sln(api_name, api_sln_dir, api_build_config))
|
||||
return false;
|
||||
|
||||
pr.step("Copying " + api_name + " assembly");
|
||||
|
||||
String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
|
||||
|
||||
// Create assemblies directory if needed
|
||||
if (!DirAccess::exists(res_assemblies_dir)) {
|
||||
DirAccess *da = DirAccess::create_for_path(res_assemblies_dir);
|
||||
Error err = da->make_dir_recursive(res_assemblies_dir);
|
||||
memdelete(da);
|
||||
|
||||
if (err != OK) {
|
||||
show_build_error_dialog("Failed to create assemblies directory. Error: " + itos(err));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the built assembly to the assemblies directory
|
||||
String api_assembly_dir = api_sln_dir.plus_file("bin").plus_file(api_build_config);
|
||||
if (!GodotSharpBuilds::copy_api_assembly(api_assembly_dir, res_assemblies_dir, api_name))
|
||||
return false;
|
||||
|
||||
pr.step("Done");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool godotsharp_build_callback() {
|
||||
|
||||
if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path()))
|
||||
return true; // No solution to build
|
||||
|
||||
if (!GodotSharpBuilds::make_api_sln(GodotSharpBuilds::API_CORE))
|
||||
return false;
|
||||
|
||||
if (!GodotSharpBuilds::make_api_sln(GodotSharpBuilds::API_EDITOR))
|
||||
return false;
|
||||
|
||||
EditorProgress pr("mono_project_debug_build", "Building project solution...", 2);
|
||||
|
||||
pr.step("Building project solution");
|
||||
|
||||
MonoBuildInfo build_info(GodotSharpDirs::get_project_sln_path(), "Tools");
|
||||
if (!GodotSharpBuilds::get_singleton()->build(build_info)) {
|
||||
GodotSharpBuilds::show_build_error_dialog("Failed to build project solution");
|
||||
return false;
|
||||
}
|
||||
|
||||
pr.step("Done");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GodotSharpBuilds *GodotSharpBuilds::singleton = NULL;
|
||||
|
||||
void GodotSharpBuilds::build_exit_callback(const MonoBuildInfo &p_build_info, int p_exit_code) {
|
||||
|
||||
BuildProcess *match = builds.getptr(p_build_info);
|
||||
ERR_FAIL_COND(!match);
|
||||
|
||||
BuildProcess &bp = *match;
|
||||
bp.on_exit(p_exit_code);
|
||||
}
|
||||
|
||||
void GodotSharpBuilds::restart_build(MonoBuildTab *p_build_tab) {
|
||||
}
|
||||
|
||||
void GodotSharpBuilds::stop_build(MonoBuildTab *p_build_tab) {
|
||||
}
|
||||
|
||||
bool GodotSharpBuilds::build(const MonoBuildInfo &p_build_info) {
|
||||
|
||||
BuildProcess *match = builds.getptr(p_build_info);
|
||||
|
||||
if (match) {
|
||||
BuildProcess &bp = *match;
|
||||
bp.start(true);
|
||||
return bp.exit_code == 0;
|
||||
} else {
|
||||
BuildProcess bp = BuildProcess(p_build_info);
|
||||
bp.start(true);
|
||||
builds.set(p_build_info, bp);
|
||||
return bp.exit_code == 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool GodotSharpBuilds::build_async(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback) {
|
||||
|
||||
BuildProcess *match = builds.getptr(p_build_info);
|
||||
|
||||
if (match) {
|
||||
BuildProcess &bp = *match;
|
||||
bp.start();
|
||||
return !bp.exited; // failed to start
|
||||
} else {
|
||||
BuildProcess bp = BuildProcess(p_build_info, p_callback);
|
||||
bp.start();
|
||||
builds.set(p_build_info, bp);
|
||||
return !bp.exited; // failed to start
|
||||
}
|
||||
}
|
||||
|
||||
GodotSharpBuilds::GodotSharpBuilds() {
|
||||
|
||||
singleton = this;
|
||||
|
||||
EditorNode::get_singleton()->add_build_callback(&godotsharp_build_callback);
|
||||
|
||||
// Build tool settings
|
||||
EditorSettings *ed_settings = EditorSettings::get_singleton();
|
||||
if (!ed_settings->has("mono/builds/build_tool")) {
|
||||
ed_settings->set("mono/builds/build_tool", MSBUILD);
|
||||
}
|
||||
ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/builds/build_tool", PROPERTY_HINT_ENUM, "MSBuild (System),MSBuild (Mono),xbuild"));
|
||||
}
|
||||
|
||||
GodotSharpBuilds::~GodotSharpBuilds() {
|
||||
|
||||
singleton = NULL;
|
||||
}
|
||||
|
||||
void GodotSharpBuilds::BuildProcess::on_exit(int p_exit_code) {
|
||||
|
||||
exited = true;
|
||||
exit_code = p_exit_code;
|
||||
build_tab->on_build_exit(p_exit_code == 0 ? MonoBuildTab::RESULT_SUCCESS : MonoBuildTab::RESULT_ERROR);
|
||||
build_instance.unref();
|
||||
|
||||
if (exit_callback)
|
||||
exit_callback(exit_code);
|
||||
}
|
||||
|
||||
void GodotSharpBuilds::BuildProcess::start(bool p_blocking) {
|
||||
|
||||
_GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
|
||||
|
||||
exit_code = -1;
|
||||
|
||||
String logs_dir = GodotSharpDirs::get_build_logs_dir().plus_file(build_info.solution.md5_text() + "_" + build_info.configuration);
|
||||
|
||||
if (build_tab) {
|
||||
build_tab->on_build_start();
|
||||
} else {
|
||||
build_tab = memnew(MonoBuildTab(build_info, logs_dir));
|
||||
MonoBottomPanel::get_singleton()->add_build_tab(build_tab);
|
||||
}
|
||||
|
||||
if (p_blocking) {
|
||||
// Required in order to update the build tasks list
|
||||
Main::iteration();
|
||||
}
|
||||
|
||||
if (!exited) {
|
||||
ERR_PRINT("BuildProcess::start called, but process still running");
|
||||
exited = true;
|
||||
build_tab->on_build_exec_failed("!exited");
|
||||
return;
|
||||
}
|
||||
|
||||
exited = false;
|
||||
|
||||
// Remove old issues file
|
||||
|
||||
String issues_file = "msbuild_issues.csv";
|
||||
DirAccessRef d = DirAccess::create_for_path(logs_dir);
|
||||
if (d->file_exists(issues_file)) {
|
||||
Error err = d->remove(issues_file);
|
||||
if (err != OK) {
|
||||
ERR_PRINTS("Cannot remove file: " + logs_dir.plus_file(issues_file));
|
||||
exited = true;
|
||||
build_tab->on_build_exec_failed("Cannot remove file: " + issues_file);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Build", "BuildInstance");
|
||||
|
||||
MonoObject *mono_object = mono_object_new(mono_domain_get(), klass->get_raw());
|
||||
|
||||
// Construct
|
||||
|
||||
Variant solution = build_info.solution;
|
||||
Variant config = build_info.configuration;
|
||||
|
||||
const Variant *ctor_args[2] = { &solution, &config };
|
||||
|
||||
MonoObject *ex = NULL;
|
||||
GDMonoMethod *ctor = klass->get_method(".ctor", 2);
|
||||
ctor->invoke(mono_object, ctor_args, &ex);
|
||||
|
||||
if (ex) {
|
||||
exited = true;
|
||||
build_tab->on_build_exec_failed("The build constructor threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(ex));
|
||||
ERR_FAIL();
|
||||
}
|
||||
|
||||
// Call Build
|
||||
|
||||
Variant logger_assembly = OS::get_singleton()->get_executable_path().get_base_dir().plus_file(EDITOR_TOOLS_ASSEMBLY_NAME) + ".dll";
|
||||
Variant logger_output_dir = logs_dir;
|
||||
Variant custom_props = build_info.custom_props;
|
||||
|
||||
const Variant *args[3] = { &logger_assembly, &logger_output_dir, &custom_props };
|
||||
|
||||
ex = NULL;
|
||||
GDMonoMethod *build_method = klass->get_method(p_blocking ? "Build" : "BuildAsync", 3);
|
||||
build_method->invoke(mono_object, args, &ex);
|
||||
|
||||
if (ex) {
|
||||
exited = true;
|
||||
build_tab->on_build_exec_failed("The build method threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(ex));
|
||||
ERR_FAIL();
|
||||
}
|
||||
|
||||
// Build returned
|
||||
|
||||
if (p_blocking) {
|
||||
exited = true;
|
||||
exit_code = klass->get_field("exitCode")->get_int_value(mono_object);
|
||||
build_tab->on_build_exit(exit_code == 0 ? MonoBuildTab::RESULT_SUCCESS : MonoBuildTab::RESULT_ERROR);
|
||||
} else {
|
||||
build_instance = MonoGCHandle::create_strong(mono_object);
|
||||
exited = false;
|
||||
}
|
||||
}
|
||||
|
||||
GodotSharpBuilds::BuildProcess::BuildProcess(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback) {
|
||||
|
||||
build_info = p_build_info;
|
||||
build_tab = NULL;
|
||||
exit_callback = p_callback;
|
||||
exited = true;
|
||||
exit_code = -1;
|
||||
}
|
96
modules/mono/editor/godotsharp_builds.h
Normal file
96
modules/mono/editor/godotsharp_builds.h
Normal file
@ -0,0 +1,96 @@
|
||||
/*************************************************************************/
|
||||
/* godotsharp_builds.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 GODOTSHARP_BUILDS_H
|
||||
#define GODOTSHARP_BUILDS_H
|
||||
|
||||
#include "mono_bottom_panel.h"
|
||||
#include "mono_build_info.h"
|
||||
|
||||
typedef void (*GodotSharpBuild_ExitCallback)(int);
|
||||
|
||||
class GodotSharpBuilds {
|
||||
|
||||
private:
|
||||
struct BuildProcess {
|
||||
Ref<MonoGCHandle> build_instance;
|
||||
MonoBuildInfo build_info;
|
||||
MonoBuildTab *build_tab;
|
||||
GodotSharpBuild_ExitCallback exit_callback;
|
||||
bool exited;
|
||||
int exit_code;
|
||||
|
||||
void on_exit(int p_exit_code);
|
||||
void start(bool p_blocking = false);
|
||||
|
||||
BuildProcess() {}
|
||||
BuildProcess(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback = NULL);
|
||||
};
|
||||
|
||||
HashMap<MonoBuildInfo, BuildProcess, MonoBuildInfo::Hasher> builds;
|
||||
|
||||
static GodotSharpBuilds *singleton;
|
||||
|
||||
friend class GDMono;
|
||||
static void _register_internal_calls();
|
||||
|
||||
public:
|
||||
enum APIType {
|
||||
API_CORE,
|
||||
API_EDITOR
|
||||
};
|
||||
|
||||
enum BuildTool {
|
||||
MSBUILD,
|
||||
MSBUILD_MONO,
|
||||
XBUILD
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ static GodotSharpBuilds *get_singleton() { return singleton; }
|
||||
|
||||
static void show_build_error_dialog(const String &p_message);
|
||||
|
||||
void build_exit_callback(const MonoBuildInfo &p_build_info, int p_exit_code);
|
||||
|
||||
void restart_build(MonoBuildTab *p_build_tab);
|
||||
void stop_build(MonoBuildTab *p_build_tab);
|
||||
|
||||
bool build(const MonoBuildInfo &p_build_info);
|
||||
bool build_async(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback = NULL);
|
||||
|
||||
static bool build_api_sln(const String &p_name, const String &p_api_sln_dir, const String &p_config);
|
||||
static bool copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name);
|
||||
|
||||
static bool make_api_sln(APIType p_api_type);
|
||||
|
||||
GodotSharpBuilds();
|
||||
~GodotSharpBuilds();
|
||||
};
|
||||
|
||||
#endif // GODOTSHARP_BUILDS_H
|
256
modules/mono/editor/godotsharp_editor.cpp
Normal file
256
modules/mono/editor/godotsharp_editor.cpp
Normal file
@ -0,0 +1,256 @@
|
||||
/*************************************************************************/
|
||||
/* godotsharp_editor.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "godotsharp_editor.h"
|
||||
|
||||
#include "core/os/os.h"
|
||||
#include "core/project_settings.h"
|
||||
#include "scene/gui/control.h"
|
||||
#include "scene/main/node.h"
|
||||
|
||||
#include "../csharp_script.h"
|
||||
#include "../godotsharp_dirs.h"
|
||||
#include "../mono_gd/gd_mono.h"
|
||||
#include "../utils/path_utils.h"
|
||||
#include "bindings_generator.h"
|
||||
#include "csharp_project.h"
|
||||
#include "net_solution.h"
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
#include "../utils/mono_reg_utils.h"
|
||||
#endif
|
||||
|
||||
class MonoReloadNode : public Node {
|
||||
GDCLASS(MonoReloadNode, Node)
|
||||
|
||||
protected:
|
||||
void _notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
|
||||
CSharpLanguage::get_singleton()->reload_assemblies_if_needed(true);
|
||||
} break;
|
||||
default: {
|
||||
} break;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
GodotSharpEditor *GodotSharpEditor::singleton = NULL;
|
||||
|
||||
bool GodotSharpEditor::_create_project_solution() {
|
||||
|
||||
EditorProgress pr("create_csharp_solution", "Generating solution...", 2);
|
||||
|
||||
pr.step("Generating C# project...");
|
||||
|
||||
String path = OS::get_singleton()->get_resource_dir();
|
||||
String name = ProjectSettings::get_singleton()->get("application/config/name");
|
||||
String guid = CSharpProject::generate_game_project(path, name);
|
||||
|
||||
if (guid.length()) {
|
||||
|
||||
NETSolution solution(name);
|
||||
|
||||
if (!solution.set_path(path)) {
|
||||
show_error_dialog("Failed to create solution.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector<String> extra_configs;
|
||||
extra_configs.push_back("Tools");
|
||||
|
||||
solution.add_new_project(name, guid, extra_configs);
|
||||
|
||||
Error sln_error = solution.save();
|
||||
|
||||
if (sln_error != OK) {
|
||||
show_error_dialog("Failed to save solution.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GodotSharpBuilds::make_api_sln(GodotSharpBuilds::API_CORE))
|
||||
return false;
|
||||
|
||||
if (!GodotSharpBuilds::make_api_sln(GodotSharpBuilds::API_EDITOR))
|
||||
return false;
|
||||
|
||||
pr.step("Done");
|
||||
|
||||
// Here, after all calls to progress_task_step
|
||||
call_deferred("_remove_create_sln_menu_option");
|
||||
|
||||
} else {
|
||||
show_error_dialog("Failed to create C# project.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void GodotSharpEditor::_menu_option_pressed(int p_id) {
|
||||
|
||||
switch (p_id) {
|
||||
case MENU_CREATE_SLN: {
|
||||
|
||||
_create_project_solution();
|
||||
} break;
|
||||
default:
|
||||
ERR_FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
void GodotSharpEditor::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_create_project_solution"), &GodotSharpEditor::_create_project_solution);
|
||||
ClassDB::bind_method(D_METHOD("_remove_create_sln_menu_option"), &GodotSharpEditor::_remove_create_sln_menu_option);
|
||||
ClassDB::bind_method(D_METHOD("_menu_option_pressed", "id"), &GodotSharpEditor::_menu_option_pressed);
|
||||
}
|
||||
|
||||
void GodotSharpEditor::show_error_dialog(const String &p_message, const String &p_title) {
|
||||
|
||||
error_dialog->set_title(p_title);
|
||||
error_dialog->set_text(p_message);
|
||||
error_dialog->popup_centered_minsize();
|
||||
}
|
||||
|
||||
Error GodotSharpEditor::open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) {
|
||||
|
||||
ExternalEditor editor = ExternalEditor(int(EditorSettings::get_singleton()->get("mono/editor/external_editor")));
|
||||
|
||||
switch (editor) {
|
||||
case EDITOR_CODE: {
|
||||
List<String> args;
|
||||
args.push_back(ProjectSettings::get_singleton()->get_resource_path());
|
||||
|
||||
String script_path = ProjectSettings::get_singleton()->globalize_path(p_script->get_path());
|
||||
|
||||
if (p_line >= 0) {
|
||||
args.push_back("-g");
|
||||
args.push_back(script_path + ":" + itos(p_line) + ":" + itos(p_col));
|
||||
} else {
|
||||
args.push_back(script_path);
|
||||
}
|
||||
|
||||
static String program = path_which("code");
|
||||
|
||||
Error err = OS::get_singleton()->execute(program.length() ? program : "code", args, false);
|
||||
|
||||
if (err != OK) {
|
||||
ERR_PRINT("GodotSharp: Could not execute external editor");
|
||||
return err;
|
||||
}
|
||||
} break;
|
||||
case EDITOR_MONODEVELOP: {
|
||||
if (!monodevel_instance)
|
||||
monodevel_instance = memnew(MonoDevelopInstance(GodotSharpDirs::get_project_sln_path()));
|
||||
|
||||
String script_path = ProjectSettings::get_singleton()->globalize_path(p_script->get_path());
|
||||
monodevel_instance->execute(script_path);
|
||||
} break;
|
||||
case EDITOR_VISUAL_STUDIO:
|
||||
// TODO
|
||||
// devenv <PathToSolutionFolder>
|
||||
// devenv /edit <PathToCsFile> /command "edit.goto <Line>"
|
||||
// HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\SxS\VS7
|
||||
default:
|
||||
return ERR_UNAVAILABLE;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool GodotSharpEditor::overrides_external_editor() {
|
||||
|
||||
return ExternalEditor(int(EditorSettings::get_singleton()->get("mono/editor/external_editor"))) != EDITOR_NONE;
|
||||
}
|
||||
|
||||
GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) {
|
||||
|
||||
singleton = this;
|
||||
|
||||
monodevel_instance = NULL;
|
||||
|
||||
editor = p_editor;
|
||||
|
||||
error_dialog = memnew(AcceptDialog);
|
||||
editor->get_gui_base()->add_child(error_dialog);
|
||||
|
||||
bottom_panel_btn = editor->add_bottom_panel_item("Mono", memnew(MonoBottomPanel(editor)));
|
||||
|
||||
godotsharp_builds = memnew(GodotSharpBuilds);
|
||||
|
||||
editor->add_child(memnew(MonoReloadNode));
|
||||
|
||||
menu_button = memnew(MenuButton);
|
||||
menu_button->set_text("Mono");
|
||||
menu_popup = menu_button->get_popup();
|
||||
|
||||
String sln_path = GodotSharpDirs::get_project_sln_path();
|
||||
String csproj_path = GodotSharpDirs::get_project_csproj_path();
|
||||
|
||||
if (!FileAccess::exists(sln_path) || !FileAccess::exists(csproj_path)) {
|
||||
bottom_panel_btn->hide();
|
||||
menu_popup->add_item("Create C# solution", MENU_CREATE_SLN);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// External editor settings
|
||||
EditorSettings *ed_settings = EditorSettings::get_singleton();
|
||||
if (!ed_settings->has("mono/editor/external_editor")) {
|
||||
ed_settings->set("mono/editor/external_editor", EDITOR_NONE);
|
||||
}
|
||||
ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/editor/external_editor", PROPERTY_HINT_ENUM, "None,MonoDevelop,Visual Studio,Visual Studio Code"));
|
||||
}
|
||||
|
||||
GodotSharpEditor::~GodotSharpEditor() {
|
||||
|
||||
singleton = NULL;
|
||||
|
||||
memdelete(godotsharp_builds);
|
||||
|
||||
if (monodevel_instance) {
|
||||
memdelete(monodevel_instance);
|
||||
monodevel_instance = NULL;
|
||||
}
|
||||
}
|
87
modules/mono/editor/godotsharp_editor.h
Normal file
87
modules/mono/editor/godotsharp_editor.h
Normal file
@ -0,0 +1,87 @@
|
||||
/*************************************************************************/
|
||||
/* godotsharp_editor.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 GODOTSHARP_EDITOR_H
|
||||
#define GODOTSHARP_EDITOR_H
|
||||
|
||||
#include "godotsharp_builds.h"
|
||||
|
||||
#include "monodevelop_instance.h"
|
||||
|
||||
class GodotSharpEditor : public Node {
|
||||
GDCLASS(GodotSharpEditor, Object)
|
||||
|
||||
EditorNode *editor;
|
||||
|
||||
MenuButton *menu_button;
|
||||
PopupMenu *menu_popup;
|
||||
|
||||
AcceptDialog *error_dialog;
|
||||
|
||||
ToolButton *bottom_panel_btn;
|
||||
|
||||
GodotSharpBuilds *godotsharp_builds;
|
||||
|
||||
MonoDevelopInstance *monodevel_instance;
|
||||
|
||||
bool _create_project_solution();
|
||||
|
||||
void _remove_create_sln_menu_option();
|
||||
|
||||
void _menu_option_pressed(int p_id);
|
||||
|
||||
static GodotSharpEditor *singleton;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
enum MenuOptions {
|
||||
MENU_CREATE_SLN
|
||||
};
|
||||
|
||||
enum ExternalEditor {
|
||||
EDITOR_NONE,
|
||||
EDITOR_MONODEVELOP,
|
||||
EDITOR_VISUAL_STUDIO,
|
||||
EDITOR_CODE,
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ static GodotSharpEditor *get_singleton() { return singleton; }
|
||||
|
||||
void show_error_dialog(const String &p_message, const String &p_title = "Error");
|
||||
|
||||
Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col);
|
||||
bool overrides_external_editor();
|
||||
|
||||
GodotSharpEditor(EditorNode *p_editor);
|
||||
~GodotSharpEditor();
|
||||
};
|
||||
|
||||
#endif // GODOTSHARP_EDITOR_H
|
441
modules/mono/editor/mono_bottom_panel.cpp
Normal file
441
modules/mono/editor/mono_bottom_panel.cpp
Normal file
@ -0,0 +1,441 @@
|
||||
/*************************************************************************/
|
||||
/* mono_bottom_panel.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "mono_bottom_panel.h"
|
||||
|
||||
#include "../csharp_script.h"
|
||||
#include "godotsharp_editor.h"
|
||||
|
||||
MonoBottomPanel *MonoBottomPanel::singleton = NULL;
|
||||
|
||||
void MonoBottomPanel::_update_build_tabs_list() {
|
||||
|
||||
build_tabs_list->clear();
|
||||
|
||||
int current_tab = build_tabs->get_current_tab();
|
||||
|
||||
bool no_current_tab = current_tab < 0 || current_tab >= build_tabs->get_tab_count();
|
||||
|
||||
for (int i = 0; i < build_tabs->get_child_count(); i++) {
|
||||
|
||||
MonoBuildTab *tab = Object::cast_to<MonoBuildTab>(build_tabs->get_child(i));
|
||||
|
||||
if (tab) {
|
||||
String item_name = tab->build_info.solution.get_file().get_basename();
|
||||
item_name += " [" + tab->build_info.configuration + "]";
|
||||
|
||||
build_tabs_list->add_item(item_name, tab->get_icon_texture());
|
||||
|
||||
String item_tooltip = String("Solution: ") + tab->build_info.solution;
|
||||
item_tooltip += String("\nConfiguration: ") + tab->build_info.configuration;
|
||||
item_tooltip += String("\nStatus: ");
|
||||
|
||||
if (tab->build_exited) {
|
||||
item_tooltip += tab->build_result == MonoBuildTab::RESULT_SUCCESS ? "Succeeded" : "Errored";
|
||||
} else {
|
||||
item_tooltip += "Running";
|
||||
}
|
||||
|
||||
if (!tab->build_exited || !tab->build_result == MonoBuildTab::RESULT_SUCCESS) {
|
||||
item_tooltip += "\nErrors: " + itos(tab->error_count);
|
||||
}
|
||||
|
||||
item_tooltip += "\nWarnings: " + itos(tab->warning_count);
|
||||
|
||||
build_tabs_list->set_item_tooltip(i, item_tooltip);
|
||||
|
||||
if (no_current_tab || current_tab == i) {
|
||||
build_tabs_list->select(i);
|
||||
_build_tab_item_selected(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MonoBottomPanel::add_build_tab(MonoBuildTab *p_build_tab) {
|
||||
|
||||
build_tabs->add_child(p_build_tab);
|
||||
raise_build_tab(p_build_tab);
|
||||
}
|
||||
|
||||
void MonoBottomPanel::raise_build_tab(MonoBuildTab *p_build_tab) {
|
||||
|
||||
ERR_FAIL_COND(p_build_tab->get_parent() != build_tabs);
|
||||
build_tabs->move_child(p_build_tab, 0);
|
||||
_update_build_tabs_list();
|
||||
}
|
||||
|
||||
void MonoBottomPanel::show_build_tab() {
|
||||
|
||||
for (int i = 0; i < panel_tabs->get_tab_count(); i++) {
|
||||
if (panel_tabs->get_tab_control(i) == panel_builds_tab) {
|
||||
panel_tabs->set_current_tab(i);
|
||||
editor->make_bottom_panel_item_visible(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ERR_PRINT("Builds tab not found");
|
||||
}
|
||||
|
||||
void MonoBottomPanel::_build_tab_item_selected(int p_idx) {
|
||||
|
||||
ERR_FAIL_INDEX(p_idx, build_tabs->get_tab_count());
|
||||
build_tabs->set_current_tab(p_idx);
|
||||
}
|
||||
|
||||
void MonoBottomPanel::_build_tab_changed(int p_idx) {
|
||||
|
||||
if (p_idx < 0 || p_idx >= build_tabs->get_tab_count()) {
|
||||
warnings_btn->set_visible(false);
|
||||
errors_btn->set_visible(false);
|
||||
} else {
|
||||
warnings_btn->set_visible(true);
|
||||
errors_btn->set_visible(true);
|
||||
}
|
||||
}
|
||||
|
||||
void MonoBottomPanel::_warnings_toggled(bool p_pressed) {
|
||||
|
||||
int current_tab = build_tabs->get_current_tab();
|
||||
ERR_FAIL_INDEX(current_tab, build_tabs->get_tab_count());
|
||||
MonoBuildTab *build_tab = Object::cast_to<MonoBuildTab>(build_tabs->get_child(current_tab));
|
||||
build_tab->warnings_visible = p_pressed;
|
||||
build_tab->_update_issues_list();
|
||||
}
|
||||
|
||||
void MonoBottomPanel::_errors_toggled(bool p_pressed) {
|
||||
|
||||
int current_tab = build_tabs->get_current_tab();
|
||||
ERR_FAIL_INDEX(current_tab, build_tabs->get_tab_count());
|
||||
MonoBuildTab *build_tab = Object::cast_to<MonoBuildTab>(build_tabs->get_child(current_tab));
|
||||
build_tab->errors_visible = p_pressed;
|
||||
build_tab->_update_issues_list();
|
||||
}
|
||||
|
||||
void MonoBottomPanel::_notification(int p_what) {
|
||||
|
||||
switch (p_what) {
|
||||
|
||||
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
|
||||
panel_tabs->add_style_override("panel", editor->get_gui_base()->get_stylebox("DebuggerPanel", "EditorStyles"));
|
||||
panel_tabs->add_style_override("tab_fg", editor->get_gui_base()->get_stylebox("DebuggerTabFG", "EditorStyles"));
|
||||
panel_tabs->add_style_override("tab_bg", editor->get_gui_base()->get_stylebox("DebuggerTabBG", "EditorStyles"));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void MonoBottomPanel::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_warnings_toggled", "pressed"), &MonoBottomPanel::_warnings_toggled);
|
||||
ClassDB::bind_method(D_METHOD("_errors_toggled", "pressed"), &MonoBottomPanel::_errors_toggled);
|
||||
ClassDB::bind_method(D_METHOD("_build_tab_item_selected", "idx"), &MonoBottomPanel::_build_tab_item_selected);
|
||||
ClassDB::bind_method(D_METHOD("_build_tab_changed", "idx"), &MonoBottomPanel::_build_tab_changed);
|
||||
}
|
||||
|
||||
MonoBottomPanel::MonoBottomPanel(EditorNode *p_editor) {
|
||||
|
||||
singleton = this;
|
||||
|
||||
editor = p_editor;
|
||||
|
||||
set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
set_anchors_and_margins_preset(Control::PRESET_WIDE);
|
||||
|
||||
panel_tabs = memnew(TabContainer);
|
||||
panel_tabs->set_tab_align(TabContainer::ALIGN_LEFT);
|
||||
panel_tabs->add_style_override("panel", editor->get_gui_base()->get_stylebox("DebuggerPanel", "EditorStyles"));
|
||||
panel_tabs->add_style_override("tab_fg", editor->get_gui_base()->get_stylebox("DebuggerTabFG", "EditorStyles"));
|
||||
panel_tabs->add_style_override("tab_bg", editor->get_gui_base()->get_stylebox("DebuggerTabBG", "EditorStyles"));
|
||||
panel_tabs->set_custom_minimum_size(Size2(0, 228) * EDSCALE);
|
||||
panel_tabs->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
add_child(panel_tabs);
|
||||
|
||||
{ // Builds
|
||||
panel_builds_tab = memnew(VBoxContainer);
|
||||
panel_builds_tab->set_name(TTR("Builds"));
|
||||
panel_builds_tab->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
panel_tabs->add_child(panel_builds_tab);
|
||||
|
||||
HBoxContainer *toolbar_hbc = memnew(HBoxContainer);
|
||||
toolbar_hbc->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
panel_builds_tab->add_child(toolbar_hbc);
|
||||
|
||||
toolbar_hbc->add_spacer();
|
||||
|
||||
warnings_btn = memnew(ToolButton);
|
||||
warnings_btn->set_text("Warnings");
|
||||
warnings_btn->set_toggle_mode(true);
|
||||
warnings_btn->set_pressed(true);
|
||||
warnings_btn->set_visible(false);
|
||||
warnings_btn->set_focus_mode(FOCUS_NONE);
|
||||
warnings_btn->connect("toggled", this, "_warnings_toggled");
|
||||
toolbar_hbc->add_child(warnings_btn);
|
||||
|
||||
errors_btn = memnew(ToolButton);
|
||||
errors_btn->set_text("Errors");
|
||||
errors_btn->set_toggle_mode(true);
|
||||
errors_btn->set_pressed(true);
|
||||
errors_btn->set_visible(false);
|
||||
errors_btn->set_focus_mode(FOCUS_NONE);
|
||||
errors_btn->connect("toggled", this, "_errors_toggled");
|
||||
toolbar_hbc->add_child(errors_btn);
|
||||
|
||||
HSplitContainer *hsc = memnew(HSplitContainer);
|
||||
hsc->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
hsc->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
panel_builds_tab->add_child(hsc);
|
||||
|
||||
build_tabs_list = memnew(ItemList);
|
||||
build_tabs_list->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
build_tabs_list->connect("item_selected", this, "_build_tab_item_selected");
|
||||
hsc->add_child(build_tabs_list);
|
||||
|
||||
build_tabs = memnew(TabContainer);
|
||||
build_tabs->set_tab_align(TabContainer::ALIGN_LEFT);
|
||||
build_tabs->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
build_tabs->set_tabs_visible(false);
|
||||
build_tabs->connect("tab_changed", this, "_build_tab_changed");
|
||||
hsc->add_child(build_tabs);
|
||||
}
|
||||
}
|
||||
|
||||
MonoBottomPanel::~MonoBottomPanel() {
|
||||
|
||||
singleton = NULL;
|
||||
}
|
||||
|
||||
void MonoBuildTab::_load_issues_from_file(const String &p_csv_file) {
|
||||
|
||||
FileAccessRef f = FileAccess::open(p_csv_file, FileAccess::READ);
|
||||
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
while (!f->eof_reached()) {
|
||||
Vector<String> csv_line = f->get_csv_line();
|
||||
|
||||
if (csv_line.size() == 1 && csv_line[0].empty())
|
||||
return;
|
||||
|
||||
ERR_CONTINUE(csv_line.size() != 7);
|
||||
|
||||
BuildIssue issue;
|
||||
issue.warning = csv_line[0] == "warning";
|
||||
issue.file = csv_line[1];
|
||||
issue.line = csv_line[2].to_int();
|
||||
issue.column = csv_line[3].to_int();
|
||||
issue.code = csv_line[4];
|
||||
issue.message = csv_line[5];
|
||||
issue.project_file = csv_line[6];
|
||||
|
||||
if (issue.warning)
|
||||
warning_count += 1;
|
||||
else
|
||||
error_count += 1;
|
||||
|
||||
issues.push_back(issue);
|
||||
}
|
||||
}
|
||||
|
||||
void MonoBuildTab::_update_issues_list() {
|
||||
|
||||
issues_list->clear();
|
||||
|
||||
Ref<Texture> warning_icon = get_icon("Warning", "EditorIcons");
|
||||
Ref<Texture> error_icon = get_icon("Error", "EditorIcons");
|
||||
|
||||
for (int i = 0; i < issues.size(); i++) {
|
||||
|
||||
const BuildIssue &issue = issues[i];
|
||||
|
||||
if (!(issue.warning ? warnings_visible : errors_visible))
|
||||
continue;
|
||||
|
||||
String tooltip;
|
||||
tooltip += String("Message: ") + issue.message;
|
||||
tooltip += String("\nCode: ") + issue.code;
|
||||
tooltip += String("\nType: ") + (issue.warning ? "warning" : "error");
|
||||
|
||||
String text;
|
||||
|
||||
if (issue.file.length()) {
|
||||
String sline = String::num_int64(issue.line);
|
||||
String scolumn = String::num_int64(issue.column);
|
||||
|
||||
text += issue.file + "(";
|
||||
text += sline + ",";
|
||||
text += scolumn + "): ";
|
||||
|
||||
tooltip += "\nFile: " + issue.file;
|
||||
tooltip += "\nLine: " + sline;
|
||||
tooltip += "\nColumn: " + scolumn;
|
||||
}
|
||||
|
||||
if (issue.project_file.length()) {
|
||||
tooltip += "\nProject: " + issue.project_file;
|
||||
}
|
||||
|
||||
text += issue.message;
|
||||
|
||||
int line_break_idx = text.find("\n");
|
||||
issues_list->add_item(line_break_idx == -1 ? text : text.substr(0, line_break_idx),
|
||||
issue.warning ? warning_icon : error_icon);
|
||||
int index = issues_list->get_item_count() - 1;
|
||||
issues_list->set_item_tooltip(index, tooltip);
|
||||
issues_list->set_item_metadata(index, i);
|
||||
}
|
||||
}
|
||||
|
||||
Ref<Texture> MonoBuildTab::get_icon_texture() const {
|
||||
|
||||
// FIXME these icons were removed... find something better
|
||||
|
||||
if (build_exited) {
|
||||
if (build_result == RESULT_ERROR) {
|
||||
return get_icon("DependencyChangedHl", "EditorIcons");
|
||||
} else {
|
||||
return get_icon("DependencyOkHl", "EditorIcons");
|
||||
}
|
||||
} else {
|
||||
return get_icon("GraphTime", "EditorIcons");
|
||||
}
|
||||
}
|
||||
|
||||
MonoBuildInfo MonoBuildTab::get_build_info() {
|
||||
|
||||
return build_info;
|
||||
}
|
||||
|
||||
void MonoBuildTab::on_build_start() {
|
||||
|
||||
build_exited = false;
|
||||
|
||||
issues.clear();
|
||||
warning_count = 0;
|
||||
error_count = 0;
|
||||
_update_issues_list();
|
||||
|
||||
MonoBottomPanel::get_singleton()->raise_build_tab(this);
|
||||
}
|
||||
|
||||
void MonoBuildTab::on_build_exit(BuildResult result) {
|
||||
|
||||
build_exited = true;
|
||||
build_result = result;
|
||||
|
||||
_load_issues_from_file(logs_dir.plus_file("msbuild_issues.csv"));
|
||||
_update_issues_list();
|
||||
|
||||
MonoBottomPanel::get_singleton()->raise_build_tab(this);
|
||||
}
|
||||
|
||||
void MonoBuildTab::on_build_exec_failed(const String &p_cause, const String &p_detailed) {
|
||||
|
||||
build_exited = true;
|
||||
build_result = RESULT_ERROR;
|
||||
|
||||
issues_list->clear();
|
||||
|
||||
String tooltip;
|
||||
|
||||
tooltip += "Message: " + (p_detailed.length() ? p_detailed : p_cause);
|
||||
tooltip += "\nType: error";
|
||||
|
||||
int line_break_idx = p_cause.find("\n");
|
||||
issues_list->add_item(line_break_idx == -1 ? p_cause : p_cause.substr(0, line_break_idx),
|
||||
get_icon("Error", "EditorIcons"));
|
||||
int index = issues_list->get_item_count() - 1;
|
||||
issues_list->set_item_tooltip(index, tooltip);
|
||||
|
||||
MonoBottomPanel::get_singleton()->raise_build_tab(this);
|
||||
}
|
||||
|
||||
void MonoBuildTab::restart_build() {
|
||||
|
||||
ERR_FAIL_COND(!build_exited);
|
||||
GodotSharpBuilds::get_singleton()->restart_build(this);
|
||||
}
|
||||
|
||||
void MonoBuildTab::stop_build() {
|
||||
|
||||
ERR_FAIL_COND(build_exited);
|
||||
GodotSharpBuilds::get_singleton()->stop_build(this);
|
||||
}
|
||||
|
||||
void MonoBuildTab::_issue_activated(int p_idx) {
|
||||
|
||||
ERR_FAIL_INDEX(p_idx, issues.size());
|
||||
|
||||
const BuildIssue &issue = issues[p_idx];
|
||||
|
||||
if (issue.project_file.empty() && issue.file.empty())
|
||||
return;
|
||||
|
||||
String project_dir = issue.project_file.length() ? issue.project_file.get_base_dir() : build_info.solution.get_base_dir();
|
||||
|
||||
String file = project_dir.simplify_path().plus_file(issue.file.simplify_path());
|
||||
|
||||
if (!FileAccess::exists(file))
|
||||
return;
|
||||
|
||||
file = ProjectSettings::get_singleton()->localize_path(file);
|
||||
|
||||
if (file.begins_with("res://")) {
|
||||
Ref<Script> script = ResourceLoader::load(file, CSharpLanguage::get_singleton()->get_type());
|
||||
|
||||
if (script.is_valid() && ScriptEditor::get_singleton()->edit(script, issue.line, issue.column)) {
|
||||
EditorNode::get_singleton()->call("_editor_select", EditorNode::EDITOR_SCRIPT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MonoBuildTab::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method("_issue_activated", &MonoBuildTab::_issue_activated);
|
||||
}
|
||||
|
||||
MonoBuildTab::MonoBuildTab(const MonoBuildInfo &p_build_info, const String &p_logs_dir) {
|
||||
|
||||
build_info = p_build_info;
|
||||
logs_dir = p_logs_dir;
|
||||
|
||||
build_exited = false;
|
||||
|
||||
issues_list = memnew(ItemList);
|
||||
issues_list->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
issues_list->connect("item_activated", this, "_issue_activated");
|
||||
add_child(issues_list);
|
||||
|
||||
error_count = 0;
|
||||
warning_count = 0;
|
||||
|
||||
errors_visible = true;
|
||||
warnings_visible = true;
|
||||
}
|
145
modules/mono/editor/mono_bottom_panel.h
Normal file
145
modules/mono/editor/mono_bottom_panel.h
Normal file
@ -0,0 +1,145 @@
|
||||
/*************************************************************************/
|
||||
/* mono_bottom_panel.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 MONO_BOTTOM_PANEL_H
|
||||
#define MONO_BOTTOM_PANEL_H
|
||||
|
||||
#include "editor/editor_node.h"
|
||||
#include "scene/gui/control.h"
|
||||
|
||||
#include "mono_build_info.h"
|
||||
|
||||
class MonoBuildTab;
|
||||
|
||||
class MonoBottomPanel : public VBoxContainer {
|
||||
|
||||
GDCLASS(MonoBottomPanel, VBoxContainer)
|
||||
|
||||
EditorNode *editor;
|
||||
|
||||
TabContainer *panel_tabs;
|
||||
|
||||
VBoxContainer *panel_builds_tab;
|
||||
|
||||
ItemList *build_tabs_list;
|
||||
TabContainer *build_tabs;
|
||||
|
||||
Button *warnings_btn;
|
||||
Button *errors_btn;
|
||||
|
||||
void _update_build_tabs_list();
|
||||
|
||||
void _build_tab_item_selected(int p_idx);
|
||||
void _build_tab_changed(int p_idx);
|
||||
|
||||
void _warnings_toggled(bool p_pressed);
|
||||
void _errors_toggled(bool p_pressed);
|
||||
|
||||
static MonoBottomPanel *singleton;
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ static MonoBottomPanel *get_singleton() { return singleton; }
|
||||
|
||||
void add_build_tab(MonoBuildTab *p_build_tab);
|
||||
void raise_build_tab(MonoBuildTab *p_build_tab);
|
||||
|
||||
void show_build_tab();
|
||||
|
||||
MonoBottomPanel(EditorNode *p_editor = NULL);
|
||||
~MonoBottomPanel();
|
||||
};
|
||||
|
||||
class MonoBuildTab : public VBoxContainer {
|
||||
|
||||
GDCLASS(MonoBuildTab, VBoxContainer)
|
||||
|
||||
public:
|
||||
enum BuildResult {
|
||||
RESULT_ERROR,
|
||||
RESULT_SUCCESS
|
||||
};
|
||||
|
||||
struct BuildIssue {
|
||||
bool warning;
|
||||
String file;
|
||||
int line;
|
||||
int column;
|
||||
String code;
|
||||
String message;
|
||||
String project_file;
|
||||
};
|
||||
|
||||
private:
|
||||
friend class MonoBottomPanel;
|
||||
|
||||
bool build_exited;
|
||||
BuildResult build_result;
|
||||
|
||||
Vector<BuildIssue> issues;
|
||||
ItemList *issues_list;
|
||||
|
||||
int error_count;
|
||||
int warning_count;
|
||||
|
||||
bool errors_visible;
|
||||
bool warnings_visible;
|
||||
|
||||
String logs_dir;
|
||||
|
||||
MonoBuildInfo build_info;
|
||||
|
||||
void _load_issues_from_file(const String &p_csv_file);
|
||||
void _update_issues_list();
|
||||
|
||||
void _issue_activated(int p_idx);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
Ref<Texture> get_icon_texture() const;
|
||||
|
||||
MonoBuildInfo get_build_info();
|
||||
|
||||
void on_build_start();
|
||||
void on_build_exit(BuildResult result);
|
||||
void on_build_exec_failed(const String &p_cause, const String &p_detailed = String());
|
||||
|
||||
void restart_build();
|
||||
void stop_build();
|
||||
|
||||
MonoBuildTab(const MonoBuildInfo &p_build_info, const String &p_logs_dir);
|
||||
};
|
||||
|
||||
#endif // MONO_BOTTOM_PANEL_H
|
64
modules/mono/editor/mono_build_info.h
Normal file
64
modules/mono/editor/mono_build_info.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*************************************************************************/
|
||||
/* mono_build_info.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 MONO_BUILD_INFO_H
|
||||
#define MONO_BUILD_INFO_H
|
||||
|
||||
#include "../mono_gd/gd_mono_utils.h"
|
||||
|
||||
struct MonoBuildInfo {
|
||||
|
||||
struct Hasher {
|
||||
static _FORCE_INLINE_ uint32_t hash(const MonoBuildInfo &p_key) {
|
||||
uint32_t hash = 0;
|
||||
|
||||
GDMonoUtils::hash_combine(hash, p_key.solution.hash());
|
||||
GDMonoUtils::hash_combine(hash, p_key.configuration.hash());
|
||||
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
String solution;
|
||||
String configuration;
|
||||
Vector<String> custom_props;
|
||||
|
||||
MonoBuildInfo() {}
|
||||
|
||||
MonoBuildInfo(const String &p_solution, const String &p_config) {
|
||||
solution = p_solution;
|
||||
configuration = p_config;
|
||||
}
|
||||
|
||||
bool operator==(const MonoBuildInfo &p_b) const {
|
||||
return p_b.solution == solution && p_b.configuration == configuration;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // MONO_BUILD_INFO_H
|
81
modules/mono/editor/monodevelop_instance.cpp
Normal file
81
modules/mono/editor/monodevelop_instance.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
/*************************************************************************/
|
||||
/* monodevelop_instance.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "monodevelop_instance.h"
|
||||
|
||||
#include "../mono_gd/gd_mono.h"
|
||||
#include "../mono_gd/gd_mono_class.h"
|
||||
|
||||
void MonoDevelopInstance::execute(const Vector<String> &p_files) {
|
||||
|
||||
ERR_FAIL_NULL(execute_method);
|
||||
ERR_FAIL_COND(gc_handle.is_null());
|
||||
|
||||
MonoObject *ex = NULL;
|
||||
|
||||
Variant files = p_files;
|
||||
const Variant *args[1] = { &files };
|
||||
execute_method->invoke(gc_handle->get_target(), args, &ex);
|
||||
|
||||
if (ex) {
|
||||
mono_print_unhandled_exception(ex);
|
||||
ERR_FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
void MonoDevelopInstance::execute(const String &p_file) {
|
||||
|
||||
Vector<String> files;
|
||||
files.push_back(p_file);
|
||||
execute(files);
|
||||
}
|
||||
|
||||
MonoDevelopInstance::MonoDevelopInstance(const String &p_solution) {
|
||||
|
||||
_GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
|
||||
|
||||
GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Editor", "MonoDevelopInstance");
|
||||
|
||||
MonoObject *obj = mono_object_new(TOOLS_DOMAIN, klass->get_raw());
|
||||
|
||||
GDMonoMethod *ctor = klass->get_method(".ctor", 1);
|
||||
MonoObject *ex = NULL;
|
||||
|
||||
Variant solution = p_solution;
|
||||
const Variant *args[1] = { &solution };
|
||||
ctor->invoke(obj, args, &ex);
|
||||
|
||||
if (ex) {
|
||||
mono_print_unhandled_exception(ex);
|
||||
ERR_FAIL();
|
||||
}
|
||||
|
||||
gc_handle = MonoGCHandle::create_strong(obj);
|
||||
execute_method = klass->get_method("Execute", 1);
|
||||
}
|
50
modules/mono/editor/monodevelop_instance.h
Normal file
50
modules/mono/editor/monodevelop_instance.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*************************************************************************/
|
||||
/* monodevelop_instance.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 MONODEVELOP_INSTANCE_H
|
||||
#define MONODEVELOP_INSTANCE_H
|
||||
|
||||
#include "reference.h"
|
||||
|
||||
#include "../mono_gc_handle.h"
|
||||
#include "../mono_gd/gd_mono_method.h"
|
||||
|
||||
class MonoDevelopInstance {
|
||||
|
||||
Ref<MonoGCHandle> gc_handle;
|
||||
GDMonoMethod *execute_method;
|
||||
|
||||
public:
|
||||
void execute(const Vector<String> &p_files);
|
||||
void execute(const String &p_files);
|
||||
|
||||
MonoDevelopInstance(const String &p_solution);
|
||||
};
|
||||
|
||||
#endif // MONODEVELOP_INSTANCE_H
|
130
modules/mono/editor/net_solution.cpp
Normal file
130
modules/mono/editor/net_solution.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
/*************************************************************************/
|
||||
/* net_solution.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "net_solution.h"
|
||||
|
||||
#include "os/dir_access.h"
|
||||
#include "os/file_access.h"
|
||||
|
||||
#include "../utils/path_utils.h"
|
||||
#include "../utils/string_utils.h"
|
||||
#include "csharp_project.h"
|
||||
|
||||
#define SOLUTION_TEMPLATE \
|
||||
"Microsoft Visual Studio Solution File, Format Version 12.00\n" \
|
||||
"# Visual Studio 2012\n" \
|
||||
"%0\n" \
|
||||
"Global\n" \
|
||||
"\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n" \
|
||||
"%1\n" \
|
||||
"\tEndGlobalSection\n" \
|
||||
"\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n" \
|
||||
"%2\n" \
|
||||
"\tEndGlobalSection\n" \
|
||||
"EndGlobal\n"
|
||||
|
||||
#define PROJECT_DECLARATION "Project(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"%0\", \"%1\", \"{%2}\"\nEndProject"
|
||||
|
||||
#define SOLUTION_PLATFORMS_CONFIG "\t\%0|Any CPU = %0|Any CPU"
|
||||
|
||||
#define PROJECT_PLATFORMS_CONFIG \
|
||||
"\t\t{%0}.%1|Any CPU.ActiveCfg = %1|Any CPU\n" \
|
||||
"\t\t{%0}.%1|Any CPU.Build.0 = %1|Any CPU"
|
||||
|
||||
void NETSolution::add_new_project(const String &p_name, const String &p_guid, const Vector<String> &p_extra_configs) {
|
||||
if (projects.has(p_name))
|
||||
WARN_PRINT("Overriding existing project.");
|
||||
|
||||
ProjectInfo procinfo;
|
||||
procinfo.guid = p_guid;
|
||||
|
||||
procinfo.configs.push_back("Debug");
|
||||
procinfo.configs.push_back("Release");
|
||||
|
||||
for (int i = 0; i < p_extra_configs.size(); i++) {
|
||||
procinfo.configs.push_back(p_extra_configs[i]);
|
||||
}
|
||||
|
||||
projects[p_name] = procinfo;
|
||||
}
|
||||
|
||||
Error NETSolution::save() {
|
||||
bool dir_exists = DirAccess::exists(path);
|
||||
ERR_EXPLAIN("The directory does not exist.");
|
||||
ERR_FAIL_COND_V(!dir_exists, ERR_FILE_BAD_PATH);
|
||||
|
||||
String projs_decl;
|
||||
String sln_platform_cfg;
|
||||
String proj_platform_cfg;
|
||||
|
||||
for (Map<String, ProjectInfo>::Element *E = projects.front(); E; E = E->next()) {
|
||||
const String &name = E->key();
|
||||
const ProjectInfo &procinfo = E->value();
|
||||
|
||||
projs_decl += sformat(PROJECT_DECLARATION, name, name + ".csproj", procinfo.guid);
|
||||
|
||||
for (int i = 0; i < procinfo.configs.size(); i++) {
|
||||
const String &config = procinfo.configs[i];
|
||||
|
||||
if (i != 0) {
|
||||
sln_platform_cfg += "\n";
|
||||
proj_platform_cfg += "\n";
|
||||
}
|
||||
|
||||
sln_platform_cfg += sformat(SOLUTION_PLATFORMS_CONFIG, config);
|
||||
proj_platform_cfg += sformat(PROJECT_PLATFORMS_CONFIG, procinfo.guid, config);
|
||||
}
|
||||
}
|
||||
|
||||
String content = sformat(SOLUTION_TEMPLATE, projs_decl, sln_platform_cfg, proj_platform_cfg);
|
||||
|
||||
FileAccessRef file = FileAccess::open(path_join(path, name + ".sln"), FileAccess::WRITE);
|
||||
ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE);
|
||||
file->store_string(content);
|
||||
file->close();
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool NETSolution::set_path(const String &p_existing_path) {
|
||||
if (p_existing_path.is_abs_path()) {
|
||||
path = p_existing_path;
|
||||
} else {
|
||||
String abspath;
|
||||
if (!rel_path_to_abs(p_existing_path, abspath))
|
||||
return false;
|
||||
path = abspath;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NETSolution::NETSolution(const String &p_name) {
|
||||
name = p_name;
|
||||
}
|
57
modules/mono/editor/net_solution.h
Normal file
57
modules/mono/editor/net_solution.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*************************************************************************/
|
||||
/* net_solution.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 NET_SOLUTION_H
|
||||
#define NET_SOLUTION_H
|
||||
|
||||
#include "map.h"
|
||||
#include "ustring.h"
|
||||
|
||||
struct NETSolution {
|
||||
String name;
|
||||
|
||||
void add_new_project(const String &p_name, const String &p_guid, const Vector<String> &p_extra_configs = Vector<String>());
|
||||
|
||||
Error save();
|
||||
|
||||
bool set_path(const String &p_existing_path);
|
||||
|
||||
NETSolution(const String &p_name);
|
||||
|
||||
private:
|
||||
struct ProjectInfo {
|
||||
String guid;
|
||||
Vector<String> configs;
|
||||
};
|
||||
|
||||
String path;
|
||||
Map<String, ProjectInfo> projects;
|
||||
};
|
||||
|
||||
#endif // NET_SOLUTION_H
|
475
modules/mono/glue/cs_files/Basis.cs
Normal file
475
modules/mono/glue/cs_files/Basis.cs
Normal file
@ -0,0 +1,475 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Basis : IEquatable<Basis>
|
||||
{
|
||||
private static readonly Basis identity = new Basis
|
||||
(
|
||||
new Vector3(1f, 0f, 0f),
|
||||
new Vector3(0f, 1f, 0f),
|
||||
new Vector3(0f, 0f, 1f)
|
||||
);
|
||||
|
||||
private static readonly Basis[] orthoBases = new Basis[24]
|
||||
{
|
||||
new Basis(1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 1f),
|
||||
new Basis(0f, -1f, 0f, 1f, 0f, 0f, 0f, 0f, 1f),
|
||||
new Basis(-1f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, 1f),
|
||||
new Basis(0f, 1f, 0f, -1f, 0f, 0f, 0f, 0f, 1f),
|
||||
new Basis(1f, 0f, 0f, 0f, 0f, -1f, 0f, 1f, 0f),
|
||||
new Basis(0f, 0f, 1f, 1f, 0f, 0f, 0f, 1f, 0f),
|
||||
new Basis(-1f, 0f, 0f, 0f, 0f, 1f, 0f, 1f, 0f),
|
||||
new Basis(0f, 0f, -1f, -1f, 0f, 0f, 0f, 1f, 0f),
|
||||
new Basis(1f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, -1f),
|
||||
new Basis(0f, 1f, 0f, 1f, 0f, 0f, 0f, 0f, -1f),
|
||||
new Basis(-1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, -1f),
|
||||
new Basis(0f, -1f, 0f, -1f, 0f, 0f, 0f, 0f, -1f),
|
||||
new Basis(1f, 0f, 0f, 0f, 0f, 1f, 0f, -1f, 0f),
|
||||
new Basis(0f, 0f, -1f, 1f, 0f, 0f, 0f, -1f, 0f),
|
||||
new Basis(-1f, 0f, 0f, 0f, 0f, -1f, 0f, -1f, 0f),
|
||||
new Basis(0f, 0f, 1f, -1f, 0f, 0f, 0f, -1f, 0f),
|
||||
new Basis(0f, 0f, 1f, 0f, 1f, 0f, -1f, 0f, 0f),
|
||||
new Basis(0f, -1f, 0f, 0f, 0f, 1f, -1f, 0f, 0f),
|
||||
new Basis(0f, 0f, -1f, 0f, -1f, 0f, -1f, 0f, 0f),
|
||||
new Basis(0f, 1f, 0f, 0f, 0f, -1f, -1f, 0f, 0f),
|
||||
new Basis(0f, 0f, 1f, 0f, -1f, 0f, 1f, 0f, 0f),
|
||||
new Basis(0f, 1f, 0f, 0f, 0f, 1f, 1f, 0f, 0f),
|
||||
new Basis(0f, 0f, -1f, 0f, 1f, 0f, 1f, 0f, 0f),
|
||||
new Basis(0f, -1f, 0f, 0f, 0f, -1f, 1f, 0f, 0f)
|
||||
};
|
||||
|
||||
public Vector3 x;
|
||||
public Vector3 y;
|
||||
public Vector3 z;
|
||||
|
||||
public static Basis Identity
|
||||
{
|
||||
get { return identity; }
|
||||
}
|
||||
|
||||
public Vector3 Scale
|
||||
{
|
||||
get
|
||||
{
|
||||
return 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()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return x;
|
||||
case 1:
|
||||
return y;
|
||||
case 2:
|
||||
return z;
|
||||
default:
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
x = value;
|
||||
return;
|
||||
case 1:
|
||||
y = value;
|
||||
return;
|
||||
case 2:
|
||||
z = value;
|
||||
return;
|
||||
default:
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float this[int index, int axis]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return x[axis];
|
||||
case 1:
|
||||
return y[axis];
|
||||
case 2:
|
||||
return z[axis];
|
||||
default:
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
x[axis] = value;
|
||||
return;
|
||||
case 1:
|
||||
y[axis] = value;
|
||||
return;
|
||||
case 2:
|
||||
z[axis] = value;
|
||||
return;
|
||||
default:
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static Basis create_from_axes(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis)
|
||||
{
|
||||
return new Basis
|
||||
(
|
||||
new Vector3(xAxis.x, yAxis.x, zAxis.x),
|
||||
new Vector3(xAxis.y, yAxis.y, zAxis.y),
|
||||
new Vector3(xAxis.z, yAxis.z, zAxis.z)
|
||||
);
|
||||
}
|
||||
|
||||
public float 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]);
|
||||
}
|
||||
|
||||
public Vector3 get_axis(int axis)
|
||||
{
|
||||
return new Vector3(this[0, axis], this[1, axis], this[2, axis]);
|
||||
}
|
||||
|
||||
public Vector3 get_euler()
|
||||
{
|
||||
Basis m = this.orthonormalized();
|
||||
|
||||
Vector3 euler;
|
||||
|
||||
euler.y = Mathf.asin(m.x[2]);
|
||||
|
||||
if (euler.y < Mathf.PI * 0.5f)
|
||||
{
|
||||
if (euler.y > -Mathf.PI * 0.5f)
|
||||
{
|
||||
euler.x = Mathf.atan2(-m.y[2], m.z[2]);
|
||||
euler.z = Mathf.atan2(-m.x[1], m.x[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
euler.z = 0.0f;
|
||||
euler.x = euler.z - Mathf.atan2(m.y[0], m.y[1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
euler.z = 0f;
|
||||
euler.x = Mathf.atan2(m.x[1], m.y[1]) - euler.z;
|
||||
}
|
||||
|
||||
return euler;
|
||||
}
|
||||
|
||||
public int get_orthogonal_index()
|
||||
{
|
||||
Basis orth = this;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
float v = orth[i, j];
|
||||
|
||||
if (v > 0.5f)
|
||||
v = 1.0f;
|
||||
else if (v < -0.5f)
|
||||
v = -1.0f;
|
||||
else
|
||||
v = 0f;
|
||||
|
||||
orth[i, j] = v;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 24; i++)
|
||||
{
|
||||
if (orthoBases[i] == orth)
|
||||
return i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Basis inverse()
|
||||
{
|
||||
Basis inv = this;
|
||||
|
||||
float[] co = new float[3]
|
||||
{
|
||||
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]
|
||||
};
|
||||
|
||||
float det = inv[0, 0] * co[0] + inv[0, 1] * co[1] + inv[0, 2] * co[2];
|
||||
|
||||
if (det == 0)
|
||||
{
|
||||
return new Basis
|
||||
(
|
||||
float.NaN, float.NaN, float.NaN,
|
||||
float.NaN, float.NaN, float.NaN,
|
||||
float.NaN, float.NaN, float.NaN
|
||||
);
|
||||
}
|
||||
|
||||
float s = 1.0f / det;
|
||||
|
||||
inv = 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
|
||||
);
|
||||
|
||||
return inv;
|
||||
}
|
||||
|
||||
public Basis orthonormalized()
|
||||
{
|
||||
Vector3 xAxis = get_axis(0);
|
||||
Vector3 yAxis = get_axis(1);
|
||||
Vector3 zAxis = get_axis(2);
|
||||
|
||||
xAxis.normalize();
|
||||
yAxis = (yAxis - xAxis * (xAxis.dot(yAxis)));
|
||||
yAxis.normalize();
|
||||
zAxis = (zAxis - xAxis * (xAxis.dot(zAxis)) - yAxis * (yAxis.dot(zAxis)));
|
||||
zAxis.normalize();
|
||||
|
||||
return Basis.create_from_axes(xAxis, yAxis, zAxis);
|
||||
}
|
||||
|
||||
public Basis rotated(Vector3 axis, float phi)
|
||||
{
|
||||
return this * new Basis(axis, phi);
|
||||
}
|
||||
|
||||
public Basis scaled(Vector3 scale)
|
||||
{
|
||||
Basis m = this;
|
||||
|
||||
m[0, 0] *= scale.x;
|
||||
m[1, 0] *= scale.x;
|
||||
m[2, 0] *= scale.x;
|
||||
m[0, 1] *= scale.y;
|
||||
m[1, 1] *= scale.y;
|
||||
m[2, 1] *= scale.y;
|
||||
m[0, 2] *= scale.z;
|
||||
m[1, 2] *= scale.z;
|
||||
m[2, 2] *= scale.z;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
public float tdotx(Vector3 with)
|
||||
{
|
||||
return this[0, 0] * with[0] + this[1, 0] * with[1] + this[2, 0] * with[2];
|
||||
}
|
||||
|
||||
public float tdoty(Vector3 with)
|
||||
{
|
||||
return this[0, 1] * with[0] + this[1, 1] * with[1] + this[2, 1] * with[2];
|
||||
}
|
||||
|
||||
public float tdotz(Vector3 with)
|
||||
{
|
||||
return this[0, 2] * with[0] + this[1, 2] * with[1] + this[2, 2] * with[2];
|
||||
}
|
||||
|
||||
public Basis transposed()
|
||||
{
|
||||
Basis tr = this;
|
||||
|
||||
float temp = this[0, 1];
|
||||
this[0, 1] = this[1, 0];
|
||||
this[1, 0] = temp;
|
||||
|
||||
temp = this[0, 2];
|
||||
this[0, 2] = this[2, 0];
|
||||
this[2, 0] = temp;
|
||||
|
||||
temp = this[1, 2];
|
||||
this[1, 2] = this[2, 1];
|
||||
this[2, 1] = temp;
|
||||
|
||||
return tr;
|
||||
}
|
||||
|
||||
public Vector3 xform(Vector3 v)
|
||||
{
|
||||
return new Vector3
|
||||
(
|
||||
this[0].dot(v),
|
||||
this[1].dot(v),
|
||||
this[2].dot(v)
|
||||
);
|
||||
}
|
||||
|
||||
public Vector3 xform_inv(Vector3 v)
|
||||
{
|
||||
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)
|
||||
);
|
||||
}
|
||||
|
||||
public Basis(Quat quat)
|
||||
{
|
||||
float s = 2.0f / quat.length_squared();
|
||||
|
||||
float xs = quat.x * s;
|
||||
float ys = quat.y * s;
|
||||
float zs = quat.z * s;
|
||||
float wx = quat.w * xs;
|
||||
float wy = quat.w * ys;
|
||||
float wz = quat.w * zs;
|
||||
float xx = quat.x * xs;
|
||||
float xy = quat.x * ys;
|
||||
float xz = quat.x * zs;
|
||||
float yy = quat.y * ys;
|
||||
float yz = quat.y * zs;
|
||||
float zz = quat.z * zs;
|
||||
|
||||
this.x = new Vector3(1.0f - (yy + zz), xy - wz, xz + wy);
|
||||
this.y = new Vector3(xy + wz, 1.0f - (xx + zz), yz - wx);
|
||||
this.z = new Vector3(xz - wy, yz + wx, 1.0f - (xx + yy));
|
||||
}
|
||||
|
||||
public Basis(Vector3 axis, float phi)
|
||||
{
|
||||
Vector3 axis_sq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z);
|
||||
|
||||
float cosine = Mathf.cos(phi);
|
||||
float sine = Mathf.sin(phi);
|
||||
|
||||
this.x = 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
|
||||
);
|
||||
|
||||
this.y = 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
|
||||
);
|
||||
|
||||
this.z = new Vector3
|
||||
(
|
||||
axis.z * axis.x * (1.0f - cosine) - axis.y * sine,
|
||||
axis.y * axis.z * (1.0f - cosine) + axis.x * sine,
|
||||
axis_sq.z + cosine * (1.0f - axis_sq.z)
|
||||
);
|
||||
}
|
||||
|
||||
public Basis(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis)
|
||||
{
|
||||
this.x = xAxis;
|
||||
this.y = yAxis;
|
||||
this.z = zAxis;
|
||||
}
|
||||
|
||||
public Basis(float xx, float xy, float xz, float yx, float yy, float yz, float zx, float zy, float zz)
|
||||
{
|
||||
this.x = new Vector3(xx, xy, xz);
|
||||
this.y = new Vector3(yx, yy, yz);
|
||||
this.z = 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])
|
||||
);
|
||||
}
|
||||
|
||||
public static bool operator ==(Basis left, Basis right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Basis left, Basis right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Basis)
|
||||
{
|
||||
return Equals((Basis)obj);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Equals(Basis other)
|
||||
{
|
||||
return x.Equals(other.x) && y.Equals(other.y) && z.Equals(other.z);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("({0}, {1}, {2})", new object[]
|
||||
{
|
||||
this.x.ToString(),
|
||||
this.y.ToString(),
|
||||
this.z.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
public string ToString(string format)
|
||||
{
|
||||
return String.Format("({0}, {1}, {2})", new object[]
|
||||
{
|
||||
this.x.ToString(format),
|
||||
this.y.ToString(format),
|
||||
this.z.ToString(format)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
590
modules/mono/glue/cs_files/Color.cs
Normal file
590
modules/mono/glue/cs_files/Color.cs
Normal file
@ -0,0 +1,590 @@
|
||||
using System;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
public struct Color : IEquatable<Color>
|
||||
{
|
||||
public float r;
|
||||
public float g;
|
||||
public float b;
|
||||
public float a;
|
||||
|
||||
public int r8
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)(r * 255.0f);
|
||||
}
|
||||
}
|
||||
|
||||
public int g8
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)(g * 255.0f);
|
||||
}
|
||||
}
|
||||
|
||||
public int b8
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)(b * 255.0f);
|
||||
}
|
||||
}
|
||||
|
||||
public int a8
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)(a * 255.0f);
|
||||
}
|
||||
}
|
||||
|
||||
public float h
|
||||
{
|
||||
get
|
||||
{
|
||||
float max = Mathf.max(r, Mathf.max(g, b));
|
||||
float min = Mathf.min(r, Mathf.min(g, b));
|
||||
|
||||
float delta = max - min;
|
||||
|
||||
if (delta == 0)
|
||||
return 0;
|
||||
|
||||
float h;
|
||||
|
||||
if (r == max)
|
||||
h = (g - b) / delta; // Between yellow & magenta
|
||||
else if (g == max)
|
||||
h = 2 + (b - r) / delta; // Between cyan & yellow
|
||||
else
|
||||
h = 4 + (r - g) / delta; // Between magenta & cyan
|
||||
|
||||
h /= 6.0f;
|
||||
|
||||
if (h < 0)
|
||||
h += 1.0f;
|
||||
|
||||
return h;
|
||||
}
|
||||
set
|
||||
{
|
||||
this = from_hsv(value, s, v);
|
||||
}
|
||||
}
|
||||
|
||||
public float s
|
||||
{
|
||||
get
|
||||
{
|
||||
float max = Mathf.max(r, Mathf.max(g, b));
|
||||
float min = Mathf.min(r, Mathf.min(g, b));
|
||||
|
||||
float delta = max - min;
|
||||
|
||||
return max != 0 ? delta / max : 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
this = from_hsv(h, value, v);
|
||||
}
|
||||
}
|
||||
|
||||
public float v
|
||||
{
|
||||
get
|
||||
{
|
||||
return Mathf.max(r, Mathf.max(g, b));
|
||||
}
|
||||
set
|
||||
{
|
||||
this = from_hsv(h, s, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Color black = new Color(0f, 0f, 0f, 1.0f);
|
||||
|
||||
public Color Black
|
||||
{
|
||||
get
|
||||
{
|
||||
return black;
|
||||
}
|
||||
}
|
||||
|
||||
public float this [int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return r;
|
||||
case 1:
|
||||
return g;
|
||||
case 2:
|
||||
return b;
|
||||
case 3:
|
||||
return a;
|
||||
default:
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
r = value;
|
||||
return;
|
||||
case 1:
|
||||
g = value;
|
||||
return;
|
||||
case 2:
|
||||
b = value;
|
||||
return;
|
||||
case 3:
|
||||
a = value;
|
||||
return;
|
||||
default:
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void to_hsv(Color color, out float hue, out float saturation, out float value)
|
||||
{
|
||||
int max = Mathf.max(color.r8, Mathf.max(color.g8, color.b8));
|
||||
int min = Mathf.min(color.r8, Mathf.min(color.g8, color.b8));
|
||||
|
||||
float delta = max - min;
|
||||
|
||||
if (delta == 0)
|
||||
{
|
||||
hue = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (color.r == max)
|
||||
hue = (color.g - color.b) / delta; // Between yellow & magenta
|
||||
else if (color.g == max)
|
||||
hue = 2 + (color.b - color.r) / delta; // Between cyan & yellow
|
||||
else
|
||||
hue = 4 + (color.r - color.g) / delta; // Between magenta & cyan
|
||||
|
||||
hue /= 6.0f;
|
||||
|
||||
if (hue < 0)
|
||||
hue += 1.0f;
|
||||
}
|
||||
|
||||
saturation = (max == 0) ? 0 : 1f - (1f * min / max);
|
||||
value = max / 255f;
|
||||
}
|
||||
|
||||
public static Color from_hsv(float hue, float saturation, float value, float alpha = 1.0f)
|
||||
{
|
||||
if (saturation == 0)
|
||||
{
|
||||
// acp_hromatic (grey)
|
||||
return new Color(value, value, value, alpha);
|
||||
}
|
||||
|
||||
int i;
|
||||
float f, p, q, t;
|
||||
|
||||
hue *= 6.0f;
|
||||
hue %= 6f;
|
||||
i = (int)hue;
|
||||
|
||||
f = hue - i;
|
||||
p = value * (1 - saturation);
|
||||
q = value * (1 - saturation * f);
|
||||
t = value * (1 - saturation * (1 - f));
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0: // Red is the dominant color
|
||||
return new Color(value, t, p, alpha);
|
||||
case 1: // Green is the dominant color
|
||||
return new Color(q, value, p, alpha);
|
||||
case 2:
|
||||
return new Color(p, value, t, alpha);
|
||||
case 3: // Blue is the dominant color
|
||||
return new Color(p, q, value, alpha);
|
||||
case 4:
|
||||
return new Color(t, p, value, alpha);
|
||||
default: // (5) Red is the dominant color
|
||||
return new Color(value, p, q, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
public Color blend(Color over)
|
||||
{
|
||||
Color res;
|
||||
|
||||
float sa = 1.0f - over.a;
|
||||
res.a = a * sa + over.a;
|
||||
|
||||
if (res.a == 0)
|
||||
{
|
||||
return new Color(0, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
res.r = (r * a * sa + over.r * over.a) / res.a;
|
||||
res.g = (g * a * sa + over.g * over.a) / res.a;
|
||||
res.b = (b * a * sa + over.b * over.a) / res.a;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public Color contrasted()
|
||||
{
|
||||
return new Color(
|
||||
(r + 0.5f) % 1.0f,
|
||||
(g + 0.5f) % 1.0f,
|
||||
(b + 0.5f) % 1.0f
|
||||
);
|
||||
}
|
||||
|
||||
public float gray()
|
||||
{
|
||||
return (r + g + b) / 3.0f;
|
||||
}
|
||||
|
||||
public Color inverted()
|
||||
{
|
||||
return new Color(
|
||||
1.0f - r,
|
||||
1.0f - g,
|
||||
1.0f - b
|
||||
);
|
||||
}
|
||||
|
||||
public Color linear_interpolate(Color b, float t)
|
||||
{
|
||||
Color res = this;
|
||||
|
||||
res.r += (t * (b.r - this.r));
|
||||
res.g += (t * (b.g - this.g));
|
||||
res.b += (t * (b.b - this.b));
|
||||
res.a += (t * (b.a - this.a));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public int to_32()
|
||||
{
|
||||
int c = (byte)(a * 255);
|
||||
c <<= 8;
|
||||
c |= (byte)(r * 255);
|
||||
c <<= 8;
|
||||
c |= (byte)(g * 255);
|
||||
c <<= 8;
|
||||
c |= (byte)(b * 255);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
public int to_ARGB32()
|
||||
{
|
||||
int c = (byte)(a * 255);
|
||||
c <<= 8;
|
||||
c |= (byte)(r * 255);
|
||||
c <<= 8;
|
||||
c |= (byte)(g * 255);
|
||||
c <<= 8;
|
||||
c |= (byte)(b * 255);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
public string to_html(bool include_alpha = true)
|
||||
{
|
||||
String txt = string.Empty;
|
||||
|
||||
txt += _to_hex(r);
|
||||
txt += _to_hex(g);
|
||||
txt += _to_hex(b);
|
||||
|
||||
if (include_alpha)
|
||||
txt = _to_hex(a) + txt;
|
||||
|
||||
return txt;
|
||||
}
|
||||
|
||||
public Color(float r, float g, float b, float a = 1.0f)
|
||||
{
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
this.a = a;
|
||||
}
|
||||
|
||||
public Color(int rgba)
|
||||
{
|
||||
this.a = (rgba & 0xFF) / 255.0f;
|
||||
rgba >>= 8;
|
||||
this.b = (rgba & 0xFF) / 255.0f;
|
||||
rgba >>= 8;
|
||||
this.g = (rgba & 0xFF) / 255.0f;
|
||||
rgba >>= 8;
|
||||
this.r = (rgba & 0xFF) / 255.0f;
|
||||
}
|
||||
|
||||
private static float _parse_col(string str, int ofs)
|
||||
{
|
||||
int ig = 0;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
int c = str[i + ofs];
|
||||
int v = 0;
|
||||
|
||||
if (c >= '0' && c <= '9')
|
||||
{
|
||||
v = c - '0';
|
||||
}
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
{
|
||||
v = c - 'a';
|
||||
v += 10;
|
||||
}
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
{
|
||||
v = c - 'A';
|
||||
v += 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
ig += v * 16;
|
||||
else
|
||||
ig += v;
|
||||
}
|
||||
|
||||
return ig;
|
||||
}
|
||||
|
||||
private String _to_hex(float val)
|
||||
{
|
||||
int v = (int)Mathf.clamp(val * 255.0f, 0, 255);
|
||||
|
||||
string ret = string.Empty;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
char[] c = { (char)0, (char)0 };
|
||||
int lv = v & 0xF;
|
||||
|
||||
if (lv < 10)
|
||||
c[0] = (char)('0' + lv);
|
||||
else
|
||||
c[0] = (char)('a' + lv - 10);
|
||||
|
||||
v >>= 4;
|
||||
ret = c + ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
internal static bool html_is_valid(string color)
|
||||
{
|
||||
if (color.Length == 0)
|
||||
return false;
|
||||
|
||||
if (color[0] == '#')
|
||||
color = color.Substring(1, color.Length - 1);
|
||||
|
||||
bool alpha = false;
|
||||
|
||||
if (color.Length == 8)
|
||||
alpha = true;
|
||||
else if (color.Length == 6)
|
||||
alpha = false;
|
||||
else
|
||||
return false;
|
||||
|
||||
if (alpha)
|
||||
{
|
||||
if ((int)_parse_col(color, 0) < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
int from = alpha ? 2 : 0;
|
||||
|
||||
if ((int)_parse_col(color, from + 0) < 0)
|
||||
return false;
|
||||
if ((int)_parse_col(color, from + 2) < 0)
|
||||
return false;
|
||||
if ((int)_parse_col(color, from + 4) < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Color Color8(byte r8, byte g8, byte b8, byte a8)
|
||||
{
|
||||
return new Color((float)r8 / 255f, (float)g8 / 255f, (float)b8 / 255f, (float)a8 / 255f);
|
||||
}
|
||||
|
||||
public Color(string rgba)
|
||||
{
|
||||
if (rgba.Length == 0)
|
||||
{
|
||||
r = 0f;
|
||||
g = 0f;
|
||||
b = 0f;
|
||||
a = 1.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
if (rgba[0] == '#')
|
||||
rgba = rgba.Substring(1);
|
||||
|
||||
bool alpha = false;
|
||||
|
||||
if (rgba.Length == 8)
|
||||
{
|
||||
alpha = true;
|
||||
}
|
||||
else if (rgba.Length == 6)
|
||||
{
|
||||
alpha = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("Invalid color code. Length is " + rgba.Length + " but a length of 6 or 8 is expected: " + rgba);
|
||||
}
|
||||
|
||||
if (alpha)
|
||||
{
|
||||
a = _parse_col(rgba, 0);
|
||||
|
||||
if (a < 0)
|
||||
throw new ArgumentOutOfRangeException("Invalid color code. Alpha is " + a + " but zero or greater is expected: " + rgba);
|
||||
}
|
||||
else
|
||||
{
|
||||
a = 1.0f;
|
||||
}
|
||||
|
||||
int from = alpha ? 2 : 0;
|
||||
|
||||
r = _parse_col(rgba, from + 0);
|
||||
|
||||
if (r < 0)
|
||||
throw new ArgumentOutOfRangeException("Invalid color code. Red is " + r + " but zero or greater is expected: " + rgba);
|
||||
|
||||
g = _parse_col(rgba, from + 2);
|
||||
|
||||
if (g < 0)
|
||||
throw new ArgumentOutOfRangeException("Invalid color code. Green is " + g + " but zero or greater is expected: " + rgba);
|
||||
|
||||
b = _parse_col(rgba, from + 4);
|
||||
|
||||
if (b < 0)
|
||||
throw new ArgumentOutOfRangeException("Invalid color code. Blue is " + b + " but zero or greater is expected: " + rgba);
|
||||
}
|
||||
|
||||
public static bool operator ==(Color left, Color right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Color left, Color right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator <(Color left, Color right)
|
||||
{
|
||||
if (left.r == right.r)
|
||||
{
|
||||
if (left.g == right.g)
|
||||
{
|
||||
if (left.b == right.b)
|
||||
return (left.a < right.a);
|
||||
else
|
||||
return (left.b < right.b);
|
||||
}
|
||||
else
|
||||
{
|
||||
return left.g < right.g;
|
||||
}
|
||||
}
|
||||
|
||||
return left.r < right.r;
|
||||
}
|
||||
|
||||
public static bool operator >(Color left, Color right)
|
||||
{
|
||||
if (left.r == right.r)
|
||||
{
|
||||
if (left.g == right.g)
|
||||
{
|
||||
if (left.b == right.b)
|
||||
return (left.a > right.a);
|
||||
else
|
||||
return (left.b > right.b);
|
||||
}
|
||||
else
|
||||
{
|
||||
return left.g > right.g;
|
||||
}
|
||||
}
|
||||
|
||||
return left.r > right.r;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Color)
|
||||
{
|
||||
return Equals((Color)obj);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Equals(Color other)
|
||||
{
|
||||
return r == other.r && g == other.g && b == other.b && a == other.a;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return r.GetHashCode() ^ g.GetHashCode() ^ b.GetHashCode() ^ a.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0},{1},{2},{3}", new object[]
|
||||
{
|
||||
this.r.ToString(),
|
||||
this.g.ToString(),
|
||||
this.b.ToString(),
|
||||
this.a.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
public string ToString(string format)
|
||||
{
|
||||
return String.Format("{0},{1},{2},{3}", new object[]
|
||||
{
|
||||
this.r.ToString(format),
|
||||
this.g.ToString(format),
|
||||
this.b.ToString(format),
|
||||
this.a.ToString(format)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
48
modules/mono/glue/cs_files/Error.cs
Normal file
48
modules/mono/glue/cs_files/Error.cs
Normal file
@ -0,0 +1,48 @@
|
||||
namespace Godot
|
||||
{
|
||||
public enum Error : int
|
||||
{
|
||||
OK = 0,
|
||||
FAILED = 1,
|
||||
ERR_UNAVAILABLE = 2,
|
||||
ERR_UNCONFIGURED = 3,
|
||||
ERR_UNAUTHORIZED = 4,
|
||||
ERR_PARAMETER_RANGE_ERROR = 5,
|
||||
ERR_OUT_OF_MEMORY = 6,
|
||||
ERR_FILE_NOT_FOUND = 7,
|
||||
ERR_FILE_BAD_DRIVE = 8,
|
||||
ERR_FILE_BAD_PATH = 9,
|
||||
ERR_FILE_NO_PERMISSION = 10,
|
||||
ERR_FILE_ALREADY_IN_USE = 11,
|
||||
ERR_FILE_CANT_OPEN = 12,
|
||||
ERR_FILE_CANT_WRITE = 13,
|
||||
ERR_FILE_CANT_READ = 14,
|
||||
ERR_FILE_UNRECOGNIZED = 15,
|
||||
ERR_FILE_CORRUPT = 16,
|
||||
ERR_FILE_MISSING_DEPENDENCIES = 17,
|
||||
ERR_FILE_EOF = 18,
|
||||
ERR_CANT_OPEN = 19,
|
||||
ERR_CANT_CREATE = 20,
|
||||
ERR_PARSE_ERROR = 43,
|
||||
ERROR_QUERY_FAILED = 21,
|
||||
ERR_ALREADY_IN_USE = 22,
|
||||
ERR_LOCKED = 23,
|
||||
ERR_TIMEOUT = 24,
|
||||
ERR_CANT_AQUIRE_RESOURCE = 28,
|
||||
ERR_INVALID_DATA = 30,
|
||||
ERR_INVALID_PARAMETER = 31,
|
||||
ERR_ALREADY_EXISTS = 32,
|
||||
ERR_DOES_NOT_EXIST = 33,
|
||||
ERR_DATABASE_CANT_READ = 34,
|
||||
ERR_DATABASE_CANT_WRITE = 35,
|
||||
ERR_COMPILATION_FAILED = 36,
|
||||
ERR_METHOD_NOT_FOUND = 37,
|
||||
ERR_LINK_FAILED = 38,
|
||||
ERR_SCRIPT_FAILED = 39,
|
||||
ERR_CYCLIC_LINK = 40,
|
||||
ERR_BUSY = 44,
|
||||
ERR_HELP = 46,
|
||||
ERR_BUG = 47,
|
||||
ERR_WTF = 49
|
||||
}
|
||||
}
|
19
modules/mono/glue/cs_files/ExportAttribute.cs
Normal file
19
modules/mono/glue/cs_files/ExportAttribute.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class ExportAttribute : Attribute
|
||||
{
|
||||
private int hint;
|
||||
private string hint_string;
|
||||
private int usage;
|
||||
|
||||
public ExportAttribute(int hint = GD.PROPERTY_HINT_NONE, string hint_string = "", int usage = GD.PROPERTY_USAGE_DEFAULT)
|
||||
{
|
||||
this.hint = hint;
|
||||
this.hint_string = hint_string;
|
||||
this.usage = usage;
|
||||
}
|
||||
}
|
||||
}
|
191
modules/mono/glue/cs_files/GD.cs
Normal file
191
modules/mono/glue/cs_files/GD.cs
Normal file
@ -0,0 +1,191 @@
|
||||
using System;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
public static class GD
|
||||
{
|
||||
/*{GodotGlobalConstants}*/
|
||||
|
||||
public static object bytes2var(byte[] bytes)
|
||||
{
|
||||
return NativeCalls.godot_icall_Godot_bytes2var(bytes);
|
||||
}
|
||||
|
||||
public static object convert(object what, int type)
|
||||
{
|
||||
return NativeCalls.godot_icall_Godot_convert(what, type);
|
||||
}
|
||||
|
||||
public static float db2linear(float db)
|
||||
{
|
||||
return (float)Math.Exp(db * 0.11512925464970228420089957273422);
|
||||
}
|
||||
|
||||
public static float dectime(float value, float amount, float step)
|
||||
{
|
||||
float sgn = value < 0 ? -1.0f : 1.0f;
|
||||
float val = Mathf.abs(value);
|
||||
val -= amount * step;
|
||||
if (val < 0.0f)
|
||||
val = 0.0f;
|
||||
return val * sgn;
|
||||
}
|
||||
|
||||
public static FuncRef funcref(Object instance, string funcname)
|
||||
{
|
||||
var ret = new FuncRef();
|
||||
ret.SetInstance(instance);
|
||||
ret.SetFunction(funcname);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int hash(object var)
|
||||
{
|
||||
return NativeCalls.godot_icall_Godot_hash(var);
|
||||
}
|
||||
|
||||
public static Object instance_from_id(int instance_id)
|
||||
{
|
||||
return NativeCalls.godot_icall_Godot_instance_from_id(instance_id);
|
||||
}
|
||||
|
||||
public static double linear2db(double linear)
|
||||
{
|
||||
return Math.Log(linear) * 8.6858896380650365530225783783321;
|
||||
}
|
||||
|
||||
public static Resource load(string path)
|
||||
{
|
||||
return ResourceLoader.Load(path);
|
||||
}
|
||||
|
||||
public static void print(params object[] what)
|
||||
{
|
||||
NativeCalls.godot_icall_Godot_print(what);
|
||||
}
|
||||
|
||||
public static void print_stack()
|
||||
{
|
||||
print(System.Environment.StackTrace);
|
||||
}
|
||||
|
||||
public static void printerr(params object[] what)
|
||||
{
|
||||
NativeCalls.godot_icall_Godot_printerr(what);
|
||||
}
|
||||
|
||||
public static void printraw(params object[] what)
|
||||
{
|
||||
NativeCalls.godot_icall_Godot_printraw(what);
|
||||
}
|
||||
|
||||
public static void prints(params object[] what)
|
||||
{
|
||||
NativeCalls.godot_icall_Godot_prints(what);
|
||||
}
|
||||
|
||||
public static void printt(params object[] what)
|
||||
{
|
||||
NativeCalls.godot_icall_Godot_printt(what);
|
||||
}
|
||||
|
||||
public static int[] range(int length)
|
||||
{
|
||||
int[] ret = new int[length];
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
ret[i] = i;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int[] range(int from, int to)
|
||||
{
|
||||
if (to < from)
|
||||
return new int[0];
|
||||
|
||||
int[] ret = new int[to - from];
|
||||
|
||||
for (int i = from; i < to; i++)
|
||||
{
|
||||
ret[i - from] = i;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int[] range(int from, int to, int increment)
|
||||
{
|
||||
if (to < from && increment > 0)
|
||||
return new int[0];
|
||||
if (to > from && increment < 0)
|
||||
return new int[0];
|
||||
|
||||
// Calculate count
|
||||
int count = 0;
|
||||
|
||||
if (increment > 0)
|
||||
count = ((to - from - 1) / increment) + 1;
|
||||
else
|
||||
count = ((from - to - 1) / -increment) + 1;
|
||||
|
||||
int[] ret = new int[count];
|
||||
|
||||
if (increment > 0)
|
||||
{
|
||||
int idx = 0;
|
||||
for (int i = from; i < to; i += increment)
|
||||
{
|
||||
ret[idx++] = i;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int idx = 0;
|
||||
for (int i = from; i > to; i += increment)
|
||||
{
|
||||
ret[idx++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static void seed(int seed)
|
||||
{
|
||||
NativeCalls.godot_icall_Godot_seed(seed);
|
||||
}
|
||||
|
||||
public static string str(params object[] what)
|
||||
{
|
||||
return NativeCalls.godot_icall_Godot_str(what);
|
||||
}
|
||||
|
||||
public static object str2var(string str)
|
||||
{
|
||||
return NativeCalls.godot_icall_Godot_str2var(str);
|
||||
}
|
||||
|
||||
public static bool type_exists(string type)
|
||||
{
|
||||
return NativeCalls.godot_icall_Godot_type_exists(type);
|
||||
}
|
||||
|
||||
public static byte[] var2bytes(object var)
|
||||
{
|
||||
return NativeCalls.godot_icall_Godot_var2bytes(var);
|
||||
}
|
||||
|
||||
public static string var2str(object var)
|
||||
{
|
||||
return NativeCalls.godot_icall_Godot_var2str(var);
|
||||
}
|
||||
|
||||
public static WeakRef weakref(Object obj)
|
||||
{
|
||||
return NativeCalls.godot_icall_Godot_weakref(Object.GetPtr(obj));
|
||||
}
|
||||
}
|
||||
}
|
17
modules/mono/glue/cs_files/GodotMethodAttribute.cs
Normal file
17
modules/mono/glue/cs_files/GodotMethodAttribute.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method, Inherited = true)]
|
||||
internal class GodotMethodAttribute : Attribute
|
||||
{
|
||||
private string methodName;
|
||||
|
||||
public string MethodName { get { return methodName; } }
|
||||
|
||||
public GodotMethodAttribute(string methodName)
|
||||
{
|
||||
this.methodName = methodName;
|
||||
}
|
||||
}
|
||||
}
|
26
modules/mono/glue/cs_files/GodotSynchronizationContext.cs
Normal file
26
modules/mono/glue/cs_files/GodotSynchronizationContext.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
public class GodotSynchronizationContext : SynchronizationContext
|
||||
{
|
||||
private readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> queue = new BlockingCollection<KeyValuePair<SendOrPostCallback, object>>();
|
||||
|
||||
public override void Post(SendOrPostCallback d, object state)
|
||||
{
|
||||
queue.Add(new KeyValuePair<SendOrPostCallback, object>(d, state));
|
||||
}
|
||||
|
||||
public void ExecutePendingContinuations()
|
||||
{
|
||||
KeyValuePair<SendOrPostCallback, object> workItem;
|
||||
while (queue.TryTake(out workItem))
|
||||
{
|
||||
workItem.Key(workItem.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
94
modules/mono/glue/cs_files/GodotTaskScheduler.cs
Normal file
94
modules/mono/glue/cs_files/GodotTaskScheduler.cs
Normal file
@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
public class GodotTaskScheduler : TaskScheduler
|
||||
{
|
||||
private GodotSynchronizationContext Context { get; set; }
|
||||
private readonly LinkedList<Task> _tasks = new LinkedList<Task>();
|
||||
|
||||
public GodotTaskScheduler()
|
||||
{
|
||||
Context = new GodotSynchronizationContext();
|
||||
}
|
||||
|
||||
protected sealed override void QueueTask(Task task)
|
||||
{
|
||||
lock (_tasks)
|
||||
{
|
||||
_tasks.AddLast(task);
|
||||
}
|
||||
}
|
||||
|
||||
protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
|
||||
{
|
||||
if (SynchronizationContext.Current != Context)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (taskWasPreviouslyQueued)
|
||||
{
|
||||
TryDequeue(task);
|
||||
}
|
||||
|
||||
return base.TryExecuteTask(task);
|
||||
}
|
||||
|
||||
protected sealed override bool TryDequeue(Task task)
|
||||
{
|
||||
lock (_tasks)
|
||||
{
|
||||
return _tasks.Remove(task);
|
||||
}
|
||||
}
|
||||
|
||||
protected sealed override IEnumerable<Task> GetScheduledTasks()
|
||||
{
|
||||
lock (_tasks)
|
||||
{
|
||||
return _tasks.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public void Activate()
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(Context);
|
||||
ExecuteQueuedTasks();
|
||||
Context.ExecutePendingContinuations();
|
||||
}
|
||||
|
||||
private void ExecuteQueuedTasks()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Task task;
|
||||
|
||||
lock (_tasks)
|
||||
{
|
||||
if (_tasks.Any())
|
||||
{
|
||||
task = _tasks.First.Value;
|
||||
_tasks.RemoveFirst();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (task != null)
|
||||
{
|
||||
if (!TryExecuteTask(task))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
modules/mono/glue/cs_files/IAwaitable.cs
Normal file
12
modules/mono/glue/cs_files/IAwaitable.cs
Normal file
@ -0,0 +1,12 @@
|
||||
namespace Godot
|
||||
{
|
||||
public interface IAwaitable
|
||||
{
|
||||
IAwaiter GetAwaiter();
|
||||
}
|
||||
|
||||
public interface IAwaitable<out TResult>
|
||||
{
|
||||
IAwaiter<TResult> GetAwaiter();
|
||||
}
|
||||
}
|
19
modules/mono/glue/cs_files/IAwaiter.cs
Normal file
19
modules/mono/glue/cs_files/IAwaiter.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
public interface IAwaiter : INotifyCompletion
|
||||
{
|
||||
bool IsCompleted { get; }
|
||||
|
||||
void GetResult();
|
||||
}
|
||||
|
||||
public interface IAwaiter<out TResult> : INotifyCompletion
|
||||
{
|
||||
bool IsCompleted { get; }
|
||||
|
||||
TResult GetResult();
|
||||
}
|
||||
}
|
36
modules/mono/glue/cs_files/MarshalUtils.cs
Normal file
36
modules/mono/glue/cs_files/MarshalUtils.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
internal static class MarshalUtils
|
||||
{
|
||||
private static Dictionary<object, object> ArraysToDictionary(object[] keys, object[] values)
|
||||
{
|
||||
Dictionary<object, object> ret = new Dictionary<object, object>();
|
||||
|
||||
for (int i = 0; i < keys.Length; i++)
|
||||
{
|
||||
ret.Add(keys[i], values[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static void DictionaryToArrays(Dictionary<object, object> from, out object[] keysTo, out object[] valuesTo)
|
||||
{
|
||||
Dictionary<object, object>.KeyCollection keys = from.Keys;
|
||||
keysTo = new object[keys.Count];
|
||||
keys.CopyTo(keysTo, 0);
|
||||
|
||||
Dictionary<object, object>.ValueCollection values = from.Values;
|
||||
valuesTo = new object[values.Count];
|
||||
values.CopyTo(valuesTo, 0);
|
||||
}
|
||||
|
||||
private static Type GetDictionaryType()
|
||||
{
|
||||
return typeof(Dictionary<object, object>);
|
||||
}
|
||||
}
|
||||
}
|
234
modules/mono/glue/cs_files/Mathf.cs
Normal file
234
modules/mono/glue/cs_files/Mathf.cs
Normal file
@ -0,0 +1,234 @@
|
||||
using System;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
public static class Mathf
|
||||
{
|
||||
public const float PI = 3.14159274f;
|
||||
public const float Epsilon = 1e-06f;
|
||||
|
||||
private const float Deg2RadConst = 0.0174532924f;
|
||||
private const float Rad2DegConst = 57.29578f;
|
||||
|
||||
public static float abs(float s)
|
||||
{
|
||||
return Math.Abs(s);
|
||||
}
|
||||
|
||||
public static float acos(float s)
|
||||
{
|
||||
return (float)Math.Acos(s);
|
||||
}
|
||||
|
||||
public static float asin(float s)
|
||||
{
|
||||
return (float)Math.Asin(s);
|
||||
}
|
||||
|
||||
public static float atan(float s)
|
||||
{
|
||||
return (float)Math.Atan(s);
|
||||
}
|
||||
|
||||
public static float atan2(float x, float y)
|
||||
{
|
||||
return (float)Math.Atan2(x, y);
|
||||
}
|
||||
|
||||
public static float ceil(float s)
|
||||
{
|
||||
return (float)Math.Ceiling(s);
|
||||
}
|
||||
|
||||
public static float clamp(float val, float min, float max)
|
||||
{
|
||||
if (val < min)
|
||||
{
|
||||
return min;
|
||||
}
|
||||
else if (val > max)
|
||||
{
|
||||
return max;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
public static float cos(float s)
|
||||
{
|
||||
return (float)Math.Cos(s);
|
||||
}
|
||||
|
||||
public static float cosh(float s)
|
||||
{
|
||||
return (float)Math.Cosh(s);
|
||||
}
|
||||
|
||||
public static int decimals(float step)
|
||||
{
|
||||
return decimals(step);
|
||||
}
|
||||
|
||||
public static int decimals(decimal step)
|
||||
{
|
||||
return BitConverter.GetBytes(decimal.GetBits(step)[3])[2];
|
||||
}
|
||||
|
||||
public static float deg2rad(float deg)
|
||||
{
|
||||
return deg * Deg2RadConst;
|
||||
}
|
||||
|
||||
public static float ease(float s, float curve)
|
||||
{
|
||||
if (s < 0f)
|
||||
{
|
||||
s = 0f;
|
||||
}
|
||||
else if (s > 1.0f)
|
||||
{
|
||||
s = 1.0f;
|
||||
}
|
||||
|
||||
if (curve > 0f)
|
||||
{
|
||||
if (curve < 1.0f)
|
||||
{
|
||||
return 1.0f - pow(1.0f - s, 1.0f / curve);
|
||||
}
|
||||
|
||||
return pow(s, curve);
|
||||
}
|
||||
else if (curve < 0f)
|
||||
{
|
||||
if (s < 0.5f)
|
||||
{
|
||||
return pow(s * 2.0f, -curve) * 0.5f;
|
||||
}
|
||||
|
||||
return (1.0f - pow(1.0f - (s - 0.5f) * 2.0f, -curve)) * 0.5f + 0.5f;
|
||||
}
|
||||
|
||||
return 0f;
|
||||
}
|
||||
|
||||
public static float exp(float s)
|
||||
{
|
||||
return (float)Math.Exp(s);
|
||||
}
|
||||
|
||||
public static float floor(float s)
|
||||
{
|
||||
return (float)Math.Floor(s);
|
||||
}
|
||||
|
||||
public static float fposmod(float x, float y)
|
||||
{
|
||||
if (x >= 0f)
|
||||
{
|
||||
return x % y;
|
||||
}
|
||||
else
|
||||
{
|
||||
return y - (-x % y);
|
||||
}
|
||||
}
|
||||
|
||||
public static float lerp(float from, float to, float weight)
|
||||
{
|
||||
return from + (to - from) * clamp(weight, 0f, 1f);
|
||||
}
|
||||
|
||||
public static float log(float s)
|
||||
{
|
||||
return (float)Math.Log(s);
|
||||
}
|
||||
|
||||
public static int max(int a, int b)
|
||||
{
|
||||
return (a > b) ? a : b;
|
||||
}
|
||||
|
||||
public static float max(float a, float b)
|
||||
{
|
||||
return (a > b) ? a : b;
|
||||
}
|
||||
|
||||
public static int min(int a, int b)
|
||||
{
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
public static float min(float a, float b)
|
||||
{
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
public static int nearest_po2(int val)
|
||||
{
|
||||
val--;
|
||||
val |= val >> 1;
|
||||
val |= val >> 2;
|
||||
val |= val >> 4;
|
||||
val |= val >> 8;
|
||||
val |= val >> 16;
|
||||
val++;
|
||||
return val;
|
||||
}
|
||||
|
||||
public static float pow(float x, float y)
|
||||
{
|
||||
return (float)Math.Pow(x, y);
|
||||
}
|
||||
|
||||
public static float rad2deg(float rad)
|
||||
{
|
||||
return rad * Rad2DegConst;
|
||||
}
|
||||
|
||||
public static float round(float s)
|
||||
{
|
||||
return (float)Math.Round(s);
|
||||
}
|
||||
|
||||
public static float sign(float s)
|
||||
{
|
||||
return (s < 0f) ? -1f : 1f;
|
||||
}
|
||||
|
||||
public static float sin(float s)
|
||||
{
|
||||
return (float)Math.Sin(s);
|
||||
}
|
||||
|
||||
public static float sinh(float s)
|
||||
{
|
||||
return (float)Math.Sinh(s);
|
||||
}
|
||||
|
||||
public static float sqrt(float s)
|
||||
{
|
||||
return (float)Math.Sqrt(s);
|
||||
}
|
||||
|
||||
public static float stepify(float s, float step)
|
||||
{
|
||||
if (step != 0f)
|
||||
{
|
||||
s = floor(s / step + 0.5f) * step;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public static float tan(float s)
|
||||
{
|
||||
return (float)Math.Tan(s);
|
||||
}
|
||||
|
||||
public static float tanh(float s)
|
||||
{
|
||||
return (float)Math.Tanh(s);
|
||||
}
|
||||
}
|
||||
}
|
209
modules/mono/glue/cs_files/Plane.cs
Normal file
209
modules/mono/glue/cs_files/Plane.cs
Normal file
@ -0,0 +1,209 @@
|
||||
using System;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
public struct Plane : IEquatable<Plane>
|
||||
{
|
||||
Vector3 normal;
|
||||
|
||||
public float x
|
||||
{
|
||||
get
|
||||
{
|
||||
return normal.x;
|
||||
}
|
||||
set
|
||||
{
|
||||
normal.x = value;
|
||||
}
|
||||
}
|
||||
|
||||
public float y
|
||||
{
|
||||
get
|
||||
{
|
||||
return normal.y;
|
||||
}
|
||||
set
|
||||
{
|
||||
normal.y = value;
|
||||
}
|
||||
}
|
||||
|
||||
public float z
|
||||
{
|
||||
get
|
||||
{
|
||||
return normal.z;
|
||||
}
|
||||
set
|
||||
{
|
||||
normal.z = value;
|
||||
}
|
||||
}
|
||||
|
||||
float d;
|
||||
|
||||
public Vector3 Center
|
||||
{
|
||||
get
|
||||
{
|
||||
return normal * d;
|
||||
}
|
||||
}
|
||||
|
||||
public float distance_to(Vector3 point)
|
||||
{
|
||||
return normal.dot(point) - d;
|
||||
}
|
||||
|
||||
public Vector3 get_any_point()
|
||||
{
|
||||
return normal * d;
|
||||
}
|
||||
|
||||
public bool has_point(Vector3 point, float epsilon = Mathf.Epsilon)
|
||||
{
|
||||
float dist = normal.dot(point) - d;
|
||||
return Mathf.abs(dist) <= epsilon;
|
||||
}
|
||||
|
||||
public Vector3 intersect_3(Plane b, Plane c)
|
||||
{
|
||||
float denom = normal.cross(b.normal).dot(c.normal);
|
||||
|
||||
if (Mathf.abs(denom) <= Mathf.Epsilon)
|
||||
return new Vector3();
|
||||
|
||||
Vector3 result = (b.normal.cross(c.normal) * this.d) +
|
||||
(c.normal.cross(normal) * b.d) +
|
||||
(normal.cross(b.normal) * c.d);
|
||||
|
||||
return result / denom;
|
||||
}
|
||||
|
||||
public Vector3 intersect_ray(Vector3 from, Vector3 dir)
|
||||
{
|
||||
float den = normal.dot(dir);
|
||||
|
||||
if (Mathf.abs(den) <= Mathf.Epsilon)
|
||||
return new Vector3();
|
||||
|
||||
float dist = (normal.dot(from) - d) / den;
|
||||
|
||||
// This is a ray, before the emiting pos (from) does not exist
|
||||
if (dist > Mathf.Epsilon)
|
||||
return new Vector3();
|
||||
|
||||
return from + dir * -dist;
|
||||
}
|
||||
|
||||
public Vector3 intersect_segment(Vector3 begin, Vector3 end)
|
||||
{
|
||||
Vector3 segment = begin - end;
|
||||
float den = normal.dot(segment);
|
||||
|
||||
if (Mathf.abs(den) <= Mathf.Epsilon)
|
||||
return new Vector3();
|
||||
|
||||
float dist = (normal.dot(begin) - d) / den;
|
||||
|
||||
if (dist < -Mathf.Epsilon || dist > (1.0f + Mathf.Epsilon))
|
||||
return new Vector3();
|
||||
|
||||
return begin + segment * -dist;
|
||||
}
|
||||
|
||||
public bool is_point_over(Vector3 point)
|
||||
{
|
||||
return normal.dot(point) > d;
|
||||
}
|
||||
|
||||
public Plane normalized()
|
||||
{
|
||||
float len = normal.length();
|
||||
|
||||
if (len == 0)
|
||||
return new Plane(0, 0, 0, 0);
|
||||
|
||||
return new Plane(normal / len, d / len);
|
||||
}
|
||||
|
||||
public Vector3 project(Vector3 point)
|
||||
{
|
||||
return point - normal * distance_to(point);
|
||||
}
|
||||
|
||||
public Plane(float a, float b, float c, float d)
|
||||
{
|
||||
normal = new Vector3(a, b, c);
|
||||
this.d = d;
|
||||
}
|
||||
|
||||
public Plane(Vector3 normal, float d)
|
||||
{
|
||||
this.normal = normal;
|
||||
this.d = d;
|
||||
}
|
||||
|
||||
public Plane(Vector3 v1, Vector3 v2, Vector3 v3)
|
||||
{
|
||||
normal = (v1 - v3).cross(v1 - v2);
|
||||
normal.normalize();
|
||||
d = normal.dot(v1);
|
||||
}
|
||||
|
||||
public static Plane operator -(Plane plane)
|
||||
{
|
||||
return new Plane(-plane.normal, -plane.d);
|
||||
}
|
||||
|
||||
public static bool operator ==(Plane left, Plane right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Plane left, Plane right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Plane)
|
||||
{
|
||||
return Equals((Plane)obj);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Equals(Plane other)
|
||||
{
|
||||
return normal == other.normal && d == other.d;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return normal.GetHashCode() ^ d.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("({0}, {1})", new object[]
|
||||
{
|
||||
this.normal.ToString(),
|
||||
this.d.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
public string ToString(string format)
|
||||
{
|
||||
return String.Format("({0}, {1})", new object[]
|
||||
{
|
||||
this.normal.ToString(format),
|
||||
this.d.ToString(format)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
328
modules/mono/glue/cs_files/Quat.cs
Normal file
328
modules/mono/glue/cs_files/Quat.cs
Normal file
@ -0,0 +1,328 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Quat : IEquatable<Quat>
|
||||
{
|
||||
private static readonly Quat identity = new Quat(0f, 0f, 0f, 1f);
|
||||
|
||||
public float x;
|
||||
public float y;
|
||||
public float z;
|
||||
public float w;
|
||||
|
||||
public static Quat Identity
|
||||
{
|
||||
get { return identity; }
|
||||
}
|
||||
|
||||
public float this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return x;
|
||||
case 1:
|
||||
return y;
|
||||
case 2:
|
||||
return z;
|
||||
case 3:
|
||||
return w;
|
||||
default:
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
x = value;
|
||||
break;
|
||||
case 1:
|
||||
y = value;
|
||||
break;
|
||||
case 2:
|
||||
z = value;
|
||||
break;
|
||||
case 3:
|
||||
w = value;
|
||||
break;
|
||||
default:
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Quat cubic_slerp(Quat b, Quat preA, Quat postB, float t)
|
||||
{
|
||||
float t2 = (1.0f - t) * t * 2f;
|
||||
Quat sp = slerp(b, t);
|
||||
Quat sq = preA.slerpni(postB, t);
|
||||
return sp.slerpni(sq, t2);
|
||||
}
|
||||
|
||||
public float dot(Quat b)
|
||||
{
|
||||
return x * b.x + y * b.y + z * b.z + w * b.w;
|
||||
}
|
||||
|
||||
public Quat inverse()
|
||||
{
|
||||
return new Quat(-x, -y, -z, w);
|
||||
}
|
||||
|
||||
public float length()
|
||||
{
|
||||
return Mathf.sqrt(length_squared());
|
||||
}
|
||||
|
||||
public float length_squared()
|
||||
{
|
||||
return dot(this);
|
||||
}
|
||||
|
||||
public Quat normalized()
|
||||
{
|
||||
return this / length();
|
||||
}
|
||||
|
||||
public void set(float x, float y, float z, float w)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.w = w;
|
||||
}
|
||||
|
||||
public Quat slerp(Quat b, float t)
|
||||
{
|
||||
// Calculate cosine
|
||||
float cosom = x * b.x + y * b.y + z * b.z + w * b.w;
|
||||
|
||||
float[] to1 = new float[4];
|
||||
|
||||
// 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;
|
||||
}
|
||||
else
|
||||
{
|
||||
to1[0] = b.x;
|
||||
to1[1] = b.y;
|
||||
to1[2] = b.z;
|
||||
to1[3] = b.w;
|
||||
}
|
||||
|
||||
float sinom, scale0, scale1;
|
||||
|
||||
// Calculate coefficients
|
||||
if ((1.0 - cosom) > Mathf.Epsilon)
|
||||
{
|
||||
// Standard case (Slerp)
|
||||
float omega = Mathf.acos(cosom);
|
||||
sinom = Mathf.sin(omega);
|
||||
scale0 = Mathf.sin((1.0f - t) * omega) / sinom;
|
||||
scale1 = Mathf.sin(t * omega) / sinom;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Quaternions are very close so we can do a linear interpolation
|
||||
scale0 = 1.0f - t;
|
||||
scale1 = t;
|
||||
}
|
||||
|
||||
// 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]
|
||||
);
|
||||
}
|
||||
|
||||
public Quat slerpni(Quat b, float t)
|
||||
{
|
||||
float dot = this.dot(b);
|
||||
|
||||
if (Mathf.abs(dot) > 0.9999f)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
float theta = Mathf.acos(dot);
|
||||
float sinT = 1.0f / Mathf.sin(theta);
|
||||
float newFactor = Mathf.sin(t * theta) * sinT;
|
||||
float invFactor = Mathf.sin((1.0f - t) * theta) * sinT;
|
||||
|
||||
return new Quat
|
||||
(
|
||||
invFactor * this.x + newFactor * b.x,
|
||||
invFactor * this.y + newFactor * b.y,
|
||||
invFactor * this.z + newFactor * b.z,
|
||||
invFactor * this.w + newFactor * b.w
|
||||
);
|
||||
}
|
||||
|
||||
public Vector3 xform(Vector3 v)
|
||||
{
|
||||
Quat q = this * v;
|
||||
q *= this.inverse();
|
||||
return new Vector3(q.x, q.y, q.z);
|
||||
}
|
||||
|
||||
public Quat(float x, float y, float z, float w)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.w = w;
|
||||
}
|
||||
|
||||
public Quat(Vector3 axis, float angle)
|
||||
{
|
||||
float d = axis.length();
|
||||
|
||||
if (d == 0f)
|
||||
{
|
||||
x = 0f;
|
||||
y = 0f;
|
||||
z = 0f;
|
||||
w = 0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
float s = Mathf.sin(-angle * 0.5f) / d;
|
||||
|
||||
x = axis.x * s;
|
||||
y = axis.y * s;
|
||||
z = axis.z * s;
|
||||
w = Mathf.cos(-angle * 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
public static Quat operator *(Quat left, Quat right)
|
||||
{
|
||||
return new Quat
|
||||
(
|
||||
left.w * right.x + left.x * right.w + left.y * right.z - left.z * right.y,
|
||||
left.w * right.y + left.y * right.w + left.z * right.x - left.x * right.z,
|
||||
left.w * right.z + left.z * right.w + left.x * right.y - left.y * right.x,
|
||||
left.w * right.w - left.x * right.x - left.y * right.y - left.z * right.z
|
||||
);
|
||||
}
|
||||
|
||||
public static Quat operator +(Quat left, Quat right)
|
||||
{
|
||||
return new Quat(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w);
|
||||
}
|
||||
|
||||
public static Quat operator -(Quat left, Quat right)
|
||||
{
|
||||
return new Quat(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w);
|
||||
}
|
||||
|
||||
public static Quat operator -(Quat left)
|
||||
{
|
||||
return new Quat(-left.x, -left.y, -left.z, -left.w);
|
||||
}
|
||||
|
||||
public static Quat operator *(Quat left, Vector3 right)
|
||||
{
|
||||
return new Quat
|
||||
(
|
||||
left.w * right.x + left.y * right.z - left.z * right.y,
|
||||
left.w * right.y + left.z * right.x - left.x * right.z,
|
||||
left.w * right.z + left.x * right.y - left.y * right.x,
|
||||
-left.x * right.x - left.y * right.y - left.z * right.z
|
||||
);
|
||||
}
|
||||
|
||||
public static Quat operator *(Vector3 left, Quat right)
|
||||
{
|
||||
return new Quat
|
||||
(
|
||||
right.w * left.x + right.y * left.z - right.z * left.y,
|
||||
right.w * left.y + right.z * left.x - right.x * left.z,
|
||||
right.w * left.z + right.x * left.y - right.y * left.x,
|
||||
-right.x * left.x - right.y * left.y - right.z * left.z
|
||||
);
|
||||
}
|
||||
|
||||
public static Quat operator *(Quat left, float right)
|
||||
{
|
||||
return new Quat(left.x * right, left.y * right, left.z * right, left.w * right);
|
||||
}
|
||||
|
||||
public static Quat operator *(float left, Quat right)
|
||||
{
|
||||
return new Quat(right.x * left, right.y * left, right.z * left, right.w * left);
|
||||
}
|
||||
|
||||
public static Quat operator /(Quat left, float right)
|
||||
{
|
||||
return left * (1.0f / right);
|
||||
}
|
||||
|
||||
public static bool operator ==(Quat left, Quat right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Quat left, Quat right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Vector2)
|
||||
{
|
||||
return Equals((Vector2)obj);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Equals(Quat other)
|
||||
{
|
||||
return x == other.x && y == other.y && z == other.z && w == other.w;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("({0}, {1}, {2}, {3})", new object[]
|
||||
{
|
||||
this.x.ToString(),
|
||||
this.y.ToString(),
|
||||
this.z.ToString(),
|
||||
this.w.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
public string ToString(string format)
|
||||
{
|
||||
return String.Format("({0}, {1}, {2}, {3})", new object[]
|
||||
{
|
||||
this.x.ToString(format),
|
||||
this.y.ToString(format),
|
||||
this.z.ToString(format),
|
||||
this.w.ToString(format)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
16
modules/mono/glue/cs_files/RPCAttributes.cs
Normal file
16
modules/mono/glue/cs_files/RPCAttributes.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)]
|
||||
public class RemoteAttribute : Attribute {}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)]
|
||||
public class SyncAttribute : Attribute {}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)]
|
||||
public class MasterAttribute : Attribute {}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)]
|
||||
public class SlaveAttribute : Attribute {}
|
||||
}
|
233
modules/mono/glue/cs_files/Rect2.cs
Normal file
233
modules/mono/glue/cs_files/Rect2.cs
Normal file
@ -0,0 +1,233 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Rect2 : IEquatable<Rect2>
|
||||
{
|
||||
private Vector2 position;
|
||||
private Vector2 size;
|
||||
|
||||
public Vector2 Position
|
||||
{
|
||||
get { return position; }
|
||||
set { position = value; }
|
||||
}
|
||||
|
||||
public Vector2 Size
|
||||
{
|
||||
get { return size; }
|
||||
set { size = value; }
|
||||
}
|
||||
|
||||
public Vector2 End
|
||||
{
|
||||
get { return position + size; }
|
||||
}
|
||||
|
||||
public float Area
|
||||
{
|
||||
get { return get_area(); }
|
||||
}
|
||||
|
||||
public Rect2 clip(Rect2 b)
|
||||
{
|
||||
Rect2 newRect = b;
|
||||
|
||||
if (!intersects(newRect))
|
||||
return new Rect2();
|
||||
|
||||
newRect.position.x = Mathf.max(b.position.x, position.x);
|
||||
newRect.position.y = Mathf.max(b.position.y, position.y);
|
||||
|
||||
Vector2 bEnd = b.position + b.size;
|
||||
Vector2 end = position + size;
|
||||
|
||||
newRect.size.x = Mathf.min(bEnd.x, end.x) - newRect.position.x;
|
||||
newRect.size.y = Mathf.min(bEnd.y, end.y) - newRect.position.y;
|
||||
|
||||
return newRect;
|
||||
}
|
||||
|
||||
public bool encloses(Rect2 b)
|
||||
{
|
||||
return (b.position.x >= position.x) && (b.position.y >= position.y) &&
|
||||
((b.position.x + b.size.x) < (position.x + size.x)) &&
|
||||
((b.position.y + b.size.y) < (position.y + size.y));
|
||||
}
|
||||
|
||||
public Rect2 expand(Vector2 to)
|
||||
{
|
||||
Rect2 expanded = this;
|
||||
|
||||
Vector2 begin = expanded.position;
|
||||
Vector2 end = expanded.position + expanded.size;
|
||||
|
||||
if (to.x < begin.x)
|
||||
begin.x = to.x;
|
||||
if (to.y < begin.y)
|
||||
begin.y = to.y;
|
||||
|
||||
if (to.x > end.x)
|
||||
end.x = to.x;
|
||||
if (to.y > end.y)
|
||||
end.y = to.y;
|
||||
|
||||
expanded.position = begin;
|
||||
expanded.size = end - begin;
|
||||
|
||||
return expanded;
|
||||
}
|
||||
|
||||
public float get_area()
|
||||
{
|
||||
return size.x * size.y;
|
||||
}
|
||||
|
||||
public Rect2 grow(float by)
|
||||
{
|
||||
Rect2 g = this;
|
||||
|
||||
g.position.x -= by;
|
||||
g.position.y -= by;
|
||||
g.size.x += by * 2;
|
||||
g.size.y += by * 2;
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
public Rect2 grow_individual(float left, float top, float right, float bottom)
|
||||
{
|
||||
Rect2 g = this;
|
||||
|
||||
g.position.x -= left;
|
||||
g.position.y -= top;
|
||||
g.size.x += left + right;
|
||||
g.size.y += top + bottom;
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
public Rect2 grow_margin(int margin, float by)
|
||||
{
|
||||
Rect2 g = this;
|
||||
|
||||
g.grow_individual((GD.MARGIN_LEFT == margin) ? by : 0,
|
||||
(GD.MARGIN_TOP == margin) ? by : 0,
|
||||
(GD.MARGIN_RIGHT == margin) ? by : 0,
|
||||
(GD.MARGIN_BOTTOM == margin) ? by : 0);
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
public bool has_no_area()
|
||||
{
|
||||
return size.x <= 0 || size.y <= 0;
|
||||
}
|
||||
|
||||
public bool has_point(Vector2 point)
|
||||
{
|
||||
if (point.x < position.x)
|
||||
return false;
|
||||
if (point.y < position.y)
|
||||
return false;
|
||||
|
||||
if (point.x >= (position.x + size.x))
|
||||
return false;
|
||||
if (point.y >= (position.y + size.y))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool intersects(Rect2 b)
|
||||
{
|
||||
if (position.x > (b.position.x + b.size.x))
|
||||
return false;
|
||||
if ((position.x + size.x) < b.position.x)
|
||||
return false;
|
||||
if (position.y > (b.position.y + b.size.y))
|
||||
return false;
|
||||
if ((position.y + size.y) < b.position.y)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Rect2 merge(Rect2 b)
|
||||
{
|
||||
Rect2 newRect;
|
||||
|
||||
newRect.position.x = Mathf.min(b.position.x, position.x);
|
||||
newRect.position.y = Mathf.min(b.position.y, position.y);
|
||||
|
||||
newRect.size.x = Mathf.max(b.position.x + b.size.x, position.x + size.x);
|
||||
newRect.size.y = Mathf.max(b.position.y + b.size.y, position.y + size.y);
|
||||
|
||||
newRect.size = newRect.size - newRect.position; // Make relative again
|
||||
|
||||
return newRect;
|
||||
}
|
||||
|
||||
public Rect2(Vector2 position, Vector2 size)
|
||||
{
|
||||
this.position = position;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public Rect2(float x, float y, float width, float height)
|
||||
{
|
||||
this.position = new Vector2(x, y);
|
||||
this.size = new Vector2(width, height);
|
||||
}
|
||||
|
||||
public static bool operator ==(Rect2 left, Rect2 right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Rect2 left, Rect2 right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Rect2)
|
||||
{
|
||||
return Equals((Rect2)obj);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Equals(Rect2 other)
|
||||
{
|
||||
return position.Equals(other.position) && size.Equals(other.size);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return position.GetHashCode() ^ size.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("({0}, {1})", new object[]
|
||||
{
|
||||
this.position.ToString(),
|
||||
this.size.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
public string ToString(string format)
|
||||
{
|
||||
return String.Format("({0}, {1})", new object[]
|
||||
{
|
||||
this.position.ToString(format),
|
||||
this.size.ToString(format)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
477
modules/mono/glue/cs_files/Rect3.cs
Normal file
477
modules/mono/glue/cs_files/Rect3.cs
Normal file
@ -0,0 +1,477 @@
|
||||
using System;
|
||||
|
||||
// file: core/math/rect3.h
|
||||
// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451
|
||||
// file: core/math/rect3.cpp
|
||||
// commit: bd282ff43f23fe845f29a3e25c8efc01bd65ffb0
|
||||
// file: core/variant_call.cpp
|
||||
// commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
public struct Rect3 : IEquatable<Rect3>
|
||||
{
|
||||
private Vector3 position;
|
||||
private Vector3 size;
|
||||
|
||||
public Vector3 Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 Size
|
||||
{
|
||||
get
|
||||
{
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 End
|
||||
{
|
||||
get
|
||||
{
|
||||
return position + size;
|
||||
}
|
||||
}
|
||||
|
||||
public bool encloses(Rect3 with)
|
||||
{
|
||||
Vector3 src_min = position;
|
||||
Vector3 src_max = position + size;
|
||||
Vector3 dst_min = with.position;
|
||||
Vector3 dst_max = with.position + with.size;
|
||||
|
||||
return ((src_min.x <= dst_min.x) &&
|
||||
(src_max.x > dst_max.x) &&
|
||||
(src_min.y <= dst_min.y) &&
|
||||
(src_max.y > dst_max.y) &&
|
||||
(src_min.z <= dst_min.z) &&
|
||||
(src_max.z > dst_max.z));
|
||||
}
|
||||
|
||||
public Rect3 expand(Vector3 to_point)
|
||||
{
|
||||
Vector3 begin = position;
|
||||
Vector3 end = position + size;
|
||||
|
||||
if (to_point.x < begin.x)
|
||||
begin.x = to_point.x;
|
||||
if (to_point.y < begin.y)
|
||||
begin.y = to_point.y;
|
||||
if (to_point.z < begin.z)
|
||||
begin.z = to_point.z;
|
||||
|
||||
if (to_point.x > end.x)
|
||||
end.x = to_point.x;
|
||||
if (to_point.y > end.y)
|
||||
end.y = to_point.y;
|
||||
if (to_point.z > end.z)
|
||||
end.z = to_point.z;
|
||||
|
||||
return new Rect3(begin, end - begin);
|
||||
}
|
||||
|
||||
public float get_area()
|
||||
{
|
||||
return size.x * size.y * size.z;
|
||||
}
|
||||
|
||||
public Vector3 get_endpoint(int idx)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0:
|
||||
return new Vector3(position.x, position.y, position.z);
|
||||
case 1:
|
||||
return new Vector3(position.x, position.y, position.z + size.z);
|
||||
case 2:
|
||||
return new Vector3(position.x, position.y + size.y, position.z);
|
||||
case 3:
|
||||
return new Vector3(position.x, position.y + size.y, position.z + size.z);
|
||||
case 4:
|
||||
return new Vector3(position.x + size.x, position.y, position.z);
|
||||
case 5:
|
||||
return new Vector3(position.x + size.x, position.y, position.z + size.z);
|
||||
case 6:
|
||||
return new Vector3(position.x + size.x, position.y + size.y, position.z);
|
||||
case 7:
|
||||
return new Vector3(position.x + size.x, position.y + size.y, position.z + size.z);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(idx), String.Format("Index is {0}, but a value from 0 to 7 is expected.", idx));
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 get_longest_axis()
|
||||
{
|
||||
Vector3 axis = new Vector3(1f, 0f, 0f);
|
||||
float max_size = size.x;
|
||||
|
||||
if (size.y > max_size)
|
||||
{
|
||||
axis = new Vector3(0f, 1f, 0f);
|
||||
max_size = size.y;
|
||||
}
|
||||
|
||||
if (size.z > max_size)
|
||||
{
|
||||
axis = new Vector3(0f, 0f, 1f);
|
||||
max_size = size.z;
|
||||
}
|
||||
|
||||
return axis;
|
||||
}
|
||||
|
||||
public Vector3.Axis get_longest_axis_index()
|
||||
{
|
||||
Vector3.Axis axis = Vector3.Axis.X;
|
||||
float max_size = size.x;
|
||||
|
||||
if (size.y > max_size)
|
||||
{
|
||||
axis = Vector3.Axis.Y;
|
||||
max_size = size.y;
|
||||
}
|
||||
|
||||
if (size.z > max_size)
|
||||
{
|
||||
axis = Vector3.Axis.Z;
|
||||
max_size = size.z;
|
||||
}
|
||||
|
||||
return axis;
|
||||
}
|
||||
|
||||
public float get_longest_axis_size()
|
||||
{
|
||||
float max_size = size.x;
|
||||
|
||||
if (size.y > max_size)
|
||||
max_size = size.y;
|
||||
|
||||
if (size.z > max_size)
|
||||
max_size = size.z;
|
||||
|
||||
return max_size;
|
||||
}
|
||||
|
||||
public Vector3 get_shortest_axis()
|
||||
{
|
||||
Vector3 axis = new Vector3(1f, 0f, 0f);
|
||||
float max_size = size.x;
|
||||
|
||||
if (size.y < max_size)
|
||||
{
|
||||
axis = new Vector3(0f, 1f, 0f);
|
||||
max_size = size.y;
|
||||
}
|
||||
|
||||
if (size.z < max_size)
|
||||
{
|
||||
axis = new Vector3(0f, 0f, 1f);
|
||||
max_size = size.z;
|
||||
}
|
||||
|
||||
return axis;
|
||||
}
|
||||
|
||||
public Vector3.Axis get_shortest_axis_index()
|
||||
{
|
||||
Vector3.Axis axis = Vector3.Axis.X;
|
||||
float max_size = size.x;
|
||||
|
||||
if (size.y < max_size)
|
||||
{
|
||||
axis = Vector3.Axis.Y;
|
||||
max_size = size.y;
|
||||
}
|
||||
|
||||
if (size.z < max_size)
|
||||
{
|
||||
axis = Vector3.Axis.Z;
|
||||
max_size = size.z;
|
||||
}
|
||||
|
||||
return axis;
|
||||
}
|
||||
|
||||
public float get_shortest_axis_size()
|
||||
{
|
||||
float max_size = size.x;
|
||||
|
||||
if (size.y < max_size)
|
||||
max_size = size.y;
|
||||
|
||||
if (size.z < max_size)
|
||||
max_size = size.z;
|
||||
|
||||
return max_size;
|
||||
}
|
||||
|
||||
public Vector3 get_support(Vector3 dir)
|
||||
{
|
||||
Vector3 half_extents = size * 0.5f;
|
||||
Vector3 ofs = position + half_extents;
|
||||
|
||||
return ofs + new Vector3(
|
||||
(dir.x > 0f) ? -half_extents.x : half_extents.x,
|
||||
(dir.y > 0f) ? -half_extents.y : half_extents.y,
|
||||
(dir.z > 0f) ? -half_extents.z : half_extents.z);
|
||||
}
|
||||
|
||||
public Rect3 grow(float by)
|
||||
{
|
||||
Rect3 res = this;
|
||||
|
||||
res.position.x -= by;
|
||||
res.position.y -= by;
|
||||
res.position.z -= by;
|
||||
res.size.x += 2.0f * by;
|
||||
res.size.y += 2.0f * by;
|
||||
res.size.z += 2.0f * by;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public bool has_no_area()
|
||||
{
|
||||
return size.x <= 0f || size.y <= 0f || size.z <= 0f;
|
||||
}
|
||||
|
||||
public bool has_no_surface()
|
||||
{
|
||||
return size.x <= 0f && size.y <= 0f && size.z <= 0f;
|
||||
}
|
||||
|
||||
public bool has_point(Vector3 point)
|
||||
{
|
||||
if (point.x < position.x)
|
||||
return false;
|
||||
if (point.y < position.y)
|
||||
return false;
|
||||
if (point.z < position.z)
|
||||
return false;
|
||||
if (point.x > position.x + size.x)
|
||||
return false;
|
||||
if (point.y > position.y + size.y)
|
||||
return false;
|
||||
if (point.z > position.z + size.z)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Rect3 intersection(Rect3 with)
|
||||
{
|
||||
Vector3 src_min = position;
|
||||
Vector3 src_max = position + size;
|
||||
Vector3 dst_min = with.position;
|
||||
Vector3 dst_max = with.position + with.size;
|
||||
|
||||
Vector3 min, max;
|
||||
|
||||
if (src_min.x > dst_max.x || src_max.x < dst_min.x)
|
||||
{
|
||||
return new Rect3();
|
||||
}
|
||||
else
|
||||
{
|
||||
min.x = (src_min.x > dst_min.x) ? src_min.x : dst_min.x;
|
||||
max.x = (src_max.x < dst_max.x) ? src_max.x : dst_max.x;
|
||||
}
|
||||
|
||||
if (src_min.y > dst_max.y || src_max.y < dst_min.y)
|
||||
{
|
||||
return new Rect3();
|
||||
}
|
||||
else
|
||||
{
|
||||
min.y = (src_min.y > dst_min.y) ? src_min.y : dst_min.y;
|
||||
max.y = (src_max.y < dst_max.y) ? src_max.y : dst_max.y;
|
||||
}
|
||||
|
||||
if (src_min.z > dst_max.z || src_max.z < dst_min.z)
|
||||
{
|
||||
return new Rect3();
|
||||
}
|
||||
else
|
||||
{
|
||||
min.z = (src_min.z > dst_min.z) ? src_min.z : dst_min.z;
|
||||
max.z = (src_max.z < dst_max.z) ? src_max.z : dst_max.z;
|
||||
}
|
||||
|
||||
return new Rect3(min, max - min);
|
||||
}
|
||||
|
||||
public bool intersects(Rect3 with)
|
||||
{
|
||||
if (position.x >= (with.position.x + with.size.x))
|
||||
return false;
|
||||
if ((position.x + size.x) <= with.position.x)
|
||||
return false;
|
||||
if (position.y >= (with.position.y + with.size.y))
|
||||
return false;
|
||||
if ((position.y + size.y) <= with.position.y)
|
||||
return false;
|
||||
if (position.z >= (with.position.z + with.size.z))
|
||||
return false;
|
||||
if ((position.z + size.z) <= with.position.z)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool intersects_plane(Plane plane)
|
||||
{
|
||||
Vector3[] points =
|
||||
{
|
||||
new Vector3(position.x, position.y, position.z),
|
||||
new Vector3(position.x, position.y, position.z + size.z),
|
||||
new Vector3(position.x, position.y + size.y, position.z),
|
||||
new Vector3(position.x, position.y + size.y, position.z + size.z),
|
||||
new Vector3(position.x + size.x, position.y, position.z),
|
||||
new Vector3(position.x + size.x, position.y, position.z + size.z),
|
||||
new Vector3(position.x + size.x, position.y + size.y, position.z),
|
||||
new Vector3(position.x + size.x, position.y + size.y, position.z + size.z),
|
||||
};
|
||||
|
||||
bool over = false;
|
||||
bool under = false;
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (plane.distance_to(points[i]) > 0)
|
||||
over = true;
|
||||
else
|
||||
under = true;
|
||||
}
|
||||
|
||||
return under && over;
|
||||
}
|
||||
|
||||
public bool intersects_segment(Vector3 from, Vector3 to)
|
||||
{
|
||||
float min = 0f;
|
||||
float max = 1f;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
float seg_from = from[i];
|
||||
float seg_to = to[i];
|
||||
float box_begin = position[i];
|
||||
float box_end = box_begin + size[i];
|
||||
float cmin, cmax;
|
||||
|
||||
if (seg_from < seg_to)
|
||||
{
|
||||
if (seg_from > box_end || seg_to < box_begin)
|
||||
return false;
|
||||
|
||||
float length = seg_to - seg_from;
|
||||
cmin = seg_from < box_begin ? (box_begin - seg_from) / length : 0f;
|
||||
cmax = seg_to > box_end ? (box_end - seg_from) / length : 1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (seg_to > box_end || seg_from < box_begin)
|
||||
return false;
|
||||
|
||||
float length = seg_to - seg_from;
|
||||
cmin = seg_from > box_end ? (box_end - seg_from) / length : 0f;
|
||||
cmax = seg_to < box_begin ? (box_begin - seg_from) / length : 1f;
|
||||
}
|
||||
|
||||
if (cmin > min)
|
||||
{
|
||||
min = cmin;
|
||||
}
|
||||
|
||||
if (cmax < max)
|
||||
max = cmax;
|
||||
if (max < min)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Rect3 merge(Rect3 with)
|
||||
{
|
||||
Vector3 beg_1 = position;
|
||||
Vector3 beg_2 = with.position;
|
||||
Vector3 end_1 = new Vector3(size.x, size.y, size.z) + beg_1;
|
||||
Vector3 end_2 = new Vector3(with.size.x, with.size.y, with.size.z) + beg_2;
|
||||
|
||||
Vector3 min = new Vector3(
|
||||
(beg_1.x < beg_2.x) ? beg_1.x : beg_2.x,
|
||||
(beg_1.y < beg_2.y) ? beg_1.y : beg_2.y,
|
||||
(beg_1.z < beg_2.z) ? beg_1.z : beg_2.z
|
||||
);
|
||||
|
||||
Vector3 max = new Vector3(
|
||||
(end_1.x > end_2.x) ? end_1.x : end_2.x,
|
||||
(end_1.y > end_2.y) ? end_1.y : end_2.y,
|
||||
(end_1.z > end_2.z) ? end_1.z : end_2.z
|
||||
);
|
||||
|
||||
return new Rect3(min, max - min);
|
||||
}
|
||||
|
||||
public Rect3(Vector3 position, Vector3 size)
|
||||
{
|
||||
this.position = position;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public static bool operator ==(Rect3 left, Rect3 right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Rect3 left, Rect3 right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Rect3)
|
||||
{
|
||||
return Equals((Rect3)obj);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Equals(Rect3 other)
|
||||
{
|
||||
return position == other.position && size == other.size;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return position.GetHashCode() ^ size.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0} - {1}", new object[]
|
||||
{
|
||||
this.position.ToString(),
|
||||
this.size.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
public string ToString(string format)
|
||||
{
|
||||
return String.Format("{0} - {1}", new object[]
|
||||
{
|
||||
this.position.ToString(format),
|
||||
this.size.ToString(format)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
59
modules/mono/glue/cs_files/SignalAwaiter.cs
Normal file
59
modules/mono/glue/cs_files/SignalAwaiter.cs
Normal file
@ -0,0 +1,59 @@
|
||||
using System;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
public class SignalAwaiter : IAwaiter<object[]>, IAwaitable<object[]>
|
||||
{
|
||||
private bool completed = false;
|
||||
private object[] result = null;
|
||||
private Action action = null;
|
||||
|
||||
public SignalAwaiter(Godot.Object source, string signal, Godot.Object target)
|
||||
{
|
||||
NativeCalls.godot_icall_Object_connect_signal_awaiter(
|
||||
Godot.Object.GetPtr(source),
|
||||
signal, Godot.Object.GetPtr(target), this
|
||||
);
|
||||
}
|
||||
|
||||
public bool IsCompleted
|
||||
{
|
||||
get
|
||||
{
|
||||
return completed;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnCompleted(Action action)
|
||||
{
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public object[] GetResult()
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
public IAwaiter<object[]> GetAwaiter()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
internal void SignalCallback(object[] args)
|
||||
{
|
||||
completed = true;
|
||||
result = args;
|
||||
|
||||
if (action != null)
|
||||
{
|
||||
action();
|
||||
}
|
||||
}
|
||||
|
||||
internal void FailureCallback()
|
||||
{
|
||||
action = null;
|
||||
completed = true;
|
||||
}
|
||||
}
|
||||
}
|
962
modules/mono/glue/cs_files/StringExtensions.cs
Normal file
962
modules/mono/glue/cs_files/StringExtensions.cs
Normal file
@ -0,0 +1,962 @@
|
||||
//using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
public static class StringExtensions
|
||||
{
|
||||
private static int get_slice_count(this string instance, string splitter)
|
||||
{
|
||||
if (instance.empty() || splitter.empty())
|
||||
return 0;
|
||||
|
||||
int pos = 0;
|
||||
int slices = 1;
|
||||
|
||||
while ((pos = instance.find(splitter, pos)) >= 0)
|
||||
{
|
||||
slices++;
|
||||
pos += splitter.Length;
|
||||
}
|
||||
|
||||
return slices;
|
||||
}
|
||||
|
||||
private static string get_slicec(this string instance, char splitter, int slice)
|
||||
{
|
||||
if (!instance.empty() && slice >= 0)
|
||||
{
|
||||
int i = 0;
|
||||
int prev = 0;
|
||||
int count = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (instance[i] == 0 || instance[i] == splitter)
|
||||
{
|
||||
if (slice == count)
|
||||
{
|
||||
return instance.Substring(prev, i - prev);
|
||||
}
|
||||
else
|
||||
{
|
||||
count++;
|
||||
prev = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// If the string is a path to a file, return the path to the file without the extension.
|
||||
// </summary>
|
||||
public static string basename(this string instance)
|
||||
{
|
||||
int index = instance.LastIndexOf('.');
|
||||
|
||||
if (index > 0)
|
||||
return instance.Substring(0, index);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Return true if the strings begins with the given string.
|
||||
// </summary>
|
||||
public static bool begins_with(this string instance, string text)
|
||||
{
|
||||
return instance.StartsWith(text);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Return the bigrams (pairs of consecutive letters) of this string.
|
||||
// </summary>
|
||||
public static string[] bigrams(this string instance)
|
||||
{
|
||||
string[] b = new string[instance.Length - 1];
|
||||
|
||||
for (int i = 0; i < b.Length; i++)
|
||||
{
|
||||
b[i] = instance.Substring(i, 2);
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Return a copy of the string with special characters escaped using the C language standard.
|
||||
// </summary>
|
||||
public static string c_escape(this string instance)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(string.Copy(instance));
|
||||
|
||||
sb.Replace("\\", "\\\\");
|
||||
sb.Replace("\a", "\\a");
|
||||
sb.Replace("\b", "\\b");
|
||||
sb.Replace("\f", "\\f");
|
||||
sb.Replace("\n", "\\n");
|
||||
sb.Replace("\r", "\\r");
|
||||
sb.Replace("\t", "\\t");
|
||||
sb.Replace("\v", "\\v");
|
||||
sb.Replace("\'", "\\'");
|
||||
sb.Replace("\"", "\\\"");
|
||||
sb.Replace("?", "\\?");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Return a copy of the string with escaped characters replaced by their meanings according to the C language standard.
|
||||
// </summary>
|
||||
public static string c_unescape(this string instance)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(string.Copy(instance));
|
||||
|
||||
sb.Replace("\\a", "\a");
|
||||
sb.Replace("\\b", "\b");
|
||||
sb.Replace("\\f", "\f");
|
||||
sb.Replace("\\n", "\n");
|
||||
sb.Replace("\\r", "\r");
|
||||
sb.Replace("\\t", "\t");
|
||||
sb.Replace("\\v", "\v");
|
||||
sb.Replace("\\'", "\'");
|
||||
sb.Replace("\\\"", "\"");
|
||||
sb.Replace("\\?", "?");
|
||||
sb.Replace("\\\\", "\\");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Change the case of some letters. Replace underscores with spaces, convert all letters to lowercase then capitalize first and every letter following the space character. For [code]capitalize camelCase mixed_with_underscores[/code] it will return [code]Capitalize Camelcase Mixed With Underscores[/code].
|
||||
// </summary>
|
||||
public static string capitalize(this string instance)
|
||||
{
|
||||
string aux = instance.Replace("_", " ").ToLower();
|
||||
string cap = string.Empty;
|
||||
|
||||
for (int i = 0; i < aux.get_slice_count(" "); i++)
|
||||
{
|
||||
string slice = aux.get_slicec(' ', i);
|
||||
if (slice.Length > 0)
|
||||
{
|
||||
slice = char.ToUpper(slice[0]) + slice.Substring(1);
|
||||
if (i > 0)
|
||||
cap += " ";
|
||||
cap += slice;
|
||||
}
|
||||
}
|
||||
|
||||
return cap;
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Perform a case-sensitive comparison to another string, return -1 if less, 0 if equal and +1 if greater.
|
||||
// </summary>
|
||||
public static int casecmp_to(this string instance, string to)
|
||||
{
|
||||
if (instance.empty())
|
||||
return to.empty() ? 0 : -1;
|
||||
|
||||
if (to.empty())
|
||||
return 1;
|
||||
|
||||
int instance_idx = 0;
|
||||
int to_idx = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (to[to_idx] == 0 && instance[instance_idx] == 0)
|
||||
return 0; // We're equal
|
||||
else if (instance[instance_idx] == 0)
|
||||
return -1; // If this is empty, and the other one is not, then we're less... I think?
|
||||
else if (to[to_idx] == 0)
|
||||
return 1; // Otherwise the other one is smaller...
|
||||
else if (instance[instance_idx] < to[to_idx]) // More than
|
||||
return -1;
|
||||
else if (instance[instance_idx] > to[to_idx]) // Less than
|
||||
return 1;
|
||||
|
||||
instance_idx++;
|
||||
to_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Return true if the string is empty.
|
||||
// </summary>
|
||||
public static bool empty(this string instance)
|
||||
{
|
||||
return string.IsNullOrEmpty(instance);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Return true if the strings ends with the given string.
|
||||
// </summary>
|
||||
public static bool ends_with(this string instance, string text)
|
||||
{
|
||||
return instance.EndsWith(text);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Erase [code]chars[/code] characters from the string starting from [code]pos[/code].
|
||||
// </summary>
|
||||
public static void erase(this StringBuilder instance, int pos, int chars)
|
||||
{
|
||||
instance.Remove(pos, chars);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// If the string is a path to a file, return the extension.
|
||||
// </summary>
|
||||
public static string extension(this string instance)
|
||||
{
|
||||
int pos = instance.find_last(".");
|
||||
|
||||
if (pos < 0)
|
||||
return instance;
|
||||
|
||||
return instance.Substring(pos + 1, instance.Length);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Find the first occurrence of a substring, return the starting position of the substring or -1 if not found. Optionally, the initial search index can be passed.
|
||||
// </summary>
|
||||
public static int find(this string instance, string what, int from = 0)
|
||||
{
|
||||
return instance.IndexOf(what, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Find the last occurrence of a substring, return the starting position of the substring or -1 if not found. Optionally, the initial search index can be passed.
|
||||
// </summary>
|
||||
public static int find_last(this string instance, string what)
|
||||
{
|
||||
return instance.LastIndexOf(what, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Find the first occurrence of a substring but search as case-insensitive, return the starting position of the substring or -1 if not found. Optionally, the initial search index can be passed.
|
||||
// </summary>
|
||||
public static int findn(this string instance, string what, int from = 0)
|
||||
{
|
||||
return instance.IndexOf(what, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// If the string is a path to a file, return the base directory.
|
||||
// </summary>
|
||||
public static string get_base_dir(this string instance)
|
||||
{
|
||||
int basepos = instance.find("://");
|
||||
|
||||
string rs = string.Empty;
|
||||
string @base = string.Empty;
|
||||
|
||||
if (basepos != -1)
|
||||
{
|
||||
int end = basepos + 3;
|
||||
rs = instance.Substring(end, instance.Length);
|
||||
@base = instance.Substring(0, end);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (instance.begins_with("/"))
|
||||
{
|
||||
rs = instance.Substring(1, instance.Length);
|
||||
@base = "/";
|
||||
}
|
||||
else
|
||||
{
|
||||
rs = instance;
|
||||
}
|
||||
}
|
||||
|
||||
int sep = Mathf.max(rs.find_last("/"), rs.find_last("\\"));
|
||||
|
||||
if (sep == -1)
|
||||
return @base;
|
||||
|
||||
return @base + rs.substr(0, sep);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// If the string is a path to a file, return the file and ignore the base directory.
|
||||
// </summary>
|
||||
public static string get_file(this string instance)
|
||||
{
|
||||
int sep = Mathf.max(instance.find_last("/"), instance.find_last("\\"));
|
||||
|
||||
if (sep == -1)
|
||||
return instance;
|
||||
|
||||
return instance.Substring(sep + 1, instance.Length);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Hash the string and return a 32 bits integer.
|
||||
// </summary>
|
||||
public static int hash(this string instance)
|
||||
{
|
||||
int index = 0;
|
||||
int hashv = 5381;
|
||||
int c;
|
||||
|
||||
while ((c = (int)instance[index++]) != 0)
|
||||
hashv = ((hashv << 5) + hashv) + c; // hash * 33 + c
|
||||
|
||||
return hashv;
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Convert a string containing an hexadecimal number into an int.
|
||||
// </summary>
|
||||
public static int hex_to_int(this string instance)
|
||||
{
|
||||
int sign = 1;
|
||||
|
||||
if (instance[0] == '-')
|
||||
{
|
||||
sign = -1;
|
||||
instance = instance.Substring(1);
|
||||
}
|
||||
|
||||
if (!instance.StartsWith("0x"))
|
||||
return 0;
|
||||
|
||||
return sign * int.Parse(instance.Substring(2), NumberStyles.HexNumber);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Insert a substring at a given position.
|
||||
// </summary>
|
||||
public static string insert(this string instance, int pos, string what)
|
||||
{
|
||||
return instance.Insert(pos, what);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// If the string is a path to a file or directory, return true if the path is absolute.
|
||||
// </summary>
|
||||
public static bool is_abs_path(this string instance)
|
||||
{
|
||||
return System.IO.Path.IsPathRooted(instance);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// If the string is a path to a file or directory, return true if the path is relative.
|
||||
// </summary>
|
||||
public static bool is_rel_path(this string instance)
|
||||
{
|
||||
return !System.IO.Path.IsPathRooted(instance);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Check whether this string is a subsequence of the given string.
|
||||
// </summary>
|
||||
public static bool is_subsequence_of(this string instance, string text, bool case_insensitive)
|
||||
{
|
||||
int len = instance.Length;
|
||||
|
||||
if (len == 0)
|
||||
return true; // Technically an empty string is subsequence of any string
|
||||
|
||||
if (len > text.Length)
|
||||
return false;
|
||||
|
||||
int src = 0;
|
||||
int tgt = 0;
|
||||
|
||||
while (instance[src] != 0 && text[tgt] != 0)
|
||||
{
|
||||
bool match = false;
|
||||
|
||||
if (case_insensitive)
|
||||
{
|
||||
char srcc = char.ToLower(instance[src]);
|
||||
char tgtc = char.ToLower(text[tgt]);
|
||||
match = srcc == tgtc;
|
||||
}
|
||||
else
|
||||
{
|
||||
match = instance[src] == text[tgt];
|
||||
}
|
||||
if (match)
|
||||
{
|
||||
src++;
|
||||
if (instance[src] == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
tgt++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Check whether this string is a subsequence of the given string, considering case.
|
||||
// </summary>
|
||||
public static bool is_subsequence_of(this string instance, string text)
|
||||
{
|
||||
return instance.is_subsequence_of(text, false);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Check whether this string is a subsequence of the given string, without considering case.
|
||||
// </summary>
|
||||
public static bool is_subsequence_ofi(this string instance, string text)
|
||||
{
|
||||
return instance.is_subsequence_of(text, true);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Check whether the string contains a valid float.
|
||||
// </summary>
|
||||
public static bool is_valid_float(this string instance)
|
||||
{
|
||||
float f;
|
||||
return float.TryParse(instance, out f);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Check whether the string contains a valid color in HTML notation.
|
||||
// </summary>
|
||||
public static bool is_valid_html_color(this string instance)
|
||||
{
|
||||
return Color.html_is_valid(instance);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Check whether the string is a valid identifier. As is common in programming languages, a valid identifier may contain only letters, digits and underscores (_) and the first character may not be a digit.
|
||||
// </summary>
|
||||
public static bool is_valid_identifier(this string instance)
|
||||
{
|
||||
int len = instance.Length;
|
||||
|
||||
if (len == 0)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
if (instance[0] >= '0' && instance[0] <= '9')
|
||||
return false; // Don't start with number plz
|
||||
}
|
||||
|
||||
bool valid_char = (instance[i] >= '0' && instance[i] <= '9') || (instance[i] >= 'a' && instance[i] <= 'z') || (instance[i] >= 'A' && instance[i] <= 'Z') || instance[i] == '_';
|
||||
|
||||
if (!valid_char)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Check whether the string contains a valid integer.
|
||||
// </summary>
|
||||
public static bool is_valid_integer(this string instance)
|
||||
{
|
||||
int f;
|
||||
return int.TryParse(instance, out f);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Check whether the string contains a valid IP address.
|
||||
// </summary>
|
||||
public static bool is_valid_ip_address(this string instance)
|
||||
{
|
||||
string[] ip = instance.split(".");
|
||||
|
||||
if (ip.Length != 4)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < ip.Length; i++)
|
||||
{
|
||||
string n = ip[i];
|
||||
if (!n.is_valid_integer())
|
||||
return false;
|
||||
|
||||
int val = n.to_int();
|
||||
if (val < 0 || val > 255)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Return a copy of the string with special characters escaped using the JSON standard.
|
||||
// </summary>
|
||||
public static string json_escape(this string instance)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(string.Copy(instance));
|
||||
|
||||
sb.Replace("\\", "\\\\");
|
||||
sb.Replace("\b", "\\b");
|
||||
sb.Replace("\f", "\\f");
|
||||
sb.Replace("\n", "\\n");
|
||||
sb.Replace("\r", "\\r");
|
||||
sb.Replace("\t", "\\t");
|
||||
sb.Replace("\v", "\\v");
|
||||
sb.Replace("\"", "\\\"");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Return an amount of characters from the left of the string.
|
||||
// </summary>
|
||||
public static string left(this string instance, int pos)
|
||||
{
|
||||
if (pos <= 0)
|
||||
return string.Empty;
|
||||
|
||||
if (pos >= instance.Length)
|
||||
return instance;
|
||||
|
||||
return instance.Substring(0, pos);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the length of the string in characters.
|
||||
/// </summary>
|
||||
public static int length(this string instance)
|
||||
{
|
||||
return instance.Length;
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Do a simple expression match, where '*' matches zero or more arbitrary characters and '?' matches any single character except '.'.
|
||||
// </summary>
|
||||
public static bool expr_match(this string instance, string expr, bool case_sensitive)
|
||||
{
|
||||
if (expr.Length == 0 || instance.Length == 0)
|
||||
return false;
|
||||
|
||||
switch (expr[0])
|
||||
{
|
||||
case '\0':
|
||||
return instance[0] == 0;
|
||||
case '*':
|
||||
return expr_match(expr + 1, instance, case_sensitive) || (instance[0] != 0 && expr_match(expr, instance + 1, case_sensitive));
|
||||
case '?':
|
||||
return instance[0] != 0 && instance[0] != '.' && expr_match(expr + 1, instance + 1, case_sensitive);
|
||||
default:
|
||||
return (case_sensitive ? instance[0] == expr[0] : char.ToUpper(instance[0]) == char.ToUpper(expr[0])) &&
|
||||
expr_match(expr + 1, instance + 1, case_sensitive);
|
||||
}
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Do a simple case sensitive expression match, using ? and * wildcards (see [method expr_match]).
|
||||
// </summary>
|
||||
public static bool match(this string instance, string expr)
|
||||
{
|
||||
return instance.expr_match(expr, true);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Do a simple case insensitive expression match, using ? and * wildcards (see [method expr_match]).
|
||||
// </summary>
|
||||
public static bool matchn(this string instance, string expr)
|
||||
{
|
||||
return instance.expr_match(expr, false);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Return the MD5 hash of the string as an array of bytes.
|
||||
// </summary>
|
||||
public static byte[] md5_buffer(this string instance)
|
||||
{
|
||||
return NativeCalls.godot_icall_String_md5_buffer(instance);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Return the MD5 hash of the string as a string.
|
||||
// </summary>
|
||||
public static string md5_text(this string instance)
|
||||
{
|
||||
return NativeCalls.godot_icall_String_md5_text(instance);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Perform a case-insensitive comparison to another string, return -1 if less, 0 if equal and +1 if greater.
|
||||
// </summary>
|
||||
public static int nocasecmp_to(this string instance, string to)
|
||||
{
|
||||
if (instance.empty())
|
||||
return to.empty() ? 0 : -1;
|
||||
|
||||
if (to.empty())
|
||||
return 1;
|
||||
|
||||
int instance_idx = 0;
|
||||
int to_idx = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (to[to_idx] == 0 && instance[instance_idx] == 0)
|
||||
return 0; // We're equal
|
||||
else if (instance[instance_idx] == 0)
|
||||
return -1; // If this is empty, and the other one is not, then we're less... I think?
|
||||
else if (to[to_idx] == 0)
|
||||
return 1; // Otherwise the other one is smaller..
|
||||
else if (char.ToUpper(instance[instance_idx]) < char.ToUpper(to[to_idx])) // More than
|
||||
return -1;
|
||||
else if (char.ToUpper(instance[instance_idx]) > char.ToUpper(to[to_idx])) // Less than
|
||||
return 1;
|
||||
|
||||
instance_idx++;
|
||||
to_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Return the character code at position [code]at[/code].
|
||||
// </summary>
|
||||
public static int ord_at(this string instance, int at)
|
||||
{
|
||||
return instance[at];
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Format a number to have an exact number of [code]digits[/code] after the decimal point.
|
||||
// </summary>
|
||||
public static string pad_decimals(this string instance, int digits)
|
||||
{
|
||||
int c = instance.find(".");
|
||||
|
||||
if (c == -1)
|
||||
{
|
||||
if (digits <= 0)
|
||||
return instance;
|
||||
|
||||
instance += ".";
|
||||
c = instance.Length - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (digits <= 0)
|
||||
return instance.Substring(0, c);
|
||||
}
|
||||
|
||||
if (instance.Length - (c + 1) > digits)
|
||||
{
|
||||
instance = instance.Substring(0, c + digits + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (instance.Length - (c + 1) < digits)
|
||||
{
|
||||
instance += "0";
|
||||
}
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Format a number to have an exact number of [code]digits[/code] before the decimal point.
|
||||
// </summary>
|
||||
public static string pad_zeros(this string instance, int digits)
|
||||
{
|
||||
string s = instance;
|
||||
int end = s.find(".");
|
||||
|
||||
if (end == -1)
|
||||
end = s.Length;
|
||||
|
||||
if (end == 0)
|
||||
return s;
|
||||
|
||||
int begin = 0;
|
||||
|
||||
while (begin < end && (s[begin] < '0' || s[begin] > '9'))
|
||||
{
|
||||
begin++;
|
||||
}
|
||||
|
||||
if (begin >= end)
|
||||
return s;
|
||||
|
||||
while (end - begin < digits)
|
||||
{
|
||||
s = s.Insert(begin, "0");
|
||||
end++;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Decode a percent-encoded string. See [method percent_encode].
|
||||
// </summary>
|
||||
public static string percent_decode(this string instance)
|
||||
{
|
||||
return Uri.UnescapeDataString(instance);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Percent-encode a string. This is meant to encode parameters in a URL when sending a HTTP GET request and bodies of form-urlencoded POST request.
|
||||
// </summary>
|
||||
public static string percent_encode(this string instance)
|
||||
{
|
||||
return Uri.EscapeDataString(instance);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// If the string is a path, this concatenates [code]file[/code] at the end of the string as a subpath. E.g. [code]"this/is".plus_file("path") == "this/is/path"[/code].
|
||||
// </summary>
|
||||
public static string plus_file(this string instance, string file)
|
||||
{
|
||||
if (instance.Length > 0 && instance[instance.Length - 1] == '/')
|
||||
return instance + file;
|
||||
else
|
||||
return instance + "/" + file;
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Replace occurrences of a substring for different ones inside the string.
|
||||
// </summary>
|
||||
public static string replace(this string instance, string what, string forwhat)
|
||||
{
|
||||
return instance.Replace(what, forwhat);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Replace occurrences of a substring for different ones inside the string, but search case-insensitive.
|
||||
// </summary>
|
||||
public static string replacen(this string instance, string what, string forwhat)
|
||||
{
|
||||
return Regex.Replace(instance, what, forwhat, RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Perform a search for a substring, but start from the end of the string instead of the beginning.
|
||||
// </summary>
|
||||
public static int rfind(this string instance, string what, int from = -1)
|
||||
{
|
||||
return NativeCalls.godot_icall_String_rfind(instance, what, from);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Perform a search for a substring, but start from the end of the string instead of the beginning. Also search case-insensitive.
|
||||
// </summary>
|
||||
public static int rfindn(this string instance, string what, int from = -1)
|
||||
{
|
||||
return NativeCalls.godot_icall_String_rfindn(instance, what, from);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Return the right side of the string from a given position.
|
||||
// </summary>
|
||||
public static string right(this string instance, int pos)
|
||||
{
|
||||
if (pos >= instance.Length)
|
||||
return instance;
|
||||
|
||||
if (pos < 0)
|
||||
return string.Empty;
|
||||
|
||||
return instance.Substring(pos, (instance.Length - pos));
|
||||
}
|
||||
|
||||
public static byte[] sha256_buffer(this string instance)
|
||||
{
|
||||
return NativeCalls.godot_icall_String_sha256_buffer(instance);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Return the SHA-256 hash of the string as a string.
|
||||
// </summary>
|
||||
public static string sha256_text(this string instance)
|
||||
{
|
||||
return NativeCalls.godot_icall_String_sha256_text(instance);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Return the similarity index of the text compared to this string. 1 means totally similar and 0 means totally dissimilar.
|
||||
// </summary>
|
||||
public static float similarity(this string instance, string text)
|
||||
{
|
||||
if (instance == text)
|
||||
{
|
||||
// Equal strings are totally similar
|
||||
return 1.0f;
|
||||
}
|
||||
if (instance.Length < 2 || text.Length < 2)
|
||||
{
|
||||
// No way to calculate similarity without a single bigram
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
string[] src_bigrams = instance.bigrams();
|
||||
string[] tgt_bigrams = text.bigrams();
|
||||
|
||||
int src_size = src_bigrams.Length;
|
||||
int tgt_size = tgt_bigrams.Length;
|
||||
|
||||
float sum = src_size + tgt_size;
|
||||
float inter = 0;
|
||||
|
||||
for (int i = 0; i < src_size; i++)
|
||||
{
|
||||
for (int j = 0; j < tgt_size; j++)
|
||||
{
|
||||
if (src_bigrams[i] == tgt_bigrams[j])
|
||||
{
|
||||
inter++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (2.0f * inter) / sum;
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Split the string by a divisor string, return an array of the substrings. Example "One,Two,Three" will return ["One","Two","Three"] if split by ",".
|
||||
// </summary>
|
||||
public static string[] split(this string instance, string divisor, bool allow_empty = true)
|
||||
{
|
||||
return instance.Split(new string[] { divisor }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Split the string in floats by using a divisor string, return an array of the substrings. Example "1,2.5,3" will return [1,2.5,3] if split by ",".
|
||||
// </summary>
|
||||
public static float[] split_floats(this string instance, string divisor, bool allow_empty = true)
|
||||
{
|
||||
List<float> ret = new List<float>();
|
||||
int from = 0;
|
||||
int len = instance.Length;
|
||||
|
||||
while (true)
|
||||
{
|
||||
int end = instance.find(divisor, from);
|
||||
if (end < 0)
|
||||
end = len;
|
||||
if (allow_empty || (end > from))
|
||||
ret.Add(float.Parse(instance.Substring(from)));
|
||||
if (end == len)
|
||||
break;
|
||||
|
||||
from = end + divisor.Length;
|
||||
}
|
||||
|
||||
return ret.ToArray();
|
||||
}
|
||||
|
||||
private static readonly char[] non_printable = {
|
||||
(char)00, (char)01, (char)02, (char)03, (char)04, (char)05,
|
||||
(char)06, (char)07, (char)08, (char)09, (char)10, (char)11,
|
||||
(char)12, (char)13, (char)14, (char)15, (char)16, (char)17,
|
||||
(char)18, (char)19, (char)20, (char)21, (char)22, (char)23,
|
||||
(char)24, (char)25, (char)26, (char)27, (char)28, (char)29,
|
||||
(char)30, (char)31, (char)32
|
||||
};
|
||||
|
||||
// <summary>
|
||||
// Return a copy of the string stripped of any non-printable character at the beginning and the end. The optional arguments are used to toggle stripping on the left and right edges respectively.
|
||||
// </summary>
|
||||
public static string strip_edges(this string instance, bool left = true, bool right = true)
|
||||
{
|
||||
if (left)
|
||||
{
|
||||
if (right)
|
||||
return instance.Trim(non_printable);
|
||||
else
|
||||
return instance.TrimStart(non_printable);
|
||||
}
|
||||
else
|
||||
{
|
||||
return instance.TrimEnd(non_printable);
|
||||
}
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Return part of the string from the position [code]from[/code], with length [code]len[/code].
|
||||
// </summary>
|
||||
public static string substr(this string instance, int from, int len)
|
||||
{
|
||||
return instance.Substring(from, len);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Convert the String (which is a character array) to PoolByteArray (which is an array of bytes). The conversion is speeded up in comparison to to_utf8() with the assumption that all the characters the String contains are only ASCII characters.
|
||||
// </summary>
|
||||
public static byte[] to_ascii(this string instance)
|
||||
{
|
||||
return Encoding.ASCII.GetBytes(instance);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Convert a string, containing a decimal number, into a [code]float[/code].
|
||||
// </summary>
|
||||
public static float to_float(this string instance)
|
||||
{
|
||||
return float.Parse(instance);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Convert a string, containing an integer number, into an [code]int[/code].
|
||||
// </summary>
|
||||
public static int to_int(this string instance)
|
||||
{
|
||||
return int.Parse(instance);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Return the string converted to lowercase.
|
||||
// </summary>
|
||||
public static string to_lower(this string instance)
|
||||
{
|
||||
return instance.ToLower();
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Return the string converted to uppercase.
|
||||
// </summary>
|
||||
public static string to_upper(this string instance)
|
||||
{
|
||||
return instance.ToUpper();
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Convert the String (which is an array of characters) to PoolByteArray (which is an array of bytes). The conversion is a bit slower than to_ascii(), but supports all UTF-8 characters. Therefore, you should prefer this function over to_ascii().
|
||||
// </summary>
|
||||
public static byte[] to_utf8(this string instance)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(instance);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Return a copy of the string with special characters escaped using the XML standard.
|
||||
// </summary>
|
||||
public static string xml_escape(this string instance)
|
||||
{
|
||||
return SecurityElement.Escape(instance);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Return a copy of the string with escaped characters replaced by their meanings according to the XML standard.
|
||||
// </summary>
|
||||
public static string xml_unescape(this string instance)
|
||||
{
|
||||
return SecurityElement.FromString(instance).Text;
|
||||
}
|
||||
}
|
||||
}
|
7
modules/mono/glue/cs_files/ToolAttribute.cs
Normal file
7
modules/mono/glue/cs_files/ToolAttribute.cs
Normal file
@ -0,0 +1,7 @@
|
||||
using System;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class ToolAttribute : Attribute {}
|
||||
}
|
168
modules/mono/glue/cs_files/Transform.cs
Normal file
168
modules/mono/glue/cs_files/Transform.cs
Normal file
@ -0,0 +1,168 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Transform : IEquatable<Transform>
|
||||
{
|
||||
public Basis basis;
|
||||
public Vector3 origin;
|
||||
|
||||
public Transform affine_inverse()
|
||||
{
|
||||
Basis basisInv = basis.inverse();
|
||||
return new Transform(basisInv, basisInv.xform(-origin));
|
||||
}
|
||||
|
||||
public Transform inverse()
|
||||
{
|
||||
Basis basisTr = basis.transposed();
|
||||
return new Transform(basisTr, basisTr.xform(-origin));
|
||||
}
|
||||
|
||||
public Transform looking_at(Vector3 target, Vector3 up)
|
||||
{
|
||||
Transform t = this;
|
||||
t.set_look_at(origin, target, up);
|
||||
return t;
|
||||
}
|
||||
|
||||
public Transform orthonormalized()
|
||||
{
|
||||
return new Transform(basis.orthonormalized(), origin);
|
||||
}
|
||||
|
||||
public Transform rotated(Vector3 axis, float phi)
|
||||
{
|
||||
return this * new Transform(new Basis(axis, phi), new Vector3());
|
||||
}
|
||||
|
||||
public Transform scaled(Vector3 scale)
|
||||
{
|
||||
return new Transform(basis.scaled(scale), origin * scale);
|
||||
}
|
||||
|
||||
public void set_look_at(Vector3 eye, Vector3 target, Vector3 up)
|
||||
{
|
||||
// Make rotation matrix
|
||||
// Z vector
|
||||
Vector3 zAxis = eye - target;
|
||||
|
||||
zAxis.normalize();
|
||||
|
||||
Vector3 yAxis = up;
|
||||
|
||||
Vector3 xAxis = yAxis.cross(zAxis);
|
||||
|
||||
// Recompute Y = Z cross X
|
||||
yAxis = zAxis.cross(xAxis);
|
||||
|
||||
xAxis.normalize();
|
||||
yAxis.normalize();
|
||||
|
||||
basis = Basis.create_from_axes(xAxis, yAxis, zAxis);
|
||||
|
||||
origin = eye;
|
||||
}
|
||||
|
||||
public Transform translated(Vector3 ofs)
|
||||
{
|
||||
return new Transform(basis, new Vector3
|
||||
(
|
||||
origin[0] += basis[0].dot(ofs),
|
||||
origin[1] += basis[1].dot(ofs),
|
||||
origin[2] += basis[2].dot(ofs)
|
||||
));
|
||||
}
|
||||
|
||||
public Vector3 xform(Vector3 v)
|
||||
{
|
||||
return new Vector3
|
||||
(
|
||||
basis[0].dot(v) + origin.x,
|
||||
basis[1].dot(v) + origin.y,
|
||||
basis[2].dot(v) + origin.z
|
||||
);
|
||||
}
|
||||
|
||||
public Vector3 xform_inv(Vector3 v)
|
||||
{
|
||||
Vector3 vInv = v - origin;
|
||||
|
||||
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)
|
||||
);
|
||||
}
|
||||
|
||||
public Transform(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis, Vector3 origin)
|
||||
{
|
||||
this.basis = Basis.create_from_axes(xAxis, yAxis, zAxis);
|
||||
this.origin = origin;
|
||||
}
|
||||
|
||||
public Transform(Basis basis, Vector3 origin)
|
||||
{
|
||||
this.basis = basis;
|
||||
this.origin = origin;
|
||||
}
|
||||
|
||||
public static Transform operator *(Transform left, Transform right)
|
||||
{
|
||||
left.origin = left.xform(right.origin);
|
||||
left.basis *= right.basis;
|
||||
return left;
|
||||
}
|
||||
|
||||
public static bool operator ==(Transform left, Transform right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Transform left, Transform right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Transform)
|
||||
{
|
||||
return Equals((Transform)obj);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Equals(Transform other)
|
||||
{
|
||||
return basis.Equals(other.basis) && origin.Equals(other.origin);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return basis.GetHashCode() ^ origin.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0} - {1}", new object[]
|
||||
{
|
||||
this.basis.ToString(),
|
||||
this.origin.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
public string ToString(string format)
|
||||
{
|
||||
return String.Format("{0} - {1}", new object[]
|
||||
{
|
||||
this.basis.ToString(format),
|
||||
this.origin.ToString(format)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
356
modules/mono/glue/cs_files/Transform2D.cs
Normal file
356
modules/mono/glue/cs_files/Transform2D.cs
Normal file
@ -0,0 +1,356 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Transform2D : IEquatable<Transform2D>
|
||||
{
|
||||
private static readonly Transform2D identity = new Transform2D
|
||||
(
|
||||
new Vector2(1f, 0f),
|
||||
new Vector2(0f, 1f),
|
||||
new Vector2(0f, 0f)
|
||||
);
|
||||
|
||||
public Vector2 x;
|
||||
public Vector2 y;
|
||||
public Vector2 o;
|
||||
|
||||
public static Transform2D Identity
|
||||
{
|
||||
get { return identity; }
|
||||
}
|
||||
|
||||
public Vector2 Origin
|
||||
{
|
||||
get { return o; }
|
||||
}
|
||||
|
||||
public float Rotation
|
||||
{
|
||||
get { return Mathf.atan2(y.x, o.y); }
|
||||
}
|
||||
|
||||
public Vector2 Scale
|
||||
{
|
||||
get { return new Vector2(x.length(), y.length()); }
|
||||
}
|
||||
|
||||
public Vector2 this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return x;
|
||||
case 1:
|
||||
return y;
|
||||
case 2:
|
||||
return o;
|
||||
default:
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
x = value;
|
||||
return;
|
||||
case 1:
|
||||
y = value;
|
||||
return;
|
||||
case 2:
|
||||
o = value;
|
||||
return;
|
||||
default:
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public float this[int index, int axis]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return x[axis];
|
||||
case 1:
|
||||
return y[axis];
|
||||
default:
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
x[axis] = value;
|
||||
return;
|
||||
case 1:
|
||||
y[axis] = value;
|
||||
return;
|
||||
default:
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Transform2D affine_inverse()
|
||||
{
|
||||
Transform2D inv = this;
|
||||
|
||||
float det = this[0, 0] * this[1, 1] - this[1, 0] * this[0, 1];
|
||||
|
||||
if (det == 0)
|
||||
{
|
||||
return new Transform2D
|
||||
(
|
||||
float.NaN, float.NaN,
|
||||
float.NaN, float.NaN,
|
||||
float.NaN, float.NaN
|
||||
);
|
||||
}
|
||||
|
||||
float idet = 1.0f / det;
|
||||
|
||||
float temp = this[0, 0];
|
||||
this[0, 0] = this[1, 1];
|
||||
this[1, 1] = temp;
|
||||
|
||||
this[0] *= new Vector2(idet, -idet);
|
||||
this[1] *= new Vector2(-idet, idet);
|
||||
|
||||
this[2] = basis_xform(-this[2]);
|
||||
|
||||
return inv;
|
||||
}
|
||||
|
||||
public Vector2 basis_xform(Vector2 v)
|
||||
{
|
||||
return new Vector2(tdotx(v), tdoty(v));
|
||||
}
|
||||
|
||||
public Vector2 basis_xform_inv(Vector2 v)
|
||||
{
|
||||
return new Vector2(x.dot(v), y.dot(v));
|
||||
}
|
||||
|
||||
public Transform2D interpolate_with(Transform2D m, float c)
|
||||
{
|
||||
float r1 = Rotation;
|
||||
float r2 = m.Rotation;
|
||||
|
||||
Vector2 s1 = Scale;
|
||||
Vector2 s2 = m.Scale;
|
||||
|
||||
// Slerp rotation
|
||||
Vector2 v1 = new Vector2(Mathf.cos(r1), Mathf.sin(r1));
|
||||
Vector2 v2 = new Vector2(Mathf.cos(r2), Mathf.sin(r2));
|
||||
|
||||
float dot = v1.dot(v2);
|
||||
|
||||
// Clamp dot to [-1, 1]
|
||||
dot = (dot < -1.0f) ? -1.0f : ((dot > 1.0f) ? 1.0f : dot);
|
||||
|
||||
Vector2 v = new Vector2();
|
||||
|
||||
if (dot > 0.9995f)
|
||||
{
|
||||
// Linearly interpolate to avoid numerical precision issues
|
||||
v = v1.linear_interpolate(v2, c).normalized();
|
||||
}
|
||||
else
|
||||
{
|
||||
float angle = c * Mathf.acos(dot);
|
||||
Vector2 v3 = (v2 - v1 * dot).normalized();
|
||||
v = v1 * Mathf.cos(angle) + v3 * Mathf.sin(angle);
|
||||
}
|
||||
|
||||
// Extract parameters
|
||||
Vector2 p1 = Origin;
|
||||
Vector2 p2 = m.Origin;
|
||||
|
||||
// Construct matrix
|
||||
Transform2D res = new Transform2D(Mathf.atan2(v.y, v.x), p1.linear_interpolate(p2, c));
|
||||
Vector2 scale = s1.linear_interpolate(s2, c);
|
||||
res.x *= scale;
|
||||
res.y *= scale;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public Transform2D inverse()
|
||||
{
|
||||
Transform2D inv = this;
|
||||
|
||||
// Swap
|
||||
float temp = inv.x.y;
|
||||
inv.x.y = inv.y.x;
|
||||
inv.y.x = temp;
|
||||
|
||||
inv.o = inv.basis_xform(-inv.o);
|
||||
|
||||
return inv;
|
||||
}
|
||||
|
||||
public Transform2D orthonormalized()
|
||||
{
|
||||
Transform2D on = this;
|
||||
|
||||
Vector2 onX = on.x;
|
||||
Vector2 onY = on.y;
|
||||
|
||||
onX.normalize();
|
||||
onY = onY - onX * (onX.dot(onY));
|
||||
onY.normalize();
|
||||
|
||||
on.x = onX;
|
||||
on.y = onY;
|
||||
|
||||
return on;
|
||||
}
|
||||
|
||||
public Transform2D rotated(float phi)
|
||||
{
|
||||
return this * new Transform2D(phi, new Vector2());
|
||||
}
|
||||
|
||||
public Transform2D scaled(Vector2 scale)
|
||||
{
|
||||
Transform2D copy = this;
|
||||
copy.x *= scale;
|
||||
copy.y *= scale;
|
||||
copy.o *= scale;
|
||||
return copy;
|
||||
}
|
||||
|
||||
private float tdotx(Vector2 with)
|
||||
{
|
||||
return this[0, 0] * with[0] + this[1, 0] * with[1];
|
||||
}
|
||||
|
||||
private float tdoty(Vector2 with)
|
||||
{
|
||||
return this[0, 1] * with[0] + this[1, 1] * with[1];
|
||||
}
|
||||
|
||||
public Transform2D translated(Vector2 offset)
|
||||
{
|
||||
Transform2D copy = this;
|
||||
copy.o += copy.basis_xform(offset);
|
||||
return copy;
|
||||
}
|
||||
|
||||
public Vector2 xform(Vector2 v)
|
||||
{
|
||||
return new Vector2(tdotx(v), tdoty(v)) + o;
|
||||
}
|
||||
|
||||
public Vector2 xform_inv(Vector2 v)
|
||||
{
|
||||
Vector2 vInv = v - o;
|
||||
return new Vector2(x.dot(vInv), y.dot(vInv));
|
||||
}
|
||||
|
||||
public Transform2D(Vector2 xAxis, Vector2 yAxis, Vector2 origin)
|
||||
{
|
||||
this.x = xAxis;
|
||||
this.y = yAxis;
|
||||
this.o = origin;
|
||||
}
|
||||
public Transform2D(float xx, float xy, float yx, float yy, float ox, float oy)
|
||||
{
|
||||
this.x = new Vector2(xx, xy);
|
||||
this.y = new Vector2(yx, yy);
|
||||
this.o = new Vector2(ox, oy);
|
||||
}
|
||||
|
||||
public Transform2D(float rot, Vector2 pos)
|
||||
{
|
||||
float cr = Mathf.cos(rot);
|
||||
float sr = Mathf.sin(rot);
|
||||
x.x = cr;
|
||||
y.y = cr;
|
||||
x.y = -sr;
|
||||
y.x = sr;
|
||||
o = pos;
|
||||
}
|
||||
|
||||
public static Transform2D operator *(Transform2D left, Transform2D right)
|
||||
{
|
||||
left.o = left.xform(right.o);
|
||||
|
||||
float x0, x1, y0, y1;
|
||||
|
||||
x0 = left.tdotx(right.x);
|
||||
x1 = left.tdoty(right.x);
|
||||
y0 = left.tdotx(right.y);
|
||||
y1 = left.tdoty(right.y);
|
||||
|
||||
left.x.x = x0;
|
||||
left.x.y = x1;
|
||||
left.y.x = y0;
|
||||
left.y.y = y1;
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
public static bool operator ==(Transform2D left, Transform2D right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Transform2D left, Transform2D right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Transform2D)
|
||||
{
|
||||
return Equals((Transform2D)obj);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Equals(Transform2D other)
|
||||
{
|
||||
return x.Equals(other.x) && y.Equals(other.y) && o.Equals(other.o);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return x.GetHashCode() ^ y.GetHashCode() ^ o.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("({0}, {1}, {2})", new object[]
|
||||
{
|
||||
this.x.ToString(),
|
||||
this.y.ToString(),
|
||||
this.o.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
public string ToString(string format)
|
||||
{
|
||||
return String.Format("({0}, {1}, {2})", new object[]
|
||||
{
|
||||
this.x.ToString(format),
|
||||
this.y.ToString(format),
|
||||
this.o.ToString(format)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
362
modules/mono/glue/cs_files/Vector2.cs
Normal file
362
modules/mono/glue/cs_files/Vector2.cs
Normal file
@ -0,0 +1,362 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// file: core/math/math_2d.h
|
||||
// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451
|
||||
// file: core/math/math_2d.cpp
|
||||
// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451
|
||||
// file: core/variant_call.cpp
|
||||
// commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Vector2 : IEquatable<Vector2>
|
||||
{
|
||||
public float x;
|
||||
public float y;
|
||||
|
||||
public float this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return x;
|
||||
case 1:
|
||||
return y;
|
||||
default:
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
x = value;
|
||||
return;
|
||||
case 1:
|
||||
y = value;
|
||||
return;
|
||||
default:
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void normalize()
|
||||
{
|
||||
float length = x * x + y * y;
|
||||
|
||||
if (length != 0f)
|
||||
{
|
||||
length = Mathf.sqrt(length);
|
||||
x /= length;
|
||||
y /= length;
|
||||
}
|
||||
}
|
||||
|
||||
private float cross(Vector2 b)
|
||||
{
|
||||
return x * b.y - y * b.x;
|
||||
}
|
||||
|
||||
public Vector2 abs()
|
||||
{
|
||||
return new Vector2(Mathf.abs(x), Mathf.abs(y));
|
||||
}
|
||||
|
||||
public float angle()
|
||||
{
|
||||
return Mathf.atan2(y, x);
|
||||
}
|
||||
|
||||
public float angle_to(Vector2 to)
|
||||
{
|
||||
return Mathf.atan2(cross(to), dot(to));
|
||||
}
|
||||
|
||||
public float angle_to_point(Vector2 to)
|
||||
{
|
||||
return Mathf.atan2(x - to.x, y - to.y);
|
||||
}
|
||||
|
||||
public float aspect()
|
||||
{
|
||||
return x / y;
|
||||
}
|
||||
|
||||
public Vector2 bounce(Vector2 n)
|
||||
{
|
||||
return -reflect(n);
|
||||
}
|
||||
|
||||
public Vector2 clamped(float length)
|
||||
{
|
||||
Vector2 v = this;
|
||||
float l = this.length();
|
||||
|
||||
if (l > 0 && length < l)
|
||||
{
|
||||
v /= l;
|
||||
v *= length;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
public Vector2 cubic_interpolate(Vector2 b, Vector2 preA, Vector2 postB, float t)
|
||||
{
|
||||
Vector2 p0 = preA;
|
||||
Vector2 p1 = this;
|
||||
Vector2 p2 = b;
|
||||
Vector2 p3 = postB;
|
||||
|
||||
float t2 = t * t;
|
||||
float t3 = t2 * t;
|
||||
|
||||
return 0.5f * ((p1 * 2.0f) +
|
||||
(-p0 + p2) * t +
|
||||
(2.0f * p0 - 5.0f * p1 + 4 * p2 - p3) * t2 +
|
||||
(-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3);
|
||||
}
|
||||
|
||||
public float distance_squared_to(Vector2 to)
|
||||
{
|
||||
return (x - to.x) * (x - to.x) + (y - to.y) * (y - to.y);
|
||||
}
|
||||
|
||||
public float distance_to(Vector2 to)
|
||||
{
|
||||
return Mathf.sqrt((x - to.x) * (x - to.x) + (y - to.y) * (y - to.y));
|
||||
}
|
||||
|
||||
public float dot(Vector2 with)
|
||||
{
|
||||
return x * with.x + y * with.y;
|
||||
}
|
||||
|
||||
public Vector2 floor()
|
||||
{
|
||||
return new Vector2(Mathf.floor(x), Mathf.floor(y));
|
||||
}
|
||||
|
||||
public bool is_normalized()
|
||||
{
|
||||
return Mathf.abs(length_squared() - 1.0f) < Mathf.Epsilon;
|
||||
}
|
||||
|
||||
public float length()
|
||||
{
|
||||
return Mathf.sqrt(x * x + y * y);
|
||||
}
|
||||
|
||||
public float length_squared()
|
||||
{
|
||||
return x * x + y * y;
|
||||
}
|
||||
|
||||
public Vector2 linear_interpolate(Vector2 b, float t)
|
||||
{
|
||||
Vector2 res = this;
|
||||
|
||||
res.x += (t * (b.x - x));
|
||||
res.y += (t * (b.y - y));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public Vector2 normalized()
|
||||
{
|
||||
Vector2 result = this;
|
||||
result.normalize();
|
||||
return result;
|
||||
}
|
||||
|
||||
public Vector2 reflect(Vector2 n)
|
||||
{
|
||||
return 2.0f * n * dot(n) - this;
|
||||
}
|
||||
|
||||
public Vector2 rotated(float phi)
|
||||
{
|
||||
float rads = angle() + phi;
|
||||
return new Vector2(Mathf.cos(rads), Mathf.sin(rads)) * length();
|
||||
}
|
||||
|
||||
public Vector2 slide(Vector2 n)
|
||||
{
|
||||
return this - n * dot(n);
|
||||
}
|
||||
|
||||
public Vector2 snapped(Vector2 by)
|
||||
{
|
||||
return new Vector2(Mathf.stepify(x, by.x), Mathf.stepify(y, by.y));
|
||||
}
|
||||
|
||||
public Vector2 tangent()
|
||||
{
|
||||
return new Vector2(y, -x);
|
||||
}
|
||||
|
||||
public Vector2(float x, float y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public static Vector2 operator +(Vector2 left, Vector2 right)
|
||||
{
|
||||
left.x += right.x;
|
||||
left.y += right.y;
|
||||
return left;
|
||||
}
|
||||
|
||||
public static Vector2 operator -(Vector2 left, Vector2 right)
|
||||
{
|
||||
left.x -= right.x;
|
||||
left.y -= right.y;
|
||||
return left;
|
||||
}
|
||||
|
||||
public static Vector2 operator -(Vector2 vec)
|
||||
{
|
||||
vec.x = -vec.x;
|
||||
vec.y = -vec.y;
|
||||
return vec;
|
||||
}
|
||||
|
||||
public static Vector2 operator *(Vector2 vec, float scale)
|
||||
{
|
||||
vec.x *= scale;
|
||||
vec.y *= scale;
|
||||
return vec;
|
||||
}
|
||||
|
||||
public static Vector2 operator *(float scale, Vector2 vec)
|
||||
{
|
||||
vec.x *= scale;
|
||||
vec.y *= scale;
|
||||
return vec;
|
||||
}
|
||||
|
||||
public static Vector2 operator *(Vector2 left, Vector2 right)
|
||||
{
|
||||
left.x *= right.x;
|
||||
left.y *= right.y;
|
||||
return left;
|
||||
}
|
||||
|
||||
public static Vector2 operator /(Vector2 vec, float scale)
|
||||
{
|
||||
vec.x /= scale;
|
||||
vec.y /= scale;
|
||||
return vec;
|
||||
}
|
||||
|
||||
public static Vector2 operator /(Vector2 left, Vector2 right)
|
||||
{
|
||||
left.x /= right.x;
|
||||
left.y /= right.y;
|
||||
return left;
|
||||
}
|
||||
|
||||
public static bool operator ==(Vector2 left, Vector2 right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Vector2 left, Vector2 right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator <(Vector2 left, Vector2 right)
|
||||
{
|
||||
if (left.x.Equals(right.x))
|
||||
{
|
||||
return left.y < right.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
return left.x < right.x;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator >(Vector2 left, Vector2 right)
|
||||
{
|
||||
if (left.x.Equals(right.x))
|
||||
{
|
||||
return left.y > right.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
return left.x > right.x;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator <=(Vector2 left, Vector2 right)
|
||||
{
|
||||
if (left.x.Equals(right.x))
|
||||
{
|
||||
return left.y <= right.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
return left.x <= right.x;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator >=(Vector2 left, Vector2 right)
|
||||
{
|
||||
if (left.x.Equals(right.x))
|
||||
{
|
||||
return left.y >= right.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
return left.x >= right.x;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Vector2)
|
||||
{
|
||||
return Equals((Vector2)obj);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Equals(Vector2 other)
|
||||
{
|
||||
return x == other.x && y == other.y;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return y.GetHashCode() ^ x.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("({0}, {1})", new object[]
|
||||
{
|
||||
this.x.ToString(),
|
||||
this.y.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
public string ToString(string format)
|
||||
{
|
||||
return String.Format("({0}, {1})", new object[]
|
||||
{
|
||||
this.x.ToString(format),
|
||||
this.y.ToString(format)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
420
modules/mono/glue/cs_files/Vector3.cs
Normal file
420
modules/mono/glue/cs_files/Vector3.cs
Normal file
@ -0,0 +1,420 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// file: core/math/vector3.h
|
||||
// commit: bd282ff43f23fe845f29a3e25c8efc01bd65ffb0
|
||||
// file: core/math/vector3.cpp
|
||||
// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451
|
||||
// file: core/variant_call.cpp
|
||||
// commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Vector3 : IEquatable<Vector3>
|
||||
{
|
||||
public enum Axis
|
||||
{
|
||||
X = 0,
|
||||
Y,
|
||||
Z
|
||||
}
|
||||
|
||||
public float x;
|
||||
public float y;
|
||||
public float z;
|
||||
|
||||
public float this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return x;
|
||||
case 1:
|
||||
return y;
|
||||
case 2:
|
||||
return z;
|
||||
default:
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
x = value;
|
||||
return;
|
||||
case 1:
|
||||
y = value;
|
||||
return;
|
||||
case 2:
|
||||
z = value;
|
||||
return;
|
||||
default:
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void normalize()
|
||||
{
|
||||
float length = this.length();
|
||||
|
||||
if (length == 0f)
|
||||
{
|
||||
x = y = z = 0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
x /= length;
|
||||
y /= length;
|
||||
z /= length;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 abs()
|
||||
{
|
||||
return new Vector3(Mathf.abs(x), Mathf.abs(y), Mathf.abs(z));
|
||||
}
|
||||
|
||||
public float angle_to(Vector3 to)
|
||||
{
|
||||
return Mathf.atan2(cross(to).length(), dot(to));
|
||||
}
|
||||
|
||||
public Vector3 bounce(Vector3 n)
|
||||
{
|
||||
return -reflect(n);
|
||||
}
|
||||
|
||||
public Vector3 ceil()
|
||||
{
|
||||
return new Vector3(Mathf.ceil(x), Mathf.ceil(y), Mathf.ceil(z));
|
||||
}
|
||||
|
||||
public Vector3 cross(Vector3 b)
|
||||
{
|
||||
return new Vector3
|
||||
(
|
||||
(y * b.z) - (z * b.y),
|
||||
(z * b.x) - (x * b.z),
|
||||
(x * b.y) - (y * b.x)
|
||||
);
|
||||
}
|
||||
|
||||
public Vector3 cubic_interpolate(Vector3 b, Vector3 preA, Vector3 postB, float t)
|
||||
{
|
||||
Vector3 p0 = preA;
|
||||
Vector3 p1 = this;
|
||||
Vector3 p2 = b;
|
||||
Vector3 p3 = postB;
|
||||
|
||||
float t2 = t * t;
|
||||
float t3 = t2 * t;
|
||||
|
||||
return 0.5f * (
|
||||
(p1 * 2.0f) + (-p0 + p2) * t +
|
||||
(2.0f * p0 - 5.0f * p1 + 4f * p2 - p3) * t2 +
|
||||
(-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3
|
||||
);
|
||||
}
|
||||
|
||||
public float distance_squared_to(Vector3 b)
|
||||
{
|
||||
return (b - this).length_squared();
|
||||
}
|
||||
|
||||
public float distance_to(Vector3 b)
|
||||
{
|
||||
return (b - this).length();
|
||||
}
|
||||
|
||||
public float dot(Vector3 b)
|
||||
{
|
||||
return x * b.x + y * b.y + z * b.z;
|
||||
}
|
||||
|
||||
public Vector3 floor()
|
||||
{
|
||||
return new Vector3(Mathf.floor(x), Mathf.floor(y), Mathf.floor(z));
|
||||
}
|
||||
|
||||
public Vector3 inverse()
|
||||
{
|
||||
return new Vector3(1.0f / x, 1.0f / y, 1.0f / z);
|
||||
}
|
||||
|
||||
public bool is_normalized()
|
||||
{
|
||||
return Mathf.abs(length_squared() - 1.0f) < Mathf.Epsilon;
|
||||
}
|
||||
|
||||
public float length()
|
||||
{
|
||||
float x2 = x * x;
|
||||
float y2 = y * y;
|
||||
float z2 = z * z;
|
||||
|
||||
return Mathf.sqrt(x2 + y2 + z2);
|
||||
}
|
||||
|
||||
public float length_squared()
|
||||
{
|
||||
float x2 = x * x;
|
||||
float y2 = y * y;
|
||||
float z2 = z * z;
|
||||
|
||||
return x2 + y2 + z2;
|
||||
}
|
||||
|
||||
public Vector3 linear_interpolate(Vector3 b, float t)
|
||||
{
|
||||
return new Vector3
|
||||
(
|
||||
x + (t * (b.x - x)),
|
||||
y + (t * (b.y - y)),
|
||||
z + (t * (b.z - z))
|
||||
);
|
||||
}
|
||||
|
||||
public Axis max_axis()
|
||||
{
|
||||
return x < y ? (y < z ? Axis.Z : Axis.Y) : (x < z ? Axis.Z : Axis.X);
|
||||
}
|
||||
|
||||
public Axis min_axis()
|
||||
{
|
||||
return x < y ? (x < z ? Axis.X : Axis.Z) : (y < z ? Axis.Y : Axis.Z);
|
||||
}
|
||||
|
||||
public Vector3 normalized()
|
||||
{
|
||||
Vector3 v = this;
|
||||
v.normalize();
|
||||
return v;
|
||||
}
|
||||
|
||||
public Basis outer(Vector3 b)
|
||||
{
|
||||
return new Basis(
|
||||
new Vector3(x * b.x, x * b.y, x * b.z),
|
||||
new Vector3(y * b.x, y * b.y, y * b.z),
|
||||
new Vector3(z * b.x, z * b.y, z * b.z)
|
||||
);
|
||||
}
|
||||
|
||||
public Vector3 reflect(Vector3 n)
|
||||
{
|
||||
#if DEBUG
|
||||
if (!n.is_normalized())
|
||||
throw new ArgumentException(String.Format("{0} is not normalized", n), nameof(n));
|
||||
#endif
|
||||
return 2.0f * n * dot(n) - this;
|
||||
}
|
||||
|
||||
public Vector3 rotated(Vector3 axis, float phi)
|
||||
{
|
||||
return new Basis(axis, phi).xform(this);
|
||||
}
|
||||
|
||||
public Vector3 slide(Vector3 n)
|
||||
{
|
||||
return this - n * dot(n);
|
||||
}
|
||||
|
||||
public Vector3 snapped(Vector3 by)
|
||||
{
|
||||
return new Vector3
|
||||
(
|
||||
Mathf.stepify(x, by.x),
|
||||
Mathf.stepify(y, by.y),
|
||||
Mathf.stepify(z, by.z)
|
||||
);
|
||||
}
|
||||
|
||||
public Basis to_diagonal_matrix()
|
||||
{
|
||||
return new Basis(
|
||||
x, 0f, 0f,
|
||||
0f, y, 0f,
|
||||
0f, 0f, z
|
||||
);
|
||||
}
|
||||
|
||||
public Vector3(float x, float y, float z)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public static Vector3 operator +(Vector3 left, Vector3 right)
|
||||
{
|
||||
left.x += right.x;
|
||||
left.y += right.y;
|
||||
left.z += right.z;
|
||||
return left;
|
||||
}
|
||||
|
||||
public static Vector3 operator -(Vector3 left, Vector3 right)
|
||||
{
|
||||
left.x -= right.x;
|
||||
left.y -= right.y;
|
||||
left.z -= right.z;
|
||||
return left;
|
||||
}
|
||||
|
||||
public static Vector3 operator -(Vector3 vec)
|
||||
{
|
||||
vec.x = -vec.x;
|
||||
vec.y = -vec.y;
|
||||
vec.z = -vec.z;
|
||||
return vec;
|
||||
}
|
||||
|
||||
public static Vector3 operator *(Vector3 vec, float scale)
|
||||
{
|
||||
vec.x *= scale;
|
||||
vec.y *= scale;
|
||||
vec.z *= scale;
|
||||
return vec;
|
||||
}
|
||||
|
||||
public static Vector3 operator *(float scale, Vector3 vec)
|
||||
{
|
||||
vec.x *= scale;
|
||||
vec.y *= scale;
|
||||
vec.z *= scale;
|
||||
return vec;
|
||||
}
|
||||
|
||||
public static Vector3 operator *(Vector3 left, Vector3 right)
|
||||
{
|
||||
left.x *= right.x;
|
||||
left.y *= right.y;
|
||||
left.z *= right.z;
|
||||
return left;
|
||||
}
|
||||
|
||||
public static Vector3 operator /(Vector3 vec, float scale)
|
||||
{
|
||||
vec.x /= scale;
|
||||
vec.y /= scale;
|
||||
vec.z /= scale;
|
||||
return vec;
|
||||
}
|
||||
|
||||
public static Vector3 operator /(Vector3 left, Vector3 right)
|
||||
{
|
||||
left.x /= right.x;
|
||||
left.y /= right.y;
|
||||
left.z /= right.z;
|
||||
return left;
|
||||
}
|
||||
|
||||
public static bool operator ==(Vector3 left, Vector3 right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Vector3 left, Vector3 right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator <(Vector3 left, Vector3 right)
|
||||
{
|
||||
if (left.x == right.x)
|
||||
{
|
||||
if (left.y == right.y)
|
||||
return left.z < right.z;
|
||||
else
|
||||
return left.y < right.y;
|
||||
}
|
||||
|
||||
return left.x < right.x;
|
||||
}
|
||||
|
||||
public static bool operator >(Vector3 left, Vector3 right)
|
||||
{
|
||||
if (left.x == right.x)
|
||||
{
|
||||
if (left.y == right.y)
|
||||
return left.z > right.z;
|
||||
else
|
||||
return left.y > right.y;
|
||||
}
|
||||
|
||||
return left.x > right.x;
|
||||
}
|
||||
|
||||
public static bool operator <=(Vector3 left, Vector3 right)
|
||||
{
|
||||
if (left.x == right.x)
|
||||
{
|
||||
if (left.y == right.y)
|
||||
return left.z <= right.z;
|
||||
else
|
||||
return left.y < right.y;
|
||||
}
|
||||
|
||||
return left.x < right.x;
|
||||
}
|
||||
|
||||
public static bool operator >=(Vector3 left, Vector3 right)
|
||||
{
|
||||
if (left.x == right.x)
|
||||
{
|
||||
if (left.y == right.y)
|
||||
return left.z >= right.z;
|
||||
else
|
||||
return left.y > right.y;
|
||||
}
|
||||
|
||||
return left.x > right.x;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Vector3)
|
||||
{
|
||||
return Equals((Vector3)obj);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Equals(Vector3 other)
|
||||
{
|
||||
return x == other.x && y == other.y && z == other.z;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("({0}, {1}, {2})", new object[]
|
||||
{
|
||||
this.x.ToString(),
|
||||
this.y.ToString(),
|
||||
this.z.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
public string ToString(string format)
|
||||
{
|
||||
return String.Format("({0}, {1}, {2})", new object[]
|
||||
{
|
||||
this.x.ToString(format),
|
||||
this.y.ToString(format),
|
||||
this.z.ToString(format)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
302
modules/mono/glue/glue_header.h
Normal file
302
modules/mono/glue/glue_header.h
Normal file
@ -0,0 +1,302 @@
|
||||
/*************************************************************************/
|
||||
/* glue_header.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "../csharp_script.h"
|
||||
#include "../mono_gd/gd_mono_class.h"
|
||||
#include "../mono_gd/gd_mono_internals.h"
|
||||
#include "../mono_gd/gd_mono_marshal.h"
|
||||
#include "../signal_awaiter_utils.h"
|
||||
|
||||
#include "bind/core_bind.h"
|
||||
#include "class_db.h"
|
||||
#include "io/marshalls.h"
|
||||
#include "object.h"
|
||||
#include "os/os.h"
|
||||
#include "project_settings.h"
|
||||
#include "reference.h"
|
||||
#include "variant_parser.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#include "editor/editor_node.h"
|
||||
#endif
|
||||
|
||||
#define GODOTSHARP_INSTANCE_OBJECT(m_instance, m_type) \
|
||||
static ClassDB::ClassInfo *ci = NULL; \
|
||||
if (!ci) { \
|
||||
ci = ClassDB::classes.getptr(m_type); \
|
||||
} \
|
||||
Object *m_instance = ci->creation_func();
|
||||
|
||||
void godot_icall_Object_Dtor(Object *ptr) {
|
||||
ERR_FAIL_NULL(ptr);
|
||||
_GodotSharp::get_singleton()->queue_dispose(ptr);
|
||||
}
|
||||
|
||||
// -- ClassDB --
|
||||
|
||||
MethodBind *godot_icall_ClassDB_get_method(MonoString *p_type, MonoString *p_method) {
|
||||
StringName type(GDMonoMarshal::mono_string_to_godot(p_type));
|
||||
StringName method(GDMonoMarshal::mono_string_to_godot(p_method));
|
||||
return ClassDB::get_method(type, method);
|
||||
}
|
||||
|
||||
// -- SignalAwaiter --
|
||||
|
||||
Error godot_icall_Object_connect_signal_awaiter(Object *p_source, MonoString *p_signal, Object *p_target, MonoObject *p_awaiter) {
|
||||
String signal = GDMonoMarshal::mono_string_to_godot(p_signal);
|
||||
return SignalAwaiterUtils::connect_signal_awaiter(p_source, signal, p_target, p_awaiter);
|
||||
}
|
||||
|
||||
// -- NodePath --
|
||||
|
||||
NodePath *godot_icall_NodePath_Ctor(MonoString *p_path) {
|
||||
return memnew(NodePath(GDMonoMarshal::mono_string_to_godot(p_path)));
|
||||
}
|
||||
|
||||
void godot_icall_NodePath_Dtor(NodePath *p_ptr) {
|
||||
ERR_FAIL_NULL(p_ptr);
|
||||
_GodotSharp::get_singleton()->queue_dispose(p_ptr);
|
||||
}
|
||||
|
||||
MonoString *godot_icall_NodePath_operator_String(NodePath *p_np) {
|
||||
return GDMonoMarshal::mono_string_from_godot(p_np->operator String());
|
||||
}
|
||||
|
||||
MonoArray *godot_icall_String_md5_buffer(MonoString *p_str) {
|
||||
Vector<uint8_t> ret = GDMonoMarshal::mono_string_to_godot(p_str).md5_buffer();
|
||||
// TODO Check possible Array/Vector<uint8_t> problem?
|
||||
return GDMonoMarshal::Array_to_mono_array(Variant(ret));
|
||||
}
|
||||
|
||||
// -- RID --
|
||||
|
||||
RID *godot_icall_RID_Ctor(Object *p_from) {
|
||||
Resource *res_from = Object::cast_to<Resource>(p_from);
|
||||
|
||||
if (res_from)
|
||||
return memnew(RID(res_from->get_rid()));
|
||||
|
||||
return memnew(RID);
|
||||
}
|
||||
|
||||
void godot_icall_RID_Dtor(RID *p_ptr) {
|
||||
ERR_FAIL_NULL(p_ptr);
|
||||
_GodotSharp::get_singleton()->queue_dispose(p_ptr);
|
||||
}
|
||||
|
||||
// -- String --
|
||||
|
||||
MonoString *godot_icall_String_md5_text(MonoString *p_str) {
|
||||
String ret = GDMonoMarshal::mono_string_to_godot(p_str).md5_text();
|
||||
return GDMonoMarshal::mono_string_from_godot(ret);
|
||||
}
|
||||
|
||||
int godot_icall_String_rfind(MonoString *p_str, MonoString *p_what, int p_from) {
|
||||
String what = GDMonoMarshal::mono_string_to_godot(p_what);
|
||||
return GDMonoMarshal::mono_string_to_godot(p_str).rfind(what, p_from);
|
||||
}
|
||||
|
||||
int godot_icall_String_rfindn(MonoString *p_str, MonoString *p_what, int p_from) {
|
||||
String what = GDMonoMarshal::mono_string_to_godot(p_what);
|
||||
return GDMonoMarshal::mono_string_to_godot(p_str).rfindn(what, p_from);
|
||||
}
|
||||
|
||||
MonoArray *godot_icall_String_sha256_buffer(MonoString *p_str) {
|
||||
Vector<uint8_t> ret = GDMonoMarshal::mono_string_to_godot(p_str).sha256_buffer();
|
||||
return GDMonoMarshal::Array_to_mono_array(Variant(ret));
|
||||
}
|
||||
|
||||
MonoString *godot_icall_String_sha256_text(MonoString *p_str) {
|
||||
String ret = GDMonoMarshal::mono_string_to_godot(p_str).sha256_text();
|
||||
return GDMonoMarshal::mono_string_from_godot(ret);
|
||||
}
|
||||
|
||||
// -- Global Scope --
|
||||
|
||||
MonoObject *godot_icall_Godot_bytes2var(MonoArray *p_bytes) {
|
||||
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);
|
||||
if (err != OK) {
|
||||
ret = RTR("Not enough bytes for decoding bytes, or invalid format.");
|
||||
}
|
||||
return GDMonoMarshal::variant_to_mono_object(ret);
|
||||
}
|
||||
|
||||
MonoObject *godot_icall_Godot_convert(MonoObject *p_what, int p_type) {
|
||||
Variant what = GDMonoMarshal::mono_object_to_variant(p_what);
|
||||
const Variant *args[1] = { &what };
|
||||
Variant::CallError ce;
|
||||
Variant ret = Variant::construct(Variant::Type(p_type), args, 1, ce);
|
||||
ERR_FAIL_COND_V(ce.error != Variant::CallError::CALL_OK, NULL);
|
||||
return GDMonoMarshal::variant_to_mono_object(ret);
|
||||
}
|
||||
|
||||
int godot_icall_Godot_hash(MonoObject *p_var) {
|
||||
return GDMonoMarshal::mono_object_to_variant(p_var).hash();
|
||||
}
|
||||
|
||||
MonoObject *godot_icall_Godot_instance_from_id(int p_instance_id) {
|
||||
return GDMonoUtils::unmanaged_get_managed(ObjectDB::get_instance(p_instance_id));
|
||||
}
|
||||
|
||||
void godot_icall_Godot_print(MonoArray *p_what) {
|
||||
Array what = GDMonoMarshal::mono_array_to_Array(p_what);
|
||||
String str;
|
||||
for (int i = 0; i < what.size(); i++)
|
||||
str += what[i].operator String();
|
||||
print_line(str);
|
||||
}
|
||||
|
||||
void godot_icall_Godot_printerr(MonoArray *p_what) {
|
||||
Array what = GDMonoMarshal::mono_array_to_Array(p_what);
|
||||
String str;
|
||||
for (int i = 0; i < what.size(); i++)
|
||||
str += what[i].operator String();
|
||||
OS::get_singleton()->printerr("%s\n", str.utf8().get_data());
|
||||
}
|
||||
|
||||
void godot_icall_Godot_printraw(MonoArray *p_what) {
|
||||
Array what = GDMonoMarshal::mono_array_to_Array(p_what);
|
||||
String str;
|
||||
for (int i = 0; i < what.size(); i++)
|
||||
str += what[i].operator String();
|
||||
OS::get_singleton()->print("%s", str.utf8().get_data());
|
||||
}
|
||||
|
||||
void godot_icall_Godot_prints(MonoArray *p_what) {
|
||||
Array what = GDMonoMarshal::mono_array_to_Array(p_what);
|
||||
String str;
|
||||
for (int i = 0; i < what.size(); i++) {
|
||||
if (i)
|
||||
str += " ";
|
||||
str += what[i].operator String();
|
||||
}
|
||||
print_line(str);
|
||||
}
|
||||
|
||||
void godot_icall_Godot_printt(MonoArray *p_what) {
|
||||
Array what = GDMonoMarshal::mono_array_to_Array(p_what);
|
||||
String str;
|
||||
for (int i = 0; i < what.size(); i++) {
|
||||
if (i)
|
||||
str += "\t";
|
||||
str += what[i].operator String();
|
||||
}
|
||||
print_line(str);
|
||||
}
|
||||
|
||||
void godot_icall_Godot_seed(int p_seed) {
|
||||
Math::seed(p_seed);
|
||||
}
|
||||
|
||||
MonoString *godot_icall_Godot_str(MonoArray *p_what) {
|
||||
String str;
|
||||
Array what = GDMonoMarshal::mono_array_to_Array(p_what);
|
||||
|
||||
for (int i = 0; i < what.size(); i++) {
|
||||
String os = what[i].operator String();
|
||||
|
||||
if (i == 0)
|
||||
str = os;
|
||||
else
|
||||
str += os;
|
||||
}
|
||||
|
||||
return GDMonoMarshal::mono_string_from_godot(str);
|
||||
}
|
||||
|
||||
MonoObject *godot_icall_Godot_str2var(MonoString *p_str) {
|
||||
Variant ret;
|
||||
|
||||
VariantParser::StreamString ss;
|
||||
ss.s = GDMonoMarshal::mono_string_to_godot(p_str);
|
||||
|
||||
String errs;
|
||||
int line;
|
||||
Error err = VariantParser::parse(&ss, ret, errs, line);
|
||||
if (err != OK) {
|
||||
String err_str = "Parse error at line " + itos(line) + ": " + errs;
|
||||
ERR_PRINTS(err_str);
|
||||
ret = err_str;
|
||||
}
|
||||
|
||||
return GDMonoMarshal::variant_to_mono_object(ret);
|
||||
}
|
||||
|
||||
bool godot_icall_Godot_type_exists(MonoString *p_type) {
|
||||
return ClassDB::class_exists(GDMonoMarshal::mono_string_to_godot(p_type));
|
||||
}
|
||||
|
||||
MonoArray *godot_icall_Godot_var2bytes(MonoObject *p_var) {
|
||||
Variant var = GDMonoMarshal::mono_object_to_variant(p_var);
|
||||
|
||||
PoolByteArray barr;
|
||||
int len;
|
||||
Error err = encode_variant(var, NULL, len);
|
||||
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);
|
||||
}
|
||||
|
||||
return GDMonoMarshal::PoolByteArray_to_mono_array(barr);
|
||||
}
|
||||
|
||||
MonoString *godot_icall_Godot_var2str(MonoObject *p_var) {
|
||||
String vars;
|
||||
VariantWriter::write_to_string(GDMonoMarshal::mono_object_to_variant(p_var), vars);
|
||||
return GDMonoMarshal::mono_string_from_godot(vars);
|
||||
}
|
||||
|
||||
MonoObject *godot_icall_Godot_weakref(Object *p_obj) {
|
||||
if (!p_obj)
|
||||
return NULL;
|
||||
|
||||
Ref<WeakRef> wref;
|
||||
Reference *ref = Object::cast_to<Reference>(p_obj);
|
||||
|
||||
if (ref) {
|
||||
REF r = ref;
|
||||
if (!r.is_valid())
|
||||
return NULL;
|
||||
|
||||
wref.instance();
|
||||
wref->set_ref(r);
|
||||
} else {
|
||||
wref.instance();
|
||||
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()));
|
||||
}
|
41
modules/mono/godotsharp_defs.h
Normal file
41
modules/mono/godotsharp_defs.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*************************************************************************/
|
||||
/* godotsharp_defs.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 GODOTSHARP_DEFS_H
|
||||
#define GODOTSHARP_DEFS_H
|
||||
|
||||
#define BINDINGS_NAMESPACE "Godot"
|
||||
#define BINDINGS_GLOBAL_SCOPE_CLASS "GD"
|
||||
#define BINDINGS_PTR_FIELD "ptr"
|
||||
#define BINDINGS_NATIVE_NAME_FIELD "nativeName"
|
||||
#define API_ASSEMBLY_NAME "GodotSharp"
|
||||
#define EDITOR_API_ASSEMBLY_NAME "GodotSharpEditor"
|
||||
#define EDITOR_TOOLS_ASSEMBLY_NAME "GodotSharpTools"
|
||||
|
||||
#endif // GODOTSHARP_DEFS_H
|
185
modules/mono/godotsharp_dirs.cpp
Normal file
185
modules/mono/godotsharp_dirs.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
/*************************************************************************/
|
||||
/* godotsharp_dirs.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "godotsharp_dirs.h"
|
||||
|
||||
#include "os/os.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#include "editor/editor_settings.h"
|
||||
#include "project_settings.h"
|
||||
#include "version.h"
|
||||
#endif
|
||||
|
||||
namespace GodotSharpDirs {
|
||||
|
||||
String _get_expected_build_config() {
|
||||
#ifdef TOOLS_ENABLED
|
||||
return "Tools";
|
||||
#else
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
return "Debug";
|
||||
#else
|
||||
return "Release";
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
String _get_mono_user_dir() {
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (EditorSettings::get_singleton()) {
|
||||
return EditorSettings::get_singleton()->get_settings_path().plus_file("mono");
|
||||
} else {
|
||||
String settings_path;
|
||||
|
||||
if (OS::get_singleton()->has_environment("APPDATA")) {
|
||||
String app_data = OS::get_singleton()->get_environment("APPDATA").replace("\\", "/");
|
||||
settings_path = app_data.plus_file(String(_MKSTR(VERSION_SHORT_NAME)).capitalize());
|
||||
} else if (OS::get_singleton()->has_environment("HOME")) {
|
||||
String home = OS::get_singleton()->get_environment("HOME");
|
||||
settings_path = home.plus_file("." + String(_MKSTR(VERSION_SHORT_NAME)).to_lower());
|
||||
}
|
||||
|
||||
return settings_path.plus_file("mono");
|
||||
}
|
||||
#else
|
||||
return OS::get_singleton()->get_data_dir().plus_file("mono");
|
||||
#endif
|
||||
}
|
||||
|
||||
class _GodotSharpDirs {
|
||||
|
||||
public:
|
||||
String res_data_dir;
|
||||
String res_metadata_dir;
|
||||
String res_assemblies_dir;
|
||||
String res_config_dir;
|
||||
String res_temp_dir;
|
||||
String res_temp_assemblies_base_dir;
|
||||
String res_temp_assemblies_dir;
|
||||
String mono_user_dir;
|
||||
String mono_logs_dir;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
String mono_solutions_dir;
|
||||
String build_logs_dir;
|
||||
String sln_filepath;
|
||||
String csproj_filepath;
|
||||
#endif
|
||||
|
||||
private:
|
||||
_GodotSharpDirs() {
|
||||
res_data_dir = "res://.mono";
|
||||
res_metadata_dir = res_data_dir.plus_file("metadata");
|
||||
res_assemblies_dir = res_data_dir.plus_file("assemblies");
|
||||
res_config_dir = res_data_dir.plus_file("etc").plus_file("mono");
|
||||
|
||||
// TODO use paths from csproj
|
||||
res_temp_dir = res_data_dir.plus_file("temp");
|
||||
res_temp_assemblies_base_dir = res_temp_dir.plus_file("bin");
|
||||
res_temp_assemblies_dir = res_temp_assemblies_base_dir.plus_file(_get_expected_build_config());
|
||||
|
||||
mono_user_dir = _get_mono_user_dir();
|
||||
mono_logs_dir = mono_user_dir.plus_file("mono_logs");
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
mono_solutions_dir = mono_user_dir.plus_file("solutions");
|
||||
build_logs_dir = mono_user_dir.plus_file("build_logs");
|
||||
String base_path = String("res://") + ProjectSettings::get_singleton()->get("application/config/name");
|
||||
sln_filepath = ProjectSettings::get_singleton()->globalize_path(base_path + ".sln");
|
||||
csproj_filepath = ProjectSettings::get_singleton()->globalize_path(base_path + ".csproj");
|
||||
#endif
|
||||
}
|
||||
|
||||
_GodotSharpDirs(const _GodotSharpDirs &);
|
||||
_GodotSharpDirs &operator=(const _GodotSharpDirs &);
|
||||
|
||||
public:
|
||||
static _GodotSharpDirs &get_singleton() {
|
||||
static _GodotSharpDirs singleton;
|
||||
return singleton;
|
||||
}
|
||||
};
|
||||
|
||||
String get_res_data_dir() {
|
||||
return _GodotSharpDirs::get_singleton().res_data_dir;
|
||||
}
|
||||
|
||||
String get_res_metadata_dir() {
|
||||
return _GodotSharpDirs::get_singleton().res_metadata_dir;
|
||||
}
|
||||
|
||||
String get_res_assemblies_dir() {
|
||||
return _GodotSharpDirs::get_singleton().res_assemblies_dir;
|
||||
}
|
||||
|
||||
String get_res_config_dir() {
|
||||
return _GodotSharpDirs::get_singleton().res_config_dir;
|
||||
}
|
||||
|
||||
String get_res_temp_dir() {
|
||||
return _GodotSharpDirs::get_singleton().res_temp_dir;
|
||||
}
|
||||
|
||||
String get_res_temp_assemblies_base_dir() {
|
||||
return _GodotSharpDirs::get_singleton().res_temp_assemblies_base_dir;
|
||||
}
|
||||
|
||||
String get_res_temp_assemblies_dir() {
|
||||
return _GodotSharpDirs::get_singleton().res_temp_assemblies_dir;
|
||||
}
|
||||
|
||||
String get_mono_user_dir() {
|
||||
return _GodotSharpDirs::get_singleton().mono_user_dir;
|
||||
}
|
||||
|
||||
String get_mono_logs_dir() {
|
||||
return _GodotSharpDirs::get_singleton().mono_logs_dir;
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
String get_mono_solutions_dir() {
|
||||
return _GodotSharpDirs::get_singleton().mono_solutions_dir;
|
||||
}
|
||||
|
||||
String get_build_logs_dir() {
|
||||
return _GodotSharpDirs::get_singleton().build_logs_dir;
|
||||
}
|
||||
|
||||
String get_project_sln_path() {
|
||||
return _GodotSharpDirs::get_singleton().sln_filepath;
|
||||
}
|
||||
|
||||
String get_project_csproj_path() {
|
||||
return _GodotSharpDirs::get_singleton().csproj_filepath;
|
||||
}
|
||||
#endif
|
||||
}
|
58
modules/mono/godotsharp_dirs.h
Normal file
58
modules/mono/godotsharp_dirs.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*************************************************************************/
|
||||
/* godotsharp_dirs.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 GODOTSHARP_DIRS_H
|
||||
#define GODOTSHARP_DIRS_H
|
||||
|
||||
#include "ustring.h"
|
||||
|
||||
namespace GodotSharpDirs {
|
||||
|
||||
String get_res_data_dir();
|
||||
String get_res_metadata_dir();
|
||||
String get_res_assemblies_dir();
|
||||
String get_res_config_dir();
|
||||
String get_res_temp_dir();
|
||||
String get_res_temp_assemblies_base_dir();
|
||||
String get_res_temp_assemblies_dir();
|
||||
|
||||
String get_mono_user_dir();
|
||||
String get_mono_logs_dir();
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
String get_mono_solutions_dir();
|
||||
String get_build_logs_dir();
|
||||
String get_custom_project_settings_dir();
|
||||
#endif
|
||||
|
||||
String get_project_sln_path();
|
||||
String get_project_csproj_path();
|
||||
}
|
||||
|
||||
#endif // GODOTSHARP_DIRS_H
|
77
modules/mono/mono_gc_handle.cpp
Normal file
77
modules/mono/mono_gc_handle.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
/*************************************************************************/
|
||||
/* mono_gc_handle.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "mono_gc_handle.h"
|
||||
|
||||
#include "mono_gd/gd_mono.h"
|
||||
|
||||
uint32_t MonoGCHandle::make_strong_handle(MonoObject *p_object) {
|
||||
|
||||
return mono_gchandle_new(
|
||||
p_object,
|
||||
false /* do not pin the object */
|
||||
);
|
||||
}
|
||||
|
||||
uint32_t MonoGCHandle::make_weak_handle(MonoObject *p_object) {
|
||||
|
||||
return mono_gchandle_new_weakref(
|
||||
p_object,
|
||||
true /* track_resurrection: allows us to invoke _notification(NOTIFICATION_PREDELETE) while disposing */
|
||||
);
|
||||
}
|
||||
|
||||
Ref<MonoGCHandle> MonoGCHandle::create_strong(MonoObject *p_object) {
|
||||
|
||||
return memnew(MonoGCHandle(make_strong_handle(p_object)));
|
||||
}
|
||||
|
||||
Ref<MonoGCHandle> MonoGCHandle::create_weak(MonoObject *p_object) {
|
||||
|
||||
return memnew(MonoGCHandle(make_weak_handle(p_object)));
|
||||
}
|
||||
|
||||
void MonoGCHandle::release() {
|
||||
|
||||
if (!released && GDMono::get_singleton()->is_runtime_initialized()) {
|
||||
mono_gchandle_free(handle);
|
||||
released = true;
|
||||
}
|
||||
}
|
||||
|
||||
MonoGCHandle::MonoGCHandle(uint32_t p_handle) {
|
||||
|
||||
released = false;
|
||||
handle = p_handle;
|
||||
}
|
||||
|
||||
MonoGCHandle::~MonoGCHandle() {
|
||||
|
||||
release();
|
||||
}
|
63
modules/mono/mono_gc_handle.h
Normal file
63
modules/mono/mono_gc_handle.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*************************************************************************/
|
||||
/* mono_gc_handle.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 CSHARP_GC_HANDLE_H
|
||||
#define CSHARP_GC_HANDLE_H
|
||||
|
||||
#include <mono/jit/jit.h>
|
||||
|
||||
#include "reference.h"
|
||||
|
||||
class MonoGCHandle : public Reference {
|
||||
|
||||
GDCLASS(MonoGCHandle, Reference)
|
||||
|
||||
bool released;
|
||||
uint32_t handle;
|
||||
|
||||
public:
|
||||
static uint32_t make_strong_handle(MonoObject *p_object);
|
||||
static uint32_t make_weak_handle(MonoObject *p_object);
|
||||
|
||||
static Ref<MonoGCHandle> create_strong(MonoObject *p_object);
|
||||
static Ref<MonoGCHandle> create_weak(MonoObject *p_object);
|
||||
|
||||
_FORCE_INLINE_ MonoObject *get_target() const { return released ? NULL : mono_gchandle_get_target(handle); }
|
||||
|
||||
_FORCE_INLINE_ void set_handle(uint32_t p_handle) {
|
||||
handle = p_handle;
|
||||
released = false;
|
||||
}
|
||||
void release();
|
||||
|
||||
MonoGCHandle(uint32_t p_handle);
|
||||
~MonoGCHandle();
|
||||
};
|
||||
|
||||
#endif // CSHARP_GC_HANDLE_H
|
771
modules/mono/mono_gd/gd_mono.cpp
Normal file
771
modules/mono/mono_gd/gd_mono.cpp
Normal file
@ -0,0 +1,771 @@
|
||||
/*************************************************************************/
|
||||
/* gd_mono.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "gd_mono.h"
|
||||
|
||||
#include <mono/metadata/mono-config.h>
|
||||
#include <mono/metadata/mono-debug.h>
|
||||
|
||||
#include "os/dir_access.h"
|
||||
#include "os/file_access.h"
|
||||
#include "os/os.h"
|
||||
#include "os/thread.h"
|
||||
#include "project_settings.h"
|
||||
|
||||
#include "../csharp_script.h"
|
||||
#include "../utils/path_utils.h"
|
||||
#include "gd_mono_utils.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#include "../editor/godotsharp_editor.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
|
||||
|
||||
GDMono *GDMono::singleton = NULL;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
static bool _wait_for_debugger_msecs(uint32_t p_msecs) {
|
||||
|
||||
do {
|
||||
if (mono_is_debugger_attached())
|
||||
return true;
|
||||
|
||||
int last_tick = OS::get_singleton()->get_ticks_msec();
|
||||
|
||||
OS::get_singleton()->delay_usec((p_msecs < 25 ? p_msecs : 25) * 1000);
|
||||
|
||||
int tdiff = OS::get_singleton()->get_ticks_msec() - last_tick;
|
||||
|
||||
if (tdiff > p_msecs) {
|
||||
p_msecs = 0;
|
||||
} else {
|
||||
p_msecs -= tdiff;
|
||||
}
|
||||
} while (p_msecs > 0);
|
||||
|
||||
return mono_is_debugger_attached();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
// temporary workaround. should be provided from Main::setup/setup2 instead
|
||||
bool _is_project_manager_requested() {
|
||||
|
||||
List<String> cmdline_args = OS::get_singleton()->get_cmdline_args();
|
||||
for (List<String>::Element *E = cmdline_args.front(); E; E = E->next()) {
|
||||
const String &arg = E->get();
|
||||
if (arg == "-p" || arg == "--project-manager")
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
void gdmono_debug_init() {
|
||||
|
||||
mono_debug_init(MONO_DEBUG_FORMAT_MONO);
|
||||
|
||||
int da_port = GLOBAL_DEF("mono/debugger_agent/port", 23685);
|
||||
bool da_suspend = GLOBAL_DEF("mono/debugger_agent/wait_for_debugger", false);
|
||||
int da_timeout = GLOBAL_DEF("mono/debugger_agent/wait_timeout", 3000);
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (Engine::get_singleton()->is_editor_hint() ||
|
||||
ProjectSettings::get_singleton()->get_resource_path().empty() ||
|
||||
_is_project_manager_requested()) {
|
||||
return;
|
||||
}
|
||||
#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();
|
||||
// --debugger-agent=help
|
||||
const char *options[] = {
|
||||
"--soft-breakpoints",
|
||||
da_args.get_data()
|
||||
};
|
||||
mono_jit_parse_options(2, (char **)options);
|
||||
}
|
||||
#endif
|
||||
|
||||
void GDMono::initialize() {
|
||||
|
||||
ERR_FAIL_NULL(Engine::get_singleton());
|
||||
|
||||
OS::get_singleton()->print("Initializing mono...\n");
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
_initialize_and_check_api_hashes();
|
||||
#endif
|
||||
|
||||
GDMonoLog::get_singleton()->initialize();
|
||||
|
||||
#ifdef MONO_PRINT_HANDLER_ENABLED
|
||||
mono_trace_set_print_handler(gdmono_MonoPrintCallback);
|
||||
mono_trace_set_printerr_handler(gdmono_MonoPrintCallback);
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
mono_reg_info = MonoRegUtils::find_mono();
|
||||
|
||||
CharString assembly_dir;
|
||||
CharString config_dir;
|
||||
|
||||
if (mono_reg_info.assembly_dir.length() && DirAccess::exists(mono_reg_info.assembly_dir)) {
|
||||
assembly_dir = mono_reg_info.assembly_dir.utf8();
|
||||
}
|
||||
|
||||
if (mono_reg_info.config_dir.length() && DirAccess::exists(mono_reg_info.config_dir)) {
|
||||
config_dir = mono_reg_info.config_dir.utf8();
|
||||
}
|
||||
|
||||
mono_set_dirs(assembly_dir.length() ? assembly_dir.get_data() : NULL,
|
||||
config_dir.length() ? config_dir.get_data() : NULL);
|
||||
#else
|
||||
mono_set_dirs(NULL, NULL);
|
||||
#endif
|
||||
|
||||
GDMonoAssembly::initialize();
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
gdmono_debug_init();
|
||||
#endif
|
||||
|
||||
mono_config_parse(NULL);
|
||||
|
||||
root_domain = mono_jit_init_version("GodotEngine.RootDomain", "v4.0.30319");
|
||||
|
||||
ERR_EXPLAIN("Mono: Failed to initialize runtime");
|
||||
ERR_FAIL_NULL(root_domain);
|
||||
|
||||
GDMonoUtils::set_main_thread(GDMonoUtils::get_current_thread());
|
||||
|
||||
runtime_initialized = true;
|
||||
|
||||
OS::get_singleton()->print("Mono: Runtime initialized\n");
|
||||
|
||||
// mscorlib assembly MUST be present at initialization
|
||||
ERR_EXPLAIN("Mono: Failed to load mscorlib assembly");
|
||||
ERR_FAIL_COND(!_load_corlib_assembly());
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
// The tools domain must be loaded here, before the scripts domain.
|
||||
// Otherwise domain unload on the scripts domain will hang indefinitely.
|
||||
|
||||
ERR_EXPLAIN("Mono: Failed to load tools domain");
|
||||
ERR_FAIL_COND(_load_tools_domain() != OK);
|
||||
|
||||
// TODO move to editor init callback, and do it lazily when required before editor init (e.g.: bindings generation)
|
||||
ERR_EXPLAIN("Mono: Failed to load Editor Tools assembly");
|
||||
ERR_FAIL_COND(!_load_editor_tools_assembly());
|
||||
#endif
|
||||
|
||||
ERR_EXPLAIN("Mono: Failed to load scripts domain");
|
||||
ERR_FAIL_COND(_load_scripts_domain() != OK);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
bool debugger_attached = _wait_for_debugger_msecs(500);
|
||||
if (!debugger_attached && OS::get_singleton()->is_stdout_verbose())
|
||||
OS::get_singleton()->printerr("Mono: Debugger wait timeout\n");
|
||||
#endif
|
||||
|
||||
_register_internal_calls();
|
||||
|
||||
// The following assemblies are not required at initialization
|
||||
_load_all_script_assemblies();
|
||||
|
||||
OS::get_singleton()->print("Mono: EVERYTHING OK\n");
|
||||
}
|
||||
|
||||
#ifndef MONO_GLUE_DISABLED
|
||||
namespace GodotSharpBindings {
|
||||
|
||||
uint64_t get_core_api_hash();
|
||||
uint64_t get_editor_api_hash();
|
||||
|
||||
void register_generated_icalls();
|
||||
} // namespace GodotSharpBindings
|
||||
#endif
|
||||
|
||||
void GDMono::_register_internal_calls() {
|
||||
#ifndef MONO_GLUE_DISABLED
|
||||
GodotSharpBindings::register_generated_icalls();
|
||||
#endif
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
GodotSharpBuilds::_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);
|
||||
|
||||
#ifndef MONO_GLUE_DISABLED
|
||||
if (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);
|
||||
|
||||
#ifndef MONO_GLUE_DISABLED
|
||||
if (api_editor_hash != GodotSharpBindings::get_editor_api_hash()) {
|
||||
ERR_PRINT("Mono: Editor API hash mismatch!");
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
}
|
||||
#endif // DEBUG_METHODS_ENABLED
|
||||
|
||||
void GDMono::add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly) {
|
||||
|
||||
assemblies[p_domain_id][p_assembly->get_name()] = p_assembly;
|
||||
}
|
||||
|
||||
bool GDMono::_load_assembly(const String &p_name, GDMonoAssembly **r_assembly) {
|
||||
|
||||
CRASH_COND(!r_assembly);
|
||||
|
||||
if (OS::get_singleton()->is_stdout_verbose())
|
||||
OS::get_singleton()->print((String() + "Mono: Loading assembly " + p_name + "...\n").utf8());
|
||||
|
||||
MonoImageOpenStatus status;
|
||||
MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8());
|
||||
MonoAssembly *assembly = mono_assembly_load_full(aname, NULL, &status, false);
|
||||
mono_assembly_name_free(aname);
|
||||
|
||||
if (!assembly)
|
||||
return false;
|
||||
|
||||
uint32_t domain_id = mono_domain_get_id(mono_domain_get());
|
||||
|
||||
GDMonoAssembly **stored_assembly = assemblies[domain_id].getptr(p_name);
|
||||
|
||||
if (stored_assembly) {
|
||||
// Loaded by our preload hook (status is not initialized when returning from a preload hook)
|
||||
ERR_FAIL_COND_V((*stored_assembly)->get_assembly() != assembly, false);
|
||||
*r_assembly = *stored_assembly;
|
||||
} else {
|
||||
ERR_FAIL_COND_V(status != MONO_IMAGE_OK, false);
|
||||
|
||||
MonoImage *assembly_image = mono_assembly_get_image(assembly);
|
||||
ERR_FAIL_NULL_V(assembly_image, false);
|
||||
|
||||
const char *path = mono_image_get_filename(assembly_image);
|
||||
|
||||
*r_assembly = memnew(GDMonoAssembly(p_name, path));
|
||||
Error error = (*r_assembly)->wrapper_for_image(assembly_image);
|
||||
|
||||
if (error != OK) {
|
||||
memdelete(*r_assembly);
|
||||
*r_assembly = NULL;
|
||||
ERR_FAIL_V(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (OS::get_singleton()->is_stdout_verbose())
|
||||
OS::get_singleton()->print(String("Mono: Assembly " + p_name + " loaded from path: " + (*r_assembly)->get_path() + "\n").utf8());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GDMono::_load_corlib_assembly() {
|
||||
|
||||
if (corlib_assembly)
|
||||
return true;
|
||||
|
||||
bool success = _load_assembly("mscorlib", &corlib_assembly);
|
||||
|
||||
if (success)
|
||||
GDMonoUtils::update_corlib_cache();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GDMono::_load_core_api_assembly() {
|
||||
|
||||
if (api_assembly)
|
||||
return true;
|
||||
|
||||
bool success = _load_assembly(API_ASSEMBLY_NAME, &api_assembly);
|
||||
|
||||
if (success)
|
||||
GDMonoUtils::update_godot_api_cache();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
bool GDMono::_load_editor_api_assembly() {
|
||||
|
||||
if (editor_api_assembly)
|
||||
return true;
|
||||
|
||||
return _load_assembly(EDITOR_API_ASSEMBLY_NAME, &editor_api_assembly);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
bool GDMono::_load_editor_tools_assembly() {
|
||||
|
||||
if (editor_tools_assembly)
|
||||
return true;
|
||||
|
||||
_GDMONO_SCOPE_DOMAIN_(tools_domain)
|
||||
|
||||
return _load_assembly(EDITOR_TOOLS_ASSEMBLY_NAME, &editor_tools_assembly);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool GDMono::_load_project_assembly() {
|
||||
|
||||
if (project_assembly)
|
||||
return true;
|
||||
|
||||
String project_assembly_name = ProjectSettings::get_singleton()->get("application/config/name");
|
||||
|
||||
bool success = _load_assembly(project_assembly_name, &project_assembly);
|
||||
|
||||
if (success)
|
||||
mono_assembly_set_main(project_assembly->get_assembly());
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GDMono::_load_all_script_assemblies() {
|
||||
|
||||
#ifndef MONO_GLUE_DISABLED
|
||||
if (!_load_core_api_assembly()) {
|
||||
if (OS::get_singleton()->is_stdout_verbose())
|
||||
OS::get_singleton()->printerr("Mono: Failed to load Core API assembly\n");
|
||||
return false;
|
||||
} else {
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (!_load_editor_api_assembly()) {
|
||||
if (OS::get_singleton()->is_stdout_verbose())
|
||||
OS::get_singleton()->printerr("Mono: Failed to load Editor API assembly\n");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!_load_project_assembly()) {
|
||||
if (OS::get_singleton()->is_stdout_verbose())
|
||||
OS::get_singleton()->printerr("Mono: Failed to load project assembly\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
if (OS::get_singleton()->is_stdout_verbose())
|
||||
OS::get_singleton()->print("Mono: Glue disbled, ignoring script assemblies\n");
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
Error GDMono::_load_scripts_domain() {
|
||||
|
||||
ERR_FAIL_COND_V(scripts_domain != NULL, ERR_BUG);
|
||||
|
||||
if (OS::get_singleton()->is_stdout_verbose()) {
|
||||
OS::get_singleton()->print("Mono: Loading scripts domain...\n");
|
||||
}
|
||||
|
||||
scripts_domain = GDMonoUtils::create_domain("GodotEngine.ScriptsDomain");
|
||||
|
||||
ERR_EXPLAIN("Mono: Could not create scripts app domain");
|
||||
ERR_FAIL_NULL_V(scripts_domain, ERR_CANT_CREATE);
|
||||
|
||||
mono_domain_set(scripts_domain, true);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error GDMono::_unload_scripts_domain() {
|
||||
|
||||
ERR_FAIL_NULL_V(scripts_domain, ERR_BUG);
|
||||
|
||||
if (OS::get_singleton()->is_stdout_verbose()) {
|
||||
OS::get_singleton()->print("Mono: Unloading scripts domain...\n");
|
||||
}
|
||||
|
||||
_GodotSharp::get_singleton()->_dispose_callback();
|
||||
|
||||
if (mono_domain_get() != root_domain)
|
||||
mono_domain_set(root_domain, true);
|
||||
|
||||
finalizing_scripts_domain = true;
|
||||
mono_domain_finalize(scripts_domain, 2000);
|
||||
finalizing_scripts_domain = false;
|
||||
|
||||
_domain_assemblies_cleanup(mono_domain_get_id(scripts_domain));
|
||||
|
||||
api_assembly = NULL;
|
||||
project_assembly = NULL;
|
||||
#ifdef TOOLS_ENABLED
|
||||
editor_api_assembly = NULL;
|
||||
#endif
|
||||
|
||||
MonoDomain *domain = scripts_domain;
|
||||
scripts_domain = NULL;
|
||||
|
||||
_GodotSharp::get_singleton()->_dispose_callback();
|
||||
|
||||
MonoObject *ex = NULL;
|
||||
mono_domain_try_unload(domain, &ex);
|
||||
|
||||
if (ex) {
|
||||
ERR_PRINT("Exception thrown when unloading scripts domain:");
|
||||
mono_print_unhandled_exception(ex);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
Error GDMono::_load_tools_domain() {
|
||||
|
||||
ERR_FAIL_COND_V(tools_domain != NULL, ERR_BUG);
|
||||
|
||||
if (OS::get_singleton()->is_stdout_verbose()) {
|
||||
OS::get_singleton()->print("Mono: Loading tools domain...\n");
|
||||
}
|
||||
|
||||
tools_domain = GDMonoUtils::create_domain("GodotEngine.ToolsDomain");
|
||||
|
||||
ERR_EXPLAIN("Mono: Could not create tools app domain");
|
||||
ERR_FAIL_NULL_V(tools_domain, ERR_CANT_CREATE);
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
Error GDMono::reload_scripts_domain() {
|
||||
|
||||
ERR_FAIL_COND_V(!runtime_initialized, ERR_BUG);
|
||||
|
||||
if (scripts_domain) {
|
||||
Error err = _unload_scripts_domain();
|
||||
if (err != OK) {
|
||||
ERR_PRINT("Mono: Failed to unload scripts domain");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
Error err = _load_scripts_domain();
|
||||
if (err != OK) {
|
||||
ERR_PRINT("Mono: Failed to load scripts domain");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!_load_all_script_assemblies()) {
|
||||
if (OS::get_singleton()->is_stdout_verbose())
|
||||
OS::get_singleton()->printerr("Mono: Failed to load script assemblies\n");
|
||||
return ERR_CANT_OPEN;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) {
|
||||
|
||||
MonoImage *image = mono_class_get_image(p_raw_class);
|
||||
|
||||
if (image == corlib_assembly->get_image())
|
||||
return corlib_assembly->get_class(p_raw_class);
|
||||
|
||||
uint32_t domain_id = mono_domain_get_id(mono_domain_get());
|
||||
HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id];
|
||||
|
||||
const String *k = NULL;
|
||||
while ((k = domain_assemblies.next(k))) {
|
||||
GDMonoAssembly *assembly = domain_assemblies.get(*k);
|
||||
if (assembly->get_image() == image) {
|
||||
GDMonoClass *klass = assembly->get_class(p_raw_class);
|
||||
|
||||
if (klass)
|
||||
return klass;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void GDMono::_domain_assemblies_cleanup(uint32_t p_domain_id) {
|
||||
|
||||
HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[p_domain_id];
|
||||
|
||||
const String *k = NULL;
|
||||
while ((k = domain_assemblies.next(k))) {
|
||||
memdelete(domain_assemblies.get(*k));
|
||||
}
|
||||
|
||||
assemblies.erase(p_domain_id);
|
||||
}
|
||||
|
||||
GDMono::GDMono() {
|
||||
|
||||
singleton = this;
|
||||
|
||||
gdmono_log = memnew(GDMonoLog);
|
||||
|
||||
runtime_initialized = false;
|
||||
finalizing_scripts_domain = false;
|
||||
|
||||
root_domain = NULL;
|
||||
scripts_domain = NULL;
|
||||
#ifdef TOOLS_ENABLED
|
||||
tools_domain = NULL;
|
||||
#endif
|
||||
|
||||
corlib_assembly = NULL;
|
||||
api_assembly = NULL;
|
||||
project_assembly = NULL;
|
||||
#ifdef TOOLS_ENABLED
|
||||
editor_api_assembly = NULL;
|
||||
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 (runtime_initialized) {
|
||||
|
||||
if (scripts_domain) {
|
||||
|
||||
Error err = _unload_scripts_domain();
|
||||
if (err != OK) {
|
||||
WARN_PRINT("Mono: Failed to unload scripts domain");
|
||||
}
|
||||
}
|
||||
|
||||
const uint32_t *k = NULL;
|
||||
while ((k = assemblies.next(k))) {
|
||||
HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies.get(*k);
|
||||
|
||||
const String *kk = NULL;
|
||||
while ((kk = domain_assemblies.next(kk))) {
|
||||
memdelete(domain_assemblies.get(*kk));
|
||||
}
|
||||
}
|
||||
assemblies.clear();
|
||||
|
||||
GDMonoUtils::clear_cache();
|
||||
|
||||
OS::get_singleton()->print("Mono: Runtime cleanup...\n");
|
||||
|
||||
runtime_initialized = false;
|
||||
mono_jit_cleanup(root_domain);
|
||||
}
|
||||
|
||||
if (gdmono_log)
|
||||
memdelete(gdmono_log);
|
||||
}
|
||||
|
||||
_GodotSharp *_GodotSharp::singleton = NULL;
|
||||
|
||||
void _GodotSharp::_dispose_object(Object *p_object) {
|
||||
|
||||
if (p_object->get_script_instance()) {
|
||||
CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_object->get_script_instance());
|
||||
if (cs_instance) {
|
||||
cs_instance->mono_object_disposed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe refcount decrement. The managed instance also counts as a reference.
|
||||
// See: CSharpLanguage::alloc_instance_binding_data(Object *p_object)
|
||||
if (Object::cast_to<Reference>(p_object)->unreference()) {
|
||||
memdelete(p_object);
|
||||
}
|
||||
}
|
||||
|
||||
void _GodotSharp::_dispose_callback() {
|
||||
|
||||
#ifndef NO_THREADS
|
||||
queue_mutex->lock();
|
||||
#endif
|
||||
|
||||
for (List<Object *>::Element *E = obj_delete_queue.front(); E; E = E->next()) {
|
||||
_dispose_object(E->get());
|
||||
}
|
||||
|
||||
for (List<NodePath *>::Element *E = np_delete_queue.front(); E; E = E->next()) {
|
||||
memdelete(E->get());
|
||||
}
|
||||
|
||||
for (List<RID *>::Element *E = rid_delete_queue.front(); E; E = E->next()) {
|
||||
memdelete(E->get());
|
||||
}
|
||||
|
||||
obj_delete_queue.clear();
|
||||
np_delete_queue.clear();
|
||||
rid_delete_queue.clear();
|
||||
queue_empty = true;
|
||||
|
||||
#ifndef NO_THREADS
|
||||
queue_mutex->unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
void _GodotSharp::attach_thread() {
|
||||
|
||||
GDMonoUtils::attach_current_thread();
|
||||
}
|
||||
|
||||
void _GodotSharp::detach_thread() {
|
||||
|
||||
GDMonoUtils::detach_current_thread();
|
||||
}
|
||||
|
||||
bool _GodotSharp::is_finalizing_domain() {
|
||||
|
||||
return GDMono::get_singleton()->is_finalizing_scripts_domain();
|
||||
}
|
||||
|
||||
bool _GodotSharp::is_domain_loaded() {
|
||||
|
||||
return GDMono::get_singleton()->get_scripts_domain() != NULL;
|
||||
}
|
||||
|
||||
#define ENQUEUE_FOR_DISPOSAL(m_queue, m_inst) \
|
||||
m_queue.push_back(m_inst); \
|
||||
if (queue_empty) { \
|
||||
queue_empty = false; \
|
||||
call_deferred("_dispose_callback"); \
|
||||
}
|
||||
|
||||
void _GodotSharp::queue_dispose(Object *p_object) {
|
||||
|
||||
if (Thread::get_main_id() == Thread::get_caller_id() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
|
||||
_dispose_object(p_object);
|
||||
} else {
|
||||
#ifndef NO_THREADS
|
||||
queue_mutex->lock();
|
||||
#endif
|
||||
|
||||
ENQUEUE_FOR_DISPOSAL(obj_delete_queue, p_object);
|
||||
|
||||
#ifndef NO_THREADS
|
||||
queue_mutex->unlock();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void _GodotSharp::queue_dispose(NodePath *p_node_path) {
|
||||
|
||||
if (Thread::get_main_id() == Thread::get_caller_id() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
|
||||
memdelete(p_node_path);
|
||||
} else {
|
||||
#ifndef NO_THREADS
|
||||
queue_mutex->lock();
|
||||
#endif
|
||||
|
||||
ENQUEUE_FOR_DISPOSAL(np_delete_queue, p_node_path);
|
||||
|
||||
#ifndef NO_THREADS
|
||||
queue_mutex->unlock();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void _GodotSharp::queue_dispose(RID *p_rid) {
|
||||
|
||||
if (Thread::get_main_id() == Thread::get_caller_id() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
|
||||
memdelete(p_rid);
|
||||
} else {
|
||||
#ifndef NO_THREADS
|
||||
queue_mutex->lock();
|
||||
#endif
|
||||
|
||||
ENQUEUE_FOR_DISPOSAL(rid_delete_queue, p_rid);
|
||||
|
||||
#ifndef NO_THREADS
|
||||
queue_mutex->unlock();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void _GodotSharp::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("attach_thread"), &_GodotSharp::attach_thread);
|
||||
ClassDB::bind_method(D_METHOD("detach_thread"), &_GodotSharp::detach_thread);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("is_finalizing_domain"), &_GodotSharp::is_finalizing_domain);
|
||||
ClassDB::bind_method(D_METHOD("is_domain_loaded"), &_GodotSharp::is_domain_loaded);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_dispose_callback"), &_GodotSharp::_dispose_callback);
|
||||
}
|
||||
|
||||
_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);
|
||||
}
|
||||
}
|
224
modules/mono/mono_gd/gd_mono.h
Normal file
224
modules/mono/mono_gd/gd_mono.h
Normal file
@ -0,0 +1,224 @@
|
||||
/*************************************************************************/
|
||||
/* gd_mono.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 GD_MONO_H
|
||||
#define GD_MONO_H
|
||||
|
||||
#include "../godotsharp_defs.h"
|
||||
#include "gd_mono_assembly.h"
|
||||
#include "gd_mono_log.h"
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
#include "../utils/mono_reg_utils.h"
|
||||
#endif
|
||||
|
||||
#define SCRIPTS_DOMAIN GDMono::get_singleton()->get_scripts_domain()
|
||||
#ifdef TOOLS_ENABLED
|
||||
#define TOOLS_DOMAIN GDMono::get_singleton()->get_tools_domain()
|
||||
#endif
|
||||
|
||||
class GDMono {
|
||||
|
||||
bool runtime_initialized;
|
||||
bool finalizing_scripts_domain;
|
||||
|
||||
MonoDomain *root_domain;
|
||||
MonoDomain *scripts_domain;
|
||||
#ifdef TOOLS_ENABLED
|
||||
MonoDomain *tools_domain;
|
||||
#endif
|
||||
|
||||
GDMonoAssembly *corlib_assembly;
|
||||
GDMonoAssembly *api_assembly;
|
||||
GDMonoAssembly *project_assembly;
|
||||
#ifdef TOOLS_ENABLED
|
||||
GDMonoAssembly *editor_api_assembly;
|
||||
GDMonoAssembly *editor_tools_assembly;
|
||||
#endif
|
||||
|
||||
HashMap<uint32_t, HashMap<String, GDMonoAssembly *> > assemblies;
|
||||
|
||||
void _domain_assemblies_cleanup(uint32_t p_domain_id);
|
||||
|
||||
bool _load_corlib_assembly();
|
||||
bool _load_core_api_assembly();
|
||||
#ifdef TOOLS_ENABLED
|
||||
bool _load_editor_api_assembly();
|
||||
bool _load_editor_tools_assembly();
|
||||
#endif
|
||||
bool _load_project_assembly();
|
||||
|
||||
bool _load_all_script_assemblies();
|
||||
|
||||
void _register_internal_calls();
|
||||
|
||||
Error _load_scripts_domain();
|
||||
Error _unload_scripts_domain();
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
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
|
||||
|
||||
bool _load_assembly(const String &p_name, GDMonoAssembly **r_assembly);
|
||||
|
||||
GDMonoLog *gdmono_log;
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
MonoRegInfo mono_reg_info;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
static GDMono *singleton;
|
||||
|
||||
public:
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
uint64_t get_api_core_hash() { return api_core_hash; }
|
||||
#ifdef TOOLS_ENABLED
|
||||
uint64_t get_api_editor_hash() { return api_editor_hash; }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
enum MemberVisibility {
|
||||
PRIVATE,
|
||||
PROTECTED_AND_INTERNAL, // FAM_AND_ASSEM
|
||||
INTERNAL, // ASSEMBLY
|
||||
PROTECTED, // FAMILY
|
||||
PUBLIC
|
||||
};
|
||||
|
||||
static GDMono *get_singleton() { return singleton; }
|
||||
|
||||
void add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly);
|
||||
|
||||
_FORCE_INLINE_ bool is_runtime_initialized() const { return runtime_initialized; }
|
||||
_FORCE_INLINE_ bool is_finalizing_scripts_domain() const { return finalizing_scripts_domain; }
|
||||
|
||||
_FORCE_INLINE_ MonoDomain *get_scripts_domain() { return scripts_domain; }
|
||||
#ifdef TOOLS_ENABLED
|
||||
_FORCE_INLINE_ MonoDomain *get_tools_domain() { return tools_domain; }
|
||||
#endif
|
||||
|
||||
_FORCE_INLINE_ GDMonoAssembly *get_corlib_assembly() const { return corlib_assembly; }
|
||||
_FORCE_INLINE_ GDMonoAssembly *get_api_assembly() const { return api_assembly; }
|
||||
_FORCE_INLINE_ GDMonoAssembly *get_project_assembly() const { return project_assembly; }
|
||||
#ifdef TOOLS_ENABLED
|
||||
_FORCE_INLINE_ GDMonoAssembly *get_editor_api_assembly() const { return editor_api_assembly; }
|
||||
_FORCE_INLINE_ GDMonoAssembly *get_editor_tools_assembly() const { return editor_tools_assembly; }
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
const MonoRegInfo &get_mono_reg_info() { return mono_reg_info; }
|
||||
#endif
|
||||
|
||||
GDMonoClass *get_class(MonoClass *p_raw_class);
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
Error reload_scripts_domain();
|
||||
#endif
|
||||
|
||||
void initialize();
|
||||
|
||||
GDMono();
|
||||
~GDMono();
|
||||
};
|
||||
|
||||
class GDMonoScopeDomain {
|
||||
|
||||
MonoDomain *prev_domain;
|
||||
|
||||
public:
|
||||
GDMonoScopeDomain(MonoDomain *p_domain) {
|
||||
MonoDomain *prev_domain = mono_domain_get();
|
||||
if (prev_domain != p_domain) {
|
||||
this->prev_domain = prev_domain;
|
||||
mono_domain_set(p_domain, false);
|
||||
} else {
|
||||
this->prev_domain = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
~GDMonoScopeDomain() {
|
||||
if (prev_domain)
|
||||
mono_domain_set(prev_domain, false);
|
||||
}
|
||||
};
|
||||
|
||||
#define _GDMONO_SCOPE_DOMAIN_(m_mono_domain) \
|
||||
GDMonoScopeDomain __gdmono__scope__domain__(m_mono_domain); \
|
||||
(void)__gdmono__scope__domain__;
|
||||
|
||||
class _GodotSharp : public Object {
|
||||
GDCLASS(_GodotSharp, Object)
|
||||
|
||||
friend class GDMono;
|
||||
|
||||
void _dispose_object(Object *p_object);
|
||||
|
||||
void _dispose_callback();
|
||||
|
||||
List<Object *> obj_delete_queue;
|
||||
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();
|
||||
|
||||
public:
|
||||
static _GodotSharp *get_singleton() { return singleton; }
|
||||
|
||||
void attach_thread();
|
||||
void detach_thread();
|
||||
|
||||
bool is_finalizing_domain();
|
||||
bool is_domain_loaded();
|
||||
|
||||
void queue_dispose(Object *p_object);
|
||||
void queue_dispose(NodePath *p_node_path);
|
||||
void queue_dispose(RID *p_rid);
|
||||
|
||||
_GodotSharp();
|
||||
~_GodotSharp();
|
||||
};
|
||||
|
||||
#endif // GD_MONO_H
|
327
modules/mono/mono_gd/gd_mono_assembly.cpp
Normal file
327
modules/mono/mono_gd/gd_mono_assembly.cpp
Normal file
@ -0,0 +1,327 @@
|
||||
/*************************************************************************/
|
||||
/* gd_mono_assembly.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "gd_mono_assembly.h"
|
||||
|
||||
#include <mono/metadata/mono-debug.h>
|
||||
#include <mono/metadata/tokentype.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "os/file_access.h"
|
||||
#include "os/os.h"
|
||||
|
||||
#include "../godotsharp_dirs.h"
|
||||
#include "gd_mono_class.h"
|
||||
|
||||
MonoAssembly *gdmono_load_assembly_from(const String &p_name, const String &p_path) {
|
||||
|
||||
MonoDomain *domain = mono_domain_get();
|
||||
|
||||
GDMonoAssembly *assembly = memnew(GDMonoAssembly(p_name, p_path));
|
||||
Error err = assembly->load(domain);
|
||||
ERR_FAIL_COND_V(err != OK, NULL);
|
||||
|
||||
GDMono::get_singleton()->add_assembly(mono_domain_get_id(domain), assembly);
|
||||
|
||||
return assembly->get_assembly();
|
||||
}
|
||||
|
||||
MonoAssembly *gdmono_MonoAssemblyPreLoad(MonoAssemblyName *aname, char **assemblies_path, void *user_data) {
|
||||
|
||||
(void)user_data; // UNUSED
|
||||
|
||||
MonoAssembly *assembly_loaded = mono_assembly_loaded(aname);
|
||||
if (assembly_loaded) // Already loaded
|
||||
return assembly_loaded;
|
||||
|
||||
static Vector<String> search_dirs;
|
||||
|
||||
if (search_dirs.empty()) {
|
||||
search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_dir());
|
||||
search_dirs.push_back(GodotSharpDirs::get_res_assemblies_dir());
|
||||
search_dirs.push_back(OS::get_singleton()->get_resource_dir());
|
||||
search_dirs.push_back(OS::get_singleton()->get_executable_path().get_base_dir());
|
||||
|
||||
const char *rootdir = mono_assembly_getrootdir();
|
||||
if (rootdir) {
|
||||
search_dirs.push_back(String(rootdir).plus_file("mono").plus_file("4.5"));
|
||||
}
|
||||
|
||||
while (assemblies_path) {
|
||||
if (*assemblies_path)
|
||||
search_dirs.push_back(*assemblies_path);
|
||||
++assemblies_path;
|
||||
}
|
||||
}
|
||||
|
||||
String name = mono_assembly_name_get_name(aname);
|
||||
bool has_extension = name.ends_with(".dll") || name.ends_with(".exe");
|
||||
|
||||
String path;
|
||||
|
||||
for (int i = 0; i < search_dirs.size(); i++) {
|
||||
const String &search_dir = search_dirs[i];
|
||||
|
||||
if (has_extension) {
|
||||
path = search_dir.plus_file(name);
|
||||
if (FileAccess::exists(path))
|
||||
return gdmono_load_assembly_from(name.get_basename(), path);
|
||||
} else {
|
||||
path = search_dir.plus_file(name + ".dll");
|
||||
if (FileAccess::exists(path))
|
||||
return gdmono_load_assembly_from(name, path);
|
||||
|
||||
path = search_dir.plus_file(name + ".exe");
|
||||
if (FileAccess::exists(path))
|
||||
return gdmono_load_assembly_from(name, path);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void GDMonoAssembly::initialize() {
|
||||
|
||||
mono_install_assembly_preload_hook(&gdmono_MonoAssemblyPreLoad, NULL);
|
||||
}
|
||||
|
||||
Error GDMonoAssembly::load(MonoDomain *p_domain) {
|
||||
|
||||
ERR_FAIL_COND_V(loaded, ERR_FILE_ALREADY_IN_USE);
|
||||
|
||||
uint64_t last_modified_time = FileAccess::get_modified_time(path);
|
||||
|
||||
Vector<uint8_t> data = FileAccess::get_file_as_array(path);
|
||||
ERR_FAIL_COND_V(data.empty(), ERR_FILE_CANT_READ);
|
||||
|
||||
String image_filename(path);
|
||||
|
||||
MonoImageOpenStatus status;
|
||||
|
||||
image = mono_image_open_from_data_with_name(
|
||||
(char *)&data[0], data.size(),
|
||||
true, &status, false,
|
||||
image_filename.utf8().get_data());
|
||||
|
||||
ERR_FAIL_COND_V(status != MONO_IMAGE_OK || image == NULL, ERR_FILE_CANT_OPEN);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
String pdb_path(path + ".pdb");
|
||||
|
||||
if (!FileAccess::exists(pdb_path)) {
|
||||
pdb_path = path.get_basename() + ".pdb"; // without .dll
|
||||
|
||||
if (!FileAccess::exists(pdb_path))
|
||||
goto no_pdb;
|
||||
}
|
||||
|
||||
pdb_data.clear();
|
||||
pdb_data = FileAccess::get_file_as_array(pdb_path);
|
||||
mono_debug_open_image_from_memory(image, &pdb_data[0], pdb_data.size());
|
||||
|
||||
no_pdb:
|
||||
|
||||
#endif
|
||||
|
||||
assembly = mono_assembly_load_from_full(image, image_filename.utf8().get_data(), &status, false);
|
||||
|
||||
ERR_FAIL_COND_V(status != MONO_IMAGE_OK || assembly == NULL, ERR_FILE_CANT_OPEN);
|
||||
|
||||
if (mono_image_get_entry_point(image)) {
|
||||
// TODO should this be removed? do we want to call main? what other effects does this have?
|
||||
mono_jit_exec(p_domain, assembly, 0, NULL);
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
modified_time = last_modified_time;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error GDMonoAssembly::wrapper_for_image(MonoImage *p_image) {
|
||||
|
||||
ERR_FAIL_COND_V(loaded, ERR_FILE_ALREADY_IN_USE);
|
||||
|
||||
assembly = mono_image_get_assembly(p_image);
|
||||
ERR_FAIL_NULL_V(assembly, FAILED);
|
||||
|
||||
image = p_image;
|
||||
|
||||
mono_image_addref(image);
|
||||
|
||||
loaded = true;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
cached_classes.clear();
|
||||
cached_raw.clear();
|
||||
|
||||
mono_image_close(image);
|
||||
|
||||
assembly = NULL;
|
||||
image = NULL;
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
GDMonoClass *GDMonoAssembly::get_class(const StringName &p_namespace, const StringName &p_name) {
|
||||
|
||||
ERR_FAIL_COND_V(!loaded, NULL);
|
||||
|
||||
ClassKey key(p_namespace, p_name);
|
||||
|
||||
GDMonoClass **match = cached_classes.getptr(key);
|
||||
|
||||
if (match)
|
||||
return *match;
|
||||
|
||||
MonoClass *mono_class = mono_class_from_name(image, String(p_namespace).utf8(), String(p_name).utf8());
|
||||
|
||||
if (!mono_class)
|
||||
return NULL;
|
||||
|
||||
GDMonoClass *wrapped_class = memnew(GDMonoClass(p_namespace, p_name, mono_class, this));
|
||||
|
||||
cached_classes[key] = wrapped_class;
|
||||
cached_raw[mono_class] = wrapped_class;
|
||||
|
||||
return wrapped_class;
|
||||
}
|
||||
|
||||
GDMonoClass *GDMonoAssembly::get_class(MonoClass *p_mono_class) {
|
||||
|
||||
ERR_FAIL_COND_V(!loaded, NULL);
|
||||
|
||||
Map<MonoClass *, GDMonoClass *>::Element *match = cached_raw.find(p_mono_class);
|
||||
|
||||
if (match)
|
||||
return match->value();
|
||||
|
||||
StringName namespace_name = mono_class_get_namespace(p_mono_class);
|
||||
StringName class_name = mono_class_get_name(p_mono_class);
|
||||
|
||||
GDMonoClass *wrapped_class = memnew(GDMonoClass(namespace_name, class_name, p_mono_class, this));
|
||||
|
||||
cached_classes[ClassKey(namespace_name, class_name)] = wrapped_class;
|
||||
cached_raw[p_mono_class] = wrapped_class;
|
||||
|
||||
return wrapped_class;
|
||||
}
|
||||
|
||||
GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class) {
|
||||
|
||||
GDMonoClass *match = NULL;
|
||||
|
||||
if (gdobject_class_cache_updated) {
|
||||
Map<StringName, GDMonoClass *>::Element *result = gdobject_class_cache.find(p_class);
|
||||
|
||||
if (result)
|
||||
match = result->get();
|
||||
} else {
|
||||
List<GDMonoClass *> nested_classes;
|
||||
|
||||
int rows = mono_image_get_table_rows(image, MONO_TABLE_TYPEDEF);
|
||||
|
||||
for (int i = 1; i < rows; i++) {
|
||||
MonoClass *mono_class = mono_class_get(image, (i + 1) | MONO_TOKEN_TYPE_DEF);
|
||||
|
||||
if (!mono_class_is_assignable_from(CACHED_CLASS_RAW(GodotObject), mono_class))
|
||||
continue;
|
||||
|
||||
GDMonoClass *current = get_class(mono_class);
|
||||
|
||||
if (!current)
|
||||
continue;
|
||||
|
||||
nested_classes.push_back(current);
|
||||
|
||||
if (!match && current->get_name() == p_class)
|
||||
match = current;
|
||||
|
||||
while (!nested_classes.empty()) {
|
||||
GDMonoClass *current_nested = nested_classes.front()->get();
|
||||
nested_classes.pop_back();
|
||||
|
||||
void *iter = NULL;
|
||||
|
||||
while (true) {
|
||||
MonoClass *raw_nested = mono_class_get_nested_types(current_nested->get_raw(), &iter);
|
||||
|
||||
if (!raw_nested)
|
||||
break;
|
||||
|
||||
GDMonoClass *nested_class = get_class(raw_nested);
|
||||
|
||||
if (nested_class) {
|
||||
gdobject_class_cache.insert(nested_class->get_name(), nested_class);
|
||||
nested_classes.push_back(nested_class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gdobject_class_cache.insert(current->get_name(), current);
|
||||
}
|
||||
|
||||
gdobject_class_cache_updated = true;
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
GDMonoAssembly::GDMonoAssembly(const String &p_name, const String &p_path) {
|
||||
|
||||
loaded = false;
|
||||
gdobject_class_cache_updated = false;
|
||||
name = p_name;
|
||||
path = p_path;
|
||||
modified_time = 0;
|
||||
assembly = NULL;
|
||||
image = NULL;
|
||||
}
|
||||
|
||||
GDMonoAssembly::~GDMonoAssembly() {
|
||||
|
||||
if (loaded)
|
||||
unload();
|
||||
}
|
113
modules/mono/mono_gd/gd_mono_assembly.h
Normal file
113
modules/mono/mono_gd/gd_mono_assembly.h
Normal file
@ -0,0 +1,113 @@
|
||||
/*************************************************************************/
|
||||
/* gd_mono_assembly.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 GD_MONO_ASSEMBLY_H
|
||||
#define GD_MONO_ASSEMBLY_H
|
||||
|
||||
#include <mono/jit/jit.h>
|
||||
#include <mono/metadata/assembly.h>
|
||||
|
||||
#include "gd_mono_utils.h"
|
||||
#include "hash_map.h"
|
||||
#include "map.h"
|
||||
#include "ustring.h"
|
||||
|
||||
class GDMonoAssembly {
|
||||
|
||||
struct ClassKey {
|
||||
struct Hasher {
|
||||
static _FORCE_INLINE_ uint32_t hash(const ClassKey &p_key) {
|
||||
uint32_t hash = 0;
|
||||
|
||||
GDMonoUtils::hash_combine(hash, p_key.namespace_name.hash());
|
||||
GDMonoUtils::hash_combine(hash, p_key.class_name.hash());
|
||||
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const ClassKey &p_a) const {
|
||||
return p_a.class_name == class_name && p_a.namespace_name == namespace_name;
|
||||
}
|
||||
|
||||
ClassKey() {}
|
||||
|
||||
ClassKey(const StringName &p_namespace_name, const StringName &p_class_name) {
|
||||
namespace_name = p_namespace_name;
|
||||
class_name = p_class_name;
|
||||
}
|
||||
|
||||
StringName namespace_name;
|
||||
StringName class_name;
|
||||
};
|
||||
|
||||
MonoAssembly *assembly;
|
||||
MonoImage *image;
|
||||
|
||||
bool loaded;
|
||||
|
||||
String name;
|
||||
String path;
|
||||
uint64_t modified_time;
|
||||
|
||||
HashMap<ClassKey, GDMonoClass *, ClassKey::Hasher> cached_classes;
|
||||
Map<MonoClass *, GDMonoClass *> cached_raw;
|
||||
|
||||
bool gdobject_class_cache_updated;
|
||||
Map<StringName, GDMonoClass *> gdobject_class_cache;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
Vector<uint8_t> pdb_data;
|
||||
#endif
|
||||
|
||||
friend class GDMono;
|
||||
static void initialize();
|
||||
|
||||
public:
|
||||
Error load(MonoDomain *p_domain);
|
||||
Error wrapper_for_image(MonoImage *p_image);
|
||||
void unload();
|
||||
|
||||
_FORCE_INLINE_ bool is_loaded() const { return loaded; }
|
||||
_FORCE_INLINE_ MonoImage *get_image() const { return image; }
|
||||
_FORCE_INLINE_ MonoAssembly *get_assembly() const { return assembly; }
|
||||
_FORCE_INLINE_ String get_name() const { return name; }
|
||||
_FORCE_INLINE_ String get_path() const { return path; }
|
||||
_FORCE_INLINE_ uint64_t get_modified_time() const { return modified_time; }
|
||||
|
||||
GDMonoClass *get_class(const StringName &p_namespace, const StringName &p_class);
|
||||
GDMonoClass *get_class(MonoClass *p_mono_class);
|
||||
|
||||
GDMonoClass *get_object_derived_class(const StringName &p_class);
|
||||
|
||||
GDMonoAssembly(const String &p_name, const String &p_path = String());
|
||||
~GDMonoAssembly();
|
||||
};
|
||||
|
||||
#endif // GD_MONO_ASSEMBLY_H
|
381
modules/mono/mono_gd/gd_mono_class.cpp
Normal file
381
modules/mono/mono_gd/gd_mono_class.cpp
Normal file
@ -0,0 +1,381 @@
|
||||
/*************************************************************************/
|
||||
/* gd_mono_class.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "gd_mono_class.h"
|
||||
|
||||
#include <mono/metadata/attrdefs.h>
|
||||
|
||||
#include "gd_mono_assembly.h"
|
||||
|
||||
MonoType *GDMonoClass::get_raw_type(GDMonoClass *p_class) {
|
||||
|
||||
return mono_class_get_type(p_class->get_raw());
|
||||
}
|
||||
|
||||
bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const {
|
||||
|
||||
return mono_class_is_assignable_from(mono_class, p_from->mono_class);
|
||||
}
|
||||
|
||||
GDMonoClass *GDMonoClass::get_parent_class() {
|
||||
|
||||
if (assembly) {
|
||||
MonoClass *parent_mono_class = mono_class_get_parent(mono_class);
|
||||
|
||||
if (parent_mono_class) {
|
||||
return GDMono::get_singleton()->get_class(parent_mono_class);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool GDMonoClass::has_method(const StringName &p_name) {
|
||||
|
||||
return get_method(p_name) != NULL;
|
||||
}
|
||||
|
||||
bool GDMonoClass::has_attribute(GDMonoClass *p_attr_class) {
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_NULL_V(p_attr_class, false);
|
||||
#endif
|
||||
|
||||
if (!attrs_fetched)
|
||||
fetch_attributes();
|
||||
|
||||
if (!attributes)
|
||||
return false;
|
||||
|
||||
return mono_custom_attrs_has_attr(attributes, p_attr_class->get_raw());
|
||||
}
|
||||
|
||||
MonoObject *GDMonoClass::get_attribute(GDMonoClass *p_attr_class) {
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_NULL_V(p_attr_class, NULL);
|
||||
#endif
|
||||
|
||||
if (!attrs_fetched)
|
||||
fetch_attributes();
|
||||
|
||||
if (!attributes)
|
||||
return NULL;
|
||||
|
||||
return mono_custom_attrs_get_attr(attributes, p_attr_class->get_raw());
|
||||
}
|
||||
|
||||
void GDMonoClass::fetch_attributes() {
|
||||
|
||||
ERR_FAIL_COND(attributes != NULL);
|
||||
|
||||
attributes = mono_custom_attrs_from_class(get_raw());
|
||||
attrs_fetched = true;
|
||||
}
|
||||
|
||||
void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base) {
|
||||
|
||||
CRASH_COND(!CACHED_CLASS(GodotObject)->is_assignable_from(this));
|
||||
|
||||
if (methods_fetched)
|
||||
return;
|
||||
|
||||
void *iter = NULL;
|
||||
MonoMethod *raw_method = NULL;
|
||||
while ((raw_method = mono_class_get_methods(get_raw(), &iter)) != NULL) {
|
||||
StringName name = mono_method_get_name(raw_method);
|
||||
|
||||
GDMonoMethod *method = get_method(raw_method, name);
|
||||
ERR_CONTINUE(!method);
|
||||
|
||||
if (method->get_name() != name) {
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
String fullname = method->get_ret_type_full_name() + " " + name + "(" + method->get_signature_desc(true) + ")";
|
||||
WARN_PRINTS("Method `" + fullname + "` is hidden by Godot API method. Should be `" +
|
||||
method->get_full_name_no_class() + "`. In class `" + namespace_name + "." + class_name + "`.");
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
// For debug builds, we also fetched from native base classes as well before if this is not a native base class.
|
||||
// This allows us to warn the user here if he is using snake_case by mistake.
|
||||
|
||||
if (p_native_base != this) {
|
||||
|
||||
GDMonoClass *native_top = p_native_base;
|
||||
while (native_top) {
|
||||
GDMonoMethod *m = native_top->get_method(name, method->get_parameters_count());
|
||||
|
||||
if (m && m->get_name() != name) {
|
||||
// found
|
||||
String fullname = m->get_ret_type_full_name() + " " + name + "(" + m->get_signature_desc(true) + ")";
|
||||
WARN_PRINTS("Method `" + fullname + "` should be `" + m->get_full_name_no_class() +
|
||||
"`. In class `" + namespace_name + "." + class_name + "`.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (native_top == CACHED_CLASS(GodotObject))
|
||||
break;
|
||||
|
||||
native_top = native_top->get_parent_class();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t flags = mono_method_get_flags(method->mono_method, NULL);
|
||||
|
||||
if (!(flags & MONO_METHOD_ATTR_VIRTUAL))
|
||||
continue;
|
||||
|
||||
// Virtual method of Godot Object derived type, let's try to find GodotMethod attribute
|
||||
|
||||
GDMonoClass *top = p_native_base;
|
||||
|
||||
while (top) {
|
||||
GDMonoMethod *base_method = top->get_method(name, method->get_parameters_count());
|
||||
|
||||
if (base_method && base_method->has_attribute(CACHED_CLASS(GodotMethodAttribute))) {
|
||||
// Found base method with GodotMethod attribute.
|
||||
// We get the original API method name from this attribute.
|
||||
// This name must point to the virtual method.
|
||||
|
||||
MonoObject *attr = base_method->get_attribute(CACHED_CLASS(GodotMethodAttribute));
|
||||
|
||||
StringName godot_method_name = CACHED_FIELD(GodotMethodAttribute, methodName)->get_string_value(attr);
|
||||
#ifdef DEBUG_ENABLED
|
||||
CRASH_COND(godot_method_name == StringName());
|
||||
#endif
|
||||
MethodKey key = MethodKey(godot_method_name, method->get_parameters_count());
|
||||
GDMonoMethod **existing_method = methods.getptr(key);
|
||||
if (existing_method)
|
||||
memdelete(*existing_method); // Must delete old one
|
||||
methods.set(key, method);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (top == CACHED_CLASS(GodotObject))
|
||||
break;
|
||||
|
||||
top = top->get_parent_class();
|
||||
}
|
||||
}
|
||||
|
||||
methods_fetched = true;
|
||||
}
|
||||
|
||||
GDMonoMethod *GDMonoClass::get_method(const StringName &p_name) {
|
||||
|
||||
ERR_FAIL_COND_V(!methods_fetched, NULL);
|
||||
|
||||
const MethodKey *k = NULL;
|
||||
|
||||
while ((k = methods.next(k))) {
|
||||
if (k->name == p_name)
|
||||
return methods.get(*k);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, int p_params_count) {
|
||||
|
||||
MethodKey key = MethodKey(p_name, p_params_count);
|
||||
|
||||
GDMonoMethod **match = methods.getptr(key);
|
||||
|
||||
if (match)
|
||||
return *match;
|
||||
|
||||
if (methods_fetched)
|
||||
return NULL;
|
||||
|
||||
MonoMethod *raw_method = mono_class_get_method_from_name(mono_class, String(p_name).utf8().get_data(), p_params_count);
|
||||
|
||||
if (raw_method) {
|
||||
GDMonoMethod *method = memnew(GDMonoMethod(p_name, raw_method));
|
||||
methods.set(key, method);
|
||||
|
||||
return method;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method) {
|
||||
|
||||
MonoMethodSignature *sig = mono_method_signature(p_raw_method);
|
||||
|
||||
int params_count = mono_signature_get_param_count(sig);
|
||||
StringName method_name = mono_method_get_name(p_raw_method);
|
||||
|
||||
return get_method(p_raw_method, method_name, params_count);
|
||||
}
|
||||
|
||||
GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name) {
|
||||
|
||||
MonoMethodSignature *sig = mono_method_signature(p_raw_method);
|
||||
int params_count = mono_signature_get_param_count(sig);
|
||||
return get_method(p_raw_method, p_name, params_count);
|
||||
}
|
||||
|
||||
GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count) {
|
||||
|
||||
ERR_FAIL_NULL_V(p_raw_method, NULL);
|
||||
|
||||
MethodKey key = MethodKey(p_name, p_params_count);
|
||||
|
||||
GDMonoMethod **match = methods.getptr(key);
|
||||
|
||||
if (match)
|
||||
return *match;
|
||||
|
||||
GDMonoMethod *method = memnew(GDMonoMethod(p_name, p_raw_method));
|
||||
methods.set(key, method);
|
||||
|
||||
return method;
|
||||
}
|
||||
|
||||
GDMonoMethod *GDMonoClass::get_method_with_desc(const String &p_description, bool p_include_namespace) {
|
||||
|
||||
MonoMethodDesc *desc = mono_method_desc_new(p_description.utf8().get_data(), p_include_namespace);
|
||||
MonoMethod *method = mono_method_desc_search_in_class(desc, mono_class);
|
||||
mono_method_desc_free(desc);
|
||||
|
||||
return get_method(method);
|
||||
}
|
||||
|
||||
GDMonoField *GDMonoClass::get_field(const StringName &p_name) {
|
||||
|
||||
Map<StringName, GDMonoField *>::Element *result = fields.find(p_name);
|
||||
|
||||
if (result)
|
||||
return result->value();
|
||||
|
||||
if (fields_fetched)
|
||||
return NULL;
|
||||
|
||||
MonoClassField *raw_field = mono_class_get_field_from_name(mono_class, String(p_name).utf8().get_data());
|
||||
|
||||
if (raw_field) {
|
||||
GDMonoField *field = memnew(GDMonoField(raw_field, this));
|
||||
fields.insert(p_name, field);
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const Vector<GDMonoField *> &GDMonoClass::get_all_fields() {
|
||||
|
||||
if (fields_fetched)
|
||||
return fields_list;
|
||||
|
||||
void *iter = NULL;
|
||||
MonoClassField *raw_field = NULL;
|
||||
while ((raw_field = mono_class_get_fields(get_raw(), &iter)) != NULL) {
|
||||
StringName name = mono_field_get_name(raw_field);
|
||||
|
||||
Map<StringName, GDMonoField *>::Element *match = fields.find(name);
|
||||
|
||||
if (match) {
|
||||
fields_list.push_back(match->get());
|
||||
} else {
|
||||
GDMonoField *field = memnew(GDMonoField(raw_field, this));
|
||||
fields.insert(name, field);
|
||||
fields_list.push_back(field);
|
||||
}
|
||||
}
|
||||
|
||||
fields_fetched = true;
|
||||
|
||||
return fields_list;
|
||||
}
|
||||
|
||||
GDMonoClass::GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly) {
|
||||
|
||||
namespace_name = p_namespace;
|
||||
class_name = p_name;
|
||||
mono_class = p_class;
|
||||
assembly = p_assembly;
|
||||
|
||||
attrs_fetched = false;
|
||||
attributes = NULL;
|
||||
|
||||
methods_fetched = false;
|
||||
fields_fetched = false;
|
||||
}
|
||||
|
||||
GDMonoClass::~GDMonoClass() {
|
||||
|
||||
if (attributes) {
|
||||
mono_custom_attrs_free(attributes);
|
||||
}
|
||||
|
||||
for (Map<StringName, GDMonoField *>::Element *E = fields.front(); E; E = E->next()) {
|
||||
memdelete(E->value());
|
||||
}
|
||||
|
||||
{
|
||||
// Ugly workaround...
|
||||
// We may have duplicated values, because we redirect snake_case methods to PascalCasel (only Godot API methods).
|
||||
// This way, we end with both the snake_case name and the PascalCasel name paired with the same method.
|
||||
// Therefore, we must avoid deleting the same pointer twice.
|
||||
|
||||
int offset = 0;
|
||||
Vector<GDMonoMethod *> deleted_methods;
|
||||
deleted_methods.resize(methods.size());
|
||||
|
||||
const MethodKey *k = NULL;
|
||||
while ((k = methods.next(k))) {
|
||||
GDMonoMethod *method = methods.get(*k);
|
||||
|
||||
if (method) {
|
||||
for (int i = 0; i < offset; i++) {
|
||||
if (deleted_methods[i] == method) {
|
||||
// Already deleted
|
||||
goto already_deleted;
|
||||
}
|
||||
}
|
||||
|
||||
deleted_methods[offset] = method;
|
||||
++offset;
|
||||
|
||||
memdelete(method);
|
||||
}
|
||||
|
||||
already_deleted:;
|
||||
}
|
||||
|
||||
methods.clear();
|
||||
}
|
||||
}
|
124
modules/mono/mono_gd/gd_mono_class.h
Normal file
124
modules/mono/mono_gd/gd_mono_class.h
Normal file
@ -0,0 +1,124 @@
|
||||
/*************************************************************************/
|
||||
/* gd_mono_class.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 GD_MONO_CLASS_H
|
||||
#define GD_MONO_CLASS_H
|
||||
|
||||
#include <mono/metadata/debug-helpers.h>
|
||||
|
||||
#include "map.h"
|
||||
#include "ustring.h"
|
||||
|
||||
#include "gd_mono_field.h"
|
||||
#include "gd_mono_header.h"
|
||||
#include "gd_mono_method.h"
|
||||
#include "gd_mono_utils.h"
|
||||
|
||||
class GDMonoClass {
|
||||
struct MethodKey {
|
||||
struct Hasher {
|
||||
static _FORCE_INLINE_ uint32_t hash(const MethodKey &p_key) {
|
||||
uint32_t hash = 0;
|
||||
|
||||
GDMonoUtils::hash_combine(hash, p_key.name.hash());
|
||||
GDMonoUtils::hash_combine(hash, HashMapHasherDefault::hash(p_key.params_count));
|
||||
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const MethodKey &p_a) const {
|
||||
return p_a.params_count == params_count && p_a.name == name;
|
||||
}
|
||||
|
||||
MethodKey() {}
|
||||
|
||||
MethodKey(const StringName &p_name, int p_params_count) {
|
||||
name = p_name;
|
||||
params_count = p_params_count;
|
||||
}
|
||||
|
||||
StringName name;
|
||||
int params_count;
|
||||
};
|
||||
|
||||
StringName namespace_name;
|
||||
StringName class_name;
|
||||
|
||||
MonoClass *mono_class;
|
||||
GDMonoAssembly *assembly;
|
||||
|
||||
bool attrs_fetched;
|
||||
MonoCustomAttrInfo *attributes;
|
||||
|
||||
bool methods_fetched;
|
||||
HashMap<MethodKey, GDMonoMethod *, MethodKey::Hasher> methods;
|
||||
|
||||
bool fields_fetched;
|
||||
Map<StringName, GDMonoField *> fields;
|
||||
Vector<GDMonoField *> fields_list;
|
||||
|
||||
friend class GDMonoAssembly;
|
||||
GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly);
|
||||
|
||||
public:
|
||||
static MonoType *get_raw_type(GDMonoClass *p_class);
|
||||
|
||||
bool is_assignable_from(GDMonoClass *p_from) const;
|
||||
|
||||
_FORCE_INLINE_ StringName get_namespace() const { return namespace_name; }
|
||||
_FORCE_INLINE_ StringName get_name() const { return class_name; }
|
||||
|
||||
_FORCE_INLINE_ MonoClass *get_raw() const { return mono_class; }
|
||||
_FORCE_INLINE_ const GDMonoAssembly *get_assembly() const { return assembly; }
|
||||
|
||||
GDMonoClass *get_parent_class();
|
||||
|
||||
bool has_method(const StringName &p_name);
|
||||
|
||||
bool has_attribute(GDMonoClass *p_attr_class);
|
||||
MonoObject *get_attribute(GDMonoClass *p_attr_class);
|
||||
|
||||
void fetch_attributes();
|
||||
void fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base);
|
||||
|
||||
GDMonoMethod *get_method(const StringName &p_name);
|
||||
GDMonoMethod *get_method(const StringName &p_name, int p_params_count);
|
||||
GDMonoMethod *get_method(MonoMethod *p_raw_method);
|
||||
GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name);
|
||||
GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count);
|
||||
GDMonoMethod *get_method_with_desc(const String &p_description, bool p_includes_namespace);
|
||||
|
||||
GDMonoField *get_field(const StringName &p_name);
|
||||
const Vector<GDMonoField *> &get_all_fields();
|
||||
|
||||
~GDMonoClass();
|
||||
};
|
||||
|
||||
#endif // GD_MONO_CLASS_H
|
362
modules/mono/mono_gd/gd_mono_field.cpp
Normal file
362
modules/mono/mono_gd/gd_mono_field.cpp
Normal file
@ -0,0 +1,362 @@
|
||||
/*************************************************************************/
|
||||
/* gd_mono_field.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "gd_mono_field.h"
|
||||
|
||||
#include <mono/metadata/attrdefs.h>
|
||||
|
||||
#include "gd_mono_class.h"
|
||||
#include "gd_mono_marshal.h"
|
||||
|
||||
void GDMonoField::set_value_raw(MonoObject *p_object, void *p_ptr) {
|
||||
mono_field_set_value(p_object, mono_field, &p_ptr);
|
||||
}
|
||||
|
||||
void GDMonoField::set_value(MonoObject *p_object, const Variant &p_value) {
|
||||
#define SET_FROM_STRUCT_AND_BREAK(m_type) \
|
||||
{ \
|
||||
const m_type &val = p_value.operator m_type(); \
|
||||
MARSHALLED_OUT(m_type, val, raw); \
|
||||
mono_field_set_value(p_object, mono_field, raw); \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define SET_FROM_PRIMITIVE(m_type) \
|
||||
{ \
|
||||
m_type val = p_value.operator m_type(); \
|
||||
mono_field_set_value(p_object, mono_field, &val); \
|
||||
}
|
||||
|
||||
#define SET_FROM_ARRAY_AND_BREAK(m_type) \
|
||||
{ \
|
||||
MonoArray *managed = GDMonoMarshal::m_type##_to_mono_array(p_value.operator m_type()); \
|
||||
mono_field_set_value(p_object, mono_field, &managed); \
|
||||
break; \
|
||||
}
|
||||
|
||||
switch (type.type_encoding) {
|
||||
case MONO_TYPE_BOOLEAN: {
|
||||
SET_FROM_PRIMITIVE(bool);
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_I1: {
|
||||
SET_FROM_PRIMITIVE(signed char);
|
||||
} break;
|
||||
case MONO_TYPE_I2: {
|
||||
SET_FROM_PRIMITIVE(signed short);
|
||||
} break;
|
||||
case MONO_TYPE_I4: {
|
||||
SET_FROM_PRIMITIVE(signed int);
|
||||
} break;
|
||||
case MONO_TYPE_I8: {
|
||||
SET_FROM_PRIMITIVE(int64_t);
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_U1: {
|
||||
SET_FROM_PRIMITIVE(unsigned char);
|
||||
} break;
|
||||
case MONO_TYPE_U2: {
|
||||
SET_FROM_PRIMITIVE(unsigned short);
|
||||
} break;
|
||||
case MONO_TYPE_U4: {
|
||||
SET_FROM_PRIMITIVE(unsigned int);
|
||||
} break;
|
||||
case MONO_TYPE_U8: {
|
||||
SET_FROM_PRIMITIVE(uint64_t);
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_R4: {
|
||||
SET_FROM_PRIMITIVE(float);
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_R8: {
|
||||
SET_FROM_PRIMITIVE(double);
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_STRING: {
|
||||
MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value);
|
||||
mono_field_set_value(p_object, mono_field, mono_string);
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_VALUETYPE: {
|
||||
GDMonoClass *tclass = type.type_class;
|
||||
|
||||
if (tclass == CACHED_CLASS(Vector2))
|
||||
SET_FROM_STRUCT_AND_BREAK(Vector2);
|
||||
|
||||
if (tclass == CACHED_CLASS(Rect2))
|
||||
SET_FROM_STRUCT_AND_BREAK(Rect2);
|
||||
|
||||
if (tclass == CACHED_CLASS(Transform2D))
|
||||
SET_FROM_STRUCT_AND_BREAK(Transform2D);
|
||||
|
||||
if (tclass == CACHED_CLASS(Vector3))
|
||||
SET_FROM_STRUCT_AND_BREAK(Vector3);
|
||||
|
||||
if (tclass == CACHED_CLASS(Basis))
|
||||
SET_FROM_STRUCT_AND_BREAK(Basis);
|
||||
|
||||
if (tclass == CACHED_CLASS(Quat))
|
||||
SET_FROM_STRUCT_AND_BREAK(Quat);
|
||||
|
||||
if (tclass == CACHED_CLASS(Transform))
|
||||
SET_FROM_STRUCT_AND_BREAK(Transform);
|
||||
|
||||
if (tclass == CACHED_CLASS(Rect3))
|
||||
SET_FROM_STRUCT_AND_BREAK(Rect3);
|
||||
|
||||
if (tclass == CACHED_CLASS(Color))
|
||||
SET_FROM_STRUCT_AND_BREAK(Color);
|
||||
|
||||
if (tclass == CACHED_CLASS(Plane))
|
||||
SET_FROM_STRUCT_AND_BREAK(Plane);
|
||||
|
||||
ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + tclass->get_name());
|
||||
ERR_FAIL();
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_ARRAY:
|
||||
case MONO_TYPE_SZARRAY: {
|
||||
MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(type.type_class));
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
|
||||
SET_FROM_ARRAY_AND_BREAK(Array);
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(uint8_t))
|
||||
SET_FROM_ARRAY_AND_BREAK(PoolByteArray);
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(int32_t))
|
||||
SET_FROM_ARRAY_AND_BREAK(PoolIntArray);
|
||||
|
||||
if (array_type->eklass == REAL_T_MONOCLASS)
|
||||
SET_FROM_ARRAY_AND_BREAK(PoolRealArray);
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(String))
|
||||
SET_FROM_ARRAY_AND_BREAK(PoolStringArray);
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(Vector2))
|
||||
SET_FROM_ARRAY_AND_BREAK(PoolVector2Array);
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(Vector3))
|
||||
SET_FROM_ARRAY_AND_BREAK(PoolVector3Array);
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(Color))
|
||||
SET_FROM_ARRAY_AND_BREAK(PoolColorArray);
|
||||
|
||||
ERR_EXPLAIN(String() + "Attempted to convert Variant to a managed array of unmarshallable element type.");
|
||||
ERR_FAIL();
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_CLASS: {
|
||||
GDMonoClass *type_class = type.type_class;
|
||||
|
||||
// GodotObject
|
||||
if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
|
||||
MonoObject *managed = GDMonoUtils::unmanaged_get_managed(p_value.operator Object *());
|
||||
mono_field_set_value(p_object, mono_field, &managed);
|
||||
break;
|
||||
}
|
||||
|
||||
if (CACHED_CLASS(NodePath) == type_class) {
|
||||
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator NodePath());
|
||||
mono_field_set_value(p_object, mono_field, &managed);
|
||||
break;
|
||||
}
|
||||
|
||||
if (CACHED_CLASS(RID) == type_class) {
|
||||
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator RID());
|
||||
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;
|
||||
|
||||
case MONO_TYPE_OBJECT: {
|
||||
GDMonoClass *type_class = type.type_class;
|
||||
|
||||
// Variant
|
||||
switch (p_value.get_type()) {
|
||||
case Variant::BOOL: {
|
||||
SET_FROM_PRIMITIVE(bool);
|
||||
} break;
|
||||
case Variant::INT: {
|
||||
SET_FROM_PRIMITIVE(int);
|
||||
} break;
|
||||
case Variant::REAL: {
|
||||
#ifdef REAL_T_IS_DOUBLE
|
||||
SET_FROM_PRIMITIVE(double);
|
||||
#else
|
||||
SET_FROM_PRIMITIVE(float);
|
||||
#endif
|
||||
} break;
|
||||
case Variant::STRING: {
|
||||
MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value);
|
||||
mono_field_set_value(p_object, mono_field, mono_string);
|
||||
} break;
|
||||
case Variant::VECTOR2: SET_FROM_STRUCT_AND_BREAK(Vector2);
|
||||
case Variant::RECT2: SET_FROM_STRUCT_AND_BREAK(Rect2);
|
||||
case Variant::VECTOR3: SET_FROM_STRUCT_AND_BREAK(Vector3);
|
||||
case Variant::TRANSFORM2D: SET_FROM_STRUCT_AND_BREAK(Transform2D);
|
||||
case Variant::PLANE: SET_FROM_STRUCT_AND_BREAK(Plane);
|
||||
case Variant::QUAT: SET_FROM_STRUCT_AND_BREAK(Quat);
|
||||
case Variant::RECT3: SET_FROM_STRUCT_AND_BREAK(Rect3);
|
||||
case Variant::BASIS: SET_FROM_STRUCT_AND_BREAK(Basis);
|
||||
case Variant::TRANSFORM: SET_FROM_STRUCT_AND_BREAK(Transform);
|
||||
case Variant::COLOR: SET_FROM_STRUCT_AND_BREAK(Color);
|
||||
case Variant::NODE_PATH: {
|
||||
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator NodePath());
|
||||
mono_field_set_value(p_object, mono_field, &managed);
|
||||
} break;
|
||||
case Variant::_RID: {
|
||||
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator RID());
|
||||
mono_field_set_value(p_object, mono_field, &managed);
|
||||
} break;
|
||||
case Variant::OBJECT: {
|
||||
MonoObject *managed = GDMonoUtils::unmanaged_get_managed(p_value.operator Object *());
|
||||
mono_field_set_value(p_object, mono_field, managed);
|
||||
break;
|
||||
}
|
||||
case Variant::DICTIONARY: {
|
||||
MonoObject *managed = GDMonoMarshal::Dictionary_to_mono_object(p_value.operator Dictionary());
|
||||
mono_field_set_value(p_object, mono_field, &managed);
|
||||
} break;
|
||||
case Variant::ARRAY: SET_FROM_ARRAY_AND_BREAK(Array);
|
||||
case Variant::POOL_BYTE_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolByteArray);
|
||||
case Variant::POOL_INT_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolIntArray);
|
||||
case Variant::POOL_REAL_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolRealArray);
|
||||
case Variant::POOL_STRING_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolStringArray);
|
||||
case Variant::POOL_VECTOR2_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolVector2Array);
|
||||
case Variant::POOL_VECTOR3_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolVector3Array);
|
||||
case Variant::POOL_COLOR_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolColorArray);
|
||||
#undef SET_FROM_ARRAY_AND_BREAK
|
||||
default: break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_GENERICINST: {
|
||||
if (CACHED_RAW_MONO_CLASS(Dictionary) == type.type_class->get_raw()) {
|
||||
MonoObject *managed = GDMonoMarshal::Dictionary_to_mono_object(p_value.operator Dictionary());
|
||||
mono_field_set_value(p_object, mono_field, &managed);
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
default: {
|
||||
ERR_PRINTS(String() + "Attempted to set the value of a field of unexpected type encoding: " + itos(type.type_encoding));
|
||||
} break;
|
||||
}
|
||||
|
||||
#undef SET_FROM_STRUCT_AND_BREAK
|
||||
#undef SET_FROM_PRIMITIVE
|
||||
}
|
||||
|
||||
bool GDMonoField::get_bool_value(MonoObject *p_object) {
|
||||
return UNBOX_BOOLEAN(get_value(p_object));
|
||||
}
|
||||
|
||||
int GDMonoField::get_int_value(MonoObject *p_object) {
|
||||
return UNBOX_INT32(get_value(p_object));
|
||||
}
|
||||
|
||||
String GDMonoField::get_string_value(MonoObject *p_object) {
|
||||
MonoObject *val = get_value(p_object);
|
||||
return val ? GDMonoMarshal::mono_string_to_godot((MonoString *)val) : String();
|
||||
}
|
||||
|
||||
bool GDMonoField::has_attribute(GDMonoClass *p_attr_class) {
|
||||
ERR_FAIL_NULL_V(p_attr_class, false);
|
||||
|
||||
if (!attrs_fetched)
|
||||
fetch_attributes();
|
||||
|
||||
if (!attributes)
|
||||
return false;
|
||||
|
||||
return mono_custom_attrs_has_attr(attributes, p_attr_class->get_raw());
|
||||
}
|
||||
|
||||
MonoObject *GDMonoField::get_attribute(GDMonoClass *p_attr_class) {
|
||||
ERR_FAIL_NULL_V(p_attr_class, NULL);
|
||||
|
||||
if (!attrs_fetched)
|
||||
fetch_attributes();
|
||||
|
||||
if (!attributes)
|
||||
return NULL;
|
||||
|
||||
return mono_custom_attrs_get_attr(attributes, p_attr_class->get_raw());
|
||||
}
|
||||
|
||||
void GDMonoField::fetch_attributes() {
|
||||
ERR_FAIL_COND(attributes != NULL);
|
||||
attributes = mono_custom_attrs_from_field(owner->get_raw(), get_raw());
|
||||
attrs_fetched = true;
|
||||
}
|
||||
|
||||
bool GDMonoField::is_static() {
|
||||
return mono_field_get_flags(mono_field) & MONO_FIELD_ATTR_STATIC;
|
||||
}
|
||||
|
||||
GDMono::MemberVisibility GDMonoField::get_visibility() {
|
||||
switch (mono_field_get_flags(mono_field) & MONO_FIELD_ATTR_FIELD_ACCESS_MASK) {
|
||||
case MONO_FIELD_ATTR_PRIVATE:
|
||||
return GDMono::PRIVATE;
|
||||
case MONO_FIELD_ATTR_FAM_AND_ASSEM:
|
||||
return GDMono::PROTECTED_AND_INTERNAL;
|
||||
case MONO_FIELD_ATTR_ASSEMBLY:
|
||||
return GDMono::INTERNAL;
|
||||
case MONO_FIELD_ATTR_FAMILY:
|
||||
return GDMono::PROTECTED;
|
||||
case MONO_FIELD_ATTR_PUBLIC:
|
||||
return GDMono::PUBLIC;
|
||||
default:
|
||||
ERR_FAIL_V(GDMono::PRIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
GDMonoField::GDMonoField(MonoClassField *p_raw_field, GDMonoClass *p_owner) {
|
||||
owner = p_owner;
|
||||
mono_field = p_raw_field;
|
||||
name = mono_field_get_name(mono_field);
|
||||
MonoType *field_type = mono_field_get_type(mono_field);
|
||||
type.type_encoding = mono_type_get_type(field_type);
|
||||
MonoClass *field_type_class = mono_class_from_mono_type(field_type);
|
||||
type.type_class = GDMono::get_singleton()->get_class(field_type_class);
|
||||
|
||||
attrs_fetched = false;
|
||||
attributes = NULL;
|
||||
}
|
||||
|
||||
GDMonoField::~GDMonoField() {
|
||||
if (attributes) {
|
||||
mono_custom_attrs_free(attributes);
|
||||
}
|
||||
}
|
74
modules/mono/mono_gd/gd_mono_field.h
Normal file
74
modules/mono/mono_gd/gd_mono_field.h
Normal file
@ -0,0 +1,74 @@
|
||||
/*************************************************************************/
|
||||
/* gd_mono_field.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 GDMONOFIELD_H
|
||||
#define GDMONOFIELD_H
|
||||
|
||||
#include "gd_mono.h"
|
||||
#include "gd_mono_header.h"
|
||||
|
||||
class GDMonoField {
|
||||
GDMonoClass *owner;
|
||||
MonoClassField *mono_field;
|
||||
|
||||
String name;
|
||||
ManagedType type;
|
||||
|
||||
bool attrs_fetched;
|
||||
MonoCustomAttrInfo *attributes;
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ String get_name() const { return name; }
|
||||
_FORCE_INLINE_ ManagedType get_type() const { return type; }
|
||||
|
||||
_FORCE_INLINE_ MonoClassField *get_raw() const { return mono_field; }
|
||||
|
||||
void set_value_raw(MonoObject *p_object, void *p_ptr);
|
||||
void set_value(MonoObject *p_object, const Variant &p_value);
|
||||
|
||||
_FORCE_INLINE_ MonoObject *get_value(MonoObject *p_object) {
|
||||
return mono_field_get_value_object(mono_domain_get(), mono_field, p_object);
|
||||
}
|
||||
|
||||
bool get_bool_value(MonoObject *p_object);
|
||||
int get_int_value(MonoObject *p_object);
|
||||
String get_string_value(MonoObject *p_object);
|
||||
|
||||
bool has_attribute(GDMonoClass *p_attr_class);
|
||||
MonoObject *get_attribute(GDMonoClass *p_attr_class);
|
||||
void fetch_attributes();
|
||||
|
||||
bool is_static();
|
||||
GDMono::MemberVisibility get_visibility();
|
||||
|
||||
GDMonoField(MonoClassField *p_raw_field, GDMonoClass *p_owner);
|
||||
~GDMonoField();
|
||||
};
|
||||
|
||||
#endif // GDMONOFIELD_H
|
59
modules/mono/mono_gd/gd_mono_header.h
Normal file
59
modules/mono/mono_gd/gd_mono_header.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*************************************************************************/
|
||||
/* gd_mono_header.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 GD_MONO_HEADER_H
|
||||
#define GD_MONO_HEADER_H
|
||||
|
||||
#include "int_types.h"
|
||||
|
||||
class GDMonoAssembly;
|
||||
class GDMonoClass;
|
||||
class GDMonoMethod;
|
||||
class GDMonoField;
|
||||
|
||||
struct ManagedType {
|
||||
int type_encoding;
|
||||
GDMonoClass *type_class;
|
||||
|
||||
ManagedType() {
|
||||
type_class = 0;
|
||||
}
|
||||
};
|
||||
|
||||
typedef union {
|
||||
uint32_t _uint32;
|
||||
float _float;
|
||||
} mono_float;
|
||||
|
||||
typedef union {
|
||||
uint64_t _uint64;
|
||||
float _double;
|
||||
} mono_double;
|
||||
|
||||
#endif // GD_MONO_HEADER_H
|
66
modules/mono/mono_gd/gd_mono_internals.cpp
Normal file
66
modules/mono/mono_gd/gd_mono_internals.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
/*************************************************************************/
|
||||
/* godotsharp_internals.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "gd_mono_internals.h"
|
||||
|
||||
#include "../csharp_script.h"
|
||||
#include "../mono_gc_handle.h"
|
||||
#include "gd_mono_utils.h"
|
||||
|
||||
namespace GDMonoInternals {
|
||||
|
||||
void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
|
||||
|
||||
// This method should not fail
|
||||
|
||||
CRASH_COND(!unmanaged);
|
||||
|
||||
// All mono objects created from the managed world (e.g.: `new Player()`)
|
||||
// need to have a CSharpScript in order for their methods to be callable from the unmanaged side
|
||||
|
||||
Reference *ref = Object::cast_to<Reference>(unmanaged);
|
||||
|
||||
GDMonoClass *klass = GDMonoUtils::get_object_class(managed);
|
||||
|
||||
CRASH_COND(!klass);
|
||||
|
||||
Ref<MonoGCHandle> gchandle = ref ? MonoGCHandle::create_weak(managed) :
|
||||
MonoGCHandle::create_strong(managed);
|
||||
|
||||
Ref<CSharpScript> script = CSharpScript::create_for_managed_type(klass);
|
||||
|
||||
CRASH_COND(script.is_null());
|
||||
|
||||
ScriptInstance *si = CSharpInstance::create_for_managed_type(unmanaged, script.ptr(), gchandle);
|
||||
|
||||
unmanaged->set_script_and_instance(script.get_ref_ptr(), si);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
42
modules/mono/mono_gd/gd_mono_internals.h
Normal file
42
modules/mono/mono_gd/gd_mono_internals.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*************************************************************************/
|
||||
/* godotsharp_internals.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 GD_MONO_INTERNALS_H
|
||||
#define GD_MONO_INTERNALS_H
|
||||
|
||||
#include <mono/jit/jit.h>
|
||||
|
||||
#include "core/object.h"
|
||||
|
||||
namespace GDMonoInternals {
|
||||
|
||||
void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged);
|
||||
}
|
||||
|
||||
#endif // GD_MONO_INTERNALS_H
|
175
modules/mono/mono_gd/gd_mono_log.cpp
Normal file
175
modules/mono/mono_gd/gd_mono_log.cpp
Normal file
@ -0,0 +1,175 @@
|
||||
/*************************************************************************/
|
||||
/* gd_mono_log.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "gd_mono_log.h"
|
||||
|
||||
#include <mono/utils/mono-logger.h>
|
||||
#include <stdlib.h> // abort
|
||||
|
||||
#include "os/dir_access.h"
|
||||
#include "os/os.h"
|
||||
|
||||
#include "../godotsharp_dirs.h"
|
||||
|
||||
static int log_level_get_id(const char *p_log_level) {
|
||||
|
||||
const char *valid_log_levels[] = { "error", "critical", "warning", "message", "info", "debug", NULL };
|
||||
|
||||
int i = 0;
|
||||
while (valid_log_levels[i]) {
|
||||
if (!strcmp(valid_log_levels[i], p_log_level))
|
||||
return i;
|
||||
i++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void gdmono_MonoLogCallback(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();
|
||||
|
||||
if (GDMonoLog::get_singleton()->get_log_level_id() >= log_level_get_id(log_level)) {
|
||||
String text(message);
|
||||
text += " (in domain ";
|
||||
text += log_domain;
|
||||
if (log_level) {
|
||||
text += ", ";
|
||||
text += log_level;
|
||||
}
|
||||
text += ")\n";
|
||||
|
||||
f->seek_end();
|
||||
f->store_string(text);
|
||||
}
|
||||
|
||||
if (fatal) {
|
||||
ERR_PRINTS("Mono: FALTAL ERROR, ABORTING! Logfile: " + GDMonoLog::get_singleton()->get_log_file_path() + "\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
GDMonoLog *GDMonoLog::singleton = NULL;
|
||||
|
||||
bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) {
|
||||
|
||||
if (!DirAccess::exists(p_logs_dir)) {
|
||||
DirAccessRef diraccess = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
ERR_FAIL_COND_V(!diraccess, false);
|
||||
Error logs_mkdir_err = diraccess->make_dir_recursive(p_logs_dir);
|
||||
ERR_EXPLAIN("Failed to create mono logs directory");
|
||||
ERR_FAIL_COND_V(logs_mkdir_err != OK, false);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
ERR_FAIL_COND(!da);
|
||||
|
||||
Error err = da->change_dir(p_logs_dir);
|
||||
ERR_FAIL_COND(err != OK);
|
||||
|
||||
ERR_FAIL_COND(da->list_dir_begin() != OK);
|
||||
|
||||
String current;
|
||||
while ((current = da->get_next()).length()) {
|
||||
if (da->current_is_dir())
|
||||
continue;
|
||||
if (!current.ends_with(".txt"))
|
||||
continue;
|
||||
|
||||
String name = current.get_basename();
|
||||
uint64_t unixtime = (uint64_t)name.to_int64();
|
||||
|
||||
if (OS::get_singleton()->get_unix_time() - unixtime > MAX_SECS) {
|
||||
da->remove(current);
|
||||
}
|
||||
}
|
||||
|
||||
da->list_dir_end();
|
||||
}
|
||||
|
||||
void GDMonoLog::initialize() {
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
const char *log_level = "debug";
|
||||
#else
|
||||
const char *log_level = "warning";
|
||||
#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);
|
||||
}
|
||||
|
||||
mono_trace_set_level_string(log_level);
|
||||
log_level_id = log_level_get_id(log_level);
|
||||
|
||||
if (log_file) {
|
||||
if (OS::get_singleton()->is_stdout_verbose())
|
||||
OS::get_singleton()->print(String("Mono: Logfile is " + log_file_path + "\n").utf8());
|
||||
mono_trace_set_log_handler(gdmono_MonoLogCallback, this);
|
||||
} else {
|
||||
OS::get_singleton()->printerr("Mono: No log file, using default log handler\n");
|
||||
}
|
||||
}
|
||||
|
||||
GDMonoLog::GDMonoLog() {
|
||||
|
||||
singleton = this;
|
||||
|
||||
log_level_id = -1;
|
||||
}
|
||||
|
||||
GDMonoLog::~GDMonoLog() {
|
||||
|
||||
singleton = NULL;
|
||||
|
||||
if (log_file) {
|
||||
log_file->close();
|
||||
memdelete(log_file);
|
||||
}
|
||||
}
|
61
modules/mono/mono_gd/gd_mono_log.h
Normal file
61
modules/mono/mono_gd/gd_mono_log.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*************************************************************************/
|
||||
/* gd_mono_log.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 GD_MONO_LOG_H
|
||||
#define GD_MONO_LOG_H
|
||||
|
||||
#include "os/file_access.h"
|
||||
|
||||
class GDMonoLog {
|
||||
|
||||
int log_level_id;
|
||||
|
||||
FileAccess *log_file;
|
||||
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;
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ static GDMonoLog *get_singleton() { return singleton; }
|
||||
|
||||
void initialize();
|
||||
|
||||
_FORCE_INLINE_ FileAccess *get_log_file() { return log_file; }
|
||||
_FORCE_INLINE_ String get_log_file_path() { return log_file_path; }
|
||||
_FORCE_INLINE_ int get_log_level_id() { return log_level_id; }
|
||||
|
||||
GDMonoLog();
|
||||
~GDMonoLog();
|
||||
};
|
||||
|
||||
#endif // GD_MONO_LOG_H
|
856
modules/mono/mono_gd/gd_mono_marshal.cpp
Normal file
856
modules/mono/mono_gd/gd_mono_marshal.cpp
Normal file
@ -0,0 +1,856 @@
|
||||
/*************************************************************************/
|
||||
/* gd_mono_marshal.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "gd_mono_marshal.h"
|
||||
|
||||
#include "gd_mono.h"
|
||||
#include "gd_mono_class.h"
|
||||
|
||||
namespace GDMonoMarshal {
|
||||
|
||||
#define RETURN_BOXED_STRUCT(m_t, m_var_in) \
|
||||
{ \
|
||||
const m_t &m_in = m_var_in->operator m_t(); \
|
||||
MARSHALLED_OUT(m_t, m_in, raw); \
|
||||
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(m_t), raw); \
|
||||
}
|
||||
|
||||
#define RETURN_UNBOXED_STRUCT(m_t, m_var_in) \
|
||||
{ \
|
||||
float *raw = UNBOX_FLOAT_PTR(m_var_in); \
|
||||
MARSHALLED_IN(m_t, raw, ret); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
Variant::Type managed_to_variant_type(const ManagedType &p_type) {
|
||||
switch (p_type.type_encoding) {
|
||||
case MONO_TYPE_BOOLEAN:
|
||||
return Variant::BOOL;
|
||||
|
||||
case MONO_TYPE_I1:
|
||||
return Variant::INT;
|
||||
case MONO_TYPE_I2:
|
||||
return Variant::INT;
|
||||
case MONO_TYPE_I4:
|
||||
return Variant::INT;
|
||||
case MONO_TYPE_I8:
|
||||
return Variant::INT;
|
||||
|
||||
case MONO_TYPE_U1:
|
||||
return Variant::INT;
|
||||
case MONO_TYPE_U2:
|
||||
return Variant::INT;
|
||||
case MONO_TYPE_U4:
|
||||
return Variant::INT;
|
||||
case MONO_TYPE_U8:
|
||||
return Variant::INT;
|
||||
|
||||
case MONO_TYPE_R4:
|
||||
return Variant::REAL;
|
||||
case MONO_TYPE_R8:
|
||||
return Variant::REAL;
|
||||
|
||||
case MONO_TYPE_STRING: {
|
||||
return Variant::STRING;
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_VALUETYPE: {
|
||||
GDMonoClass *tclass = p_type.type_class;
|
||||
|
||||
if (tclass == CACHED_CLASS(Vector2))
|
||||
return Variant::VECTOR2;
|
||||
|
||||
if (tclass == CACHED_CLASS(Rect2))
|
||||
return Variant::RECT2;
|
||||
|
||||
if (tclass == CACHED_CLASS(Transform2D))
|
||||
return Variant::TRANSFORM2D;
|
||||
|
||||
if (tclass == CACHED_CLASS(Vector3))
|
||||
return Variant::VECTOR3;
|
||||
|
||||
if (tclass == CACHED_CLASS(Basis))
|
||||
return Variant::BASIS;
|
||||
|
||||
if (tclass == CACHED_CLASS(Quat))
|
||||
return Variant::QUAT;
|
||||
|
||||
if (tclass == CACHED_CLASS(Transform))
|
||||
return Variant::TRANSFORM;
|
||||
|
||||
if (tclass == CACHED_CLASS(Rect3))
|
||||
return Variant::RECT3;
|
||||
|
||||
if (tclass == CACHED_CLASS(Color))
|
||||
return Variant::COLOR;
|
||||
|
||||
if (tclass == CACHED_CLASS(Plane))
|
||||
return Variant::PLANE;
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_ARRAY:
|
||||
case MONO_TYPE_SZARRAY: {
|
||||
MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(p_type.type_class));
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
|
||||
return Variant::ARRAY;
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(uint8_t))
|
||||
return Variant::POOL_BYTE_ARRAY;
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(int32_t))
|
||||
return Variant::POOL_INT_ARRAY;
|
||||
|
||||
if (array_type->eklass == REAL_T_MONOCLASS)
|
||||
return Variant::POOL_REAL_ARRAY;
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(String))
|
||||
return Variant::POOL_STRING_ARRAY;
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(Vector2))
|
||||
return Variant::POOL_VECTOR2_ARRAY;
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(Vector3))
|
||||
return Variant::POOL_VECTOR3_ARRAY;
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(Color))
|
||||
return Variant::POOL_COLOR_ARRAY;
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_CLASS: {
|
||||
GDMonoClass *type_class = p_type.type_class;
|
||||
|
||||
// GodotObject
|
||||
if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
|
||||
return Variant::OBJECT;
|
||||
}
|
||||
|
||||
if (CACHED_CLASS(NodePath) == type_class) {
|
||||
return Variant::NODE_PATH;
|
||||
}
|
||||
|
||||
if (CACHED_CLASS(RID) == type_class) {
|
||||
return Variant::_RID;
|
||||
}
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_GENERICINST: {
|
||||
if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_raw()) {
|
||||
return Variant::DICTIONARY;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
// No error, the caller will decide what to do in this case
|
||||
return Variant::NIL;
|
||||
}
|
||||
|
||||
String mono_to_utf8_string(MonoString *p_mono_string) {
|
||||
MonoError error;
|
||||
char *utf8 = mono_string_to_utf8_checked(p_mono_string, &error);
|
||||
|
||||
ERR_EXPLAIN("Conversion of MonoString to UTF8 failed.");
|
||||
ERR_FAIL_COND_V(!mono_error_ok(&error), String());
|
||||
|
||||
String ret = String::utf8(utf8);
|
||||
|
||||
mono_free(utf8);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
String mono_to_utf16_string(MonoString *p_mono_string) {
|
||||
int len = mono_string_length(p_mono_string);
|
||||
String ret;
|
||||
|
||||
if (len == 0)
|
||||
return ret;
|
||||
|
||||
ret.resize(len + 1);
|
||||
ret.set(len, 0);
|
||||
|
||||
CharType *src = (CharType *)mono_string_chars(p_mono_string);
|
||||
CharType *dst = &(ret.operator[](0));
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
MonoObject *variant_to_mono_object(const Variant *p_var) {
|
||||
ManagedType type;
|
||||
|
||||
type.type_encoding = MONO_TYPE_OBJECT;
|
||||
|
||||
return variant_to_mono_object(p_var, type);
|
||||
}
|
||||
|
||||
MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type) {
|
||||
switch (p_type.type_encoding) {
|
||||
case MONO_TYPE_BOOLEAN: {
|
||||
MonoBoolean val = p_var->operator bool();
|
||||
return BOX_BOOLEAN(val);
|
||||
}
|
||||
|
||||
case MONO_TYPE_I1: {
|
||||
char val = p_var->operator signed char();
|
||||
return BOX_INT8(val);
|
||||
}
|
||||
case MONO_TYPE_I2: {
|
||||
short val = p_var->operator signed short();
|
||||
return BOX_INT16(val);
|
||||
}
|
||||
case MONO_TYPE_I4: {
|
||||
int val = p_var->operator signed int();
|
||||
return BOX_INT32(val);
|
||||
}
|
||||
case MONO_TYPE_I8: {
|
||||
int64_t val = p_var->operator int64_t();
|
||||
return BOX_INT64(val);
|
||||
}
|
||||
|
||||
case MONO_TYPE_U1: {
|
||||
char val = p_var->operator unsigned char();
|
||||
return BOX_UINT8(val);
|
||||
}
|
||||
case MONO_TYPE_U2: {
|
||||
short val = p_var->operator unsigned short();
|
||||
return BOX_UINT16(val);
|
||||
}
|
||||
case MONO_TYPE_U4: {
|
||||
int val = p_var->operator unsigned int();
|
||||
return BOX_UINT32(val);
|
||||
}
|
||||
case MONO_TYPE_U8: {
|
||||
uint64_t val = p_var->operator uint64_t();
|
||||
return BOX_UINT64(val);
|
||||
}
|
||||
|
||||
case MONO_TYPE_R4: {
|
||||
float val = p_var->operator float();
|
||||
return BOX_FLOAT(val);
|
||||
}
|
||||
case MONO_TYPE_R8: {
|
||||
double val = p_var->operator double();
|
||||
return BOX_DOUBLE(val);
|
||||
}
|
||||
|
||||
case MONO_TYPE_STRING: {
|
||||
return (MonoObject *)mono_string_from_godot(p_var->operator String());
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_VALUETYPE: {
|
||||
GDMonoClass *tclass = p_type.type_class;
|
||||
|
||||
if (tclass == CACHED_CLASS(Vector2))
|
||||
RETURN_BOXED_STRUCT(Vector2, p_var);
|
||||
|
||||
if (tclass == CACHED_CLASS(Rect2))
|
||||
RETURN_BOXED_STRUCT(Rect2, p_var);
|
||||
|
||||
if (tclass == CACHED_CLASS(Transform2D))
|
||||
RETURN_BOXED_STRUCT(Transform2D, p_var);
|
||||
|
||||
if (tclass == CACHED_CLASS(Vector3))
|
||||
RETURN_BOXED_STRUCT(Vector3, p_var);
|
||||
|
||||
if (tclass == CACHED_CLASS(Basis))
|
||||
RETURN_BOXED_STRUCT(Basis, p_var);
|
||||
|
||||
if (tclass == CACHED_CLASS(Quat))
|
||||
RETURN_BOXED_STRUCT(Quat, p_var);
|
||||
|
||||
if (tclass == CACHED_CLASS(Transform))
|
||||
RETURN_BOXED_STRUCT(Transform, p_var);
|
||||
|
||||
if (tclass == CACHED_CLASS(Rect3))
|
||||
RETURN_BOXED_STRUCT(Rect3, p_var);
|
||||
|
||||
if (tclass == CACHED_CLASS(Color))
|
||||
RETURN_BOXED_STRUCT(Color, p_var);
|
||||
|
||||
if (tclass == CACHED_CLASS(Plane))
|
||||
RETURN_BOXED_STRUCT(Plane, p_var);
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_ARRAY:
|
||||
case MONO_TYPE_SZARRAY: {
|
||||
MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(p_type.type_class));
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
|
||||
return (MonoObject *)Array_to_mono_array(p_var->operator Array());
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(uint8_t))
|
||||
return (MonoObject *)PoolByteArray_to_mono_array(p_var->operator PoolByteArray());
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(int32_t))
|
||||
return (MonoObject *)PoolIntArray_to_mono_array(p_var->operator PoolIntArray());
|
||||
|
||||
if (array_type->eklass == REAL_T_MONOCLASS)
|
||||
return (MonoObject *)PoolRealArray_to_mono_array(p_var->operator PoolRealArray());
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(String))
|
||||
return (MonoObject *)PoolStringArray_to_mono_array(p_var->operator PoolStringArray());
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(Vector2))
|
||||
return (MonoObject *)PoolVector2Array_to_mono_array(p_var->operator PoolVector2Array());
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(Vector3))
|
||||
return (MonoObject *)PoolVector3Array_to_mono_array(p_var->operator PoolVector3Array());
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(Color))
|
||||
return (MonoObject *)PoolColorArray_to_mono_array(p_var->operator PoolColorArray());
|
||||
|
||||
ERR_EXPLAIN(String() + "Attempted to convert Variant to a managed array of unmarshallable element type.");
|
||||
ERR_FAIL_V(NULL);
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_CLASS: {
|
||||
GDMonoClass *type_class = p_type.type_class;
|
||||
|
||||
// GodotObject
|
||||
if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
|
||||
return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *());
|
||||
}
|
||||
|
||||
if (CACHED_CLASS(NodePath) == type_class) {
|
||||
return GDMonoUtils::create_managed_from(p_var->operator NodePath());
|
||||
}
|
||||
|
||||
if (CACHED_CLASS(RID) == type_class) {
|
||||
return GDMonoUtils::create_managed_from(p_var->operator RID());
|
||||
}
|
||||
} break;
|
||||
case MONO_TYPE_OBJECT: {
|
||||
// Variant
|
||||
switch (p_var->get_type()) {
|
||||
case Variant::BOOL: {
|
||||
MonoBoolean val = p_var->operator bool();
|
||||
return BOX_BOOLEAN(val);
|
||||
}
|
||||
case Variant::INT: {
|
||||
int val = p_var->operator signed int();
|
||||
return BOX_INT32(val);
|
||||
}
|
||||
case Variant::REAL: {
|
||||
#ifdef REAL_T_IS_DOUBLE
|
||||
double val = p_var->operator double();
|
||||
return BOX_DOUBLE(val);
|
||||
#else
|
||||
float val = p_var->operator float();
|
||||
return BOX_FLOAT(val);
|
||||
#endif
|
||||
}
|
||||
case Variant::STRING:
|
||||
return (MonoObject *)mono_string_from_godot(p_var->operator String());
|
||||
case Variant::VECTOR2:
|
||||
RETURN_BOXED_STRUCT(Vector2, p_var);
|
||||
case Variant::RECT2:
|
||||
RETURN_BOXED_STRUCT(Rect2, p_var);
|
||||
case Variant::VECTOR3:
|
||||
RETURN_BOXED_STRUCT(Vector3, p_var);
|
||||
case Variant::TRANSFORM2D:
|
||||
RETURN_BOXED_STRUCT(Transform2D, p_var);
|
||||
case Variant::PLANE:
|
||||
RETURN_BOXED_STRUCT(Plane, p_var);
|
||||
case Variant::QUAT:
|
||||
RETURN_BOXED_STRUCT(Quat, p_var);
|
||||
case Variant::RECT3:
|
||||
RETURN_BOXED_STRUCT(Rect3, p_var);
|
||||
case Variant::BASIS:
|
||||
RETURN_BOXED_STRUCT(Basis, p_var);
|
||||
case Variant::TRANSFORM:
|
||||
RETURN_BOXED_STRUCT(Transform, p_var);
|
||||
case Variant::COLOR:
|
||||
RETURN_BOXED_STRUCT(Color, p_var);
|
||||
case Variant::NODE_PATH:
|
||||
return GDMonoUtils::create_managed_from(p_var->operator NodePath());
|
||||
case Variant::_RID:
|
||||
return GDMonoUtils::create_managed_from(p_var->operator RID());
|
||||
case Variant::OBJECT: {
|
||||
return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *());
|
||||
}
|
||||
case Variant::DICTIONARY:
|
||||
return Dictionary_to_mono_object(p_var->operator Dictionary());
|
||||
case Variant::ARRAY:
|
||||
return (MonoObject *)Array_to_mono_array(p_var->operator Array());
|
||||
case Variant::POOL_BYTE_ARRAY:
|
||||
return (MonoObject *)PoolByteArray_to_mono_array(p_var->operator PoolByteArray());
|
||||
case Variant::POOL_INT_ARRAY:
|
||||
return (MonoObject *)PoolIntArray_to_mono_array(p_var->operator PoolIntArray());
|
||||
case Variant::POOL_REAL_ARRAY:
|
||||
return (MonoObject *)PoolRealArray_to_mono_array(p_var->operator PoolRealArray());
|
||||
case Variant::POOL_STRING_ARRAY:
|
||||
return (MonoObject *)PoolStringArray_to_mono_array(p_var->operator PoolStringArray());
|
||||
case Variant::POOL_VECTOR2_ARRAY:
|
||||
return (MonoObject *)PoolVector2Array_to_mono_array(p_var->operator PoolVector2Array());
|
||||
case Variant::POOL_VECTOR3_ARRAY:
|
||||
return (MonoObject *)PoolVector3Array_to_mono_array(p_var->operator PoolVector3Array());
|
||||
case Variant::POOL_COLOR_ARRAY:
|
||||
return (MonoObject *)PoolColorArray_to_mono_array(p_var->operator PoolColorArray());
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case MONO_TYPE_GENERICINST: {
|
||||
if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_raw()) {
|
||||
return Dictionary_to_mono_object(p_var->operator Dictionary());
|
||||
}
|
||||
} break;
|
||||
} break;
|
||||
}
|
||||
|
||||
ERR_EXPLAIN(String() + "Attempted to convert Variant to an unmarshallable managed type. Name: \'" +
|
||||
p_type.type_class->get_name() + "\' Encoding: " + itos(p_type.type_encoding));
|
||||
ERR_FAIL_V(NULL);
|
||||
}
|
||||
|
||||
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_raw_type(tclass);
|
||||
|
||||
ManagedType type;
|
||||
|
||||
type.type_encoding = mono_type_get_type(raw_type);
|
||||
type.type_class = tclass;
|
||||
|
||||
return mono_object_to_variant(p_obj, type);
|
||||
}
|
||||
|
||||
Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) {
|
||||
switch (p_type.type_encoding) {
|
||||
case MONO_TYPE_BOOLEAN:
|
||||
return (bool)UNBOX_BOOLEAN(p_obj);
|
||||
|
||||
case MONO_TYPE_I1:
|
||||
return UNBOX_INT8(p_obj);
|
||||
case MONO_TYPE_I2:
|
||||
return UNBOX_INT16(p_obj);
|
||||
case MONO_TYPE_I4:
|
||||
return UNBOX_INT32(p_obj);
|
||||
case MONO_TYPE_I8:
|
||||
return UNBOX_INT64(p_obj);
|
||||
|
||||
case MONO_TYPE_U1:
|
||||
return UNBOX_UINT8(p_obj);
|
||||
case MONO_TYPE_U2:
|
||||
return UNBOX_UINT16(p_obj);
|
||||
case MONO_TYPE_U4:
|
||||
return UNBOX_UINT32(p_obj);
|
||||
case MONO_TYPE_U8:
|
||||
return UNBOX_UINT64(p_obj);
|
||||
|
||||
case MONO_TYPE_R4:
|
||||
return UNBOX_FLOAT(p_obj);
|
||||
case MONO_TYPE_R8:
|
||||
return UNBOX_DOUBLE(p_obj);
|
||||
|
||||
case MONO_TYPE_STRING: {
|
||||
String str = mono_string_to_godot((MonoString *)p_obj);
|
||||
return str;
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_VALUETYPE: {
|
||||
GDMonoClass *tclass = p_type.type_class;
|
||||
|
||||
if (tclass == CACHED_CLASS(Vector2))
|
||||
RETURN_UNBOXED_STRUCT(Vector2, p_obj);
|
||||
|
||||
if (tclass == CACHED_CLASS(Rect2))
|
||||
RETURN_UNBOXED_STRUCT(Rect2, p_obj);
|
||||
|
||||
if (tclass == CACHED_CLASS(Transform2D))
|
||||
RETURN_UNBOXED_STRUCT(Transform2D, p_obj);
|
||||
|
||||
if (tclass == CACHED_CLASS(Vector3))
|
||||
RETURN_UNBOXED_STRUCT(Vector3, p_obj);
|
||||
|
||||
if (tclass == CACHED_CLASS(Basis))
|
||||
RETURN_UNBOXED_STRUCT(Basis, p_obj);
|
||||
|
||||
if (tclass == CACHED_CLASS(Quat))
|
||||
RETURN_UNBOXED_STRUCT(Quat, p_obj);
|
||||
|
||||
if (tclass == CACHED_CLASS(Transform))
|
||||
RETURN_UNBOXED_STRUCT(Transform, p_obj);
|
||||
|
||||
if (tclass == CACHED_CLASS(Rect3))
|
||||
RETURN_UNBOXED_STRUCT(Rect3, p_obj);
|
||||
|
||||
if (tclass == CACHED_CLASS(Color))
|
||||
RETURN_UNBOXED_STRUCT(Color, p_obj);
|
||||
|
||||
if (tclass == CACHED_CLASS(Plane))
|
||||
RETURN_UNBOXED_STRUCT(Plane, p_obj);
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_ARRAY:
|
||||
case MONO_TYPE_SZARRAY: {
|
||||
MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(p_type.type_class));
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
|
||||
return mono_array_to_Array((MonoArray *)p_obj);
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(uint8_t))
|
||||
return mono_array_to_PoolByteArray((MonoArray *)p_obj);
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(int32_t))
|
||||
return mono_array_to_PoolIntArray((MonoArray *)p_obj);
|
||||
|
||||
if (array_type->eklass == REAL_T_MONOCLASS)
|
||||
return mono_array_to_PoolRealArray((MonoArray *)p_obj);
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(String))
|
||||
return mono_array_to_PoolStringArray((MonoArray *)p_obj);
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(Vector2))
|
||||
return mono_array_to_PoolVector2Array((MonoArray *)p_obj);
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(Vector3))
|
||||
return mono_array_to_PoolVector3Array((MonoArray *)p_obj);
|
||||
|
||||
if (array_type->eklass == CACHED_CLASS_RAW(Color))
|
||||
return mono_array_to_PoolColorArray((MonoArray *)p_obj);
|
||||
|
||||
ERR_EXPLAIN(String() + "Attempted to convert a managed array of unmarshallable element type to Variant.");
|
||||
ERR_FAIL_V(Variant());
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_CLASS: {
|
||||
GDMonoClass *type_class = p_type.type_class;
|
||||
|
||||
// GodotObject
|
||||
if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
|
||||
GDMonoField *ptr_field = CACHED_FIELD(GodotObject, ptr);
|
||||
|
||||
ERR_FAIL_NULL_V(ptr_field, Variant());
|
||||
|
||||
void *ptr_to_unmanaged = UNBOX_PTR(ptr_field->get_value(p_obj));
|
||||
|
||||
if (!ptr_to_unmanaged) // IntPtr.Zero
|
||||
return Variant();
|
||||
|
||||
Object *object_ptr = static_cast<Object *>(ptr_to_unmanaged);
|
||||
|
||||
if (!object_ptr)
|
||||
return Variant();
|
||||
|
||||
return object_ptr;
|
||||
}
|
||||
|
||||
if (CACHED_CLASS(NodePath) == type_class) {
|
||||
return UNBOX_PTR(CACHED_FIELD(NodePath, ptr)->get_value(p_obj));
|
||||
}
|
||||
|
||||
if (CACHED_CLASS(RID) == type_class) {
|
||||
return UNBOX_PTR(CACHED_FIELD(RID, ptr)->get_value(p_obj));
|
||||
}
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_GENERICINST: {
|
||||
if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_raw()) {
|
||||
return mono_object_to_Dictionary(p_obj);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
ERR_EXPLAIN(String() + "Attempted to convert an unmarshallable managed type to Variant. Name: \'" +
|
||||
p_type.type_class->get_name() + "\' Encoding: " + itos(p_type.type_encoding));
|
||||
ERR_FAIL_V(Variant());
|
||||
}
|
||||
|
||||
MonoArray *Array_to_mono_array(const Array &p_array) {
|
||||
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_array.size());
|
||||
|
||||
for (int i = 0; i < p_array.size(); i++) {
|
||||
MonoObject *boxed = variant_to_mono_object(p_array[i]);
|
||||
mono_array_set(ret, MonoObject *, i, boxed);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Array mono_array_to_Array(MonoArray *p_array) {
|
||||
Array ret;
|
||||
int length = mono_array_length(p_array);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
MonoObject *elem = mono_array_get(p_array, MonoObject *, i);
|
||||
ret.push_back(mono_object_to_variant(elem));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// TODO Optimize reading/writing from/to PoolArrays
|
||||
|
||||
MonoArray *PoolIntArray_to_mono_array(const PoolIntArray &p_array) {
|
||||
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(int32_t), p_array.size());
|
||||
|
||||
for (int i = 0; i < p_array.size(); i++) {
|
||||
mono_array_set(ret, int32_t, i, p_array[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
PoolIntArray mono_array_to_PoolIntArray(MonoArray *p_array) {
|
||||
PoolIntArray ret;
|
||||
int length = mono_array_length(p_array);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
int32_t elem = mono_array_get(p_array, int32_t, i);
|
||||
ret.push_back(elem);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
MonoArray *PoolByteArray_to_mono_array(const PoolByteArray &p_array) {
|
||||
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), p_array.size());
|
||||
|
||||
for (int i = 0; i < p_array.size(); i++) {
|
||||
mono_array_set(ret, uint8_t, i, p_array[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
PoolByteArray mono_array_to_PoolByteArray(MonoArray *p_array) {
|
||||
PoolByteArray ret;
|
||||
int length = mono_array_length(p_array);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
uint8_t elem = mono_array_get(p_array, uint8_t, i);
|
||||
ret.push_back(elem);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
MonoArray *PoolRealArray_to_mono_array(const PoolRealArray &p_array) {
|
||||
MonoArray *ret = mono_array_new(mono_domain_get(), REAL_T_MONOCLASS, p_array.size());
|
||||
|
||||
for (int i = 0; i < p_array.size(); i++) {
|
||||
mono_array_set(ret, real_t, i, p_array[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
PoolRealArray mono_array_to_PoolRealArray(MonoArray *p_array) {
|
||||
PoolRealArray ret;
|
||||
int length = mono_array_length(p_array);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
real_t elem = mono_array_get(p_array, real_t, i);
|
||||
ret.push_back(elem);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
MonoArray *PoolStringArray_to_mono_array(const PoolStringArray &p_array) {
|
||||
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(String), p_array.size());
|
||||
|
||||
for (int i = 0; i < p_array.size(); i++) {
|
||||
MonoString *boxed = mono_string_from_godot(p_array[i]);
|
||||
mono_array_set(ret, MonoString *, i, boxed);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
PoolStringArray mono_array_to_PoolStringArray(MonoArray *p_array) {
|
||||
PoolStringArray ret;
|
||||
int length = mono_array_length(p_array);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
MonoString *elem = mono_array_get(p_array, MonoString *, i);
|
||||
ret.push_back(mono_string_to_godot(elem));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
MonoArray *PoolColorArray_to_mono_array(const PoolColorArray &p_array) {
|
||||
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Color), p_array.size());
|
||||
|
||||
for (int i = 0; i < p_array.size(); i++) {
|
||||
#ifdef YOLOCOPY
|
||||
mono_array_set(ret, Color, i, p_array[i]);
|
||||
#else
|
||||
real_t *raw = (real_t *)mono_array_addr_with_size(ret, sizeof(real_t) * 4, i);
|
||||
const Color &elem = p_array[i];
|
||||
raw[0] = elem.r;
|
||||
raw[4] = elem.g;
|
||||
raw[8] = elem.b;
|
||||
raw[12] = elem.a;
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
PoolColorArray mono_array_to_PoolColorArray(MonoArray *p_array) {
|
||||
PoolColorArray ret;
|
||||
int length = mono_array_length(p_array);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
real_t *raw_elem = mono_array_get(p_array, real_t *, i);
|
||||
MARSHALLED_IN(Color, raw_elem, elem);
|
||||
ret.push_back(elem);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
MonoArray *PoolVector2Array_to_mono_array(const PoolVector2Array &p_array) {
|
||||
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Vector2), p_array.size());
|
||||
|
||||
for (int i = 0; i < p_array.size(); i++) {
|
||||
#ifdef YOLOCOPY
|
||||
mono_array_set(ret, Vector2, i, p_array[i]);
|
||||
#else
|
||||
real_t *raw = (real_t *)mono_array_addr_with_size(ret, sizeof(real_t) * 2, i);
|
||||
const Vector2 &elem = p_array[i];
|
||||
raw[0] = elem.x;
|
||||
raw[4] = elem.y;
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
PoolVector2Array mono_array_to_PoolVector2Array(MonoArray *p_array) {
|
||||
PoolVector2Array ret;
|
||||
int length = mono_array_length(p_array);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
real_t *raw_elem = mono_array_get(p_array, real_t *, i);
|
||||
MARSHALLED_IN(Vector2, raw_elem, elem);
|
||||
ret.push_back(elem);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
MonoArray *PoolVector3Array_to_mono_array(const PoolVector3Array &p_array) {
|
||||
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Vector3), p_array.size());
|
||||
|
||||
for (int i = 0; i < p_array.size(); i++) {
|
||||
#ifdef YOLOCOPY
|
||||
mono_array_set(ret, Vector3, i, p_array[i]);
|
||||
#else
|
||||
real_t *raw = (real_t *)mono_array_addr_with_size(ret, sizeof(real_t) * 3, i);
|
||||
const Vector3 &elem = p_array[i];
|
||||
raw[0] = elem.x;
|
||||
raw[4] = elem.y;
|
||||
raw[8] = elem.z;
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array) {
|
||||
PoolVector3Array ret;
|
||||
int length = mono_array_length(p_array);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
real_t *raw_elem = mono_array_get(p_array, real_t *, i);
|
||||
MARSHALLED_IN(Vector3, raw_elem, elem);
|
||||
ret.push_back(elem);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
MonoObject *Dictionary_to_mono_object(const Dictionary &p_dict) {
|
||||
MonoArray *keys = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_dict.size());
|
||||
MonoArray *values = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_dict.size());
|
||||
|
||||
int i = 0;
|
||||
const Variant *dkey = NULL;
|
||||
while ((dkey = p_dict.next(dkey))) {
|
||||
mono_array_set(keys, MonoObject *, i, variant_to_mono_object(dkey));
|
||||
mono_array_set(values, MonoObject *, i, variant_to_mono_object(p_dict[*dkey]));
|
||||
i++;
|
||||
}
|
||||
|
||||
GDMonoUtils::MarshalUtils_ArraysToDict arrays_to_dict = CACHED_METHOD_THUNK(MarshalUtils, ArraysToDictionary);
|
||||
|
||||
MonoObject *ex = NULL;
|
||||
MonoObject *ret = arrays_to_dict(keys, values, &ex);
|
||||
|
||||
if (ex) {
|
||||
mono_print_unhandled_exception(ex);
|
||||
ERR_FAIL_V(NULL);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Dictionary mono_object_to_Dictionary(MonoObject *p_dict) {
|
||||
Dictionary ret;
|
||||
|
||||
GDMonoUtils::MarshalUtils_DictToArrays dict_to_arrays = CACHED_METHOD_THUNK(MarshalUtils, DictionaryToArrays);
|
||||
|
||||
MonoArray *keys = NULL;
|
||||
MonoArray *values = NULL;
|
||||
MonoObject *ex = NULL;
|
||||
dict_to_arrays(p_dict, &keys, &values, &ex);
|
||||
|
||||
if (ex) {
|
||||
mono_print_unhandled_exception(ex);
|
||||
ERR_FAIL_V(Dictionary());
|
||||
}
|
||||
|
||||
int length = mono_array_length(keys);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
MonoObject *key_obj = mono_array_get(keys, MonoObject *, i);
|
||||
MonoObject *value_obj = mono_array_get(values, MonoObject *, i);
|
||||
|
||||
Variant key = key_obj ? mono_object_to_variant(key_obj) : Variant();
|
||||
Variant value = value_obj ? mono_object_to_variant(value_obj) : Variant();
|
||||
|
||||
ret[key] = value;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
229
modules/mono/mono_gd/gd_mono_marshal.h
Normal file
229
modules/mono/mono_gd/gd_mono_marshal.h
Normal file
@ -0,0 +1,229 @@
|
||||
/*************************************************************************/
|
||||
/* gd_mono_marshal.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 GDMONOMARSHAL_H
|
||||
#define GDMONOMARSHAL_H
|
||||
|
||||
#include "gd_mono.h"
|
||||
#include "gd_mono_utils.h"
|
||||
#include "variant.h"
|
||||
|
||||
namespace GDMonoMarshal {
|
||||
|
||||
#define UNBOX_CHAR_PTR(x) (char *)mono_object_unbox(x)
|
||||
#define UNBOX_FLOAT_PTR(x) (float *)mono_object_unbox(x)
|
||||
|
||||
#define UNBOX_DOUBLE(x) *(double *)mono_object_unbox(x)
|
||||
#define UNBOX_FLOAT(x) *(float *)mono_object_unbox(x)
|
||||
#define UNBOX_INT64(x) *(int64_t *)mono_object_unbox(x)
|
||||
#define UNBOX_INT32(x) *(int32_t *)mono_object_unbox(x)
|
||||
#define UNBOX_INT16(x) *(int16_t *)mono_object_unbox(x)
|
||||
#define UNBOX_INT8(x) *(int8_t *)mono_object_unbox(x)
|
||||
#define UNBOX_UINT64(x) *(uint64_t *)mono_object_unbox(x)
|
||||
#define UNBOX_UINT32(x) *(uint32_t *)mono_object_unbox(x)
|
||||
#define UNBOX_UINT16(x) *(uint16_t *)mono_object_unbox(x)
|
||||
#define UNBOX_UINT8(x) *(uint8_t *)mono_object_unbox(x)
|
||||
#define UNBOX_BOOLEAN(x) *(MonoBoolean *)mono_object_unbox(x)
|
||||
#define UNBOX_PTR(x) mono_object_unbox(x)
|
||||
|
||||
#define BOX_DOUBLE(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(double), &x)
|
||||
#define BOX_FLOAT(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(float), &x)
|
||||
#define BOX_INT64(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int64_t), &x)
|
||||
#define BOX_INT32(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int32_t), &x)
|
||||
#define BOX_INT16(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int16_t), &x)
|
||||
#define BOX_INT8(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int8_t), &x)
|
||||
#define BOX_UINT64(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint64_t), &x)
|
||||
#define BOX_UINT32(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint32_t), &x)
|
||||
#define BOX_UINT16(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint16_t), &x)
|
||||
#define BOX_UINT8(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), &x)
|
||||
#define BOX_BOOLEAN(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(bool), &x)
|
||||
#define BOX_PTR(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(IntPtr), x)
|
||||
|
||||
Variant::Type managed_to_variant_type(const ManagedType &p_type);
|
||||
|
||||
// String
|
||||
|
||||
String mono_to_utf8_string(MonoString *p_mono_string);
|
||||
String mono_to_utf16_string(MonoString *p_mono_string);
|
||||
|
||||
_FORCE_INLINE_ String mono_string_to_godot(MonoString *p_mono_string) {
|
||||
if (sizeof(CharType) == 2)
|
||||
return mono_to_utf16_string(p_mono_string);
|
||||
|
||||
return mono_to_utf8_string(p_mono_string);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ MonoString *mono_from_utf8_string(const String &p_string) {
|
||||
return mono_string_new(mono_domain_get(), p_string.utf8().get_data());
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ MonoString *mono_from_utf16_string(const String &p_string) {
|
||||
return mono_string_from_utf16((mono_unichar2 *)p_string.c_str());
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ MonoString *mono_string_from_godot(const String &p_string) {
|
||||
if (sizeof(CharType) == 2)
|
||||
return mono_from_utf16_string(p_string);
|
||||
|
||||
return mono_from_utf8_string(p_string);
|
||||
}
|
||||
|
||||
// Variant
|
||||
|
||||
MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type);
|
||||
MonoObject *variant_to_mono_object(const Variant *p_var);
|
||||
|
||||
_FORCE_INLINE_ MonoObject *variant_to_mono_object(Variant p_var) {
|
||||
return variant_to_mono_object(&p_var);
|
||||
}
|
||||
|
||||
Variant mono_object_to_variant(MonoObject *p_obj);
|
||||
Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type);
|
||||
|
||||
// Array
|
||||
|
||||
MonoArray *Array_to_mono_array(const Array &p_array);
|
||||
Array mono_array_to_Array(MonoArray *p_array);
|
||||
|
||||
// PoolIntArray
|
||||
|
||||
MonoArray *PoolIntArray_to_mono_array(const PoolIntArray &p_array);
|
||||
PoolIntArray mono_array_to_PoolIntArray(MonoArray *p_array);
|
||||
|
||||
// PoolByteArray
|
||||
|
||||
MonoArray *PoolByteArray_to_mono_array(const PoolByteArray &p_array);
|
||||
PoolByteArray mono_array_to_PoolByteArray(MonoArray *p_array);
|
||||
|
||||
// PoolRealArray
|
||||
|
||||
MonoArray *PoolRealArray_to_mono_array(const PoolRealArray &p_array);
|
||||
PoolRealArray mono_array_to_PoolRealArray(MonoArray *p_array);
|
||||
|
||||
// PoolStringArray
|
||||
|
||||
MonoArray *PoolStringArray_to_mono_array(const PoolStringArray &p_array);
|
||||
PoolStringArray mono_array_to_PoolStringArray(MonoArray *p_array);
|
||||
|
||||
// PoolColorArray
|
||||
|
||||
MonoArray *PoolColorArray_to_mono_array(const PoolColorArray &p_array);
|
||||
PoolColorArray mono_array_to_PoolColorArray(MonoArray *p_array);
|
||||
|
||||
// PoolVector2Array
|
||||
|
||||
MonoArray *PoolVector2Array_to_mono_array(const PoolVector2Array &p_array);
|
||||
PoolVector2Array mono_array_to_PoolVector2Array(MonoArray *p_array);
|
||||
|
||||
// PoolVector3Array
|
||||
|
||||
MonoArray *PoolVector3Array_to_mono_array(const PoolVector3Array &p_array);
|
||||
PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array);
|
||||
|
||||
// Dictionary
|
||||
|
||||
MonoObject *Dictionary_to_mono_object(const Dictionary &p_dict);
|
||||
Dictionary mono_object_to_Dictionary(MonoObject *p_dict);
|
||||
|
||||
#ifdef YOLO_COPY
|
||||
#define MARSHALLED_OUT(m_t, m_in, m_out) m_t *m_out = (m_t *)&m_in;
|
||||
#define MARSHALLED_IN(m_t, m_in, m_out) m_t m_out = *reinterpret_cast<m_t *>(m_in);
|
||||
#else
|
||||
|
||||
// Expects m_in to be of type float*
|
||||
|
||||
#define MARSHALLED_OUT(m_t, m_in, m_out) MARSHALLED_OUT_##m_t(m_in, m_out)
|
||||
#define MARSHALLED_IN(m_t, m_in, m_out) MARSHALLED_IN_##m_t(m_in, m_out)
|
||||
|
||||
// Vector2
|
||||
|
||||
#define MARSHALLED_OUT_Vector2(m_in, m_out) real_t m_out[2] = { m_in.x, m_in.y };
|
||||
#define MARSHALLED_IN_Vector2(m_in, m_out) Vector2 m_out(m_in[0], m_in[1]);
|
||||
|
||||
// Rect2
|
||||
|
||||
#define MARSHALLED_OUT_Rect2(m_in, m_out) real_t m_out[4] = { m_in.position.x, m_in.position.y, m_in.size.width, m_in.size.height };
|
||||
#define MARSHALLED_IN_Rect2(m_in, m_out) Rect2 m_out(m_in[0], m_in[1], m_in[2], m_in[3]);
|
||||
|
||||
// Transform2D
|
||||
|
||||
#define MARSHALLED_OUT_Transform2D(m_in, m_out) real_t m_out[6] = { m_in[0].x, m_in[0].y, m_in[1].x, m_in[1].y, m_in[2].x, m_in[2].y };
|
||||
#define MARSHALLED_IN_Transform2D(m_in, m_out) Transform2D m_out(m_in[0], m_in[1], m_in[2], m_in[3], m_in[4], m_in[5]);
|
||||
|
||||
// Vector3
|
||||
|
||||
#define MARSHALLED_OUT_Vector3(m_in, m_out) real_t m_out[3] = { m_in.x, m_in.y, m_in.z };
|
||||
#define MARSHALLED_IN_Vector3(m_in, m_out) Vector3 m_out(m_in[0], m_in[1], m_in[2]);
|
||||
|
||||
// Basis
|
||||
|
||||
#define MARSHALLED_OUT_Basis(m_in, m_out) real_t m_out[9] = { \
|
||||
m_in[0].x, m_in[0].y, m_in[0].z, \
|
||||
m_in[1].x, m_in[1].y, m_in[1].z, \
|
||||
m_in[2].x, m_in[2].y, m_in[2].z \
|
||||
};
|
||||
#define MARSHALLED_IN_Basis(m_in, m_out) Basis m_out(m_in[0], m_in[1], m_in[2], m_in[3], m_in[4], m_in[5], m_in[6], m_in[7], m_in[8]);
|
||||
|
||||
// Quat
|
||||
|
||||
#define MARSHALLED_OUT_Quat(m_in, m_out) real_t m_out[4] = { m_in.x, m_in.y, m_in.z, m_in.w };
|
||||
#define MARSHALLED_IN_Quat(m_in, m_out) Quat m_out(m_in[0], m_in[1], m_in[2], m_in[3]);
|
||||
|
||||
// Transform
|
||||
|
||||
#define MARSHALLED_OUT_Transform(m_in, m_out) real_t m_out[12] = { \
|
||||
m_in.basis[0].x, m_in.basis[0].y, m_in.basis[0].z, \
|
||||
m_in.basis[1].x, m_in.basis[1].y, m_in.basis[1].z, \
|
||||
m_in.basis[2].x, m_in.basis[2].y, m_in.basis[2].z, \
|
||||
m_in.origin.x, m_in.origin.y, m_in.origin.z \
|
||||
};
|
||||
#define MARSHALLED_IN_Transform(m_in, m_out) Transform m_out( \
|
||||
Basis(m_in[0], m_in[1], m_in[2], m_in[3], m_in[4], m_in[5], m_in[6], m_in[7], m_in[8]), \
|
||||
Vector3(m_in[9], m_in[10], m_in[11]));
|
||||
|
||||
// Rect3
|
||||
|
||||
#define MARSHALLED_OUT_Rect3(m_in, m_out) real_t m_out[6] = { m_in.position.x, m_in.position.y, m_in.position.z, m_in.size.x, m_in.size.y, m_in.size.z };
|
||||
#define MARSHALLED_IN_Rect3(m_in, m_out) Rect3 m_out(Vector3(m_in[0], m_in[1], m_in[2]), Vector3(m_in[3], m_in[4], m_in[5]));
|
||||
|
||||
// Color
|
||||
|
||||
#define MARSHALLED_OUT_Color(m_in, m_out) real_t m_out[4] = { m_in.r, m_in.g, m_in.b, m_in.a };
|
||||
#define MARSHALLED_IN_Color(m_in, m_out) Color m_out(m_in[0], m_in[1], m_in[2], m_in[3]);
|
||||
|
||||
// Plane
|
||||
|
||||
#define MARSHALLED_OUT_Plane(m_in, m_out) real_t m_out[4] = { m_in.normal.x, m_in.normal.y, m_in.normal.z, m_in.d };
|
||||
#define MARSHALLED_IN_Plane(m_in, m_out) Plane m_out(m_in[0], m_in[1], m_in[2], m_in[3]);
|
||||
|
||||
#endif
|
||||
|
||||
} // GDMonoMarshal
|
||||
|
||||
#endif // GDMONOMARSHAL_H
|
192
modules/mono/mono_gd/gd_mono_method.cpp
Normal file
192
modules/mono/mono_gd/gd_mono_method.cpp
Normal file
@ -0,0 +1,192 @@
|
||||
/*************************************************************************/
|
||||
/* gd_mono_method.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "gd_mono_method.h"
|
||||
|
||||
#include "gd_mono_class.h"
|
||||
#include "gd_mono_marshal.h"
|
||||
|
||||
void GDMonoMethod::_update_signature() {
|
||||
// Apparently MonoMethodSignature needs not to be freed.
|
||||
// mono_method_signature caches the result, we don't need to cache it ourselves.
|
||||
|
||||
MonoMethodSignature *method_sig = mono_method_signature(mono_method);
|
||||
_update_signature(method_sig);
|
||||
}
|
||||
|
||||
void GDMonoMethod::_update_signature(MonoMethodSignature *p_method_sig) {
|
||||
is_instance = mono_signature_is_instance(p_method_sig);
|
||||
params_count = mono_signature_get_param_count(p_method_sig);
|
||||
|
||||
MonoType *ret_type = mono_signature_get_return_type(p_method_sig);
|
||||
if (ret_type) {
|
||||
return_type.type_encoding = mono_type_get_type(ret_type);
|
||||
|
||||
if (return_type.type_encoding != MONO_TYPE_VOID) {
|
||||
MonoClass *ret_type_class = mono_class_from_mono_type(ret_type);
|
||||
return_type.type_class = GDMono::get_singleton()->get_class(ret_type_class);
|
||||
}
|
||||
}
|
||||
|
||||
void *iter = NULL;
|
||||
MonoType *param_raw_type;
|
||||
while ((param_raw_type = mono_signature_get_params(p_method_sig, &iter)) != NULL) {
|
||||
ManagedType param_type;
|
||||
|
||||
param_type.type_encoding = mono_type_get_type(param_raw_type);
|
||||
|
||||
if (param_type.type_encoding != MONO_TYPE_VOID) {
|
||||
MonoClass *param_type_class = mono_class_from_mono_type(param_raw_type);
|
||||
param_type.type_class = GDMono::get_singleton()->get_class(param_type_class);
|
||||
}
|
||||
|
||||
param_types.push_back(param_type);
|
||||
}
|
||||
}
|
||||
|
||||
void *GDMonoMethod::get_thunk() {
|
||||
return mono_method_get_unmanaged_thunk(mono_method);
|
||||
}
|
||||
|
||||
MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params, MonoObject **r_exc) {
|
||||
if (get_return_type().type_encoding != MONO_TYPE_VOID || get_parameters_count() > 0) {
|
||||
MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), get_parameters_count());
|
||||
|
||||
for (int i = 0; i < params_count; i++) {
|
||||
MonoObject *boxed_param = GDMonoMarshal::variant_to_mono_object(p_params[i], param_types[i]);
|
||||
mono_array_set(params, MonoObject *, i, boxed_param);
|
||||
}
|
||||
|
||||
return mono_runtime_invoke_array(mono_method, p_object, params, r_exc);
|
||||
} else {
|
||||
mono_runtime_invoke(mono_method, p_object, NULL, r_exc);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
MonoObject *GDMonoMethod::invoke(MonoObject *p_object, MonoObject **r_exc) {
|
||||
ERR_FAIL_COND_V(get_parameters_count() > 0, NULL);
|
||||
return invoke_raw(p_object, NULL, r_exc);
|
||||
}
|
||||
|
||||
MonoObject *GDMonoMethod::invoke_raw(MonoObject *p_object, void **p_params, MonoObject **r_exc) {
|
||||
return mono_runtime_invoke(mono_method, p_object, p_params, r_exc);
|
||||
}
|
||||
|
||||
bool GDMonoMethod::has_attribute(GDMonoClass *p_attr_class) {
|
||||
ERR_FAIL_NULL_V(p_attr_class, false);
|
||||
|
||||
if (!attrs_fetched)
|
||||
fetch_attributes();
|
||||
|
||||
if (!attributes)
|
||||
return false;
|
||||
|
||||
return mono_custom_attrs_has_attr(attributes, p_attr_class->get_raw());
|
||||
}
|
||||
|
||||
MonoObject *GDMonoMethod::get_attribute(GDMonoClass *p_attr_class) {
|
||||
ERR_FAIL_NULL_V(p_attr_class, NULL);
|
||||
|
||||
if (!attrs_fetched)
|
||||
fetch_attributes();
|
||||
|
||||
if (!attributes)
|
||||
return NULL;
|
||||
|
||||
return mono_custom_attrs_get_attr(attributes, p_attr_class->get_raw());
|
||||
}
|
||||
|
||||
void GDMonoMethod::fetch_attributes() {
|
||||
ERR_FAIL_COND(attributes != NULL);
|
||||
attributes = mono_custom_attrs_from_method(mono_method);
|
||||
attrs_fetched = true;
|
||||
}
|
||||
|
||||
String GDMonoMethod::get_full_name(bool p_signature) const {
|
||||
char *res = mono_method_full_name(mono_method, p_signature);
|
||||
String full_name(res);
|
||||
mono_free(res);
|
||||
return full_name;
|
||||
}
|
||||
|
||||
String GDMonoMethod::get_full_name_no_class() const {
|
||||
String res;
|
||||
|
||||
MonoMethodSignature *method_sig = mono_method_signature(mono_method);
|
||||
|
||||
char *ret_str = mono_type_full_name(mono_signature_get_return_type(method_sig));
|
||||
res += ret_str;
|
||||
mono_free(ret_str);
|
||||
|
||||
res += " ";
|
||||
res += name;
|
||||
res += "(";
|
||||
|
||||
char *sig_desc = mono_signature_get_desc(method_sig, true);
|
||||
res += sig_desc;
|
||||
mono_free(sig_desc);
|
||||
|
||||
res += ")";
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
String GDMonoMethod::get_ret_type_full_name() const {
|
||||
MonoMethodSignature *method_sig = mono_method_signature(mono_method);
|
||||
char *ret_str = mono_type_full_name(mono_signature_get_return_type(method_sig));
|
||||
String res = ret_str;
|
||||
mono_free(ret_str);
|
||||
return res;
|
||||
}
|
||||
|
||||
String GDMonoMethod::get_signature_desc(bool p_namespaces) const {
|
||||
MonoMethodSignature *method_sig = mono_method_signature(mono_method);
|
||||
char *sig_desc = mono_signature_get_desc(method_sig, p_namespaces);
|
||||
String res = sig_desc;
|
||||
mono_free(sig_desc);
|
||||
return res;
|
||||
}
|
||||
|
||||
GDMonoMethod::GDMonoMethod(StringName p_name, MonoMethod *p_method) {
|
||||
name = p_name;
|
||||
|
||||
mono_method = p_method;
|
||||
|
||||
attrs_fetched = false;
|
||||
attributes = NULL;
|
||||
|
||||
_update_signature();
|
||||
}
|
||||
|
||||
GDMonoMethod::~GDMonoMethod() {
|
||||
if (attributes) {
|
||||
mono_custom_attrs_free(attributes);
|
||||
}
|
||||
}
|
81
modules/mono/mono_gd/gd_mono_method.h
Normal file
81
modules/mono/mono_gd/gd_mono_method.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*************************************************************************/
|
||||
/* gd_mono_method.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 GD_MONO_METHOD_H
|
||||
#define GD_MONO_METHOD_H
|
||||
|
||||
#include "gd_mono.h"
|
||||
#include "gd_mono_header.h"
|
||||
|
||||
class GDMonoMethod {
|
||||
|
||||
StringName name;
|
||||
|
||||
bool is_instance;
|
||||
int params_count;
|
||||
ManagedType return_type;
|
||||
Vector<ManagedType> param_types;
|
||||
|
||||
bool attrs_fetched;
|
||||
MonoCustomAttrInfo *attributes;
|
||||
|
||||
void _update_signature();
|
||||
void _update_signature(MonoMethodSignature *p_method_sig);
|
||||
|
||||
friend class GDMonoClass;
|
||||
|
||||
MonoMethod *mono_method;
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ StringName get_name() { return name; }
|
||||
|
||||
_FORCE_INLINE_ bool is_static() { return !is_instance; }
|
||||
_FORCE_INLINE_ int get_parameters_count() { return params_count; }
|
||||
_FORCE_INLINE_ ManagedType get_return_type() { return return_type; }
|
||||
|
||||
void *get_thunk();
|
||||
|
||||
MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoObject **r_exc = NULL);
|
||||
MonoObject *invoke(MonoObject *p_object, MonoObject **r_exc = NULL);
|
||||
MonoObject *invoke_raw(MonoObject *p_object, void **p_params, MonoObject **r_exc = NULL);
|
||||
|
||||
bool has_attribute(GDMonoClass *p_attr_class);
|
||||
MonoObject *get_attribute(GDMonoClass *p_attr_class);
|
||||
void fetch_attributes();
|
||||
|
||||
String get_full_name(bool p_signature = false) const;
|
||||
String get_full_name_no_class() const;
|
||||
String get_ret_type_full_name() const;
|
||||
String get_signature_desc(bool p_namespaces = false) const;
|
||||
|
||||
GDMonoMethod(StringName p_name, MonoMethod *p_method);
|
||||
~GDMonoMethod();
|
||||
};
|
||||
|
||||
#endif // GD_MONO_METHOD_H
|
367
modules/mono/mono_gd/gd_mono_utils.cpp
Normal file
367
modules/mono/mono_gd/gd_mono_utils.cpp
Normal file
@ -0,0 +1,367 @@
|
||||
/*************************************************************************/
|
||||
/* gd_mono_utils.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "gd_mono_utils.h"
|
||||
|
||||
#include "os/dir_access.h"
|
||||
#include "project_settings.h"
|
||||
#include "reference.h"
|
||||
|
||||
#include "../csharp_script.h"
|
||||
#include "gd_mono.h"
|
||||
#include "gd_mono_class.h"
|
||||
#include "gd_mono_marshal.h"
|
||||
|
||||
namespace GDMonoUtils {
|
||||
|
||||
MonoCache mono_cache;
|
||||
|
||||
#define CACHE_AND_CHECK(m_var, m_val) \
|
||||
{ \
|
||||
m_var = m_val; \
|
||||
if (!m_var) ERR_PRINT("Mono Cache: Member " #m_var " is null. This is really bad!"); \
|
||||
}
|
||||
|
||||
#define CACHE_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.class_##m_class, m_val)
|
||||
#define CACHE_NS_CLASS_AND_CHECK(m_ns, m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.class_##m_ns##_##m_class, m_val)
|
||||
#define CACHE_RAW_MONO_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.rawclass_##m_class, m_val)
|
||||
#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_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method, m_val)
|
||||
|
||||
void MonoCache::clear_members() {
|
||||
|
||||
class_MonoObject = NULL;
|
||||
class_bool = NULL;
|
||||
class_int8_t = NULL;
|
||||
class_int16_t = NULL;
|
||||
class_int32_t = NULL;
|
||||
class_int64_t = NULL;
|
||||
class_uint8_t = NULL;
|
||||
class_uint16_t = NULL;
|
||||
class_uint32_t = NULL;
|
||||
class_uint64_t = NULL;
|
||||
class_float = NULL;
|
||||
class_double = NULL;
|
||||
class_String = NULL;
|
||||
class_IntPtr = NULL;
|
||||
|
||||
rawclass_Dictionary = NULL;
|
||||
|
||||
class_Vector2 = NULL;
|
||||
class_Rect2 = NULL;
|
||||
class_Transform2D = NULL;
|
||||
class_Vector3 = NULL;
|
||||
class_Basis = NULL;
|
||||
class_Quat = NULL;
|
||||
class_Transform = NULL;
|
||||
class_Rect3 = NULL;
|
||||
class_Color = NULL;
|
||||
class_Plane = NULL;
|
||||
class_NodePath = NULL;
|
||||
class_RID = NULL;
|
||||
class_GodotObject = NULL;
|
||||
class_Node = NULL;
|
||||
class_Control = NULL;
|
||||
class_Spatial = NULL;
|
||||
class_WeakRef = NULL;
|
||||
class_MarshalUtils = NULL;
|
||||
|
||||
class_ExportAttribute = NULL;
|
||||
field_ExportAttribute_hint = NULL;
|
||||
field_ExportAttribute_hint_string = NULL;
|
||||
field_ExportAttribute_usage = NULL;
|
||||
class_ToolAttribute = NULL;
|
||||
class_RemoteAttribute = NULL;
|
||||
class_SyncAttribute = NULL;
|
||||
class_MasterAttribute = NULL;
|
||||
class_SlaveAttribute = NULL;
|
||||
class_GodotMethodAttribute = NULL;
|
||||
field_GodotMethodAttribute_methodName = NULL;
|
||||
|
||||
field_GodotObject_ptr = NULL;
|
||||
field_NodePath_ptr = NULL;
|
||||
field_Image_ptr = NULL;
|
||||
field_RID_ptr = NULL;
|
||||
|
||||
methodthunk_MarshalUtils_DictionaryToArrays = NULL;
|
||||
methodthunk_MarshalUtils_ArraysToDictionary = NULL;
|
||||
methodthunk_GodotObject__AwaitedSignalCallback = NULL;
|
||||
methodthunk_SignalAwaiter_FailureCallback = NULL;
|
||||
methodthunk_GodotTaskScheduler_Activate = NULL;
|
||||
|
||||
task_scheduler_handle = Ref<MonoGCHandle>();
|
||||
}
|
||||
|
||||
#define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class))
|
||||
|
||||
void update_corlib_cache() {
|
||||
|
||||
CACHE_CLASS_AND_CHECK(MonoObject, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_object_class()));
|
||||
CACHE_CLASS_AND_CHECK(bool, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_boolean_class()));
|
||||
CACHE_CLASS_AND_CHECK(int8_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_sbyte_class()));
|
||||
CACHE_CLASS_AND_CHECK(int16_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int16_class()));
|
||||
CACHE_CLASS_AND_CHECK(int32_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int32_class()));
|
||||
CACHE_CLASS_AND_CHECK(int64_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int64_class()));
|
||||
CACHE_CLASS_AND_CHECK(uint8_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_byte_class()));
|
||||
CACHE_CLASS_AND_CHECK(uint16_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint16_class()));
|
||||
CACHE_CLASS_AND_CHECK(uint32_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint32_class()));
|
||||
CACHE_CLASS_AND_CHECK(uint64_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint64_class()));
|
||||
CACHE_CLASS_AND_CHECK(float, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_single_class()));
|
||||
CACHE_CLASS_AND_CHECK(double, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_double_class()));
|
||||
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()));
|
||||
}
|
||||
|
||||
void update_godot_api_cache() {
|
||||
|
||||
CACHE_CLASS_AND_CHECK(Vector2, GODOT_API_CLASS(Vector2));
|
||||
CACHE_CLASS_AND_CHECK(Rect2, GODOT_API_CLASS(Rect2));
|
||||
CACHE_CLASS_AND_CHECK(Transform2D, GODOT_API_CLASS(Transform2D));
|
||||
CACHE_CLASS_AND_CHECK(Vector3, GODOT_API_CLASS(Vector3));
|
||||
CACHE_CLASS_AND_CHECK(Basis, GODOT_API_CLASS(Basis));
|
||||
CACHE_CLASS_AND_CHECK(Quat, GODOT_API_CLASS(Quat));
|
||||
CACHE_CLASS_AND_CHECK(Transform, GODOT_API_CLASS(Transform));
|
||||
CACHE_CLASS_AND_CHECK(Rect3, GODOT_API_CLASS(Rect3));
|
||||
CACHE_CLASS_AND_CHECK(Color, GODOT_API_CLASS(Color));
|
||||
CACHE_CLASS_AND_CHECK(Plane, GODOT_API_CLASS(Plane));
|
||||
CACHE_CLASS_AND_CHECK(NodePath, GODOT_API_CLASS(NodePath));
|
||||
CACHE_CLASS_AND_CHECK(RID, GODOT_API_CLASS(NodePath));
|
||||
CACHE_CLASS_AND_CHECK(GodotObject, GODOT_API_CLASS(Object));
|
||||
CACHE_CLASS_AND_CHECK(Node, GODOT_API_CLASS(Node));
|
||||
CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control));
|
||||
CACHE_CLASS_AND_CHECK(Spatial, GODOT_API_CLASS(Spatial));
|
||||
CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef));
|
||||
CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils));
|
||||
|
||||
// Attributes
|
||||
CACHE_CLASS_AND_CHECK(ExportAttribute, GODOT_API_CLASS(ExportAttribute));
|
||||
CACHE_FIELD_AND_CHECK(ExportAttribute, hint, CACHED_CLASS(ExportAttribute)->get_field("hint"));
|
||||
CACHE_FIELD_AND_CHECK(ExportAttribute, hint_string, CACHED_CLASS(ExportAttribute)->get_field("hint_string"));
|
||||
CACHE_FIELD_AND_CHECK(ExportAttribute, usage, CACHED_CLASS(ExportAttribute)->get_field("usage"));
|
||||
CACHE_CLASS_AND_CHECK(ToolAttribute, GODOT_API_CLASS(ToolAttribute));
|
||||
CACHE_CLASS_AND_CHECK(RemoteAttribute, GODOT_API_CLASS(RemoteAttribute));
|
||||
CACHE_CLASS_AND_CHECK(SyncAttribute, GODOT_API_CLASS(SyncAttribute));
|
||||
CACHE_CLASS_AND_CHECK(MasterAttribute, GODOT_API_CLASS(MasterAttribute));
|
||||
CACHE_CLASS_AND_CHECK(SlaveAttribute, GODOT_API_CLASS(SlaveAttribute));
|
||||
CACHE_CLASS_AND_CHECK(GodotMethodAttribute, GODOT_API_CLASS(GodotMethodAttribute));
|
||||
CACHE_FIELD_AND_CHECK(GodotMethodAttribute, methodName, CACHED_CLASS(GodotMethodAttribute)->get_field("methodName"));
|
||||
|
||||
CACHE_FIELD_AND_CHECK(GodotObject, ptr, CACHED_CLASS(GodotObject)->get_field(BINDINGS_PTR_FIELD));
|
||||
CACHE_FIELD_AND_CHECK(NodePath, ptr, CACHED_CLASS(NodePath)->get_field(BINDINGS_PTR_FIELD));
|
||||
CACHE_FIELD_AND_CHECK(RID, ptr, CACHED_CLASS(RID)->get_field(BINDINGS_PTR_FIELD));
|
||||
|
||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryToArrays, (MarshalUtils_DictToArrays)CACHED_CLASS(MarshalUtils)->get_method("DictionaryToArrays", 3)->get_thunk());
|
||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArraysToDictionary, (MarshalUtils_ArraysToDict)CACHED_CLASS(MarshalUtils)->get_method("ArraysToDictionary", 2)->get_thunk());
|
||||
CACHE_METHOD_THUNK_AND_CHECK(GodotObject, _AwaitedSignalCallback, (GodotObject__AwaitedSignalCallback)CACHED_CLASS(GodotObject)->get_method("_AwaitedSignalCallback", 2)->get_thunk());
|
||||
CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, (SignalAwaiter_FailureCallback)GODOT_API_CLASS(SignalAwaiter)->get_method("FailureCallback", 0)->get_thunk());
|
||||
CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method("Activate", 0)->get_thunk());
|
||||
|
||||
{
|
||||
/*
|
||||
* TODO Right now we only support Dictionary<object, object>.
|
||||
* It would be great if we could support other key/value types
|
||||
* without forcing the user to copy the entries.
|
||||
*/
|
||||
GDMonoMethod *method_get_dict_type = CACHED_CLASS(MarshalUtils)->get_method("GetDictionaryType", 0);
|
||||
ERR_FAIL_NULL(method_get_dict_type);
|
||||
MonoReflectionType *dict_refl_type = (MonoReflectionType *)method_get_dict_type->invoke(NULL);
|
||||
ERR_FAIL_NULL(dict_refl_type);
|
||||
MonoType *dict_type = mono_reflection_type_get_type(dict_refl_type);
|
||||
ERR_FAIL_NULL(dict_type);
|
||||
|
||||
CACHE_RAW_MONO_CLASS_AND_CHECK(Dictionary, mono_class_from_mono_type(dict_type));
|
||||
}
|
||||
|
||||
MonoObject *task_scheduler = mono_object_new(SCRIPTS_DOMAIN, GODOT_API_CLASS(GodotTaskScheduler)->get_raw());
|
||||
mono_runtime_object_init(task_scheduler);
|
||||
mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler);
|
||||
}
|
||||
|
||||
void clear_cache() {
|
||||
mono_cache.cleanup();
|
||||
mono_cache.clear_members();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
// Only called if the owner does not have a CSharpInstance
|
||||
void *data = unmanaged->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
|
||||
|
||||
if (data) {
|
||||
return ((Map<Object *, Ref<MonoGCHandle> >::Element *)data)->value()->get_target();
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void set_main_thread(MonoThread *p_thread) {
|
||||
mono_thread_set_main(p_thread);
|
||||
}
|
||||
|
||||
void attach_current_thread() {
|
||||
ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized());
|
||||
MonoThread *mono_thread = mono_thread_attach(SCRIPTS_DOMAIN);
|
||||
ERR_FAIL_NULL(mono_thread);
|
||||
}
|
||||
|
||||
void detach_current_thread() {
|
||||
ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized());
|
||||
MonoThread *mono_thread = mono_thread_current();
|
||||
ERR_FAIL_NULL(mono_thread);
|
||||
mono_thread_detach(mono_thread);
|
||||
}
|
||||
|
||||
MonoThread *get_current_thread() {
|
||||
return mono_thread_current();
|
||||
}
|
||||
|
||||
GDMonoClass *get_object_class(MonoObject *p_object) {
|
||||
return GDMono::get_singleton()->get_class(mono_object_get_class(p_object));
|
||||
}
|
||||
|
||||
GDMonoClass *type_get_proxy_class(const StringName &p_type) {
|
||||
String class_name = p_type;
|
||||
|
||||
if (class_name[0] == '_')
|
||||
class_name = class_name.substr(1, class_name.length());
|
||||
|
||||
GDMonoClass *klass = GDMono::get_singleton()->get_api_assembly()->get_class(BINDINGS_NAMESPACE, class_name);
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (!klass) {
|
||||
return GDMono::get_singleton()->get_editor_api_assembly()->get_class(BINDINGS_NAMESPACE, class_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
return klass;
|
||||
}
|
||||
|
||||
GDMonoClass *get_class_native_base(GDMonoClass *p_class) {
|
||||
GDMonoClass *klass = p_class;
|
||||
|
||||
do {
|
||||
const GDMonoAssembly *assembly = klass->get_assembly();
|
||||
if (assembly == GDMono::get_singleton()->get_api_assembly())
|
||||
return klass;
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (assembly == GDMono::get_singleton()->get_editor_api_assembly())
|
||||
return klass;
|
||||
#endif
|
||||
} while ((klass = klass->get_parent_class()) != NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringName &p_native, Object *p_object) {
|
||||
String object_type = p_object->get_class_name();
|
||||
|
||||
if (object_type[0] == '_')
|
||||
object_type = object_type.substr(1, object_type.length());
|
||||
|
||||
if (!ClassDB::is_parent_class(object_type, p_native)) {
|
||||
ERR_EXPLAIN("Type inherits from native type '" + p_native + "', so it can't be instanced in object of type: '" + p_object->get_class() + "'");
|
||||
ERR_FAIL_V(NULL);
|
||||
}
|
||||
|
||||
MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, p_class->get_raw());
|
||||
ERR_FAIL_NULL_V(mono_object, NULL);
|
||||
|
||||
CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, p_object);
|
||||
|
||||
// Construct
|
||||
mono_runtime_object_init(mono_object);
|
||||
|
||||
return mono_object;
|
||||
}
|
||||
|
||||
MonoObject *create_managed_from(const NodePath &p_from) {
|
||||
MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, CACHED_CLASS_RAW(NodePath));
|
||||
ERR_FAIL_NULL_V(mono_object, NULL);
|
||||
|
||||
// Construct
|
||||
mono_runtime_object_init(mono_object);
|
||||
|
||||
CACHED_FIELD(NodePath, ptr)->set_value_raw(mono_object, memnew(NodePath(p_from)));
|
||||
|
||||
return mono_object;
|
||||
}
|
||||
|
||||
MonoObject *create_managed_from(const RID &p_from) {
|
||||
MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, CACHED_CLASS_RAW(RID));
|
||||
ERR_FAIL_NULL_V(mono_object, NULL);
|
||||
|
||||
// Construct
|
||||
mono_runtime_object_init(mono_object);
|
||||
|
||||
CACHED_FIELD(RID, ptr)->set_value_raw(mono_object, memnew(RID(p_from)));
|
||||
|
||||
return mono_object;
|
||||
}
|
||||
|
||||
MonoDomain *create_domain(const String &p_friendly_name) {
|
||||
MonoDomain *domain = mono_domain_create_appdomain((char *)p_friendly_name.utf8().get_data(), NULL);
|
||||
|
||||
if (domain) {
|
||||
// Workaround to avoid this exception:
|
||||
// System.Configuration.ConfigurationErrorsException: Error Initializing the configuration system.
|
||||
// ---> System.ArgumentException: The 'ExeConfigFilename' argument cannot be null.
|
||||
mono_domain_set_config(domain, ".", "");
|
||||
}
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
String get_exception_name_and_message(MonoObject *p_ex) {
|
||||
String res;
|
||||
|
||||
MonoClass *klass = mono_object_get_class(p_ex);
|
||||
MonoType *type = mono_class_get_type(klass);
|
||||
|
||||
char *full_name = mono_type_full_name(type);
|
||||
res += full_name;
|
||||
mono_free(full_name);
|
||||
|
||||
res += ": ";
|
||||
|
||||
MonoProperty *prop = mono_class_get_property_from_name(klass, "Message");
|
||||
MonoString *msg = (MonoString *)mono_property_get_value(prop, p_ex, NULL, NULL);
|
||||
res += GDMonoMarshal::mono_string_to_godot(msg);
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
182
modules/mono/mono_gd/gd_mono_utils.h
Normal file
182
modules/mono/mono_gd/gd_mono_utils.h
Normal file
@ -0,0 +1,182 @@
|
||||
/*************************************************************************/
|
||||
/* gd_mono_utils.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 GD_MONOUTILS_H
|
||||
#define GD_MONOUTILS_H
|
||||
|
||||
#include <mono/metadata/threads.h>
|
||||
|
||||
#include "../mono_gc_handle.h"
|
||||
#include "gd_mono_header.h"
|
||||
|
||||
#include "object.h"
|
||||
#include "reference.h"
|
||||
|
||||
namespace GDMonoUtils {
|
||||
|
||||
typedef MonoObject *(*MarshalUtils_DictToArrays)(MonoObject *, MonoArray **, MonoArray **, MonoObject **);
|
||||
typedef MonoObject *(*MarshalUtils_ArraysToDict)(MonoArray *, MonoArray *, MonoObject **);
|
||||
typedef MonoObject *(*GodotObject__AwaitedSignalCallback)(MonoObject *, MonoArray **, MonoObject *, MonoObject **);
|
||||
typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoObject **);
|
||||
typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoObject **);
|
||||
|
||||
struct MonoCache {
|
||||
// Format for cached classes in the Godot namespace: class_<Class>
|
||||
// Macro: CACHED_CLASS(<Class>)
|
||||
|
||||
// Format for cached classes in a different namespace: class_<Namespace>_<Class>
|
||||
// Macro: CACHED_NS_CLASS(<Namespace>, <Class>)
|
||||
|
||||
// -----------------------------------------------
|
||||
// corlib classes
|
||||
|
||||
// Let's use the no-namespace format for these too
|
||||
GDMonoClass *class_MonoObject;
|
||||
GDMonoClass *class_bool;
|
||||
GDMonoClass *class_int8_t;
|
||||
GDMonoClass *class_int16_t;
|
||||
GDMonoClass *class_int32_t;
|
||||
GDMonoClass *class_int64_t;
|
||||
GDMonoClass *class_uint8_t;
|
||||
GDMonoClass *class_uint16_t;
|
||||
GDMonoClass *class_uint32_t;
|
||||
GDMonoClass *class_uint64_t;
|
||||
GDMonoClass *class_float;
|
||||
GDMonoClass *class_double;
|
||||
GDMonoClass *class_String;
|
||||
GDMonoClass *class_IntPtr;
|
||||
|
||||
MonoClass *rawclass_Dictionary;
|
||||
// -----------------------------------------------
|
||||
|
||||
GDMonoClass *class_Vector2;
|
||||
GDMonoClass *class_Rect2;
|
||||
GDMonoClass *class_Transform2D;
|
||||
GDMonoClass *class_Vector3;
|
||||
GDMonoClass *class_Basis;
|
||||
GDMonoClass *class_Quat;
|
||||
GDMonoClass *class_Transform;
|
||||
GDMonoClass *class_Rect3;
|
||||
GDMonoClass *class_Color;
|
||||
GDMonoClass *class_Plane;
|
||||
GDMonoClass *class_NodePath;
|
||||
GDMonoClass *class_RID;
|
||||
GDMonoClass *class_GodotObject;
|
||||
GDMonoClass *class_Node;
|
||||
GDMonoClass *class_Control;
|
||||
GDMonoClass *class_Spatial;
|
||||
GDMonoClass *class_WeakRef;
|
||||
GDMonoClass *class_MarshalUtils;
|
||||
|
||||
GDMonoClass *class_ExportAttribute;
|
||||
GDMonoField *field_ExportAttribute_hint;
|
||||
GDMonoField *field_ExportAttribute_hint_string;
|
||||
GDMonoField *field_ExportAttribute_usage;
|
||||
GDMonoClass *class_ToolAttribute;
|
||||
GDMonoClass *class_RemoteAttribute;
|
||||
GDMonoClass *class_SyncAttribute;
|
||||
GDMonoClass *class_MasterAttribute;
|
||||
GDMonoClass *class_SlaveAttribute;
|
||||
GDMonoClass *class_GodotMethodAttribute;
|
||||
GDMonoField *field_GodotMethodAttribute_methodName;
|
||||
|
||||
GDMonoField *field_GodotObject_ptr;
|
||||
GDMonoField *field_NodePath_ptr;
|
||||
GDMonoField *field_Image_ptr;
|
||||
GDMonoField *field_RID_ptr;
|
||||
|
||||
MarshalUtils_DictToArrays methodthunk_MarshalUtils_DictionaryToArrays;
|
||||
MarshalUtils_ArraysToDict methodthunk_MarshalUtils_ArraysToDictionary;
|
||||
GodotObject__AwaitedSignalCallback methodthunk_GodotObject__AwaitedSignalCallback;
|
||||
SignalAwaiter_FailureCallback methodthunk_SignalAwaiter_FailureCallback;
|
||||
GodotTaskScheduler_Activate methodthunk_GodotTaskScheduler_Activate;
|
||||
|
||||
Ref<MonoGCHandle> task_scheduler_handle;
|
||||
|
||||
void clear_members();
|
||||
void cleanup() {}
|
||||
|
||||
MonoCache() {
|
||||
clear_members();
|
||||
}
|
||||
};
|
||||
|
||||
extern MonoCache mono_cache;
|
||||
|
||||
void update_corlib_cache();
|
||||
void update_godot_api_cache();
|
||||
void clear_cache();
|
||||
|
||||
_FORCE_INLINE_ void hash_combine(uint32_t &p_hash, const uint32_t &p_with_hash) {
|
||||
p_hash ^= p_with_hash + 0x9e3779b9 + (p_hash << 6) + (p_hash >> 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the object has a csharp script, returns the target of the gchandle stored in the script instance
|
||||
* Otherwise returns a newly constructed MonoObject* which is attached to the object
|
||||
* Returns NULL on error
|
||||
*/
|
||||
MonoObject *unmanaged_get_managed(Object *unmanaged);
|
||||
|
||||
void set_main_thread(MonoThread *p_thread);
|
||||
void attach_current_thread();
|
||||
void detach_current_thread();
|
||||
MonoThread *get_current_thread();
|
||||
|
||||
GDMonoClass *get_object_class(MonoObject *p_object);
|
||||
GDMonoClass *type_get_proxy_class(const StringName &p_type);
|
||||
GDMonoClass *get_class_native_base(GDMonoClass *p_class);
|
||||
|
||||
MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringName &p_native, Object *p_object);
|
||||
|
||||
MonoObject *create_managed_from(const NodePath &p_from);
|
||||
MonoObject *create_managed_from(const RID &p_from);
|
||||
|
||||
MonoDomain *create_domain(const String &p_friendly_name);
|
||||
|
||||
String get_exception_name_and_message(MonoObject *p_ex);
|
||||
|
||||
} // GDMonoUtils
|
||||
|
||||
#define NATIVE_GDMONOCLASS_NAME(m_class) (GDMonoMarshal::mono_string_to_godot((MonoString *)m_class->get_field("nativeName")->get_value(NULL)))
|
||||
|
||||
#define CACHED_CLASS(m_class) (GDMonoUtils::mono_cache.class_##m_class)
|
||||
#define CACHED_CLASS_RAW(m_class) (GDMonoUtils::mono_cache.class_##m_class->get_raw())
|
||||
#define CACHED_NS_CLASS(m_ns, m_class) (GDMonoUtils::mono_cache.class_##m_ns##_##m_class)
|
||||
#define CACHED_RAW_MONO_CLASS(m_class) (GDMonoUtils::mono_cache.rawclass_##m_class)
|
||||
#define CACHED_FIELD(m_class, m_field) (GDMonoUtils::mono_cache.field_##m_class##_##m_field)
|
||||
#define CACHED_METHOD_THUNK(m_class, m_method) (GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method)
|
||||
|
||||
#ifdef REAL_T_IS_DOUBLE
|
||||
#define REAL_T_MONOCLASS CACHED_CLASS_RAW(double)
|
||||
#else
|
||||
#define REAL_T_MONOCLASS CACHED_CLASS_RAW(float)
|
||||
#endif
|
||||
|
||||
#endif // GD_MONOUTILS_H
|
54
modules/mono/mono_reg_utils.py
Normal file
54
modules/mono/mono_reg_utils.py
Normal file
@ -0,0 +1,54 @@
|
||||
import os
|
||||
|
||||
if os.name == 'nt':
|
||||
import _winreg as winreg
|
||||
|
||||
|
||||
def _reg_open_key(key, subkey):
|
||||
try:
|
||||
return winreg.OpenKey(key, subkey)
|
||||
except (WindowsError, EnvironmentError) as e:
|
||||
import platform
|
||||
if platform.architecture()[0] == '32bit':
|
||||
bitness_sam = winreg.KEY_WOW64_64KEY
|
||||
else:
|
||||
bitness_sam = winreg.KEY_WOW64_32KEY
|
||||
return winreg.OpenKey(key, subkey, 0, winreg.KEY_READ | bitness_sam)
|
||||
|
||||
|
||||
def _find_mono_in_reg(subkey):
|
||||
try:
|
||||
with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, subkey) as hKey:
|
||||
value, regtype = winreg.QueryValueEx(hKey, 'SdkInstallRoot')
|
||||
return value
|
||||
except (WindowsError, EnvironmentError) as e:
|
||||
return None
|
||||
|
||||
def _find_mono_in_reg_old(subkey):
|
||||
try:
|
||||
with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, subkey) as hKey:
|
||||
default_clr, regtype = winreg.QueryValueEx(hKey, 'DefaultCLR')
|
||||
if default_clr:
|
||||
return _find_mono_in_reg(subkey + '\\' + default_clr)
|
||||
return None
|
||||
except (WindowsError, EnvironmentError):
|
||||
return None
|
||||
|
||||
|
||||
def find_mono_root_dir():
|
||||
dir = _find_mono_in_reg(r'SOFTWARE\Mono')
|
||||
if dir:
|
||||
return dir
|
||||
dir = _find_mono_in_reg_old(r'SOFTWARE\Novell\Mono')
|
||||
if dir:
|
||||
return dir
|
||||
return None
|
||||
|
||||
|
||||
def find_msbuild_tools_path_reg():
|
||||
try:
|
||||
with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0') as hKey:
|
||||
value, regtype = winreg.QueryValueEx(hKey, 'MSBuildToolsPath')
|
||||
return value
|
||||
except (WindowsError, EnvironmentError) as e:
|
||||
return None
|
71
modules/mono/register_types.cpp
Normal file
71
modules/mono/register_types.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
/*************************************************************************/
|
||||
/* register_types.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "register_types.h"
|
||||
|
||||
#include "project_settings.h"
|
||||
|
||||
#include "csharp_script.h"
|
||||
|
||||
CSharpLanguage *script_language_cs = NULL;
|
||||
ResourceFormatLoaderCSharpScript *resource_loader_cs = NULL;
|
||||
ResourceFormatSaverCSharpScript *resource_saver_cs = NULL;
|
||||
|
||||
_GodotSharp *_godotsharp = NULL;
|
||||
|
||||
void register_mono_types() {
|
||||
ClassDB::register_class<CSharpScript>();
|
||||
|
||||
_godotsharp = memnew(_GodotSharp);
|
||||
|
||||
ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("GodotSharp", _GodotSharp::get_singleton()));
|
||||
|
||||
script_language_cs = memnew(CSharpLanguage);
|
||||
script_language_cs->set_language_index(ScriptServer::get_language_count());
|
||||
ScriptServer::register_language(script_language_cs);
|
||||
|
||||
resource_loader_cs = memnew(ResourceFormatLoaderCSharpScript);
|
||||
ResourceLoader::add_resource_format_loader(resource_loader_cs);
|
||||
resource_saver_cs = memnew(ResourceFormatSaverCSharpScript);
|
||||
ResourceSaver::add_resource_format_saver(resource_saver_cs);
|
||||
}
|
||||
|
||||
void unregister_mono_types() {
|
||||
ScriptServer::unregister_language(script_language_cs);
|
||||
|
||||
if (script_language_cs)
|
||||
memdelete(script_language_cs);
|
||||
if (resource_loader_cs)
|
||||
memdelete(resource_loader_cs);
|
||||
if (resource_saver_cs)
|
||||
memdelete(resource_saver_cs);
|
||||
|
||||
if (_godotsharp)
|
||||
memdelete(_godotsharp);
|
||||
}
|
31
modules/mono/register_types.h
Normal file
31
modules/mono/register_types.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*************************************************************************/
|
||||
/* register_types.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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. */
|
||||
/*************************************************************************/
|
||||
void register_mono_types();
|
||||
void unregister_mono_types();
|
77
modules/mono/signal_awaiter_utils.cpp
Normal file
77
modules/mono/signal_awaiter_utils.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
/*************************************************************************/
|
||||
/* signal_awaiter_utils.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "signal_awaiter_utils.h"
|
||||
|
||||
#include "mono_gd/gd_mono_utils.h"
|
||||
|
||||
namespace SignalAwaiterUtils {
|
||||
|
||||
Error connect_signal_awaiter(Object *p_source, const String &p_signal, Object *p_target, MonoObject *p_awaiter) {
|
||||
|
||||
ERR_FAIL_NULL_V(p_source, ERR_INVALID_DATA);
|
||||
ERR_FAIL_NULL_V(p_target, ERR_INVALID_DATA);
|
||||
|
||||
uint32_t awaiter_handle = MonoGCHandle::make_strong_handle(p_awaiter);
|
||||
Ref<SignalAwaiterHandle> sa_con = memnew(SignalAwaiterHandle(awaiter_handle));
|
||||
Vector<Variant> binds;
|
||||
binds.push_back(sa_con);
|
||||
Error err = p_source->connect(p_signal, p_target, "_AwaitedSignalCallback", binds, Object::CONNECT_ONESHOT);
|
||||
|
||||
if (err != OK) {
|
||||
// set it as completed to prevent it from calling the failure callback when deleted
|
||||
// the awaiter will be aware of the failure by checking the returned error
|
||||
sa_con->set_completed(true);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
SignalAwaiterHandle::SignalAwaiterHandle(uint32_t p_handle)
|
||||
: MonoGCHandle(p_handle) {
|
||||
}
|
||||
|
||||
SignalAwaiterHandle::~SignalAwaiterHandle() {
|
||||
if (!completed) {
|
||||
GDMonoUtils::SignalAwaiter_FailureCallback thunk = CACHED_METHOD_THUNK(SignalAwaiter, FailureCallback);
|
||||
|
||||
MonoObject *awaiter = get_target();
|
||||
|
||||
if (awaiter) {
|
||||
MonoObject *ex = NULL;
|
||||
thunk(awaiter, &ex);
|
||||
|
||||
if (ex) {
|
||||
mono_print_unhandled_exception(ex);
|
||||
ERR_FAIL_V();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
53
modules/mono/signal_awaiter_utils.h
Normal file
53
modules/mono/signal_awaiter_utils.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*************************************************************************/
|
||||
/* signal_awaiter_utils.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 SIGNAL_AWAITER_UTILS_H
|
||||
#define SIGNAL_AWAITER_UTILS_H
|
||||
|
||||
#include "mono_gc_handle.h"
|
||||
#include "reference.h"
|
||||
|
||||
namespace SignalAwaiterUtils {
|
||||
|
||||
Error connect_signal_awaiter(Object *p_source, const String &p_signal, Object *p_target, MonoObject *p_awaiter);
|
||||
}
|
||||
|
||||
class SignalAwaiterHandle : public MonoGCHandle {
|
||||
|
||||
bool completed;
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ bool is_completed() { return completed; }
|
||||
_FORCE_INLINE_ void set_completed(bool p_completed) { completed = p_completed; }
|
||||
|
||||
SignalAwaiterHandle(uint32_t p_handle);
|
||||
~SignalAwaiterHandle();
|
||||
};
|
||||
|
||||
#endif // SIGNAL_AWAITER_UTILS_H
|
228
modules/mono/utils/mono_reg_utils.cpp
Normal file
228
modules/mono/utils/mono_reg_utils.cpp
Normal file
@ -0,0 +1,228 @@
|
||||
/*************************************************************************/
|
||||
/* mono_reg_utils.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "mono_reg_utils.h"
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
|
||||
#include "os/os.h"
|
||||
|
||||
// Here, after os/os.h
|
||||
#include <windows.h>
|
||||
|
||||
namespace MonoRegUtils {
|
||||
|
||||
template <int>
|
||||
REGSAM bitness_sam_impl();
|
||||
|
||||
template <>
|
||||
REGSAM bitness_sam_impl<4>() {
|
||||
return KEY_WOW64_64KEY;
|
||||
}
|
||||
|
||||
template <>
|
||||
REGSAM bitness_sam_impl<8>() {
|
||||
return KEY_WOW64_32KEY;
|
||||
}
|
||||
|
||||
REGSAM _get_bitness_sam() {
|
||||
return bitness_sam_impl<sizeof(size_t)>();
|
||||
}
|
||||
|
||||
LONG _RegOpenKey(HKEY hKey, LPCWSTR lpSubKey, PHKEY phkResult) {
|
||||
|
||||
LONG res = RegOpenKeyExW(hKey, lpSubKey, 0, KEY_READ, phkResult);
|
||||
|
||||
if (res != ERROR_SUCCESS)
|
||||
res = RegOpenKeyExW(hKey, lpSubKey, 0, KEY_READ | _get_bitness_sam(), phkResult);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
LONG _RegKeyQueryString(HKEY hKey, const String &p_value_name, String &r_value) {
|
||||
|
||||
Vector<WCHAR> buffer;
|
||||
buffer.resize(512);
|
||||
DWORD dwBufferSize = buffer.size();
|
||||
|
||||
LONG res = RegQueryValueExW(hKey, p_value_name.c_str(), 0, NULL, (LPBYTE)buffer.ptr(), &dwBufferSize);
|
||||
|
||||
if (res == ERROR_MORE_DATA) {
|
||||
// dwBufferSize now contains the actual size
|
||||
Vector<WCHAR> buffer;
|
||||
buffer.resize(dwBufferSize);
|
||||
res = RegQueryValueExW(hKey, p_value_name.c_str(), 0, NULL, (LPBYTE)buffer.ptr(), &dwBufferSize);
|
||||
}
|
||||
|
||||
if (res == ERROR_SUCCESS) {
|
||||
r_value = String(buffer.ptr(), buffer.size());
|
||||
} else {
|
||||
r_value = String();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
LONG _find_mono_in_reg(const String &p_subkey, MonoRegInfo &r_info, bool p_old_reg = false) {
|
||||
|
||||
HKEY hKey;
|
||||
LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, p_subkey.c_str(), &hKey);
|
||||
|
||||
if (res != ERROR_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
if (!p_old_reg) {
|
||||
res = _RegKeyQueryString(hKey, "Version", r_info.version);
|
||||
if (res != ERROR_SUCCESS)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
res = _RegKeyQueryString(hKey, "SdkInstallRoot", r_info.install_root_dir);
|
||||
if (res != ERROR_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
res = _RegKeyQueryString(hKey, "FrameworkAssemblyDirectory", r_info.assembly_dir);
|
||||
if (res != ERROR_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
res = _RegKeyQueryString(hKey, "MonoConfigDir", r_info.config_dir);
|
||||
if (res != ERROR_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
if (r_info.install_root_dir.ends_with("\\"))
|
||||
r_info.bin_dir = r_info.install_root_dir + "bin";
|
||||
else
|
||||
r_info.bin_dir = r_info.install_root_dir + "\\bin";
|
||||
|
||||
cleanup:
|
||||
RegCloseKey(hKey);
|
||||
return res;
|
||||
}
|
||||
|
||||
LONG _find_mono_in_reg_old(const String &p_subkey, MonoRegInfo &r_info) {
|
||||
|
||||
String default_clr;
|
||||
|
||||
HKEY hKey;
|
||||
LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, p_subkey.c_str(), &hKey);
|
||||
|
||||
if (res != ERROR_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
res = _RegKeyQueryString(hKey, "DefaultCLR", default_clr);
|
||||
|
||||
if (res == ERROR_SUCCESS && default_clr.length()) {
|
||||
r_info.version = default_clr;
|
||||
res = _find_mono_in_reg(p_subkey + "\\" + default_clr, r_info, true);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
RegCloseKey(hKey);
|
||||
return res;
|
||||
}
|
||||
|
||||
MonoRegInfo find_mono() {
|
||||
|
||||
MonoRegInfo info;
|
||||
|
||||
if (_find_mono_in_reg("Software\\Mono", info) == ERROR_SUCCESS)
|
||||
return info;
|
||||
|
||||
if (_find_mono_in_reg_old("Software\\Novell\\Mono", info) == ERROR_SUCCESS)
|
||||
return info;
|
||||
|
||||
ERR_PRINT("Cannot find mono in the registry");
|
||||
|
||||
return MonoRegInfo();
|
||||
}
|
||||
|
||||
String find_msbuild_tools_path() {
|
||||
|
||||
String msbuild_tools_path;
|
||||
|
||||
// Try to find 15.0 with vswhere
|
||||
|
||||
String vswhere_path = OS::get_singleton()->get_environment(sizeof(size_t) == 8 ? "ProgramFiles(x86)" : "ProgramFiles");
|
||||
vswhere_path += "\\Microsoft Visual Studio\\Installer\\vswhere.exe";
|
||||
|
||||
List<String> vswhere_args;
|
||||
vswhere_args.push_back("-latest");
|
||||
vswhere_args.push_back("-requires");
|
||||
vswhere_args.push_back("Microsoft.Component.MSBuild");
|
||||
|
||||
String output;
|
||||
int exit_code;
|
||||
OS::get_singleton()->execute(vswhere_path, vswhere_args, true, NULL, &output, &exit_code);
|
||||
|
||||
if (exit_code == 0) {
|
||||
Vector<String> lines = output.split("\n");
|
||||
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
const String &line = lines[i];
|
||||
int sep_idx = line.find(":");
|
||||
|
||||
if (sep_idx > 0) {
|
||||
String key = line.substr(0, sep_idx); // No need to trim
|
||||
|
||||
if (key == "installationPath") {
|
||||
String val = line.substr(sep_idx + 1, line.length()).strip_edges();
|
||||
|
||||
ERR_BREAK(val.empty());
|
||||
|
||||
if (!val.ends_with("\\")) {
|
||||
val += "\\";
|
||||
}
|
||||
|
||||
return val + "MSBuild\\15.0\\Bin";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to find 14.0 in the Registry
|
||||
|
||||
HKEY hKey;
|
||||
LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\14.0", &hKey);
|
||||
|
||||
if (res != ERROR_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
res = _RegKeyQueryString(hKey, "MSBuildToolsPath", msbuild_tools_path);
|
||||
|
||||
if (res != ERROR_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
RegCloseKey(hKey);
|
||||
|
||||
return msbuild_tools_path;
|
||||
}
|
||||
} // namespace MonoRegUtils
|
||||
|
||||
#endif WINDOWS_ENABLED
|
54
modules/mono/utils/mono_reg_utils.h
Normal file
54
modules/mono/utils/mono_reg_utils.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*************************************************************************/
|
||||
/* mono_reg_utils.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 MONO_REG_UTILS_H
|
||||
#define MONO_REG_UTILS_H
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
|
||||
#include "ustring.h"
|
||||
|
||||
struct MonoRegInfo {
|
||||
|
||||
String version;
|
||||
String install_root_dir;
|
||||
String assembly_dir;
|
||||
String config_dir;
|
||||
String bin_dir;
|
||||
};
|
||||
|
||||
namespace MonoRegUtils {
|
||||
|
||||
MonoRegInfo find_mono();
|
||||
String find_msbuild_tools_path();
|
||||
} // MonoRegUtils
|
||||
|
||||
#endif // WINDOWS_ENABLED
|
||||
|
||||
#endif // MONO_REG_UTILS_H
|
111
modules/mono/utils/path_utils.cpp
Normal file
111
modules/mono/utils/path_utils.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
/*************************************************************************/
|
||||
/* path_utils.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "path_utils.h"
|
||||
|
||||
#include "os/dir_access.h"
|
||||
#include "os/file_access.h"
|
||||
#include "os/os.h"
|
||||
#include "project_settings.h"
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
#define ENV_PATH_SEP ";"
|
||||
#else
|
||||
#define ENV_PATH_SEP ":"
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
String path_which(const String &p_name) {
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
Vector<String> exts = OS::get_singleton()->get_environment("PATHEXT").split(ENV_PATH_SEP, false);
|
||||
#endif
|
||||
Vector<String> env_path = OS::get_singleton()->get_environment("PATH").split(ENV_PATH_SEP, false);
|
||||
|
||||
if (env_path.empty())
|
||||
return String();
|
||||
|
||||
for (int i = 0; i < env_path.size(); i++) {
|
||||
String p = path_join(env_path[i], p_name);
|
||||
|
||||
if (FileAccess::exists(p))
|
||||
return p;
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
for (int j = 0; j < exts.size(); j++) {
|
||||
String p2 = p + exts[j];
|
||||
|
||||
if (FileAccess::exists(p2))
|
||||
return p2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return String();
|
||||
}
|
||||
|
||||
void fix_path(const String &p_path, String &r_out) {
|
||||
r_out = p_path.replace("\\", "/");
|
||||
|
||||
while (true) { // in case of using 2 or more slash
|
||||
String compare = r_out.replace("//", "/");
|
||||
if (r_out == compare)
|
||||
break;
|
||||
else
|
||||
r_out = compare;
|
||||
}
|
||||
}
|
||||
|
||||
bool rel_path_to_abs(const String &p_existing_path, String &r_abs_path) {
|
||||
#ifdef WINDOWS_ENABLED
|
||||
CharType ret[_MAX_PATH];
|
||||
if (_wfullpath(ret, p_existing_path.c_str(), _MAX_PATH)) {
|
||||
String abspath = String(ret).replace("\\", "/");
|
||||
int pos = abspath.find(":/");
|
||||
if (pos != -1) {
|
||||
r_abs_path = abspath.substr(pos - 1, abspath.length());
|
||||
} else {
|
||||
r_abs_path = abspath;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
char ret[PATH_MAX];
|
||||
if (realpath(p_existing_path.utf8().get_data(), ret)) {
|
||||
String retstr;
|
||||
if (!retstr.parse_utf8(ret)) {
|
||||
r_abs_path = retstr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
53
modules/mono/utils/path_utils.h
Normal file
53
modules/mono/utils/path_utils.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*************************************************************************/
|
||||
/* path_utils.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 PATH_UTILS_H
|
||||
#define PATH_UTILS_H
|
||||
|
||||
#include "ustring.h"
|
||||
|
||||
_FORCE_INLINE_ String path_join(const String &e1, const String &e2) {
|
||||
return e1.plus_file(e2);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ String path_join(const String &e1, const String &e2, const String &e3) {
|
||||
return e1.plus_file(e2).plus_file(e3);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ String path_join(const String &e1, const String &e2, const String &e3, const String &e4) {
|
||||
return e1.plus_file(e2).plus_file(e3).plus_file(e4);
|
||||
}
|
||||
|
||||
String path_which(const String &p_name);
|
||||
|
||||
void fix_path(const String &p_path, String &r_out);
|
||||
|
||||
bool rel_path_to_abs(const String &p_existing_path, String &r_abs_path);
|
||||
|
||||
#endif // PATH_UTILS_H
|
128
modules/mono/utils/string_utils.cpp
Normal file
128
modules/mono/utils/string_utils.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
/*************************************************************************/
|
||||
/* string_utils.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 "string_utils.h"
|
||||
|
||||
namespace {
|
||||
|
||||
int sfind(const String &p_text, int p_from) {
|
||||
if (p_from < 0)
|
||||
return -1;
|
||||
|
||||
int src_len = 2;
|
||||
int len = p_text.length();
|
||||
|
||||
if (src_len == 0 || len == 0)
|
||||
return -1;
|
||||
|
||||
const CharType *src = p_text.c_str();
|
||||
|
||||
for (int i = p_from; i <= (len - src_len); i++) {
|
||||
bool found = true;
|
||||
|
||||
for (int j = 0; j < src_len; j++) {
|
||||
int read_pos = i + j;
|
||||
|
||||
if (read_pos >= len) {
|
||||
ERR_PRINT("read_pos >= len");
|
||||
return -1;
|
||||
};
|
||||
|
||||
switch (j) {
|
||||
case 0:
|
||||
found = src[read_pos] == '%';
|
||||
break;
|
||||
case 1: {
|
||||
CharType c = src[read_pos];
|
||||
found = src[read_pos] == 's' || (c >= '0' || c <= '4');
|
||||
break;
|
||||
}
|
||||
default:
|
||||
found = false;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
String sformat(const String &p_text, const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4, const Variant &p5) {
|
||||
if (p_text.length() < 2)
|
||||
return p_text;
|
||||
|
||||
Array args;
|
||||
|
||||
if (p1.get_type() != Variant::NIL) {
|
||||
args.push_back(p1);
|
||||
|
||||
if (p2.get_type() != Variant::NIL) {
|
||||
args.push_back(p2);
|
||||
|
||||
if (p3.get_type() != Variant::NIL) {
|
||||
args.push_back(p3);
|
||||
|
||||
if (p4.get_type() != Variant::NIL) {
|
||||
args.push_back(p4);
|
||||
|
||||
if (p5.get_type() != Variant::NIL) {
|
||||
args.push_back(p5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String new_string;
|
||||
|
||||
int findex = 0;
|
||||
int search_from = 0;
|
||||
int result = 0;
|
||||
|
||||
while ((result = sfind(p_text, search_from)) >= 0) {
|
||||
CharType c = p_text[result + 1];
|
||||
|
||||
int req_index = (c == 's' ? findex++ : c - '0');
|
||||
|
||||
new_string += p_text.substr(search_from, result - search_from);
|
||||
new_string += args[req_index].operator String();
|
||||
search_from = result + 2;
|
||||
}
|
||||
|
||||
new_string += p_text.substr(search_from, p_text.length() - search_from);
|
||||
|
||||
return new_string;
|
||||
}
|
38
modules/mono/utils/string_utils.h
Normal file
38
modules/mono/utils/string_utils.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*************************************************************************/
|
||||
/* string_utils.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2017 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 STRING_FORMAT_H
|
||||
#define STRING_FORMAT_H
|
||||
|
||||
#include "ustring.h"
|
||||
#include "variant.h"
|
||||
|
||||
String sformat(const String &p_text, const Variant &p1 = Variant(), const Variant &p2 = Variant(), const Variant &p3 = Variant(), const Variant &p4 = Variant(), const Variant &p5 = Variant());
|
||||
|
||||
#endif // STRING_FORMAT_H
|
Loading…
Reference in New Issue
Block a user