Add Array and Dictionary wrapper classes to C#
This commit is contained in:
parent
2f69e36cef
commit
ee3c476c9a
|
@ -1609,7 +1609,7 @@ void CSharpScript::load_script_signals(GDMonoClass *p_class, GDMonoClass *p_nati
|
||||||
|
|
||||||
bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Vector<Argument> ¶ms) {
|
bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Vector<Argument> ¶ms) {
|
||||||
if (p_delegate->has_attribute(CACHED_CLASS(SignalAttribute))) {
|
if (p_delegate->has_attribute(CACHED_CLASS(SignalAttribute))) {
|
||||||
MonoType *raw_type = GDMonoClass::get_raw_type(p_delegate);
|
MonoType *raw_type = p_delegate->get_mono_type();
|
||||||
|
|
||||||
if (mono_type_get_type(raw_type) == MONO_TYPE_CLASS) {
|
if (mono_type_get_type(raw_type) == MONO_TYPE_CLASS) {
|
||||||
// Arguments are accessibles as arguments of .Invoke method
|
// Arguments are accessibles as arguments of .Invoke method
|
||||||
|
|
|
@ -100,8 +100,6 @@
|
||||||
#define C_METHOD_MONOSTR_FROM_GODOT C_NS_MONOMARSHAL "::mono_string_from_godot"
|
#define C_METHOD_MONOSTR_FROM_GODOT C_NS_MONOMARSHAL "::mono_string_from_godot"
|
||||||
#define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type
|
#define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type
|
||||||
#define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array"
|
#define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array"
|
||||||
#define C_METHOD_MANAGED_TO_DICT C_NS_MONOMARSHAL "::mono_object_to_Dictionary"
|
|
||||||
#define C_METHOD_MANAGED_FROM_DICT C_NS_MONOMARSHAL "::Dictionary_to_mono_object"
|
|
||||||
|
|
||||||
#define BINDINGS_GENERATOR_VERSION UINT32_C(2)
|
#define BINDINGS_GENERATOR_VERSION UINT32_C(2)
|
||||||
|
|
||||||
|
@ -1338,7 +1336,6 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
|
||||||
} else if (return_type->cs_out.empty()) {
|
} else if (return_type->cs_out.empty()) {
|
||||||
p_output.push_back("return " + im_call + ";\n");
|
p_output.push_back("return " + im_call + ";\n");
|
||||||
} else {
|
} else {
|
||||||
p_output.push_back(INDENT3);
|
|
||||||
p_output.push_back(sformat(return_type->cs_out, im_call, return_type->cs_type, return_type->im_type_out));
|
p_output.push_back(sformat(return_type->cs_out, im_call, return_type->cs_type, return_type->im_type_out));
|
||||||
p_output.push_back("\n");
|
p_output.push_back("\n");
|
||||||
}
|
}
|
||||||
|
@ -2344,7 +2341,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
|
||||||
|
|
||||||
#define INSERT_ARRAY(m_type, m_proxy_t) INSERT_ARRAY_FULL(m_type, m_type, m_proxy_t)
|
#define INSERT_ARRAY(m_type, m_proxy_t) INSERT_ARRAY_FULL(m_type, m_type, m_proxy_t)
|
||||||
|
|
||||||
INSERT_ARRAY(Array, object);
|
|
||||||
INSERT_ARRAY(PoolIntArray, int);
|
INSERT_ARRAY(PoolIntArray, int);
|
||||||
INSERT_ARRAY_FULL(PoolByteArray, PoolByteArray, byte);
|
INSERT_ARRAY_FULL(PoolByteArray, PoolByteArray, byte);
|
||||||
|
|
||||||
|
@ -2362,20 +2358,36 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
|
||||||
|
|
||||||
#undef INSERT_ARRAY
|
#undef INSERT_ARRAY
|
||||||
|
|
||||||
|
// Array
|
||||||
|
itype = TypeInterface();
|
||||||
|
itype.name = "Array";
|
||||||
|
itype.cname = itype.name;
|
||||||
|
itype.proxy_name = "Array";
|
||||||
|
itype.c_out = "\treturn memnew(Array(%1));\n";
|
||||||
|
itype.c_type = itype.name;
|
||||||
|
itype.c_type_in = itype.c_type + "*";
|
||||||
|
itype.c_type_out = itype.c_type + "*";
|
||||||
|
itype.cs_type = itype.proxy_name;
|
||||||
|
itype.cs_in = "%0." CS_SMETHOD_GETINSTANCE "()";
|
||||||
|
itype.cs_out = "return new Array(%0);";
|
||||||
|
itype.im_type_in = "IntPtr";
|
||||||
|
itype.im_type_out = "IntPtr";
|
||||||
|
builtin_types.insert(itype.cname, itype);
|
||||||
|
|
||||||
// Dictionary
|
// Dictionary
|
||||||
itype = TypeInterface();
|
itype = TypeInterface();
|
||||||
itype.name = "Dictionary";
|
itype.name = "Dictionary";
|
||||||
itype.cname = itype.name;
|
itype.cname = itype.name;
|
||||||
itype.proxy_name = "Dictionary<object, object>";
|
itype.proxy_name = "Dictionary";
|
||||||
itype.c_in = "\t%0 %1_in = " C_METHOD_MANAGED_TO_DICT "(%1);\n";
|
itype.c_out = "\treturn memnew(Dictionary(%1));\n";
|
||||||
itype.c_out = "\treturn " C_METHOD_MANAGED_FROM_DICT "(%1);\n";
|
|
||||||
itype.c_arg_in = "&%s_in";
|
|
||||||
itype.c_type = itype.name;
|
itype.c_type = itype.name;
|
||||||
itype.c_type_in = "MonoObject*";
|
itype.c_type_in = itype.c_type + "*";
|
||||||
itype.c_type_out = "MonoObject*";
|
itype.c_type_out = itype.c_type + "*";
|
||||||
itype.cs_type = itype.proxy_name;
|
itype.cs_type = itype.proxy_name;
|
||||||
itype.im_type_in = itype.proxy_name;
|
itype.cs_in = "%0." CS_SMETHOD_GETINSTANCE "()";
|
||||||
itype.im_type_out = itype.proxy_name;
|
itype.cs_out = "return new Dictionary(%0);";
|
||||||
|
itype.im_type_in = "IntPtr";
|
||||||
|
itype.im_type_out = "IntPtr";
|
||||||
builtin_types.insert(itype.cname, itype);
|
builtin_types.insert(itype.cname, itype);
|
||||||
|
|
||||||
// void (fictitious type to represent the return type of methods that do not return anything)
|
// void (fictitious type to represent the return type of methods that do not return anything)
|
||||||
|
|
|
@ -0,0 +1,240 @@
|
||||||
|
/*************************************************************************/
|
||||||
|
/* collections_glue.cpp */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
|
||||||
|
/* */
|
||||||
|
/* 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 "collections_glue.h"
|
||||||
|
|
||||||
|
#include <mono/metadata/exception.h>
|
||||||
|
|
||||||
|
#include "../mono_gd/gd_mono_class.h"
|
||||||
|
|
||||||
|
Array *godot_icall_Array_Ctor() {
|
||||||
|
return memnew(Array);
|
||||||
|
}
|
||||||
|
|
||||||
|
void godot_icall_Array_Dtor(Array *ptr) {
|
||||||
|
memdelete(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MonoObject *godot_icall_Array_At(Array *ptr, int index) {
|
||||||
|
if (index < 0 || index > ptr->size()) {
|
||||||
|
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index));
|
||||||
|
}
|
||||||
|
|
||||||
|
void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value) {
|
||||||
|
if (index < 0 || index > ptr->size()) {
|
||||||
|
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ptr->operator[](index) = GDMonoMarshal::mono_object_to_variant(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int godot_icall_Array_Count(Array *ptr) {
|
||||||
|
return ptr->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void godot_icall_Array_Add(Array *ptr, MonoObject *item) {
|
||||||
|
ptr->append(GDMonoMarshal::mono_object_to_variant(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
void godot_icall_Array_Clear(Array *ptr) {
|
||||||
|
ptr->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool godot_icall_Array_Contains(Array *ptr, MonoObject *item) {
|
||||||
|
return ptr->find(GDMonoMarshal::mono_object_to_variant(item)) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int array_index) {
|
||||||
|
int count = ptr->size();
|
||||||
|
|
||||||
|
if (mono_array_length(array) < (array_index + count)) {
|
||||||
|
MonoException *exc = mono_get_exception_argument("", "Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
|
||||||
|
GDMonoUtils::set_pending_exception(exc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(ptr->operator[](i));
|
||||||
|
mono_array_setref(array, array_index, boxed);
|
||||||
|
array_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int godot_icall_Array_IndexOf(Array *ptr, MonoObject *item) {
|
||||||
|
return ptr->find(GDMonoMarshal::mono_object_to_variant(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
void godot_icall_Array_Insert(Array *ptr, int index, MonoObject *item) {
|
||||||
|
if (index < 0 || index > ptr->size()) {
|
||||||
|
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ptr->insert(index, GDMonoMarshal::mono_object_to_variant(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool godot_icall_Array_Remove(Array *ptr, MonoObject *item) {
|
||||||
|
int idx = ptr->find(GDMonoMarshal::mono_object_to_variant(item));
|
||||||
|
if (idx >= 0) {
|
||||||
|
ptr->remove(idx);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void godot_icall_Array_RemoveAt(Array *ptr, int index) {
|
||||||
|
if (index < 0 || index > ptr->size()) {
|
||||||
|
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ptr->remove(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary *godot_icall_Dictionary_Ctor() {
|
||||||
|
return memnew(Dictionary);
|
||||||
|
}
|
||||||
|
|
||||||
|
void godot_icall_Dictionary_Dtor(Dictionary *ptr) {
|
||||||
|
memdelete(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MonoObject *godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key) {
|
||||||
|
Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
|
||||||
|
if (ret == NULL) {
|
||||||
|
MonoObject *exc = mono_object_new(mono_domain_get(), CACHED_CLASS(KeyNotFoundException)->get_mono_ptr());
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
CRASH_COND(!exc);
|
||||||
|
#endif
|
||||||
|
GDMonoUtils::runtime_object_init(exc);
|
||||||
|
GDMonoUtils::set_pending_exception((MonoException *)exc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return GDMonoMarshal::variant_to_mono_object(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
void godot_icall_Dictionary_SetValue(Dictionary *ptr, MonoObject *key, MonoObject *value) {
|
||||||
|
ptr->operator[](GDMonoMarshal::mono_object_to_variant(key)) = GDMonoMarshal::mono_object_to_variant(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Array *godot_icall_Dictionary_Keys(Dictionary *ptr) {
|
||||||
|
return memnew(Array(ptr->keys()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Array *godot_icall_Dictionary_Values(Dictionary *ptr) {
|
||||||
|
return memnew(Array(ptr->values()));
|
||||||
|
}
|
||||||
|
|
||||||
|
int godot_icall_Dictionary_Count(Dictionary *ptr) {
|
||||||
|
return ptr->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *value) {
|
||||||
|
Variant varKey = GDMonoMarshal::mono_object_to_variant(key);
|
||||||
|
Variant *ret = ptr->getptr(varKey);
|
||||||
|
if (ret != NULL) {
|
||||||
|
GDMonoUtils::set_pending_exception(mono_get_exception_argument("key", "An element with the same key already exists"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ptr->operator[](varKey) = GDMonoMarshal::mono_object_to_variant(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void godot_icall_Dictionary_Clear(Dictionary *ptr) {
|
||||||
|
ptr->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value) {
|
||||||
|
// no dupes
|
||||||
|
Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
|
||||||
|
return ret != NULL && *ret == GDMonoMarshal::mono_object_to_variant(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key) {
|
||||||
|
return ptr->has(GDMonoMarshal::mono_object_to_variant(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key) {
|
||||||
|
return ptr->erase_checked(GDMonoMarshal::mono_object_to_variant(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value) {
|
||||||
|
Variant varKey = GDMonoMarshal::mono_object_to_variant(key);
|
||||||
|
|
||||||
|
// no dupes
|
||||||
|
Variant *ret = ptr->getptr(varKey);
|
||||||
|
if (ret != NULL && *ret == GDMonoMarshal::mono_object_to_variant(value)) {
|
||||||
|
ptr->erase_checked(varKey);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value) {
|
||||||
|
Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
|
||||||
|
if (ret == NULL) {
|
||||||
|
*value = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*value = GDMonoMarshal::variant_to_mono_object(ret);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void godot_register_collections_icalls() {
|
||||||
|
mono_add_internal_call("Godot.Array::godot_icall_Array_Ctor", (void *)godot_icall_Array_Ctor);
|
||||||
|
mono_add_internal_call("Godot.Array::godot_icall_Array_Dtor", (void *)godot_icall_Array_Dtor);
|
||||||
|
mono_add_internal_call("Godot.Array::godot_icall_Array_At", (void *)godot_icall_Array_At);
|
||||||
|
mono_add_internal_call("Godot.Array::godot_icall_Array_SetAt", (void *)godot_icall_Array_SetAt);
|
||||||
|
mono_add_internal_call("Godot.Array::godot_icall_Array_Count", (void *)godot_icall_Array_Count);
|
||||||
|
mono_add_internal_call("Godot.Array::godot_icall_Array_Add", (void *)godot_icall_Array_Add);
|
||||||
|
mono_add_internal_call("Godot.Array::godot_icall_Array_Clear", (void *)godot_icall_Array_Clear);
|
||||||
|
mono_add_internal_call("Godot.Array::godot_icall_Array_Contains", (void *)godot_icall_Array_Contains);
|
||||||
|
mono_add_internal_call("Godot.Array::godot_icall_Array_CopyTo", (void *)godot_icall_Array_CopyTo);
|
||||||
|
mono_add_internal_call("Godot.Array::godot_icall_Array_IndexOf", (void *)godot_icall_Array_IndexOf);
|
||||||
|
mono_add_internal_call("Godot.Array::godot_icall_Array_Insert", (void *)godot_icall_Array_Insert);
|
||||||
|
mono_add_internal_call("Godot.Array::godot_icall_Array_Remove", (void *)godot_icall_Array_Remove);
|
||||||
|
mono_add_internal_call("Godot.Array::godot_icall_Array_RemoveAt", (void *)godot_icall_Array_RemoveAt);
|
||||||
|
|
||||||
|
mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Ctor", (void *)godot_icall_Dictionary_Ctor);
|
||||||
|
mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Dtor", (void *)godot_icall_Dictionary_Dtor);
|
||||||
|
mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_GetValue", (void *)godot_icall_Dictionary_GetValue);
|
||||||
|
mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_SetValue", (void *)godot_icall_Dictionary_SetValue);
|
||||||
|
mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Keys", (void *)godot_icall_Dictionary_Keys);
|
||||||
|
mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Values", (void *)godot_icall_Dictionary_Values);
|
||||||
|
mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Count", (void *)godot_icall_Dictionary_Count);
|
||||||
|
mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Add", (void *)godot_icall_Dictionary_Add);
|
||||||
|
mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Clear", (void *)godot_icall_Dictionary_Clear);
|
||||||
|
mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Contains", (void *)godot_icall_Dictionary_Contains);
|
||||||
|
mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_ContainsKey", (void *)godot_icall_Dictionary_ContainsKey);
|
||||||
|
mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_RemoveKey", (void *)godot_icall_Dictionary_RemoveKey);
|
||||||
|
mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Remove", (void *)godot_icall_Dictionary_Remove);
|
||||||
|
mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_TryGetValue", (void *)godot_icall_Dictionary_TryGetValue);
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
/*************************************************************************/
|
||||||
|
/* collections_glue.h */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
|
||||||
|
/* */
|
||||||
|
/* 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 COLLECTIONS_GLUE_H
|
||||||
|
#define COLLECTIONS_GLUE_H
|
||||||
|
|
||||||
|
#include "core/array.h"
|
||||||
|
|
||||||
|
#include "../mono_gd/gd_mono_marshal.h"
|
||||||
|
|
||||||
|
// Array
|
||||||
|
|
||||||
|
Array *godot_icall_Array_Ctor();
|
||||||
|
|
||||||
|
void godot_icall_Array_Dtor(Array *ptr);
|
||||||
|
|
||||||
|
MonoObject *godot_icall_Array_At(Array *ptr, int index);
|
||||||
|
|
||||||
|
void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value);
|
||||||
|
|
||||||
|
int godot_icall_Array_Count(Array *ptr);
|
||||||
|
|
||||||
|
void godot_icall_Array_Add(Array *ptr, MonoObject *item);
|
||||||
|
|
||||||
|
void godot_icall_Array_Clear(Array *ptr);
|
||||||
|
|
||||||
|
bool godot_icall_Array_Contains(Array *ptr, MonoObject *item);
|
||||||
|
|
||||||
|
void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int array_index);
|
||||||
|
|
||||||
|
int godot_icall_Array_IndexOf(Array *ptr, MonoObject *item);
|
||||||
|
|
||||||
|
void godot_icall_Array_Insert(Array *ptr, int index, MonoObject *item);
|
||||||
|
|
||||||
|
bool godot_icall_Array_Remove(Array *ptr, MonoObject *item);
|
||||||
|
|
||||||
|
void godot_icall_Array_RemoveAt(Array *ptr, int index);
|
||||||
|
|
||||||
|
// Dictionary
|
||||||
|
|
||||||
|
Dictionary *godot_icall_Dictionary_Ctor();
|
||||||
|
|
||||||
|
void godot_icall_Dictionary_Dtor(Dictionary *ptr);
|
||||||
|
|
||||||
|
MonoObject *godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key);
|
||||||
|
|
||||||
|
void godot_icall_Dictionary_SetValue(Dictionary *ptr, MonoObject *key, MonoObject *value);
|
||||||
|
|
||||||
|
Array *godot_icall_Dictionary_Keys(Dictionary *ptr);
|
||||||
|
|
||||||
|
Array *godot_icall_Dictionary_Values(Dictionary *ptr);
|
||||||
|
|
||||||
|
int godot_icall_Dictionary_Count(Dictionary *ptr);
|
||||||
|
|
||||||
|
void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *value);
|
||||||
|
|
||||||
|
void godot_icall_Dictionary_Clear(Dictionary *ptr);
|
||||||
|
|
||||||
|
bool godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value);
|
||||||
|
|
||||||
|
bool godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key);
|
||||||
|
|
||||||
|
bool godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key);
|
||||||
|
|
||||||
|
bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value);
|
||||||
|
|
||||||
|
bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value);
|
||||||
|
|
||||||
|
// Register internal calls
|
||||||
|
|
||||||
|
void godot_register_collections_icalls();
|
||||||
|
|
||||||
|
#endif // COLLECTIONS_GLUE_H
|
|
@ -0,0 +1,335 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Godot
|
||||||
|
{
|
||||||
|
class ArraySafeHandle : SafeHandle
|
||||||
|
{
|
||||||
|
public ArraySafeHandle(IntPtr handle) : base(IntPtr.Zero, true)
|
||||||
|
{
|
||||||
|
this.handle = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsInvalid
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return handle == IntPtr.Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool ReleaseHandle()
|
||||||
|
{
|
||||||
|
Array.godot_icall_Array_Dtor(handle);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Array : IList<object>, ICollection<object>, IEnumerable<object>, IDisposable
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static IntPtr godot_icall_Array_Ctor();
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static void godot_icall_Array_Dtor(IntPtr ptr);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static object godot_icall_Array_At(IntPtr ptr, int index);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static void godot_icall_Array_SetAt(IntPtr ptr, int index, object value);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static int godot_icall_Array_Count(IntPtr ptr);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static void godot_icall_Array_Add(IntPtr ptr, object item);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static void godot_icall_Array_Clear(IntPtr ptr);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static bool godot_icall_Array_Contains(IntPtr ptr, object item);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static void godot_icall_Array_CopyTo(IntPtr ptr, object[] array, int arrayIndex);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static int godot_icall_Array_IndexOf(IntPtr ptr, object item);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static void godot_icall_Array_Insert(IntPtr ptr, int index, object item);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static bool godot_icall_Array_Remove(IntPtr ptr, object item);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static void godot_icall_Array_RemoveAt(IntPtr ptr, int index);
|
||||||
|
|
||||||
|
ArraySafeHandle safeHandle;
|
||||||
|
bool disposed = false;
|
||||||
|
|
||||||
|
public Array()
|
||||||
|
{
|
||||||
|
safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor());
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Array(ArraySafeHandle handle)
|
||||||
|
{
|
||||||
|
safeHandle = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Array(IntPtr handle)
|
||||||
|
{
|
||||||
|
safeHandle = new ArraySafeHandle(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal IntPtr GetPtr()
|
||||||
|
{
|
||||||
|
return safeHandle.DangerousGetHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (safeHandle != null)
|
||||||
|
{
|
||||||
|
safeHandle.Dispose();
|
||||||
|
safeHandle = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
disposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object this[int index]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return godot_icall_Array_At(GetPtr(), index);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
godot_icall_Array_SetAt(GetPtr(), index, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return godot_icall_Array_Count(GetPtr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsReadOnly
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(object item)
|
||||||
|
{
|
||||||
|
godot_icall_Array_Add(GetPtr(), item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
godot_icall_Array_Clear(GetPtr());
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(object item)
|
||||||
|
{
|
||||||
|
return godot_icall_Array_Contains(GetPtr(), item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(object[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
if (array == null)
|
||||||
|
throw new ArgumentNullException(nameof(array), "Value cannot be null.");
|
||||||
|
|
||||||
|
if (arrayIndex < 0)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension.");
|
||||||
|
|
||||||
|
// Internal call may throw ArgumentException
|
||||||
|
godot_icall_Array_CopyTo(GetPtr(), array, arrayIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<object> GetEnumerator()
|
||||||
|
{
|
||||||
|
int count = Count;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
yield return godot_icall_Array_At(GetPtr(), i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int IndexOf(object item)
|
||||||
|
{
|
||||||
|
return godot_icall_Array_IndexOf(GetPtr(), item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Insert(int index, object item)
|
||||||
|
{
|
||||||
|
godot_icall_Array_Insert(GetPtr(), index, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(object item)
|
||||||
|
{
|
||||||
|
return godot_icall_Array_Remove(GetPtr(), item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAt(int index)
|
||||||
|
{
|
||||||
|
godot_icall_Array_RemoveAt(GetPtr(), index);
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Array<T> : IList<T>, ICollection<T>, IEnumerable<T>
|
||||||
|
{
|
||||||
|
Array objectArray;
|
||||||
|
|
||||||
|
public Array()
|
||||||
|
{
|
||||||
|
objectArray = new Array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array(Array array)
|
||||||
|
{
|
||||||
|
objectArray = array;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Array(IntPtr handle)
|
||||||
|
{
|
||||||
|
objectArray = new Array(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Array(ArraySafeHandle handle)
|
||||||
|
{
|
||||||
|
objectArray = new Array(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator Array(Array<T> from)
|
||||||
|
{
|
||||||
|
return from.objectArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T this[int index]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (T)objectArray[index];
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
objectArray[index] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return objectArray.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsReadOnly
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return objectArray.IsReadOnly;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(T item)
|
||||||
|
{
|
||||||
|
objectArray.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
objectArray.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(T item)
|
||||||
|
{
|
||||||
|
return objectArray.Contains(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(T[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
if (array == null)
|
||||||
|
throw new ArgumentNullException(nameof(array), "Value cannot be null.");
|
||||||
|
|
||||||
|
if (arrayIndex < 0)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension.");
|
||||||
|
|
||||||
|
// TODO This may be quite slow because every element access is an internal call.
|
||||||
|
// It could be moved entirely to an internal call if we find out how to do the cast there.
|
||||||
|
|
||||||
|
int count = objectArray.Count;
|
||||||
|
|
||||||
|
if (array.Length < (arrayIndex + count))
|
||||||
|
throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
array[arrayIndex] = (T)objectArray[i];
|
||||||
|
arrayIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<T> GetEnumerator()
|
||||||
|
{
|
||||||
|
int count = objectArray.Count;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
yield return (T)objectArray[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int IndexOf(T item)
|
||||||
|
{
|
||||||
|
return objectArray.IndexOf(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Insert(int index, T item)
|
||||||
|
{
|
||||||
|
objectArray.Insert(index, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(T item)
|
||||||
|
{
|
||||||
|
return objectArray.Remove(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAt(int index)
|
||||||
|
{
|
||||||
|
objectArray.RemoveAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,401 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Godot
|
||||||
|
{
|
||||||
|
class DictionarySafeHandle : SafeHandle
|
||||||
|
{
|
||||||
|
public DictionarySafeHandle(IntPtr handle) : base(IntPtr.Zero, true)
|
||||||
|
{
|
||||||
|
this.handle = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsInvalid
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return handle == IntPtr.Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool ReleaseHandle()
|
||||||
|
{
|
||||||
|
Dictionary.godot_icall_Dictionary_Dtor(handle);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Dictionary :
|
||||||
|
IDictionary<object, object>,
|
||||||
|
ICollection<KeyValuePair<object, object>>,
|
||||||
|
IEnumerable<KeyValuePair<object, object>>,
|
||||||
|
IDisposable
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static IntPtr godot_icall_Dictionary_Ctor();
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static void godot_icall_Dictionary_Dtor(IntPtr ptr);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static object godot_icall_Dictionary_GetValue(IntPtr ptr, object key);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static void godot_icall_Dictionary_SetValue(IntPtr ptr, object key, object value);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static IntPtr godot_icall_Dictionary_Keys(IntPtr ptr);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static IntPtr godot_icall_Dictionary_Values(IntPtr ptr);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static int godot_icall_Dictionary_Count(IntPtr ptr);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static void godot_icall_Dictionary_Add(IntPtr ptr, object key, object value);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static void godot_icall_Dictionary_Clear(IntPtr ptr);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static bool godot_icall_Dictionary_Contains(IntPtr ptr, object key, object value);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static bool godot_icall_Dictionary_ContainsKey(IntPtr ptr, object key);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static bool godot_icall_Dictionary_RemoveKey(IntPtr ptr, object key);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static bool godot_icall_Dictionary_Remove(IntPtr ptr, object key, object value);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static bool godot_icall_Dictionary_TryGetValue(IntPtr ptr, object key, out object value);
|
||||||
|
|
||||||
|
DictionarySafeHandle safeHandle;
|
||||||
|
bool disposed = false;
|
||||||
|
|
||||||
|
public Dictionary()
|
||||||
|
{
|
||||||
|
safeHandle = new DictionarySafeHandle(godot_icall_Dictionary_Ctor());
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Dictionary(DictionarySafeHandle handle)
|
||||||
|
{
|
||||||
|
safeHandle = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Dictionary(IntPtr handle)
|
||||||
|
{
|
||||||
|
safeHandle = new DictionarySafeHandle(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal IntPtr GetPtr()
|
||||||
|
{
|
||||||
|
return safeHandle.DangerousGetHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (safeHandle != null)
|
||||||
|
{
|
||||||
|
safeHandle.Dispose();
|
||||||
|
safeHandle = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
disposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object this[object key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return godot_icall_Dictionary_GetValue(GetPtr(), key);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
godot_icall_Dictionary_SetValue(GetPtr(), key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICollection<object> Keys
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
IntPtr handle = godot_icall_Dictionary_Keys(GetPtr());
|
||||||
|
return new Array(new ArraySafeHandle(handle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICollection<object> Values
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
IntPtr handle = godot_icall_Dictionary_Values(GetPtr());
|
||||||
|
return new Array(new ArraySafeHandle(handle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return godot_icall_Dictionary_Count(GetPtr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsReadOnly
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(object key, object value)
|
||||||
|
{
|
||||||
|
godot_icall_Dictionary_Add(GetPtr(), key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(KeyValuePair<object, object> item)
|
||||||
|
{
|
||||||
|
Add(item.Key, item.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
godot_icall_Dictionary_Clear(GetPtr());
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(KeyValuePair<object, object> item)
|
||||||
|
{
|
||||||
|
return godot_icall_Dictionary_Contains(GetPtr(), item.Key, item.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ContainsKey(object key)
|
||||||
|
{
|
||||||
|
return godot_icall_Dictionary_ContainsKey(GetPtr(), key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(KeyValuePair<object, object>[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
// TODO 3 internal calls, can reduce to 1
|
||||||
|
Array keys = (Array)Keys;
|
||||||
|
Array values = (Array)Values;
|
||||||
|
int count = Count;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
// TODO 2 internal calls, can reduce to 1
|
||||||
|
array[arrayIndex] = new KeyValuePair<object, object>(keys[i], values[i]);
|
||||||
|
arrayIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<KeyValuePair<object, object>> GetEnumerator()
|
||||||
|
{
|
||||||
|
// TODO 3 internal calls, can reduce to 1
|
||||||
|
Array keys = (Array)Keys;
|
||||||
|
Array values = (Array)Values;
|
||||||
|
int count = Count;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
// TODO 2 internal calls, can reduce to 1
|
||||||
|
yield return new KeyValuePair<object, object>(keys[i], values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(object key)
|
||||||
|
{
|
||||||
|
return godot_icall_Dictionary_RemoveKey(GetPtr(), key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(KeyValuePair<object, object> item)
|
||||||
|
{
|
||||||
|
return godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(object key, out object value)
|
||||||
|
{
|
||||||
|
object retValue;
|
||||||
|
bool found = godot_icall_Dictionary_TryGetValue(GetPtr(), key, out retValue);
|
||||||
|
value = found ? retValue : default(object);
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class Dictionary<TKey, TValue> :
|
||||||
|
IDictionary<TKey, TValue>,
|
||||||
|
ICollection<KeyValuePair<TKey, TValue>>,
|
||||||
|
IEnumerable<KeyValuePair<TKey, TValue>>
|
||||||
|
{
|
||||||
|
Dictionary objectDict;
|
||||||
|
|
||||||
|
public Dictionary()
|
||||||
|
{
|
||||||
|
objectDict = new Dictionary();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dictionary(Dictionary dictionary)
|
||||||
|
{
|
||||||
|
objectDict = dictionary;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Dictionary(IntPtr handle)
|
||||||
|
{
|
||||||
|
objectDict = new Dictionary(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Dictionary(DictionarySafeHandle handle)
|
||||||
|
{
|
||||||
|
objectDict = new Dictionary(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator Dictionary(Dictionary<TKey, TValue> from)
|
||||||
|
{
|
||||||
|
return from.objectDict;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TValue this[TKey key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (TValue)objectDict[key];
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
objectDict[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICollection<TKey> Keys
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
IntPtr handle = Dictionary.godot_icall_Dictionary_Keys(objectDict.GetPtr());
|
||||||
|
return new Array<TKey>(new ArraySafeHandle(handle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICollection<TValue> Values
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
IntPtr handle = Dictionary.godot_icall_Dictionary_Values(objectDict.GetPtr());
|
||||||
|
return new Array<TValue>(new ArraySafeHandle(handle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return objectDict.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsReadOnly
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return objectDict.IsReadOnly;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(TKey key, TValue value)
|
||||||
|
{
|
||||||
|
objectDict.Add(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(KeyValuePair<TKey, TValue> item)
|
||||||
|
{
|
||||||
|
objectDict.Add(item.Key, item.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
objectDict.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(KeyValuePair<TKey, TValue> item)
|
||||||
|
{
|
||||||
|
return objectDict.Contains(new KeyValuePair<object, object>(item.Key, item.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ContainsKey(TKey key)
|
||||||
|
{
|
||||||
|
return objectDict.ContainsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
// TODO 3 internal calls, can reduce to 1
|
||||||
|
Array<TKey> keys = (Array<TKey>)Keys;
|
||||||
|
Array<TValue> values = (Array<TValue>)Values;
|
||||||
|
int count = Count;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
// TODO 2 internal calls, can reduce to 1
|
||||||
|
array[arrayIndex] = new KeyValuePair<TKey, TValue>(keys[i], values[i]);
|
||||||
|
arrayIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
||||||
|
{
|
||||||
|
// TODO 3 internal calls, can reduce to 1
|
||||||
|
Array<TKey> keys = (Array<TKey>)Keys;
|
||||||
|
Array<TValue> values = (Array<TValue>)Values;
|
||||||
|
int count = Count;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
// TODO 2 internal calls, can reduce to 1
|
||||||
|
yield return new KeyValuePair<TKey, TValue>(keys[i], values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(TKey key)
|
||||||
|
{
|
||||||
|
return objectDict.Remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(KeyValuePair<TKey, TValue> item)
|
||||||
|
{
|
||||||
|
return objectDict.Remove(new KeyValuePair<object, object>(item.Key, item.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(TKey key, out TValue value)
|
||||||
|
{
|
||||||
|
object retValue;
|
||||||
|
bool found = objectDict.TryGetValue(key, out retValue);
|
||||||
|
value = found ? (TValue)retValue : default(TValue);
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,36 +1,17 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Godot
|
namespace Godot
|
||||||
{
|
{
|
||||||
internal static class MarshalUtils
|
static class MarshalUtils
|
||||||
{
|
{
|
||||||
private static Dictionary<object, object> ArraysToDictionary(object[] keys, object[] values)
|
static bool IsArrayGenericType(Type type)
|
||||||
{
|
{
|
||||||
var ret = new Dictionary<object, object>();
|
return type.GetGenericTypeDefinition() == typeof(Array<>);
|
||||||
|
|
||||||
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)
|
static bool IsDictionaryGenericType(Type type)
|
||||||
{
|
{
|
||||||
var keys = from.Keys;
|
return type.GetGenericTypeDefinition() == typeof(Dictionary<, >);
|
||||||
keysTo = new object[keys.Count];
|
|
||||||
keys.CopyTo(keysTo, 0);
|
|
||||||
|
|
||||||
var values = from.Values;
|
|
||||||
valuesTo = new object[values.Count];
|
|
||||||
values.CopyTo(valuesTo, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Type GetDictionaryType()
|
|
||||||
{
|
|
||||||
return typeof(Dictionary<object, object>);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
|
||||||
#include "builtin_types_glue.h"
|
#include "builtin_types_glue.h"
|
||||||
|
#include "collections_glue.h"
|
||||||
|
|
||||||
#include "../csharp_script.h"
|
#include "../csharp_script.h"
|
||||||
#include "../mono_gd/gd_mono_class.h"
|
#include "../mono_gd/gd_mono_class.h"
|
||||||
|
@ -308,4 +309,5 @@ MonoObject *godot_icall_Godot_weakref(Object *p_obj) {
|
||||||
|
|
||||||
void godot_register_header_icalls() {
|
void godot_register_header_icalls() {
|
||||||
godot_register_builtin_type_icalls();
|
godot_register_builtin_type_icalls();
|
||||||
|
godot_register_collections_icalls();
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,10 +33,32 @@
|
||||||
#include <mono/metadata/attrdefs.h>
|
#include <mono/metadata/attrdefs.h>
|
||||||
|
|
||||||
#include "gd_mono_assembly.h"
|
#include "gd_mono_assembly.h"
|
||||||
|
#include "gd_mono_marshal.h"
|
||||||
|
|
||||||
MonoType *GDMonoClass::get_raw_type(GDMonoClass *p_class) {
|
String GDMonoClass::get_full_name(MonoClass *p_mono_class) {
|
||||||
|
// mono_type_get_full_name is not exposed to embedders, but this seems to do the job
|
||||||
|
MonoReflectionType *type_obj = mono_type_get_object(mono_domain_get(), get_mono_type(p_mono_class));
|
||||||
|
|
||||||
return mono_class_get_type(p_class->get_mono_ptr());
|
MonoException *exc = NULL;
|
||||||
|
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||||
|
MonoString *str = mono_object_to_string((MonoObject *)type_obj, (MonoObject **)&exc);
|
||||||
|
GD_MONO_END_RUNTIME_INVOKE;
|
||||||
|
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||||
|
|
||||||
|
return GDMonoMarshal::mono_string_to_godot(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
MonoType *GDMonoClass::get_mono_type(MonoClass *p_mono_class) {
|
||||||
|
return mono_class_get_type(p_mono_class);
|
||||||
|
}
|
||||||
|
|
||||||
|
String GDMonoClass::get_full_name() const {
|
||||||
|
return get_full_name(mono_class);
|
||||||
|
}
|
||||||
|
|
||||||
|
MonoType *GDMonoClass::get_mono_type() {
|
||||||
|
// Care, you cannot compare MonoType pointers
|
||||||
|
return get_mono_type(mono_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const {
|
bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const {
|
||||||
|
@ -44,14 +66,6 @@ bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const {
|
||||||
return mono_class_is_assignable_from(mono_class, p_from->mono_class);
|
return mono_class_is_assignable_from(mono_class, p_from->mono_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
String GDMonoClass::get_full_name() const {
|
|
||||||
|
|
||||||
String res = namespace_name;
|
|
||||||
if (res.length())
|
|
||||||
res += ".";
|
|
||||||
return res + class_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
GDMonoClass *GDMonoClass::get_parent_class() {
|
GDMonoClass *GDMonoClass::get_parent_class() {
|
||||||
|
|
||||||
if (assembly) {
|
if (assembly) {
|
||||||
|
|
|
@ -98,7 +98,11 @@ class GDMonoClass {
|
||||||
GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly);
|
GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static MonoType *get_raw_type(GDMonoClass *p_class);
|
static String get_full_name(MonoClass *p_mono_class);
|
||||||
|
static MonoType *get_mono_type(MonoClass *p_mono_class);
|
||||||
|
|
||||||
|
String get_full_name() const;
|
||||||
|
MonoType *get_mono_type();
|
||||||
|
|
||||||
bool is_assignable_from(GDMonoClass *p_from) const;
|
bool is_assignable_from(GDMonoClass *p_from) const;
|
||||||
|
|
||||||
|
@ -108,8 +112,6 @@ public:
|
||||||
_FORCE_INLINE_ MonoClass *get_mono_ptr() const { return mono_class; }
|
_FORCE_INLINE_ MonoClass *get_mono_ptr() const { return mono_class; }
|
||||||
_FORCE_INLINE_ const GDMonoAssembly *get_assembly() const { return assembly; }
|
_FORCE_INLINE_ const GDMonoAssembly *get_assembly() const { return assembly; }
|
||||||
|
|
||||||
String get_full_name() const;
|
|
||||||
|
|
||||||
GDMonoClass *get_parent_class();
|
GDMonoClass *get_parent_class();
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
|
|
|
@ -148,7 +148,7 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
|
||||||
|
|
||||||
case MONO_TYPE_ARRAY:
|
case MONO_TYPE_ARRAY:
|
||||||
case MONO_TYPE_SZARRAY: {
|
case MONO_TYPE_SZARRAY: {
|
||||||
MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(type.type_class));
|
MonoArrayType *array_type = mono_type_get_array_type(type.type_class->get_mono_type());
|
||||||
|
|
||||||
if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
|
if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
|
||||||
SET_FROM_ARRAY_AND_BREAK(Array);
|
SET_FROM_ARRAY_AND_BREAK(Array);
|
||||||
|
@ -200,6 +200,18 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (CACHED_CLASS(Dictionary) == type_class) {
|
||||||
|
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
|
||||||
|
mono_field_set_value(p_object, mono_field, managed);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CACHED_CLASS(Array) == type_class) {
|
||||||
|
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
|
||||||
|
mono_field_set_value(p_object, mono_field, managed);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + type_class->get_name());
|
ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + type_class->get_name());
|
||||||
ERR_FAIL();
|
ERR_FAIL();
|
||||||
} break;
|
} break;
|
||||||
|
@ -248,10 +260,13 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Variant::DICTIONARY: {
|
case Variant::DICTIONARY: {
|
||||||
MonoObject *managed = GDMonoMarshal::Dictionary_to_mono_object(p_value.operator Dictionary());
|
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
|
||||||
|
mono_field_set_value(p_object, mono_field, managed);
|
||||||
|
} break;
|
||||||
|
case Variant::ARRAY: {
|
||||||
|
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
|
||||||
mono_field_set_value(p_object, mono_field, managed);
|
mono_field_set_value(p_object, mono_field, managed);
|
||||||
} break;
|
} break;
|
||||||
case Variant::ARRAY: SET_FROM_ARRAY_AND_BREAK(Array);
|
|
||||||
case Variant::POOL_BYTE_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolByteArray);
|
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_INT_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolIntArray);
|
||||||
case Variant::POOL_REAL_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolRealArray);
|
case Variant::POOL_REAL_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolRealArray);
|
||||||
|
@ -265,8 +280,28 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case MONO_TYPE_GENERICINST: {
|
case MONO_TYPE_GENERICINST: {
|
||||||
if (CACHED_RAW_MONO_CLASS(Dictionary) == type.type_class->get_mono_ptr()) {
|
MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type.type_class->get_mono_type());
|
||||||
MonoObject *managed = GDMonoMarshal::Dictionary_to_mono_object(p_value.operator Dictionary());
|
|
||||||
|
MonoException *exc = NULL;
|
||||||
|
|
||||||
|
GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
|
||||||
|
MonoBoolean is_dict = type_is_dict((MonoObject *)reftype, (MonoObject **)&exc);
|
||||||
|
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||||
|
|
||||||
|
if (is_dict) {
|
||||||
|
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), type.type_class);
|
||||||
|
mono_field_set_value(p_object, mono_field, managed);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
exc = NULL;
|
||||||
|
|
||||||
|
GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
|
||||||
|
MonoBoolean is_array = type_is_array((MonoObject *)reftype, (MonoObject **)&exc);
|
||||||
|
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||||
|
|
||||||
|
if (is_array) {
|
||||||
|
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), type.type_class);
|
||||||
mono_field_set_value(p_object, mono_field, managed);
|
mono_field_set_value(p_object, mono_field, managed);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,8 @@ struct ManagedType {
|
||||||
GDMonoClass *type_class;
|
GDMonoClass *type_class;
|
||||||
|
|
||||||
ManagedType() {
|
ManagedType() {
|
||||||
type_class = 0;
|
type_encoding = 0;
|
||||||
|
type_class = NULL;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -120,7 +120,7 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
|
||||||
|
|
||||||
case MONO_TYPE_ARRAY:
|
case MONO_TYPE_ARRAY:
|
||||||
case MONO_TYPE_SZARRAY: {
|
case MONO_TYPE_SZARRAY: {
|
||||||
MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(p_type.type_class));
|
MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type());
|
||||||
|
|
||||||
if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
|
if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
|
||||||
return Variant::ARRAY;
|
return Variant::ARRAY;
|
||||||
|
@ -162,12 +162,36 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
|
||||||
if (CACHED_CLASS(RID) == type_class) {
|
if (CACHED_CLASS(RID) == type_class) {
|
||||||
return Variant::_RID;
|
return Variant::_RID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (CACHED_CLASS(Dictionary) == type_class) {
|
||||||
|
return Variant::DICTIONARY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CACHED_CLASS(Array) == type_class) {
|
||||||
|
return Variant::ARRAY;
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case MONO_TYPE_GENERICINST: {
|
case MONO_TYPE_GENERICINST: {
|
||||||
if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_mono_ptr()) {
|
MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type());
|
||||||
|
|
||||||
|
MonoException *exc = NULL;
|
||||||
|
GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
|
||||||
|
MonoBoolean is_dict = type_is_dict((MonoObject *)reftype, (MonoObject **)&exc);
|
||||||
|
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||||
|
|
||||||
|
if (is_dict) {
|
||||||
return Variant::DICTIONARY;
|
return Variant::DICTIONARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exc = NULL;
|
||||||
|
GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
|
||||||
|
MonoBoolean is_array = type_is_array((MonoObject *)reftype, (MonoObject **)&exc);
|
||||||
|
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||||
|
|
||||||
|
if (is_array) {
|
||||||
|
return Variant::ARRAY;
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
|
@ -216,6 +240,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var) {
|
||||||
ManagedType type;
|
ManagedType type;
|
||||||
|
|
||||||
type.type_encoding = MONO_TYPE_OBJECT;
|
type.type_encoding = MONO_TYPE_OBJECT;
|
||||||
|
// type.type_class is not needed when we specify the MONO_TYPE_OBJECT encoding
|
||||||
|
|
||||||
return variant_to_mono_object(p_var, type);
|
return variant_to_mono_object(p_var, type);
|
||||||
}
|
}
|
||||||
|
@ -315,7 +340,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
|
||||||
|
|
||||||
case MONO_TYPE_ARRAY:
|
case MONO_TYPE_ARRAY:
|
||||||
case MONO_TYPE_SZARRAY: {
|
case MONO_TYPE_SZARRAY: {
|
||||||
MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(p_type.type_class));
|
MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type());
|
||||||
|
|
||||||
if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
|
if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
|
||||||
return (MonoObject *)Array_to_mono_array(p_var->operator Array());
|
return (MonoObject *)Array_to_mono_array(p_var->operator Array());
|
||||||
|
@ -360,6 +385,14 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
|
||||||
if (CACHED_CLASS(RID) == type_class) {
|
if (CACHED_CLASS(RID) == type_class) {
|
||||||
return GDMonoUtils::create_managed_from(p_var->operator RID());
|
return GDMonoUtils::create_managed_from(p_var->operator RID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (CACHED_CLASS(Dictionary) == type_class) {
|
||||||
|
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CACHED_CLASS(Array) == type_class) {
|
||||||
|
return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
case MONO_TYPE_OBJECT: {
|
case MONO_TYPE_OBJECT: {
|
||||||
// Variant
|
// Variant
|
||||||
|
@ -411,9 +444,9 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
|
||||||
return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *());
|
return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *());
|
||||||
}
|
}
|
||||||
case Variant::DICTIONARY:
|
case Variant::DICTIONARY:
|
||||||
return Dictionary_to_mono_object(p_var->operator Dictionary());
|
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
|
||||||
case Variant::ARRAY:
|
case Variant::ARRAY:
|
||||||
return (MonoObject *)Array_to_mono_array(p_var->operator Array());
|
return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
|
||||||
case Variant::POOL_BYTE_ARRAY:
|
case Variant::POOL_BYTE_ARRAY:
|
||||||
return (MonoObject *)PoolByteArray_to_mono_array(p_var->operator PoolByteArray());
|
return (MonoObject *)PoolByteArray_to_mono_array(p_var->operator PoolByteArray());
|
||||||
case Variant::POOL_INT_ARRAY:
|
case Variant::POOL_INT_ARRAY:
|
||||||
|
@ -433,8 +466,24 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MONO_TYPE_GENERICINST: {
|
case MONO_TYPE_GENERICINST: {
|
||||||
if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_mono_ptr()) {
|
MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type());
|
||||||
return Dictionary_to_mono_object(p_var->operator Dictionary());
|
|
||||||
|
MonoException *exc = NULL;
|
||||||
|
GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
|
||||||
|
MonoBoolean is_dict = type_is_dict((MonoObject *)reftype, (MonoObject **)&exc);
|
||||||
|
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||||
|
|
||||||
|
if (is_dict) {
|
||||||
|
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), p_type.type_class);
|
||||||
|
}
|
||||||
|
|
||||||
|
exc = NULL;
|
||||||
|
GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
|
||||||
|
MonoBoolean is_array = type_is_array((MonoObject *)reftype, (MonoObject **)&exc);
|
||||||
|
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||||
|
|
||||||
|
if (is_array) {
|
||||||
|
return GDMonoUtils::create_managed_from(p_var->operator Array(), p_type.type_class);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
} break;
|
} break;
|
||||||
|
@ -452,7 +501,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
|
||||||
GDMonoClass *tclass = GDMono::get_singleton()->get_class(mono_object_get_class(p_obj));
|
GDMonoClass *tclass = GDMono::get_singleton()->get_class(mono_object_get_class(p_obj));
|
||||||
ERR_FAIL_COND_V(!tclass, Variant());
|
ERR_FAIL_COND_V(!tclass, Variant());
|
||||||
|
|
||||||
MonoType *raw_type = tclass->get_raw_type(tclass);
|
MonoType *raw_type = tclass->get_mono_type();
|
||||||
|
|
||||||
ManagedType type;
|
ManagedType type;
|
||||||
|
|
||||||
|
@ -531,7 +580,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
|
||||||
|
|
||||||
case MONO_TYPE_ARRAY:
|
case MONO_TYPE_ARRAY:
|
||||||
case MONO_TYPE_SZARRAY: {
|
case MONO_TYPE_SZARRAY: {
|
||||||
MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(type.type_class));
|
MonoArrayType *array_type = mono_type_get_array_type(type.type_class->get_mono_type());
|
||||||
|
|
||||||
if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
|
if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
|
||||||
return mono_array_to_Array((MonoArray *)p_obj);
|
return mono_array_to_Array((MonoArray *)p_obj);
|
||||||
|
@ -579,11 +628,51 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
|
||||||
RID *ptr = unbox<RID *>(CACHED_FIELD(RID, ptr)->get_value(p_obj));
|
RID *ptr = unbox<RID *>(CACHED_FIELD(RID, ptr)->get_value(p_obj));
|
||||||
return ptr ? Variant(*ptr) : Variant();
|
return ptr ? Variant(*ptr) : Variant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (CACHED_CLASS(Array) == type_class) {
|
||||||
|
MonoException *exc = NULL;
|
||||||
|
GDMonoUtils::Array_GetPtr get_ptr = CACHED_METHOD_THUNK(Array, GetPtr);
|
||||||
|
Array *ptr = get_ptr(p_obj, (MonoObject **)&exc);
|
||||||
|
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||||
|
return ptr ? Variant(*ptr) : Variant();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CACHED_CLASS(Dictionary) == type_class) {
|
||||||
|
MonoException *exc = NULL;
|
||||||
|
GDMonoUtils::Dictionary_GetPtr get_ptr = CACHED_METHOD_THUNK(Dictionary, GetPtr);
|
||||||
|
Dictionary *ptr = get_ptr(p_obj, (MonoObject **)&exc);
|
||||||
|
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||||
|
return ptr ? Variant(*ptr) : Variant();
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case MONO_TYPE_GENERICINST: {
|
case MONO_TYPE_GENERICINST: {
|
||||||
if (CACHED_RAW_MONO_CLASS(Dictionary) == type.type_class->get_mono_ptr()) {
|
MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type.type_class->get_mono_type());
|
||||||
return mono_object_to_Dictionary(p_obj);
|
|
||||||
|
MonoException *exc = NULL;
|
||||||
|
|
||||||
|
GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
|
||||||
|
MonoBoolean is_dict = type_is_dict((MonoObject *)reftype, (MonoObject **)&exc);
|
||||||
|
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||||
|
|
||||||
|
if (is_dict) {
|
||||||
|
MonoException *exc = NULL;
|
||||||
|
MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
|
||||||
|
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||||
|
return *unbox<Dictionary *>(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
exc = NULL;
|
||||||
|
|
||||||
|
GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
|
||||||
|
MonoBoolean is_array = type_is_array((MonoObject *)reftype, (MonoObject **)&exc);
|
||||||
|
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||||
|
|
||||||
|
if (is_array) {
|
||||||
|
MonoException *exc = NULL;
|
||||||
|
MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
|
||||||
|
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||||
|
return *unbox<Array *>(ret);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
@ -822,66 +911,4 @@ PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array) {
|
||||||
|
|
||||||
return ret;
|
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);
|
|
||||||
|
|
||||||
MonoException *exc = NULL;
|
|
||||||
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
|
||||||
MonoObject *ret = arrays_to_dict(keys, values, (MonoObject **)&exc);
|
|
||||||
GD_MONO_END_RUNTIME_INVOKE;
|
|
||||||
|
|
||||||
if (exc) {
|
|
||||||
GDMonoUtils::set_pending_exception(exc);
|
|
||||||
ERR_FAIL_V(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary mono_object_to_Dictionary(MonoObject *p_dict) {
|
|
||||||
Dictionary ret;
|
|
||||||
|
|
||||||
if (!p_dict)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
GDMonoUtils::MarshalUtils_DictToArrays dict_to_arrays = CACHED_METHOD_THUNK(MarshalUtils, DictionaryToArrays);
|
|
||||||
|
|
||||||
MonoArray *keys = NULL;
|
|
||||||
MonoArray *values = NULL;
|
|
||||||
MonoException *exc = NULL;
|
|
||||||
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
|
||||||
dict_to_arrays(p_dict, &keys, &values, (MonoObject **)&exc);
|
|
||||||
GD_MONO_END_RUNTIME_INVOKE;
|
|
||||||
|
|
||||||
if (exc) {
|
|
||||||
GDMonoUtils::set_pending_exception(exc);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
} // namespace GDMonoMarshal
|
} // namespace GDMonoMarshal
|
||||||
|
|
|
@ -143,11 +143,6 @@ PoolVector2Array mono_array_to_PoolVector2Array(MonoArray *p_array);
|
||||||
MonoArray *PoolVector3Array_to_mono_array(const PoolVector3Array &p_array);
|
MonoArray *PoolVector3Array_to_mono_array(const PoolVector3Array &p_array);
|
||||||
PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *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
|
#ifdef YOLO_COPY
|
||||||
#define MARSHALLED_OUT(m_t, m_in, m_out) m_t *m_out = (m_t *)&m_in;
|
#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);
|
#define MARSHALLED_IN(m_t, m_in, m_out) m_t m_out = *reinterpret_cast<m_t *>(m_in);
|
||||||
|
|
|
@ -139,23 +139,8 @@ bool GDMonoProperty::has_setter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc) {
|
void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc) {
|
||||||
MonoMethod *prop_method = mono_property_get_set_method(mono_property);
|
void *params[1] = { p_value };
|
||||||
|
set_value(p_object, params, r_exc);
|
||||||
MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), 1);
|
|
||||||
mono_array_set(params, MonoObject *, 0, p_value);
|
|
||||||
|
|
||||||
MonoException *exc = NULL;
|
|
||||||
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
|
||||||
mono_runtime_invoke_array(prop_method, p_object, params, (MonoObject **)&exc);
|
|
||||||
GD_MONO_END_RUNTIME_INVOKE;
|
|
||||||
|
|
||||||
if (exc) {
|
|
||||||
if (r_exc) {
|
|
||||||
*r_exc = exc;
|
|
||||||
} else {
|
|
||||||
GDMonoUtils::set_pending_exception(exc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GDMonoProperty::set_value(MonoObject *p_object, void **p_params, MonoException **r_exc) {
|
void GDMonoProperty::set_value(MonoObject *p_object, void **p_params, MonoException **r_exc) {
|
||||||
|
|
|
@ -87,6 +87,8 @@ void MonoCache::clear_members() {
|
||||||
method_System_Diagnostics_StackTrace_ctor_Exception_bool = NULL;
|
method_System_Diagnostics_StackTrace_ctor_Exception_bool = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class_KeyNotFoundException = NULL;
|
||||||
|
|
||||||
rawclass_Dictionary = NULL;
|
rawclass_Dictionary = NULL;
|
||||||
|
|
||||||
class_Vector2 = NULL;
|
class_Vector2 = NULL;
|
||||||
|
@ -107,6 +109,8 @@ void MonoCache::clear_members() {
|
||||||
class_Control = NULL;
|
class_Control = NULL;
|
||||||
class_Spatial = NULL;
|
class_Spatial = NULL;
|
||||||
class_WeakRef = NULL;
|
class_WeakRef = NULL;
|
||||||
|
class_Array = NULL;
|
||||||
|
class_Dictionary = NULL;
|
||||||
class_MarshalUtils = NULL;
|
class_MarshalUtils = NULL;
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
|
@ -134,8 +138,10 @@ void MonoCache::clear_members() {
|
||||||
field_Image_ptr = NULL;
|
field_Image_ptr = NULL;
|
||||||
field_RID_ptr = NULL;
|
field_RID_ptr = NULL;
|
||||||
|
|
||||||
methodthunk_MarshalUtils_DictionaryToArrays = NULL;
|
methodthunk_Array_GetPtr = NULL;
|
||||||
methodthunk_MarshalUtils_ArraysToDictionary = NULL;
|
methodthunk_Dictionary_GetPtr = NULL;
|
||||||
|
methodthunk_MarshalUtils_IsArrayGenericType = NULL;
|
||||||
|
methodthunk_MarshalUtils_IsDictionaryGenericType = NULL;
|
||||||
methodthunk_SignalAwaiter_SignalCallback = NULL;
|
methodthunk_SignalAwaiter_SignalCallback = NULL;
|
||||||
methodthunk_SignalAwaiter_FailureCallback = NULL;
|
methodthunk_SignalAwaiter_FailureCallback = NULL;
|
||||||
methodthunk_GodotTaskScheduler_Activate = NULL;
|
methodthunk_GodotTaskScheduler_Activate = NULL;
|
||||||
|
@ -175,6 +181,8 @@ void update_corlib_cache() {
|
||||||
CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_Exception_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(System.Exception,bool)", true));
|
CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_Exception_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(System.Exception,bool)", true));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
CACHE_CLASS_AND_CHECK(KeyNotFoundException, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections.Generic", "KeyNotFoundException"));
|
||||||
|
|
||||||
mono_cache.corlib_cache_updated = true;
|
mono_cache.corlib_cache_updated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,6 +206,8 @@ void update_godot_api_cache() {
|
||||||
CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control));
|
CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control));
|
||||||
CACHE_CLASS_AND_CHECK(Spatial, GODOT_API_CLASS(Spatial));
|
CACHE_CLASS_AND_CHECK(Spatial, GODOT_API_CLASS(Spatial));
|
||||||
CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef));
|
CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef));
|
||||||
|
CACHE_CLASS_AND_CHECK(Array, GODOT_API_CLASS(Array));
|
||||||
|
CACHE_CLASS_AND_CHECK(Dictionary, GODOT_API_CLASS(Dictionary));
|
||||||
CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils));
|
CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils));
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
|
@ -224,8 +234,10 @@ void update_godot_api_cache() {
|
||||||
CACHE_FIELD_AND_CHECK(NodePath, ptr, CACHED_CLASS(NodePath)->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_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(Array, GetPtr, (Array_GetPtr)GODOT_API_CLASS(Array)->get_method("GetPtr", 0)->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(Dictionary, GetPtr, (Dictionary_GetPtr)GODOT_API_CLASS(Dictionary)->get_method("GetPtr", 0)->get_thunk());
|
||||||
|
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsArrayGenericType, (IsArrayGenericType)GODOT_API_CLASS(MarshalUtils)->get_method("IsArrayGenericType", 1)->get_thunk());
|
||||||
|
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsDictionaryGenericType, (IsDictionaryGenericType)GODOT_API_CLASS(MarshalUtils)->get_method("IsDictionaryGenericType", 1)->get_thunk());
|
||||||
CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, (SignalAwaiter_SignalCallback)GODOT_API_CLASS(SignalAwaiter)->get_method("SignalCallback", 1)->get_thunk());
|
CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, (SignalAwaiter_SignalCallback)GODOT_API_CLASS(SignalAwaiter)->get_method("SignalCallback", 1)->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(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());
|
CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method("Activate", 0)->get_thunk());
|
||||||
|
@ -234,24 +246,9 @@ void update_godot_api_cache() {
|
||||||
CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, (DebugUtils_StackFrameInfo)GODOT_API_CLASS(DebuggingUtils)->get_method("GetStackFrameInfo", 4)->get_thunk());
|
CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, (DebugUtils_StackFrameInfo)GODOT_API_CLASS(DebuggingUtils)->get_method("GetStackFrameInfo", 4)->get_thunk());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{
|
// TODO Move to CSharpLanguage::init()
|
||||||
/*
|
|
||||||
* 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_mono_ptr());
|
MonoObject *task_scheduler = mono_object_new(SCRIPTS_DOMAIN, GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr());
|
||||||
mono_runtime_object_init(task_scheduler);
|
GDMonoUtils::runtime_object_init(task_scheduler);
|
||||||
mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler);
|
mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler);
|
||||||
|
|
||||||
mono_cache.godot_api_cache_updated = true;
|
mono_cache.godot_api_cache_updated = true;
|
||||||
|
@ -304,6 +301,12 @@ MonoThread *get_current_thread() {
|
||||||
return mono_thread_current();
|
return mono_thread_current();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void runtime_object_init(MonoObject *p_this_obj) {
|
||||||
|
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||||
|
mono_runtime_object_init(p_this_obj);
|
||||||
|
GD_MONO_END_RUNTIME_INVOKE;
|
||||||
|
}
|
||||||
|
|
||||||
GDMonoClass *get_object_class(MonoObject *p_object) {
|
GDMonoClass *get_object_class(MonoObject *p_object) {
|
||||||
return GDMono::get_singleton()->get_class(mono_object_get_class(p_object));
|
return GDMono::get_singleton()->get_class(mono_object_get_class(p_object));
|
||||||
}
|
}
|
||||||
|
@ -358,7 +361,7 @@ MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringNa
|
||||||
CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, p_object);
|
CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, p_object);
|
||||||
|
|
||||||
// Construct
|
// Construct
|
||||||
mono_runtime_object_init(mono_object);
|
GDMonoUtils::runtime_object_init(mono_object);
|
||||||
|
|
||||||
return mono_object;
|
return mono_object;
|
||||||
}
|
}
|
||||||
|
@ -368,7 +371,7 @@ MonoObject *create_managed_from(const NodePath &p_from) {
|
||||||
ERR_FAIL_NULL_V(mono_object, NULL);
|
ERR_FAIL_NULL_V(mono_object, NULL);
|
||||||
|
|
||||||
// Construct
|
// Construct
|
||||||
mono_runtime_object_init(mono_object);
|
GDMonoUtils::runtime_object_init(mono_object);
|
||||||
|
|
||||||
CACHED_FIELD(NodePath, ptr)->set_value_raw(mono_object, memnew(NodePath(p_from)));
|
CACHED_FIELD(NodePath, ptr)->set_value_raw(mono_object, memnew(NodePath(p_from)));
|
||||||
|
|
||||||
|
@ -380,13 +383,73 @@ MonoObject *create_managed_from(const RID &p_from) {
|
||||||
ERR_FAIL_NULL_V(mono_object, NULL);
|
ERR_FAIL_NULL_V(mono_object, NULL);
|
||||||
|
|
||||||
// Construct
|
// Construct
|
||||||
mono_runtime_object_init(mono_object);
|
GDMonoUtils::runtime_object_init(mono_object);
|
||||||
|
|
||||||
CACHED_FIELD(RID, ptr)->set_value_raw(mono_object, memnew(RID(p_from)));
|
CACHED_FIELD(RID, ptr)->set_value_raw(mono_object, memnew(RID(p_from)));
|
||||||
|
|
||||||
return mono_object;
|
return mono_object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class) {
|
||||||
|
MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, p_class->get_mono_ptr());
|
||||||
|
ERR_FAIL_NULL_V(mono_object, NULL);
|
||||||
|
|
||||||
|
// Search constructor that takes a pointer as parameter
|
||||||
|
MonoMethod *m;
|
||||||
|
void *iter = NULL;
|
||||||
|
while ((m = mono_class_get_methods(p_class->get_mono_ptr(), &iter))) {
|
||||||
|
if (strcmp(mono_method_get_name(m), ".ctor") == 0) {
|
||||||
|
MonoMethodSignature *sig = mono_method_signature(m);
|
||||||
|
void *front = NULL;
|
||||||
|
if (mono_signature_get_param_count(sig) == 1 &&
|
||||||
|
mono_class_from_mono_type(mono_signature_get_params(sig, &front)) == CACHED_CLASS(IntPtr)->get_mono_ptr()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CRASH_COND(m == NULL);
|
||||||
|
|
||||||
|
Array *new_array = memnew(Array(p_from));
|
||||||
|
void *args[1] = { &new_array };
|
||||||
|
|
||||||
|
MonoException *exc = NULL;
|
||||||
|
mono_runtime_invoke(m, mono_object, args, (MonoObject **)&exc);
|
||||||
|
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||||
|
|
||||||
|
return mono_object;
|
||||||
|
}
|
||||||
|
|
||||||
|
MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class) {
|
||||||
|
MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, p_class->get_mono_ptr());
|
||||||
|
ERR_FAIL_NULL_V(mono_object, NULL);
|
||||||
|
|
||||||
|
// Search constructor that takes a pointer as parameter
|
||||||
|
MonoMethod *m;
|
||||||
|
void *iter = NULL;
|
||||||
|
while ((m = mono_class_get_methods(p_class->get_mono_ptr(), &iter))) {
|
||||||
|
if (strcmp(mono_method_get_name(m), ".ctor") == 0) {
|
||||||
|
MonoMethodSignature *sig = mono_method_signature(m);
|
||||||
|
void *front = NULL;
|
||||||
|
if (mono_signature_get_param_count(sig) == 1 &&
|
||||||
|
mono_class_from_mono_type(mono_signature_get_params(sig, &front)) == CACHED_CLASS(IntPtr)->get_mono_ptr()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CRASH_COND(m == NULL);
|
||||||
|
|
||||||
|
Dictionary *new_dict = memnew(Dictionary(p_from));
|
||||||
|
void *args[1] = { &new_dict };
|
||||||
|
|
||||||
|
MonoException *exc = NULL;
|
||||||
|
mono_runtime_invoke(m, mono_object, args, (MonoObject **)&exc);
|
||||||
|
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||||
|
|
||||||
|
return mono_object;
|
||||||
|
}
|
||||||
|
|
||||||
MonoDomain *create_domain(const String &p_friendly_name) {
|
MonoDomain *create_domain(const String &p_friendly_name) {
|
||||||
MonoDomain *domain = mono_domain_create_appdomain((char *)p_friendly_name.utf8().get_data(), NULL);
|
MonoDomain *domain = mono_domain_create_appdomain((char *)p_friendly_name.utf8().get_data(), NULL);
|
||||||
|
|
||||||
|
@ -400,10 +463,10 @@ MonoDomain *create_domain(const String &p_friendly_name) {
|
||||||
return domain;
|
return domain;
|
||||||
}
|
}
|
||||||
|
|
||||||
String get_exception_name_and_message(MonoException *p_ex) {
|
String get_exception_name_and_message(MonoException *p_exc) {
|
||||||
String res;
|
String res;
|
||||||
|
|
||||||
MonoClass *klass = mono_object_get_class((MonoObject *)p_ex);
|
MonoClass *klass = mono_object_get_class((MonoObject *)p_exc);
|
||||||
MonoType *type = mono_class_get_type(klass);
|
MonoType *type = mono_class_get_type(klass);
|
||||||
|
|
||||||
char *full_name = mono_type_full_name(type);
|
char *full_name = mono_type_full_name(type);
|
||||||
|
@ -413,12 +476,24 @@ String get_exception_name_and_message(MonoException *p_ex) {
|
||||||
res += ": ";
|
res += ": ";
|
||||||
|
|
||||||
MonoProperty *prop = mono_class_get_property_from_name(klass, "Message");
|
MonoProperty *prop = mono_class_get_property_from_name(klass, "Message");
|
||||||
MonoString *msg = (MonoString *)mono_property_get_value(prop, (MonoObject *)p_ex, NULL, NULL);
|
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||||
|
MonoString *msg = (MonoString *)mono_property_get_value(prop, (MonoObject *)p_exc, NULL, NULL);
|
||||||
|
GD_MONO_END_RUNTIME_INVOKE;
|
||||||
res += GDMonoMarshal::mono_string_to_godot(msg);
|
res += GDMonoMarshal::mono_string_to_godot(msg);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_exception_message(MonoException *p_exc, String message) {
|
||||||
|
MonoClass *klass = mono_object_get_class((MonoObject *)p_exc);
|
||||||
|
MonoProperty *prop = mono_class_get_property_from_name(klass, "Message");
|
||||||
|
MonoString *msg = GDMonoMarshal::mono_string_from_godot(message);
|
||||||
|
void *params[1] = { msg };
|
||||||
|
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||||
|
mono_property_set_value(prop, (MonoObject *)p_exc, params, NULL);
|
||||||
|
GD_MONO_END_RUNTIME_INVOKE;
|
||||||
|
}
|
||||||
|
|
||||||
void debug_print_unhandled_exception(MonoException *p_exc) {
|
void debug_print_unhandled_exception(MonoException *p_exc) {
|
||||||
print_unhandled_exception(p_exc);
|
print_unhandled_exception(p_exc);
|
||||||
debug_send_unhandled_exception_error(p_exc);
|
debug_send_unhandled_exception_error(p_exc);
|
||||||
|
|
|
@ -41,14 +41,24 @@
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "reference.h"
|
#include "reference.h"
|
||||||
|
|
||||||
|
#define UNLIKELY_UNHANDLED_EXCEPTION(m_exc) \
|
||||||
|
if (unlikely(m_exc != NULL)) { \
|
||||||
|
GDMonoUtils::debug_unhandled_exception(m_exc); \
|
||||||
|
_UNREACHABLE_(); \
|
||||||
|
}
|
||||||
|
|
||||||
namespace GDMonoUtils {
|
namespace GDMonoUtils {
|
||||||
|
|
||||||
typedef MonoObject *(*MarshalUtils_DictToArrays)(MonoObject *, MonoArray **, MonoArray **, MonoObject **);
|
typedef Array *(*Array_GetPtr)(MonoObject *, MonoObject **);
|
||||||
typedef MonoObject *(*MarshalUtils_ArraysToDict)(MonoArray *, MonoArray *, MonoObject **);
|
typedef Dictionary *(*Dictionary_GetPtr)(MonoObject *, MonoObject **);
|
||||||
typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray *, MonoObject **);
|
typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray *, MonoObject **);
|
||||||
typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoObject **);
|
typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoObject **);
|
||||||
typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoObject **);
|
typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoObject **);
|
||||||
typedef MonoArray *(*StackTrace_GetFrames)(MonoObject *, MonoObject **);
|
typedef MonoArray *(*StackTrace_GetFrames)(MonoObject *, MonoObject **);
|
||||||
|
typedef MonoBoolean (*IsArrayGenericType)(MonoObject *, MonoObject **);
|
||||||
|
typedef MonoBoolean (*IsDictionaryGenericType)(MonoObject *, MonoObject **);
|
||||||
|
typedef MonoBoolean (*IsArrayGenericType)(MonoObject *, MonoObject **);
|
||||||
|
typedef MonoBoolean (*IsDictionaryGenericType)(MonoObject *, MonoObject **);
|
||||||
typedef void (*DebugUtils_StackFrameInfo)(MonoObject *, MonoString **, int *, MonoString **, MonoObject **);
|
typedef void (*DebugUtils_StackFrameInfo)(MonoObject *, MonoString **, int *, MonoString **, MonoObject **);
|
||||||
|
|
||||||
struct MonoCache {
|
struct MonoCache {
|
||||||
|
@ -79,6 +89,8 @@ struct MonoCache {
|
||||||
GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool;
|
GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
GDMonoClass *class_KeyNotFoundException;
|
||||||
|
|
||||||
MonoClass *rawclass_Dictionary;
|
MonoClass *rawclass_Dictionary;
|
||||||
// -----------------------------------------------
|
// -----------------------------------------------
|
||||||
|
|
||||||
|
@ -100,6 +112,8 @@ struct MonoCache {
|
||||||
GDMonoClass *class_Control;
|
GDMonoClass *class_Control;
|
||||||
GDMonoClass *class_Spatial;
|
GDMonoClass *class_Spatial;
|
||||||
GDMonoClass *class_WeakRef;
|
GDMonoClass *class_WeakRef;
|
||||||
|
GDMonoClass *class_Array;
|
||||||
|
GDMonoClass *class_Dictionary;
|
||||||
GDMonoClass *class_MarshalUtils;
|
GDMonoClass *class_MarshalUtils;
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
|
@ -127,8 +141,10 @@ struct MonoCache {
|
||||||
GDMonoField *field_Image_ptr;
|
GDMonoField *field_Image_ptr;
|
||||||
GDMonoField *field_RID_ptr;
|
GDMonoField *field_RID_ptr;
|
||||||
|
|
||||||
MarshalUtils_DictToArrays methodthunk_MarshalUtils_DictionaryToArrays;
|
Array_GetPtr methodthunk_Array_GetPtr;
|
||||||
MarshalUtils_ArraysToDict methodthunk_MarshalUtils_ArraysToDictionary;
|
Dictionary_GetPtr methodthunk_Dictionary_GetPtr;
|
||||||
|
IsArrayGenericType methodthunk_MarshalUtils_IsArrayGenericType;
|
||||||
|
IsDictionaryGenericType methodthunk_MarshalUtils_IsDictionaryGenericType;
|
||||||
SignalAwaiter_SignalCallback methodthunk_SignalAwaiter_SignalCallback;
|
SignalAwaiter_SignalCallback methodthunk_SignalAwaiter_SignalCallback;
|
||||||
SignalAwaiter_FailureCallback methodthunk_SignalAwaiter_FailureCallback;
|
SignalAwaiter_FailureCallback methodthunk_SignalAwaiter_FailureCallback;
|
||||||
GodotTaskScheduler_Activate methodthunk_GodotTaskScheduler_Activate;
|
GodotTaskScheduler_Activate methodthunk_GodotTaskScheduler_Activate;
|
||||||
|
@ -175,6 +191,8 @@ _FORCE_INLINE_ bool is_main_thread() {
|
||||||
return mono_domain_get() != NULL && mono_thread_get_main() == mono_thread_current();
|
return mono_domain_get() != NULL && mono_thread_get_main() == mono_thread_current();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void runtime_object_init(MonoObject *p_this_obj);
|
||||||
|
|
||||||
GDMonoClass *get_object_class(MonoObject *p_object);
|
GDMonoClass *get_object_class(MonoObject *p_object);
|
||||||
GDMonoClass *type_get_proxy_class(const StringName &p_type);
|
GDMonoClass *type_get_proxy_class(const StringName &p_type);
|
||||||
GDMonoClass *get_class_native_base(GDMonoClass *p_class);
|
GDMonoClass *get_class_native_base(GDMonoClass *p_class);
|
||||||
|
@ -183,10 +201,13 @@ MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringNa
|
||||||
|
|
||||||
MonoObject *create_managed_from(const NodePath &p_from);
|
MonoObject *create_managed_from(const NodePath &p_from);
|
||||||
MonoObject *create_managed_from(const RID &p_from);
|
MonoObject *create_managed_from(const RID &p_from);
|
||||||
|
MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class);
|
||||||
|
MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class);
|
||||||
|
|
||||||
MonoDomain *create_domain(const String &p_friendly_name);
|
MonoDomain *create_domain(const String &p_friendly_name);
|
||||||
|
|
||||||
String get_exception_name_and_message(MonoException *p_ex);
|
String get_exception_name_and_message(MonoException *p_exc);
|
||||||
|
void set_exception_message(MonoException *p_exc, String message);
|
||||||
|
|
||||||
void debug_print_unhandled_exception(MonoException *p_exc);
|
void debug_print_unhandled_exception(MonoException *p_exc);
|
||||||
void debug_send_unhandled_exception_error(MonoException *p_exc);
|
void debug_send_unhandled_exception_error(MonoException *p_exc);
|
||||||
|
|
Loading…
Reference in New Issue