C#: Code cleanup and greatly reduce use of C# pointers

This commit is contained in:
Ignacio Roldán Etcheverry 2021-12-28 23:25:16 +01:00
parent 34db8d2c6c
commit e5e7a795b1
51 changed files with 2195 additions and 1347 deletions

View file

@ -12,3 +12,32 @@ insert_final_newline = true
trim_trailing_whitespace = true
max_line_length = 120
csharp_indent_case_contents_when_block = false
[*.cs]
# CA1707: Identifiers should not contain underscores
# TODO:
# Maybe we could disable this selectively only
# where it's not desired and for generated code.
dotnet_diagnostic.CA1707.severity = none
# CA1711: Identifiers should not have incorrect suffix
# Disable warning for suffixes like EventHandler, Flags, Enum, etc.
dotnet_diagnostic.CA1711.severity = none
# CA1716: Identifiers should not match keywords
# TODO: We should look into this.
dotnet_diagnostic.CA1716.severity = warning
# CA1720: Identifiers should not contain type names
dotnet_diagnostic.CA1720.severity = none
# CA1805: Do not initialize unnecessarily
# Don't tell me what to do.
dotnet_diagnostic.CA1805.severity = none
# CA1304: Specify CultureInfo
# TODO: We should look into this.
dotnet_diagnostic.CA1304.severity = warning
# CA1305: Specify IFormatProvider
# TODO: We should look into this. Disabled for now because it's annoying.
dotnet_diagnostic.CA1305.severity = none
# CA1310: Specify StringComparison for correctness
# TODO: We should look into this. Disabled for now because it's annoying.
dotnet_diagnostic.CA1310.severity = none
# Diagnostics to prevent defensive copies of `in` struct parameters
resharper_possibly_impure_method_call_on_readonly_variable_highlighting = error

View file

@ -1,2 +1,5 @@
# Do not ignore solution files inside the mono module. Overrides Godot's global gitignore.
!*.sln
# Fody
FodyWeavers.xsd

View file

@ -104,7 +104,7 @@ Error CSharpLanguage::execute_file(const String &p_path) {
return OK;
}
extern void *godotsharp_pinvoke_funcs[176];
extern void *godotsharp_pinvoke_funcs[178];
[[maybe_unused]] volatile void **do_not_strip_godotsharp_pinvoke_funcs;
#ifdef TOOLS_ENABLED
extern void *godotsharp_editor_pinvoke_funcs[32];

View file

@ -8,8 +8,8 @@
</Target>
<Target Name="GenerateGodotNupkgsVersionsFile"
DependsOnTargets="PrepareForBuild;_GenerateGodotNupkgsVersionsFile"
BeforeTargets="BeforeCompile;CoreCompile">
DependsOnTargets="_GenerateGodotNupkgsVersionsFile"
BeforeTargets="PrepareForBuild;CompileDesignTime;BeforeCompile;CoreCompile">
<ItemGroup>
<Compile Include="$(GeneratedGodotNupkgsVersionsFile)" />
<FileWrites Include="$(GeneratedGodotNupkgsVersionsFile)" />

View file

@ -1,6 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<!-- Specify compile items manually to avoid including dangling generated items. -->
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
</PropertyGroup>
<Import Project="GenerateGodotNupkgsVersions.targets" />
</Project>

View file

@ -233,11 +233,11 @@ namespace GodotTools.Export
}
}
var initialAssemblies = assemblies.Duplicate();
godot_dictionary initialAssembliesAux = ((Godot.Collections.Dictionary)initialAssemblies).NativeValue;
using godot_string buildConfigAux = Marshaling.mono_string_to_godot(buildConfig);
using godot_string bclDirAux = Marshaling.mono_string_to_godot(bclDir);
godot_dictionary assembliesAux = ((Godot.Collections.Dictionary)assemblies).NativeValue;
// var initialAssemblies = assemblies.Duplicate();
// godot_dictionary initialAssembliesAux = ((Godot.Collections.Dictionary)initialAssemblies).NativeValue;
// using godot_string buildConfigAux = Marshaling.ConvertStringToNative(buildConfig);
// using godot_string bclDirAux = Marshaling.ConvertStringToNative(bclDir);
// godot_dictionary assembliesAux = ((Godot.Collections.Dictionary)assemblies).NativeValue;
// TODO
throw new NotImplementedException();
//internal_GetExportedAssemblyDependencies(initialAssembliesAux, buildConfigAux, bclDirAux, ref assembliesAux);

View file

@ -12,8 +12,8 @@ namespace GodotTools.Internals
public EditorProgress(string task, string label, int amount, bool canCancel = false)
{
Task = task;
using godot_string taskIn = Marshaling.mono_string_to_godot(task);
using godot_string labelIn = Marshaling.mono_string_to_godot(label);
using godot_string taskIn = Marshaling.ConvertStringToNative(task);
using godot_string labelIn = Marshaling.ConvertStringToNative(label);
Internal.godot_icall_EditorProgress_Create(taskIn, labelIn, amount, canCancel);
}
@ -27,22 +27,22 @@ namespace GodotTools.Internals
public void Dispose()
{
using godot_string taskIn = Marshaling.mono_string_to_godot(Task);
using godot_string taskIn = Marshaling.ConvertStringToNative(Task);
Internal.godot_icall_EditorProgress_Dispose(taskIn);
GC.SuppressFinalize(this);
}
public void Step(string state, int step = -1, bool forceRefresh = true)
{
using godot_string taskIn = Marshaling.mono_string_to_godot(Task);
using godot_string stateIn = Marshaling.mono_string_to_godot(state);
using godot_string taskIn = Marshaling.ConvertStringToNative(Task);
using godot_string stateIn = Marshaling.ConvertStringToNative(state);
Internal.godot_icall_EditorProgress_Step(taskIn, stateIn, step, forceRefresh);
}
public bool TryStep(string state, int step = -1, bool forceRefresh = true)
{
using godot_string taskIn = Marshaling.mono_string_to_godot(Task);
using godot_string stateIn = Marshaling.mono_string_to_godot(state);
using godot_string taskIn = Marshaling.ConvertStringToNative(Task);
using godot_string stateIn = Marshaling.ConvertStringToNative(state);
return Internal.godot_icall_EditorProgress_Step(taskIn, stateIn, step, forceRefresh);
}
}

View file

@ -10,37 +10,37 @@ namespace GodotTools.Internals
public static unsafe object GlobalDef(string setting, object defaultValue, bool restartIfChanged = false)
{
using godot_string settingIn = Marshaling.mono_string_to_godot(setting);
using godot_variant defaultValueIn = Marshaling.mono_object_to_variant(defaultValue);
using godot_string settingIn = Marshaling.ConvertStringToNative(setting);
using godot_variant defaultValueIn = Marshaling.ConvertManagedObjectToVariant(defaultValue);
Internal.godot_icall_Globals_GlobalDef(settingIn, defaultValueIn, restartIfChanged, out godot_variant result);
using (result)
return Marshaling.variant_to_mono_object(&result);
return Marshaling.ConvertVariantToManagedObject(result);
}
public static unsafe object EditorDef(string setting, object defaultValue, bool restartIfChanged = false)
{
using godot_string settingIn = Marshaling.mono_string_to_godot(setting);
using godot_variant defaultValueIn = Marshaling.mono_object_to_variant(defaultValue);
using godot_string settingIn = Marshaling.ConvertStringToNative(setting);
using godot_variant defaultValueIn = Marshaling.ConvertManagedObjectToVariant(defaultValue);
Internal.godot_icall_Globals_EditorDef(settingIn, defaultValueIn, restartIfChanged, out godot_variant result);
using (result)
return Marshaling.variant_to_mono_object(&result);
return Marshaling.ConvertVariantToManagedObject(result);
}
public static unsafe object EditorShortcut(string setting)
public static object EditorShortcut(string setting)
{
using godot_string settingIn = Marshaling.mono_string_to_godot(setting);
using godot_string settingIn = Marshaling.ConvertStringToNative(setting);
Internal.godot_icall_Globals_EditorShortcut(settingIn, out godot_variant result);
using (result)
return Marshaling.variant_to_mono_object(&result);
return Marshaling.ConvertVariantToManagedObject(result);
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public static string TTR(this string text)
{
using godot_string textIn = Marshaling.mono_string_to_godot(text);
using godot_string textIn = Marshaling.ConvertStringToNative(text);
Internal.godot_icall_Globals_TTR(textIn, out godot_string dest);
using (dest)
return Marshaling.mono_string_from_godot(dest);
return Marshaling.ConvertStringToManaged(dest);
}
}
}

View file

@ -11,7 +11,7 @@ namespace GodotTools.Internals
{
Internal.godot_icall_GodotSharpDirs_ResMetadataDir(out godot_string dest);
using (dest)
return Marshaling.mono_string_from_godot(dest);
return Marshaling.ConvertStringToManaged(dest);
}
}
@ -21,7 +21,7 @@ namespace GodotTools.Internals
{
Internal.godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir(out godot_string dest);
using (dest)
return Marshaling.mono_string_from_godot(dest);
return Marshaling.ConvertStringToManaged(dest);
}
}
@ -31,7 +31,7 @@ namespace GodotTools.Internals
{
Internal.godot_icall_GodotSharpDirs_MonoUserDir(out godot_string dest);
using (dest)
return Marshaling.mono_string_from_godot(dest);
return Marshaling.ConvertStringToManaged(dest);
}
}
@ -41,7 +41,7 @@ namespace GodotTools.Internals
{
Internal.godot_icall_GodotSharpDirs_BuildLogsDirs(out godot_string dest);
using (dest)
return Marshaling.mono_string_from_godot(dest);
return Marshaling.ConvertStringToManaged(dest);
}
}
@ -51,7 +51,7 @@ namespace GodotTools.Internals
{
Internal.godot_icall_GodotSharpDirs_ProjectSlnPath(out godot_string dest);
using (dest)
return Marshaling.mono_string_from_godot(dest);
return Marshaling.ConvertStringToManaged(dest);
}
}
@ -61,7 +61,7 @@ namespace GodotTools.Internals
{
Internal.godot_icall_GodotSharpDirs_ProjectCsProjPath(out godot_string dest);
using (dest)
return Marshaling.mono_string_from_godot(dest);
return Marshaling.ConvertStringToManaged(dest);
}
}
@ -71,7 +71,7 @@ namespace GodotTools.Internals
{
Internal.godot_icall_GodotSharpDirs_DataEditorToolsDir(out godot_string dest);
using (dest)
return Marshaling.mono_string_from_godot(dest);
return Marshaling.ConvertStringToManaged(dest);
}
}
}

View file

@ -18,7 +18,7 @@ namespace GodotTools.Internals
{
godot_icall_Internal_FullExportTemplatesDir(out godot_string dest);
using (dest)
return Marshaling.mono_string_from_godot(dest);
return Marshaling.ConvertStringToManaged(dest);
}
}
@ -26,7 +26,7 @@ namespace GodotTools.Internals
public static bool IsMacOSAppBundleInstalled(string bundleId)
{
using godot_string bundleIdIn = Marshaling.mono_string_to_godot(bundleId);
using godot_string bundleIdIn = Marshaling.ConvertStringToNative(bundleId);
return godot_icall_Internal_IsMacOSAppBundleInstalled(bundleIdIn);
}
@ -53,7 +53,7 @@ namespace GodotTools.Internals
{
godot_icall_Internal_MonoWindowsInstallRoot(out godot_string dest);
using (dest)
return Marshaling.mono_string_from_godot(dest);
return Marshaling.ConvertStringToManaged(dest);
}
}
@ -67,10 +67,10 @@ namespace GodotTools.Internals
public static unsafe string[] CodeCompletionRequest(CodeCompletionRequest.CompletionKind kind,
string scriptFile)
{
using godot_string scriptFileIn = Marshaling.mono_string_to_godot(scriptFile);
using godot_string scriptFileIn = Marshaling.ConvertStringToNative(scriptFile);
godot_icall_Internal_CodeCompletionRequest((int)kind, scriptFileIn, out godot_packed_string_array res);
using (res)
return Marshaling.PackedStringArray_to_mono_array(&res);
return Marshaling.ConvertNativePackedStringArrayToSystemArray(res);
}
#region Internal

View file

@ -63,7 +63,7 @@ namespace GodotTools.Utils
Internal.godot_icall_Utils_OS_GetPlatformName(out godot_string dest);
using (dest)
{
string platformName = Marshaling.mono_string_from_godot(dest);
string platformName = Marshaling.ConvertStringToManaged(dest);
return name.Equals(platformName, StringComparison.OrdinalIgnoreCase);
}
}
@ -73,7 +73,7 @@ namespace GodotTools.Utils
Internal.godot_icall_Utils_OS_GetPlatformName(out godot_string dest);
using (dest)
{
string platformName = Marshaling.mono_string_from_godot(dest);
string platformName = Marshaling.ConvertStringToManaged(dest);
return names.Any(p => p.Equals(platformName, StringComparison.OrdinalIgnoreCase));
}
}
@ -185,7 +185,7 @@ namespace GodotTools.Utils
return searchDirs.Select(dir => Path.Combine(dir, name))
.FirstOrDefault(path =>
{
using godot_string pathIn = Marshaling.mono_string_to_godot(path);
using godot_string pathIn = Marshaling.ConvertStringToNative(path);
return File.Exists(path) && Internal.godot_icall_Utils_OS_UnixFileHasExecutableAccess(pathIn);
});
}

View file

@ -101,12 +101,12 @@ StringBuilder &operator<<(StringBuilder &r_sb, const char *p_cstring) {
#define C_METHOD_ENGINE_GET_SINGLETON C_NS_MONOUTILS ".EngineGetSingleton"
#define C_NS_MONOMARSHAL "Marshaling"
#define C_METHOD_MANAGED_TO_VARIANT C_NS_MONOMARSHAL ".mono_object_to_variant"
#define C_METHOD_MANAGED_FROM_VARIANT C_NS_MONOMARSHAL ".variant_to_mono_object"
#define C_METHOD_MONOSTR_TO_GODOT C_NS_MONOMARSHAL ".mono_string_to_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_FROM(m_type) C_NS_MONOMARSHAL "." #m_type "_to_mono_array"
#define C_METHOD_MANAGED_TO_VARIANT C_NS_MONOMARSHAL ".ConvertManagedObjectToVariant"
#define C_METHOD_MANAGED_FROM_VARIANT C_NS_MONOMARSHAL ".ConvertVariantToManagedObject"
#define C_METHOD_MONOSTR_TO_GODOT C_NS_MONOMARSHAL ".ConvertStringToNative"
#define C_METHOD_MONOSTR_FROM_GODOT C_NS_MONOMARSHAL ".ConvertStringToManaged"
#define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL ".ConvertSystemArrayToNative" #m_type
#define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL ".ConvertNative" #m_type "ToSystemArray"
#define C_METHOD_MANAGED_TO_CALLABLE C_NS_MONOMARSHAL ".ConvertCallableToNative"
#define C_METHOD_MANAGED_FROM_CALLABLE C_NS_MONOMARSHAL ".ConvertCallableToManaged"
#define C_METHOD_MANAGED_TO_SIGNAL C_NS_MONOMARSHAL ".ConvertSignalToNative"
@ -122,7 +122,7 @@ void BindingsGenerator::TypeInterface::postsetup_enum_type(BindingsGenerator::Ty
// any of the changes done here to the 'uint32_t' type interface as well.
r_enum_itype.cs_type = r_enum_itype.proxy_name;
r_enum_itype.cs_in = "(int)%s";
r_enum_itype.cs_in_expr = "(int)%0";
r_enum_itype.cs_out = "%5return (%2)%0(%1);";
{
@ -391,23 +391,23 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
xml_output.append(tag);
xml_output.append("</c>");
} else if (tag == "PackedByteArray") {
xml_output.append("<see cref=\"T:byte[]\"/>");
xml_output.append("<see cref=\"byte\"/>[]");
} else if (tag == "PackedInt32Array") {
xml_output.append("<see cref=\"T:int[]\"/>");
xml_output.append("<see cref=\"int\"/>[]");
} else if (tag == "PackedInt64Array") {
xml_output.append("<see cref=\"T:long[]\"/>");
xml_output.append("<see cref=\"long\"/>[]");
} else if (tag == "PackedFloat32Array") {
xml_output.append("<see cref=\"T:float[]\"/>");
xml_output.append("<see cref=\"float\"/>[]");
} else if (tag == "PackedFloat64Array") {
xml_output.append("<see cref=\"T:double[]\"/>");
xml_output.append("<see cref=\"double\"/>[]");
} else if (tag == "PackedStringArray") {
xml_output.append("<see cref=\"T:string[]\"/>");
xml_output.append("<see cref=\"string\"/>[]");
} else if (tag == "PackedVector2Array") {
xml_output.append("<see cref=\"T:" BINDINGS_NAMESPACE ".Vector2[]\"/>");
xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Vector2\"/>[]");
} else if (tag == "PackedVector3Array") {
xml_output.append("<see cref=\"T:" BINDINGS_NAMESPACE ".Vector3[]\"/>");
xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Vector3\"/>[]");
} else if (tag == "PackedColorArray") {
xml_output.append("<see cref=\"T:" BINDINGS_NAMESPACE ".Color[]\"/>");
xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Color\"/>[]");
} else {
const TypeInterface *target_itype = _get_type_or_null(TypeReference(tag));
@ -1380,6 +1380,8 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
"#pragma warning disable CS1573 // Disable warning: "
"'Parameter has no matching param tag in the XML comment'\n");
output.append("\n#nullable disable\n");
output.append("\nnamespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
const DocData::ClassDoc *class_doc = itype.class_doc;
@ -1413,20 +1415,17 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
}
output.append(itype.proxy_name);
if (itype.is_singleton) {
output.append("\n");
} else if (is_derived_type) {
if (is_derived_type && !itype.is_singleton) {
if (obj_types.has(itype.base_name)) {
output.append(" : ");
output.append(obj_types[itype.base_name].proxy_name);
output.append("\n");
} else {
ERR_PRINT("Base type '" + itype.base_name.operator String() + "' does not exist, for class '" + itype.name + "'.");
return ERR_INVALID_DATA;
}
}
output.append(INDENT1 "{");
output.append("\n" INDENT1 "{");
// Add constants
@ -1546,7 +1545,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
// Add native constructor static field
output << MEMBER_BEGIN << "[DebuggerBrowsable(DebuggerBrowsableState.Never)]\n"
<< INDENT2 "private static unsafe readonly delegate* unmanaged<IntPtr> "
<< INDENT2 "private static readonly unsafe delegate* unmanaged<IntPtr> "
<< CS_STATIC_FIELD_NATIVE_CTOR " = " ICALL_CLASSDB_GET_CONSTRUCTOR
<< "(" BINDINGS_NATIVE_NAME_FIELD ");\n";
}
@ -1608,7 +1607,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
// TODO: string is ok for now. But should be replaced with StringName in the future for performance.
output << MEMBER_BEGIN "internal " << (is_derived_type ? "override" : "virtual")
<< " unsafe bool InternalGodotScriptCall(string method, godot_variant** args, "
<< " bool InternalGodotScriptCall(string method, NativeVariantPtrArgs args, "
<< "int argCount, out godot_variant ret)\n"
<< INDENT2 "{\n";
@ -1646,10 +1645,10 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
if (arg_type->cname == name_cache.type_Array_generic || arg_type->cname == name_cache.type_Dictionary_generic) {
String arg_cs_type = arg_type->cs_type + _get_generic_type_parameters(*arg_type, iarg.type.generic_type_parameters);
output << "new " << arg_cs_type << "((" << arg_type->cs_type << ")Marshaling.variant_to_mono_object_of_type(args["
output << "new " << arg_cs_type << "((" << arg_type->cs_type << ")Marshaling.ConvertVariantToManagedObjectOfType(args["
<< itos(i) << "], typeof(" << arg_type->cs_type << ")))";
} else {
output << "(" << arg_type->cs_type << ")Marshaling.variant_to_mono_object_of_type(args["
output << "(" << arg_type->cs_type << ")Marshaling.ConvertVariantToManagedObjectOfType(args["
<< itos(i) << "], typeof(" << arg_type->cs_type << "))";
}
}
@ -1658,7 +1657,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
if (imethod.return_type.cname != name_cache.type_void) {
// TODO: static marshaling (no reflection, no runtime type checks)
output << INDENT4 "ret = Marshaling.mono_object_to_variant(retBoxed);\n";
output << INDENT4 "ret = Marshaling.ConvertManagedObjectToVariant(retBoxed);\n";
output << INDENT4 "return true;\n";
} else {
output << INDENT4 "ret = default;\n";
@ -1858,11 +1857,17 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
String arguments_sig;
StringBuilder cs_in_statements;
bool cs_in_is_unsafe = false;
bool cs_in_expr_is_unsafe = false;
String icall_params = method_bind_field;
if (!p_imethod.is_static) {
icall_params += ", " + sformat(p_itype.cs_in, "this");
if (p_itype.cs_in.size()) {
cs_in_statements << sformat(p_itype.cs_in, p_itype.c_type, "this",
String(), String(), String(), INDENT3);
}
icall_params += ", " + sformat(p_itype.cs_in_expr, "this");
}
StringBuilder default_args_doc;
@ -1924,10 +1929,10 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
if (iarg.default_argument.size() && iarg.def_param_mode != ArgumentInterface::CONSTANT) {
// The default value of an argument must be constant. Otherwise we make it Nullable and do the following:
// Type arg_in = arg.HasValue ? arg.Value : <non-const default value>;
String arg_in = iarg.name;
arg_in += "_in";
String arg_or_defval_local = iarg.name;
arg_or_defval_local += "OrDefVal";
cs_in_statements << INDENT3 << arg_cs_type << " " << arg_in << " = " << iarg.name;
cs_in_statements << INDENT3 << arg_cs_type << " " << arg_or_defval_local << " = " << iarg.name;
if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL) {
cs_in_statements << ".HasValue ? ";
@ -1952,7 +1957,16 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
cs_in_statements << def_arg << ";\n";
icall_params += arg_type->cs_in.is_empty() ? arg_in : sformat(arg_type->cs_in, arg_in);
if (arg_type->cs_in.size()) {
cs_in_statements << sformat(arg_type->cs_in, arg_type->c_type, arg_or_defval_local,
String(), String(), String(), INDENT3);
}
if (arg_type->cs_in_expr.is_empty()) {
icall_params += arg_or_defval_local;
} else {
icall_params += sformat(arg_type->cs_in_expr, arg_or_defval_local, arg_type->c_type);
}
// Apparently the name attribute must not include the @
String param_tag_name = iarg.name.begins_with("@") ? iarg.name.substr(1, iarg.name.length()) : iarg.name;
@ -1961,10 +1975,15 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
default_args_doc.append(MEMBER_BEGIN "/// <param name=\"" + param_tag_name + "\">If the parameter is null, then the default value is <c>" + param_def_arg + "</c>.</param>");
} else {
icall_params += arg_type->cs_in.is_empty() ? iarg.name : sformat(arg_type->cs_in, iarg.name);
if (arg_type->cs_in.size()) {
cs_in_statements << sformat(arg_type->cs_in, arg_type->c_type, iarg.name,
String(), String(), String(), INDENT3);
}
icall_params += arg_type->cs_in_expr.is_empty() ? iarg.name : sformat(arg_type->cs_in_expr, iarg.name, arg_type->c_type);
}
cs_in_is_unsafe |= arg_type->cs_in_is_unsafe;
cs_in_expr_is_unsafe |= arg_type->cs_in_expr_is_unsafe;
}
// Generate method
@ -2034,7 +2053,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
p_output.append("virtual ");
}
if (cs_in_is_unsafe) {
if (cs_in_expr_is_unsafe) {
p_output.append("unsafe ");
}
@ -2082,7 +2101,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
im_call += ".";
im_call += im_icall->name;
if (p_imethod.arguments.size()) {
if (p_imethod.arguments.size() && cs_in_statements.get_string_length() > 0) {
p_output.append(cs_in_statements.as_string());
}
@ -2319,8 +2338,6 @@ Error BindingsGenerator::_generate_cs_native_calls(const InternalCall &p_icall,
auto generate_call_and_return_stmts = [&](const char *base_indent) {
if (p_icall.is_vararg) {
r_output << base_indent << "godot_variant_call_error vcall_error;\n";
// MethodBind Call
r_output << base_indent;
@ -2341,12 +2358,12 @@ Error BindingsGenerator::_generate_cs_native_calls(const InternalCall &p_icall,
r_output << C_CLASS_NATIVE_FUNCS ".godotsharp_method_bind_call("
<< CS_PARAM_METHODBIND ", " << (p_icall.is_static ? "IntPtr.Zero" : CS_PARAM_INSTANCE)
<< ", " << (p_icall.get_arguments_count() ? "(godot_variant**)" C_LOCAL_PTRCALL_ARGS : "null")
<< ", total_length, &vcall_error);\n";
<< ", total_length, out _);\n";
if (!ret_void) {
if (return_type->cname != name_cache.type_Variant) {
if (return_type->cname == name_cache.enum_Error) {
r_output << base_indent << C_LOCAL_RET " = VariantUtils.ConvertToInt64(&" C_LOCAL_VARARG_RET ");\n";
r_output << base_indent << C_LOCAL_RET " = VariantUtils.ConvertToInt64(" C_LOCAL_VARARG_RET ");\n";
} else {
// TODO: Use something similar to c_in_vararg (see usage above, with error if not implemented)
CRASH_NOW_MSG("Custom VarArg return type not implemented: " + return_type->name);
@ -2384,9 +2401,9 @@ Error BindingsGenerator::_generate_cs_native_calls(const InternalCall &p_icall,
r_output << INDENT3 "int vararg_length = " << vararg_arg << ".Length;\n"
<< INDENT3 "int total_length = " << real_argc_str << " + vararg_length;\n";
r_output << INDENT3 "Span<godot_variant> varargs_span = vararg_length <= VarArgsSpanThreshold ?\n"
<< INDENT4 "stackalloc godot_variant[VarArgsSpanThreshold].Cleared() :\n"
<< INDENT4 "new godot_variant[vararg_length];\n";
r_output << INDENT3 "Span<godot_variant.movable> varargs_span = vararg_length <= VarArgsSpanThreshold ?\n"
<< INDENT4 "stackalloc godot_variant.movable[VarArgsSpanThreshold].Cleared() :\n"
<< INDENT4 "new godot_variant.movable[vararg_length];\n";
r_output << INDENT3 "Span<IntPtr> " C_LOCAL_PTRCALL_ARGS "_span = total_length <= VarArgsSpanThreshold ?\n"
<< INDENT4 "stackalloc IntPtr[VarArgsSpanThreshold] :\n"
@ -2394,7 +2411,7 @@ Error BindingsGenerator::_generate_cs_native_calls(const InternalCall &p_icall,
r_output << INDENT3 "using var variantSpanDisposer = new VariantSpanDisposer(varargs_span);\n";
r_output << INDENT3 "fixed (godot_variant* varargs = &MemoryMarshal.GetReference(varargs_span))\n"
r_output << INDENT3 "fixed (godot_variant* varargs = &MemoryMarshal.GetReference(varargs_span).DangerousSelfRef)\n"
<< INDENT3 "fixed (IntPtr* " C_LOCAL_PTRCALL_ARGS " = "
"&MemoryMarshal.GetReference(" C_LOCAL_PTRCALL_ARGS "_span))\n"
<< OPEN_BLOCK_L3;
@ -2678,14 +2695,14 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
itype.c_out = "%5return ";
itype.c_out += C_METHOD_UNMANAGED_GET_MANAGED;
itype.c_out += itype.is_ref_counted ? "(%1._reference);\n" : "(%1);\n";
itype.c_out += itype.is_ref_counted ? "(%1.Reference);\n" : "(%1);\n";
itype.cs_type = itype.proxy_name;
if (itype.is_singleton) {
itype.cs_in = "Object." CS_STATIC_METHOD_GETINSTANCE "(" CS_PROPERTY_SINGLETON ")";
itype.cs_in_expr = "Object." CS_STATIC_METHOD_GETINSTANCE "(" CS_PROPERTY_SINGLETON ")";
} else {
itype.cs_in = "Object." CS_STATIC_METHOD_GETINSTANCE "(%0)";
itype.cs_in_expr = "Object." CS_STATIC_METHOD_GETINSTANCE "(%0)";
}
itype.cs_out = "%5return (%2)%0(%1);";
@ -3128,8 +3145,13 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
case Variant::STRING_NAME:
case Variant::NODE_PATH:
if (r_iarg.type.cname == name_cache.type_StringName || r_iarg.type.cname == name_cache.type_NodePath) {
r_iarg.default_argument = "(%s)\"" + r_iarg.default_argument + "\"";
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF;
if (r_iarg.default_argument.length() > 0) {
r_iarg.default_argument = "(%s)\"" + r_iarg.default_argument + "\"";
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF;
} else {
// No need for a special `in` statement to change `null` to `""`. Marshaling takes care of this already.
r_iarg.default_argument = "null";
}
} else {
CRASH_COND(r_iarg.type.cname != name_cache.type_String);
r_iarg.default_argument = "\"" + r_iarg.default_argument + "\"";
@ -3175,8 +3197,11 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
r_iarg.default_argument = "null";
break;
case Variant::DICTIONARY:
r_iarg.default_argument = "new %s()";
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF;
ERR_FAIL_COND_V_MSG(!p_val.operator Dictionary().is_empty(), false,
"Default value of type 'Dictionary' must be an empty dictionary.");
// The [cs_in] expression already interprets null values as empty dictionaries.
r_iarg.default_argument = "null";
r_iarg.def_param_mode = ArgumentInterface::CONSTANT;
break;
case Variant::RID:
ERR_FAIL_COND_V_MSG(r_iarg.type.cname != name_cache.type_RID, false,
@ -3188,8 +3213,11 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
r_iarg.default_argument = "default";
break;
case Variant::ARRAY:
r_iarg.default_argument = "new %s { }";
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF;
ERR_FAIL_COND_V_MSG(!p_val.operator Array().is_empty(), false,
"Default value of type 'Array' must be an empty array.");
// The [cs_in] expression already interprets null values as empty arrays.
r_iarg.default_argument = "null";
r_iarg.def_param_mode = ArgumentInterface::CONSTANT;
break;
case Variant::PACKED_BYTE_ARRAY:
case Variant::PACKED_INT32_ARRAY:
@ -3285,8 +3313,8 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype = TypeInterface::create_value_type(String(#m_type)); \
itype.c_type_in = #m_type "*"; \
itype.c_type_out = itype.cs_type; \
itype.cs_in = "&%s"; \
itype.cs_in_is_unsafe = true; \
itype.cs_in_expr = "&%0"; \
itype.cs_in_expr_is_unsafe = true; \
builtin_types.insert(itype.cname, itype); \
}
@ -3311,7 +3339,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
// bool
itype = TypeInterface::create_value_type(String("bool"));
itype.cs_in = "%s.ToGodotBool()";
itype.cs_in_expr = "%0.ToGodotBool()";
itype.cs_out = "%5return %0(%1).ToBool();";
itype.c_type = "godot_bool";
itype.c_type_in = itype.c_type;
@ -3411,15 +3439,14 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.cname = itype.name;
itype.proxy_name = "StringName";
itype.cs_type = itype.proxy_name;
itype.cs_in = "ref %0.NativeValue";
itype.cs_in_expr = "(%1)(%0?.NativeValue ?? default)";
// Cannot pass null StringName to ptrcall
itype.c_in = "%5using %0 %1_in = " C_CLASS_NATIVE_FUNCS ".godotsharp_string_name_new_copy(%1);\n";
itype.c_out = "%5return %0.CreateTakingOwnershipOfDisposableValue(%1);\n";
itype.c_arg_in = "&%s_in";
itype.c_arg_in = "&%s";
itype.c_type = "godot_string_name";
itype.c_type_in = "ref " + itype.c_type;
itype.c_type_in = itype.c_type;
itype.c_type_out = itype.cs_type;
itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromStringName(ref %1);\n";
itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromStringName(%1);\n";
itype.c_type_is_disposable_struct = false; // [c_out] takes ownership
itype.c_ret_needs_default_initialization = true;
builtin_types.insert(itype.cname, itype);
@ -3430,13 +3457,12 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.cname = itype.name;
itype.proxy_name = "NodePath";
itype.cs_type = itype.proxy_name;
itype.cs_in = "ref %0.NativeValue";
itype.cs_in_expr = "(%1)(%0?.NativeValue ?? default)";
// Cannot pass null NodePath to ptrcall
itype.c_in = "%5using %0 %1_in = " C_CLASS_NATIVE_FUNCS ".godotsharp_node_path_new_copy(%1);\n";
itype.c_out = "%5return %0.CreateTakingOwnershipOfDisposableValue(%1);\n";
itype.c_arg_in = "&%s_in";
itype.c_arg_in = "&%s";
itype.c_type = "godot_node_path";
itype.c_type_in = "ref " + itype.c_type;
itype.c_type_in = itype.c_type;
itype.c_type_out = itype.cs_type;
itype.c_type_is_disposable_struct = false; // [c_out] takes ownership
itype.c_ret_needs_default_initialization = true;
@ -3461,7 +3487,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.proxy_name = "object";
itype.cs_type = itype.proxy_name;
itype.c_in = "%5using %0 %1_in = " C_METHOD_MANAGED_TO_VARIANT "(%1);\n";
itype.c_out = "%5return " C_METHOD_MANAGED_FROM_VARIANT "(&%1);\n";
itype.c_out = "%5return " C_METHOD_MANAGED_FROM_VARIANT "(%1);\n";
itype.c_arg_in = "&%s_in";
itype.c_type = "godot_variant";
itype.c_type_in = itype.cs_type;
@ -3471,9 +3497,9 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
// Callable
itype = TypeInterface::create_value_type(String("Callable"));
itype.cs_in = "ref %s";
itype.cs_in_expr = "ref %0";
itype.c_in = "%5using %0 %1_in = " C_METHOD_MANAGED_TO_CALLABLE "(ref %1);\n";
itype.c_out = "%5return " C_METHOD_MANAGED_FROM_CALLABLE "(&%1);\n";
itype.c_out = "%5return " C_METHOD_MANAGED_FROM_CALLABLE "(in %1);\n";
itype.c_arg_in = "&%s_in";
itype.c_type = "godot_callable";
itype.c_type_in = "ref " + itype.cs_type;
@ -3487,7 +3513,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.cname = itype.name;
itype.proxy_name = "SignalInfo";
itype.cs_type = itype.proxy_name;
itype.cs_in = "ref %s";
itype.cs_in_expr = "ref %0";
itype.c_in = "%5using %0 %1_in = " C_METHOD_MANAGED_TO_SIGNAL "(ref %1);\n";
itype.c_out = "%5return " C_METHOD_MANAGED_FROM_SIGNAL "(&%1);\n";
itype.c_arg_in = "&%s_in";
@ -3503,6 +3529,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.cname = itype.name;
itype.proxy_name = "object[]";
itype.cs_type = "params object[]";
itype.cs_in_expr = "%0 ?? Array.Empty<object>()";
// c_type, c_in and c_arg_in are hard-coded in the generator.
// c_out and c_type_out are not applicable to VarArg.
itype.c_arg_in = "&%s_in";
@ -3517,7 +3544,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.proxy_name = #m_proxy_t "[]"; \
itype.cs_type = itype.proxy_name; \
itype.c_in = "%5using %0 %1_in = " C_METHOD_MONOARRAY_TO(m_type) "(%1);\n"; \
itype.c_out = "%5return " C_METHOD_MONOARRAY_FROM(m_type) "(&%1);\n"; \
itype.c_out = "%5return " C_METHOD_MONOARRAY_FROM(m_type) "(%1);\n"; \
itype.c_arg_in = "&%s_in"; \
itype.c_type = #m_managed_type; \
itype.c_type_in = itype.proxy_name; \
@ -3550,12 +3577,11 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.proxy_name = itype.name;
itype.type_parameter_count = 1;
itype.cs_type = BINDINGS_NAMESPACE_COLLECTIONS "." + itype.proxy_name;
itype.cs_in = "ref %0.NativeValue";
itype.c_in = "%5using %0 %1_in = " C_CLASS_NATIVE_FUNCS ".godotsharp_array_new_copy(%1);\n";
itype.cs_in_expr = "(%1)(%0 ?? new()).NativeValue";
itype.c_out = "%5return %0.CreateTakingOwnershipOfDisposableValue(%1);\n";
itype.c_arg_in = "&%s_in";
itype.c_arg_in = "&%s";
itype.c_type = "godot_array";
itype.c_type_in = "ref " + itype.c_type;
itype.c_type_in = itype.c_type;
itype.c_type_out = itype.cs_type;
itype.c_type_is_disposable_struct = false; // [c_out] takes ownership
itype.c_ret_needs_default_initialization = true;
@ -3575,12 +3601,11 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.proxy_name = itype.name;
itype.type_parameter_count = 2;
itype.cs_type = BINDINGS_NAMESPACE_COLLECTIONS "." + itype.proxy_name;
itype.cs_in = "ref %0.NativeValue";
itype.c_in = "%5using %0 %1_in = " C_CLASS_NATIVE_FUNCS ".godotsharp_dictionary_new_copy(%1);\n";
itype.cs_in_expr = "(%1)(%0 ?? new()).NativeValue";
itype.c_out = "%5return %0.CreateTakingOwnershipOfDisposableValue(%1);\n";
itype.c_arg_in = "&%s_in";
itype.c_arg_in = "&%s";
itype.c_type = "godot_dictionary";
itype.c_type_in = "ref " + itype.c_type;
itype.c_type_in = itype.c_type;
itype.c_type_out = itype.cs_type;
itype.c_type_is_disposable_struct = false; // [c_out] takes ownership
itype.c_ret_needs_default_initialization = true;

View file

@ -265,9 +265,9 @@ class BindingsGenerator {
// --- C INTERFACE ---
/**
* One or more statements that manipulate the parameter before being passed as argument of a ptrcall.
* One or more statements that transform the parameter before being passed as argument of a ptrcall.
* If the statement adds a local that must be passed as the argument instead of the parameter,
* the name of that local must be specified with [c_arg_in].
* the expression with the name of that local must be specified with [c_arg_in].
* Formatting elements:
* %0: [c_type] of the parameter
* %1: name of the parameter
@ -277,7 +277,7 @@ class BindingsGenerator {
String c_in;
/**
* One or more statements that manipulate the parameter before being passed as argument of a vararg call.
* One or more statements that transform the parameter before being passed as argument of a vararg call.
* If the statement adds a local that must be passed as the argument instead of the parameter,
* the name of that local must be specified with [c_arg_in].
* Formatting elements:
@ -348,10 +348,23 @@ class BindingsGenerator {
* An expression that overrides the way the parameter is passed to the internal call.
* If empty, the parameter is passed as is.
* Formatting elements:
* %0 or %s: name of the parameter
* %0: name of the parameter
* %1: [c_type] of the parameter
*/
String cs_in_expr;
bool cs_in_expr_is_unsafe = false;
/**
* One or more statements that transform the parameter before being passed to the internal call.
* If the statement adds a local that must be passed as the argument instead of the parameter,
* the expression with the name of that local must be specified with [cs_in_expr].
* Formatting elements:
* %0: [c_type] of the parameter
* %1: name of the parameter
* %2-4: reserved
* %5: indentation text
*/
String cs_in;
bool cs_in_is_unsafe = false;
/**
* One or more statements that determine how a variable of this type is returned from a method.

View file

@ -0,0 +1,8 @@
[**/Generated/**.cs]
# Validate parameter is non-null before using it
# Useful for generated code, as it disables nullable
dotnet_diagnostic.CA1062.severity = error
# CA1069: Enums should not have duplicate values
dotnet_diagnostic.CA1069.severity = none
# CA1708: Identifiers should differ by more than case
dotnet_diagnostic.CA1708.severity = none

View file

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using Godot.NativeInterop;
namespace Godot.Collections
@ -14,14 +15,14 @@ namespace Godot.Collections
/// </summary>
public sealed class Array : IList, IDisposable
{
public godot_array NativeValue;
internal godot_array.movable NativeValue;
/// <summary>
/// Constructs a new empty <see cref="Array"/>.
/// </summary>
public Array()
{
NativeValue = NativeFuncs.godotsharp_array_new();
NativeValue = (godot_array.movable)NativeFuncs.godotsharp_array_new();
}
/// <summary>
@ -32,7 +33,7 @@ namespace Godot.Collections
public Array(IEnumerable collection) : this()
{
if (collection == null)
throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'");
throw new ArgumentNullException(nameof(collection));
foreach (object element in collection)
Add(element);
@ -47,9 +48,9 @@ namespace Godot.Collections
public Array(params object[] array) : this()
{
if (array == null)
throw new NullReferenceException($"Parameter '{nameof(array)} cannot be null.'");
throw new ArgumentNullException(nameof(array));
NativeValue = NativeFuncs.godotsharp_array_new();
NativeValue = (godot_array.movable)NativeFuncs.godotsharp_array_new();
int length = array.Length;
Resize(length);
@ -60,7 +61,9 @@ namespace Godot.Collections
private Array(godot_array nativeValueToOwn)
{
NativeValue = nativeValueToOwn;
NativeValue = (godot_array.movable)(nativeValueToOwn.IsAllocated ?
nativeValueToOwn :
NativeFuncs.godotsharp_array_new());
}
// Explicit name to make it very clear
@ -84,7 +87,7 @@ namespace Godot.Collections
public void Dispose(bool disposing)
{
// Always dispose `NativeValue` even if disposing is true
NativeValue.Dispose();
NativeValue.DangerousSelfRef.Dispose();
}
/// <summary>
@ -95,7 +98,8 @@ namespace Godot.Collections
public Array Duplicate(bool deep = false)
{
godot_array newArray;
NativeFuncs.godotsharp_array_duplicate(ref NativeValue, deep.ToGodotBool(), out newArray);
var self = (godot_array)NativeValue;
NativeFuncs.godotsharp_array_duplicate(ref self, deep.ToGodotBool(), out newArray);
return CreateTakingOwnershipOfDisposableValue(newArray);
}
@ -104,12 +108,20 @@ namespace Godot.Collections
/// </summary>
/// <param name="newSize">The new size of the array.</param>
/// <returns><see cref="Error.Ok"/> if successful, or an error code.</returns>
public Error Resize(int newSize) => NativeFuncs.godotsharp_array_resize(ref NativeValue, newSize);
public Error Resize(int newSize)
{
var self = (godot_array)NativeValue;
return NativeFuncs.godotsharp_array_resize(ref self, newSize);
}
/// <summary>
/// Shuffles the contents of this <see cref="Array"/> into a random order.
/// </summary>
public void Shuffle() => NativeFuncs.godotsharp_array_shuffle(ref NativeValue);
public void Shuffle()
{
var self = (godot_array)NativeValue;
NativeFuncs.godotsharp_array_shuffle(ref self);
}
/// <summary>
/// Concatenates these two <see cref="Array"/>s.
@ -119,6 +131,17 @@ namespace Godot.Collections
/// <returns>A new Godot Array with the contents of both arrays.</returns>
public static Array operator +(Array left, Array right)
{
if (left == null)
{
if (right == null)
return new Array();
return right.Duplicate(deep: false);
}
if (right == null)
return left.Duplicate(deep: false);
int leftCount = left.Count;
int rightCount = right.Count;
@ -146,14 +169,15 @@ namespace Godot.Collections
get
{
GetVariantBorrowElementAt(index, out godot_variant borrowElem);
return Marshaling.variant_to_mono_object(&borrowElem);
return Marshaling.ConvertVariantToManagedObject(borrowElem);
}
set
{
if (index < 0 || index >= Count)
throw new IndexOutOfRangeException();
godot_variant* ptrw = NativeFuncs.godotsharp_array_ptrw(ref NativeValue);
ptrw[index] = Marshaling.mono_object_to_variant(value);
throw new ArgumentOutOfRangeException(nameof(index));
var self = (godot_array)NativeValue;
godot_variant* ptrw = NativeFuncs.godotsharp_array_ptrw(ref self);
ptrw[index] = Marshaling.ConvertManagedObjectToVariant(value);
}
}
@ -163,10 +187,11 @@ namespace Godot.Collections
/// </summary>
/// <param name="value">The object to add.</param>
/// <returns>The new size after adding the object.</returns>
public unsafe int Add(object value)
public int Add(object value)
{
using godot_variant variantValue = Marshaling.mono_object_to_variant(value);
return NativeFuncs.godotsharp_array_add(ref NativeValue, &variantValue);
using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(value);
var self = (godot_array)NativeValue;
return NativeFuncs.godotsharp_array_add(ref self, variantValue);
}
/// <summary>
@ -187,10 +212,11 @@ namespace Godot.Collections
/// </summary>
/// <param name="value">The object to search for.</param>
/// <returns>The index of the object, or -1 if not found.</returns>
public unsafe int IndexOf(object value)
public int IndexOf(object value)
{
using godot_variant variantValue = Marshaling.mono_object_to_variant(value);
return NativeFuncs.godotsharp_array_index_of(ref NativeValue, &variantValue);
using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(value);
var self = (godot_array)NativeValue;
return NativeFuncs.godotsharp_array_index_of(ref self, variantValue);
}
/// <summary>
@ -201,13 +227,14 @@ namespace Godot.Collections
/// </summary>
/// <param name="index">The index to insert at.</param>
/// <param name="value">The object to insert.</param>
public unsafe void Insert(int index, object value)
public void Insert(int index, object value)
{
if (index < 0 || index > Count)
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(index));
using godot_variant variantValue = Marshaling.mono_object_to_variant(value);
NativeFuncs.godotsharp_array_insert(ref NativeValue, index, &variantValue);
using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(value);
var self = (godot_array)NativeValue;
NativeFuncs.godotsharp_array_insert(ref self, index, variantValue);
}
/// <summary>
@ -229,9 +256,10 @@ namespace Godot.Collections
public void RemoveAt(int index)
{
if (index < 0 || index > Count)
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(index));
NativeFuncs.godotsharp_array_remove_at(ref NativeValue, index);
var self = (godot_array)NativeValue;
NativeFuncs.godotsharp_array_remove_at(ref self, index);
}
// ICollection
@ -241,7 +269,7 @@ namespace Godot.Collections
/// This is also known as the size or length of the array.
/// </summary>
/// <returns>The number of elements.</returns>
public int Count => NativeValue.Size;
public int Count => NativeValue.DangerousSelfRef.Size;
object ICollection.SyncRoot => this;
@ -252,21 +280,21 @@ namespace Godot.Collections
/// untyped C# array, starting at the given index.
/// </summary>
/// <param name="array">The array to copy to.</param>
/// <param name="destIndex">The index to start at.</param>
public void CopyTo(System.Array array, int destIndex)
/// <param name="index">The index to start at.</param>
public void CopyTo(System.Array array, int index)
{
if (array == null)
throw new ArgumentNullException(nameof(array), "Value cannot be null.");
if (destIndex < 0)
if (index < 0)
{
throw new ArgumentOutOfRangeException(nameof(destIndex),
throw new ArgumentOutOfRangeException(nameof(index),
"Number was less than the array's lower bound in the first dimension.");
}
int count = Count;
if (array.Length < (destIndex + count))
if (array.Length < (index + count))
{
throw new ArgumentException(
"Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
@ -276,9 +304,9 @@ namespace Godot.Collections
{
for (int i = 0; i < count; i++)
{
object obj = Marshaling.variant_to_mono_object(&(*NativeValue._p)._arrayVector._ptr[i]);
array.SetValue(obj, destIndex);
destIndex++;
object obj = Marshaling.ConvertVariantToManagedObject(NativeValue.DangerousSelfRef.Elements[i]);
array.SetValue(obj, index);
index++;
}
}
}
@ -303,11 +331,12 @@ namespace Godot.Collections
/// Converts this <see cref="Array"/> to a string.
/// </summary>
/// <returns>A string representation of this array.</returns>
public override unsafe string ToString()
public override string ToString()
{
using godot_string str = default;
NativeFuncs.godotsharp_array_to_string(ref NativeValue, &str);
return Marshaling.mono_string_from_godot(str);
var self = (godot_array)NativeValue;
NativeFuncs.godotsharp_array_to_string(ref self, out godot_string str);
using (str)
return Marshaling.ConvertStringToManaged(str);
}
/// <summary>
@ -316,7 +345,7 @@ namespace Godot.Collections
internal void GetVariantBorrowElementAt(int index, out godot_variant elem)
{
if (index < 0 || index >= Count)
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(index));
GetVariantBorrowElementAtUnchecked(index, out elem);
}
@ -325,7 +354,7 @@ namespace Godot.Collections
/// </summary>
internal unsafe void GetVariantBorrowElementAtUnchecked(int index, out godot_variant elem)
{
elem = (*NativeValue._p)._arrayVector._ptr[index];
elem = NativeValue.DangerousSelfRef.Elements[index];
}
}
@ -344,11 +373,16 @@ namespace Godot.Collections
/// </summary>
/// <typeparam name="T">The type of the array.</typeparam>
[SuppressMessage("ReSharper", "RedundantExtendsListEntry")]
[SuppressMessage("Naming", "CA1710", MessageId = "Identifiers should have correct suffix")]
public sealed class Array<T> : IList<T>, ICollection<T>, IEnumerable<T>, IGenericGodotArray
{
private readonly Array _underlyingArray;
internal ref godot_array NativeValue => ref _underlyingArray.NativeValue;
internal ref godot_array.movable NativeValue
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref _underlyingArray.NativeValue;
}
// ReSharper disable StaticMemberInGenericType
// Warning is about unique static fields being created for each generic type combination:
@ -376,7 +410,7 @@ namespace Godot.Collections
public Array(IEnumerable<T> collection)
{
if (collection == null)
throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'");
throw new ArgumentNullException(nameof(collection));
_underlyingArray = new Array(collection);
}
@ -389,9 +423,7 @@ namespace Godot.Collections
public Array(params T[] array) : this()
{
if (array == null)
{
throw new NullReferenceException($"Parameter '{nameof(array)} cannot be null.'");
}
throw new ArgumentNullException(nameof(array));
_underlyingArray = new Array(array);
}
@ -415,7 +447,7 @@ namespace Godot.Collections
/// <param name="from">The typed array to convert.</param>
public static explicit operator Array(Array<T> from)
{
return from._underlyingArray;
return from?._underlyingArray;
}
/// <summary>
@ -454,6 +486,17 @@ namespace Godot.Collections
/// <returns>A new Godot Array with the contents of both arrays.</returns>
public static Array<T> operator +(Array<T> left, Array<T> right)
{
if (left == null)
{
if (right == null)
return new Array<T>();
return right.Duplicate(deep: false);
}
if (right == null)
return left.Duplicate(deep: false);
return new Array<T>(left._underlyingArray + right._underlyingArray);
}
@ -468,10 +511,7 @@ namespace Godot.Collections
get
{
_underlyingArray.GetVariantBorrowElementAt(index, out godot_variant borrowElem);
unsafe
{
return (T)Marshaling.variant_to_mono_object_of_type(&borrowElem, TypeOfElements);
}
return (T)Marshaling.ConvertVariantToManagedObjectOfType(borrowElem, TypeOfElements);
}
set => _underlyingArray[index] = value;
}

View file

@ -167,7 +167,7 @@ namespace Godot
case 2:
return Column2;
default:
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(column));
}
}
set
@ -184,7 +184,7 @@ namespace Godot
Column2 = value;
return;
default:
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(column));
}
}
}
@ -386,7 +386,7 @@ namespace Godot
case 2:
return Row2;
default:
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(index));
}
}
@ -413,7 +413,7 @@ namespace Godot
Row2 = value;
return;
default:
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(index));
}
}

View file

@ -18,22 +18,24 @@ namespace Godot.Bridge
if (godotObject == null)
{
*ret = default;
(*refCallError).error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INSTANCE_IS_NULL;
(*refCallError).Error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INSTANCE_IS_NULL;
return false.ToGodotBool();
}
using godot_string dest = default;
NativeFuncs.godotsharp_string_name_as_string(&dest, method);
string methodStr = Marshaling.mono_string_from_godot(dest);
NativeFuncs.godotsharp_string_name_as_string(out godot_string dest, CustomUnsafe.AsRef(method));
string methodStr;
using (dest)
methodStr = Marshaling.ConvertStringToManaged(dest);
bool methodInvoked = godotObject.InternalGodotScriptCall(methodStr, args, argCount, out godot_variant retValue);
bool methodInvoked = godotObject.InternalGodotScriptCall(methodStr, new NativeVariantPtrArgs(args),
argCount, out godot_variant retValue);
if (!methodInvoked)
{
*ret = default;
// This is important, as it tells Object::call that no method was called.
// Otherwise, it would prevent Object::call from calling native methods.
(*refCallError).error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD;
(*refCallError).Error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD;
return false.ToGodotBool();
}
@ -60,12 +62,15 @@ namespace Godot.Bridge
throw new InvalidOperationException();
var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
NativeFuncs.godotsharp_string_name_new_copy(name));
NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(name)));
if (godotObject.InternalGodotScriptSetFieldOrPropViaReflection(nameManaged.ToString(), value))
if (godotObject.InternalGodotScriptSetFieldOrPropViaReflection(
nameManaged.ToString(), CustomUnsafe.AsRef(value)))
{
return true.ToGodotBool();
}
object valueManaged = Marshaling.variant_to_mono_object(value);
object valueManaged = Marshaling.ConvertVariantToManagedObject(CustomUnsafe.AsRef(value));
return godotObject._Set(nameManaged, valueManaged).ToGodotBool();
}
@ -89,10 +94,10 @@ namespace Godot.Bridge
throw new InvalidOperationException();
var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
NativeFuncs.godotsharp_string_name_new_copy(name));
NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(name)));
if (godotObject.InternalGodotScriptGetFieldOrPropViaReflection(nameManaged.ToString(),
out godot_variant outRetValue))
out godot_variant outRetValue))
{
*outRet = outRetValue;
return true.ToGodotBool();
@ -106,7 +111,7 @@ namespace Godot.Bridge
return false.ToGodotBool();
}
*outRet = Marshaling.mono_object_to_variant(ret);
*outRet = Marshaling.ConvertManagedObjectToVariant(ret);
return true.ToGodotBool();
}
catch (Exception e)
@ -158,7 +163,7 @@ namespace Godot.Bridge
return;
}
*outRes = Marshaling.mono_string_to_godot(resultStr);
*outRes = Marshaling.ConvertStringToNative(resultStr);
*outValid = true.ToGodotBool();
}
catch (Exception e)

View file

@ -104,8 +104,8 @@ namespace Godot.Bridge
for (int i = 0; i < paramCount; i++)
{
invokeParams[i] = Marshaling.variant_to_mono_object_of_type(
args[i], parameters[i].ParameterType);
invokeParams[i] = Marshaling.ConvertVariantToManagedObjectOfType(
*args[i], parameters[i].ParameterType);
}
ctor.Invoke(obj, invokeParams);
@ -149,7 +149,7 @@ namespace Godot.Bridge
return;
}
*outRes = NativeFuncs.godotsharp_string_name_new_copy(nativeName.NativeValue);
*outRes = NativeFuncs.godotsharp_string_name_new_copy((godot_string_name)nativeName.NativeValue);
}
catch (Exception e)
{
@ -177,7 +177,7 @@ namespace Godot.Bridge
{
// Performance is not critical here as this will be replaced with a generated dictionary.
using var stringName = StringName.CreateTakingOwnershipOfDisposableValue(
NativeFuncs.godotsharp_string_name_new_copy(nativeTypeName));
NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(nativeTypeName)));
string nativeTypeNameStr = stringName.ToString();
if (nativeTypeNameStr[0] == '_')
@ -277,7 +277,8 @@ namespace Godot.Bridge
*outOwnerIsNull = false.ToGodotBool();
owner.InternalRaiseEventSignal(eventSignalName, args, argCount);
owner.InternalRaiseEventSignal(CustomUnsafe.AsRef(eventSignalName),
new NativeVariantPtrArgs(args), argCount);
}
catch (Exception e)
{
@ -302,9 +303,10 @@ namespace Godot.Bridge
// Legacy signals
foreach (var signalDelegate in top
.GetNestedTypes(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public)
.Where(nestedType => typeof(Delegate).IsAssignableFrom(nestedType))
.Where(@delegate => @delegate.GetCustomAttributes().OfType<SignalAttribute>().Any()))
.GetNestedTypes(BindingFlags.DeclaredOnly | BindingFlags.NonPublic |
BindingFlags.Public)
.Where(nestedType => typeof(Delegate).IsAssignableFrom(nestedType))
.Where(@delegate => @delegate.GetCustomAttributes().OfType<SignalAttribute>().Any()))
{
var invokeMethod = signalDelegate.GetMethod("Invoke");
@ -315,7 +317,7 @@ namespace Godot.Bridge
foreach (var parameters in invokeMethod.GetParameters())
{
var paramType = Marshaling.managed_to_variant_type(
var paramType = Marshaling.ConvertManagedTypeToVariantType(
parameters.ParameterType, out bool nilIsVariant);
signalParams.Add(new Dictionary()
{
@ -341,8 +343,8 @@ namespace Godot.Bridge
BindingFlags.NonPublic | BindingFlags.Public);
foreach (var eventSignalField in fields
.Where(f => typeof(Delegate).IsAssignableFrom(f.FieldType))
.Where(f => foundEventSignals.Contains(f.Name)))
.Where(f => typeof(Delegate).IsAssignableFrom(f.FieldType))
.Where(f => foundEventSignals.Contains(f.Name)))
{
var delegateType = eventSignalField.FieldType;
var invokeMethod = delegateType.GetMethod("Invoke");
@ -354,7 +356,7 @@ namespace Godot.Bridge
foreach (var parameters in invokeMethod.GetParameters())
{
var paramType = Marshaling.managed_to_variant_type(
var paramType = Marshaling.ConvertManagedTypeToVariantType(
parameters.ParameterType, out bool nilIsVariant);
signalParams.Add(new Dictionary()
{
@ -370,7 +372,7 @@ namespace Godot.Bridge
top = top.BaseType;
}
*outRetSignals = NativeFuncs.godotsharp_dictionary_new_copy(signals.NativeValue);
*outRetSignals = NativeFuncs.godotsharp_dictionary_new_copy((godot_dictionary)signals.NativeValue);
}
catch (Exception e)
{
@ -387,7 +389,7 @@ namespace Godot.Bridge
// Performance is not critical here as this will be replaced with source generators.
using var signals = new Dictionary();
string signalNameStr = Marshaling.mono_string_from_godot(*signalName);
string signalNameStr = Marshaling.ConvertStringToManaged(*signalName);
Type top = _scriptBridgeMap[scriptPtr];
Type native = Object.InternalGetClassNativeBase(top);
@ -401,7 +403,7 @@ namespace Godot.Bridge
.Where(nestedType => typeof(Delegate).IsAssignableFrom(nestedType))
.Where(@delegate => @delegate.GetCustomAttributes().OfType<SignalAttribute>().Any())
.Any(signalDelegate => signalDelegate.Name == signalNameStr)
)
)
{
return true.ToGodotBool();
}
@ -413,7 +415,7 @@ namespace Godot.Bridge
BindingFlags.NonPublic | BindingFlags.Public)
.Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any())
.Any(eventSignal => eventSignal.Name == signalNameStr)
)
)
{
return true.ToGodotBool();
}
@ -440,7 +442,7 @@ namespace Godot.Bridge
if (!_scriptBridgeMap.TryGetValue(scriptPtr, out var scriptType))
return false.ToGodotBool();
string methodStr = Marshaling.mono_string_from_godot(*method);
string methodStr = Marshaling.ConvertStringToManaged(*method);
if (deep.ToBool())
{
@ -517,7 +519,7 @@ namespace Godot.Bridge
{
try
{
string scriptPathStr = Marshaling.mono_string_from_godot(*scriptPath);
string scriptPathStr = Marshaling.ConvertStringToManaged(*scriptPath);
if (!_scriptLookupMap.TryGetValue(scriptPathStr, out var lookupInfo))
return false.ToGodotBool();
@ -612,7 +614,8 @@ namespace Godot.Bridge
}
*outRpcFunctionsDest =
NativeFuncs.godotsharp_dictionary_new_copy(((Dictionary)rpcFunctions).NativeValue);
NativeFuncs.godotsharp_dictionary_new_copy(
(godot_dictionary)((Dictionary)rpcFunctions).NativeValue);
}
catch (Exception e)
{

View file

@ -1,5 +1,7 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Godot.NativeInterop;
namespace Godot
{
@ -24,7 +26,7 @@ namespace Godot
/// }
/// </code>
/// </example>
public struct Callable
public readonly struct Callable
{
private readonly Object _target;
private readonly StringName _method;
@ -34,10 +36,12 @@ namespace Godot
/// Object that contains the method.
/// </summary>
public Object Target => _target;
/// <summary>
/// Name of the method that will be called.
/// </summary>
public StringName Method => _method;
/// <summary>
/// Delegate of the method that will be called.
/// </summary>
@ -73,15 +77,43 @@ namespace Godot
_delegate = @delegate;
}
private const int VarArgsSpanThreshold = 5;
/// <summary>
/// Calls the method represented by this <see cref="Callable"/>.
/// Arguments can be passed and should match the method's signature.
/// </summary>
/// <param name="args">Arguments that will be passed to the method call.</param>
/// <returns>The value returned by the method.</returns>
public object Call(params object[] args)
public unsafe object Call(params object[] args)
{
return godot_icall_Callable_Call(ref this, args);
using godot_callable callable = Marshaling.ConvertCallableToNative(this);
int argc = args.Length;
Span<godot_variant.movable> argsStoreSpan = argc <= VarArgsSpanThreshold ?
stackalloc godot_variant.movable[VarArgsSpanThreshold].Cleared() :
new godot_variant.movable[argc];
Span<IntPtr> argsSpan = argc <= 10 ?
stackalloc IntPtr[argc] :
new IntPtr[argc];
using var variantSpanDisposer = new VariantSpanDisposer(argsStoreSpan);
fixed (godot_variant* varargs = &MemoryMarshal.GetReference(argsStoreSpan).DangerousSelfRef)
fixed (IntPtr* argsPtr = &MemoryMarshal.GetReference(argsSpan))
{
for (int i = 0; i < argc; i++)
{
varargs[i] = Marshaling.ConvertManagedObjectToVariant(args[i]);
argsPtr[i] = new IntPtr(&varargs[i]);
}
using godot_variant ret = NativeFuncs.godotsharp_callable_call(callable,
(godot_variant**)argsPtr, argc, out _);
return Marshaling.ConvertVariantToManagedObject(ret);
}
}
/// <summary>
@ -89,9 +121,33 @@ namespace Godot
/// Arguments can be passed and should match the method's signature.
/// </summary>
/// <param name="args">Arguments that will be passed to the method call.</param>
public void CallDeferred(params object[] args)
public unsafe void CallDeferred(params object[] args)
{
godot_icall_Callable_CallDeferred(ref this, args);
using godot_callable callable = Marshaling.ConvertCallableToNative(this);
int argc = args.Length;
Span<godot_variant.movable> argsStoreSpan = argc <= VarArgsSpanThreshold ?
stackalloc godot_variant.movable[VarArgsSpanThreshold].Cleared() :
new godot_variant.movable[argc];
Span<IntPtr> argsSpan = argc <= 10 ?
stackalloc IntPtr[argc] :
new IntPtr[argc];
using var variantSpanDisposer = new VariantSpanDisposer(argsStoreSpan);
fixed (godot_variant* varargs = &MemoryMarshal.GetReference(argsStoreSpan).DangerousSelfRef)
fixed (IntPtr* argsPtr = &MemoryMarshal.GetReference(argsSpan))
{
for (int i = 0; i < argc; i++)
{
varargs[i] = Marshaling.ConvertManagedObjectToVariant(args[i]);
argsPtr[i] = new IntPtr(&varargs[i]);
}
NativeFuncs.godotsharp_callable_call_deferred(callable, (godot_variant**)argsPtr, argc);
}
}
[MethodImpl(MethodImplOptions.InternalCall)]

View file

@ -210,7 +210,7 @@ namespace Godot
case 3:
return a;
default:
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(index));
}
}
set
@ -230,7 +230,7 @@ namespace Godot
a = value;
return;
default:
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(index));
}
}
}
@ -841,7 +841,7 @@ namespace Godot
return ParseCol4(str, ofs) * 16 + ParseCol4(str, ofs + 1);
}
private string ToHex32(float val)
private static string ToHex32(float val)
{
byte b = (byte)Mathf.RoundToInt(Mathf.Clamp(val * 255, 0, 255));
return b.HexEncode();
@ -849,7 +849,7 @@ namespace Godot
internal static bool HtmlIsValid(string color)
{
if (color.Length == 0)
if (string.IsNullOrEmpty(color))
{
return false;
}

View file

@ -18,7 +18,7 @@ namespace Godot
else
sb.Append(type);
sb.Append(" ");
sb.Append(' ');
}
[UnmanagedCallersOnly]
@ -55,15 +55,15 @@ namespace Godot
if (methodBase is MethodInfo)
sb.AppendTypeName(((MethodInfo)methodBase).ReturnType);
sb.Append(methodBase.DeclaringType.FullName);
sb.Append(".");
sb.Append(methodBase.DeclaringType?.FullName ?? "<unknown>");
sb.Append('.');
sb.Append(methodBase.Name);
if (methodBase.IsGenericMethod)
{
Type[] genericParams = methodBase.GetGenericArguments();
sb.Append("<");
sb.Append('<');
for (int j = 0; j < genericParams.Length; j++)
{
@ -73,10 +73,10 @@ namespace Godot
sb.AppendTypeName(genericParams[j]);
}
sb.Append(">");
sb.Append('>');
}
sb.Append("(");
sb.Append('(');
bool varArgs = (methodBase.CallingConvention & CallingConventions.VarArgs) != 0;
@ -93,7 +93,7 @@ namespace Godot
sb.AppendTypeName(parameter[i].ParameterType);
}
sb.Append(")");
sb.Append(')');
methodDecl = sb.ToString();
}

View file

@ -48,13 +48,13 @@ namespace Godot
for (uint i = 0; i < argc; i++)
{
managedArgs[i] = Marshaling.variant_to_mono_object_of_type(
args[i], parameterInfos[i].ParameterType);
managedArgs[i] = Marshaling.ConvertVariantToManagedObjectOfType(
*args[i], parameterInfos[i].ParameterType);
}
object invokeRet = @delegate.DynamicInvoke(managedArgs);
*outRet = Marshaling.mono_object_to_variant(invokeRet);
*outRet = Marshaling.ConvertManagedObjectToVariant(invokeRet);
}
catch (Exception e)
{

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Collections;
using Godot.NativeInterop;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
namespace Godot.Collections
{
@ -15,14 +16,14 @@ namespace Godot.Collections
IDictionary,
IDisposable
{
public godot_dictionary NativeValue;
internal godot_dictionary.movable NativeValue;
/// <summary>
/// Constructs a new empty <see cref="Dictionary"/>.
/// </summary>
public Dictionary()
{
NativeValue = NativeFuncs.godotsharp_dictionary_new();
NativeValue = (godot_dictionary.movable)NativeFuncs.godotsharp_dictionary_new();
}
/// <summary>
@ -33,7 +34,7 @@ namespace Godot.Collections
public Dictionary(IDictionary dictionary) : this()
{
if (dictionary == null)
throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'");
throw new ArgumentNullException(nameof(dictionary));
foreach (DictionaryEntry entry in dictionary)
Add(entry.Key, entry.Value);
@ -41,7 +42,9 @@ namespace Godot.Collections
private Dictionary(godot_dictionary nativeValueToOwn)
{
NativeValue = nativeValueToOwn;
NativeValue = (godot_dictionary.movable)(nativeValueToOwn.IsAllocated ?
nativeValueToOwn :
NativeFuncs.godotsharp_dictionary_new());
}
// Explicit name to make it very clear
@ -65,7 +68,7 @@ namespace Godot.Collections
public void Dispose(bool disposing)
{
// Always dispose `NativeValue` even if disposing is true
NativeValue.Dispose();
NativeValue.DangerousSelfRef.Dispose();
}
/// <summary>
@ -76,7 +79,8 @@ namespace Godot.Collections
public Dictionary Duplicate(bool deep = false)
{
godot_dictionary newDictionary;
NativeFuncs.godotsharp_dictionary_duplicate(ref NativeValue, deep.ToGodotBool(), out newDictionary);
var self = (godot_dictionary)NativeValue;
NativeFuncs.godotsharp_dictionary_duplicate(ref self, deep.ToGodotBool(), out newDictionary);
return CreateTakingOwnershipOfDisposableValue(newDictionary);
}
@ -90,7 +94,8 @@ namespace Godot.Collections
get
{
godot_array keysArray;
NativeFuncs.godotsharp_dictionary_keys(ref NativeValue, out keysArray);
var self = (godot_dictionary)NativeValue;
NativeFuncs.godotsharp_dictionary_keys(ref self, out keysArray);
return Array.CreateTakingOwnershipOfDisposableValue(keysArray);
}
}
@ -103,22 +108,25 @@ namespace Godot.Collections
get
{
godot_array valuesArray;
NativeFuncs.godotsharp_dictionary_values(ref NativeValue, out valuesArray);
var self = (godot_dictionary)NativeValue;
NativeFuncs.godotsharp_dictionary_values(ref self, out valuesArray);
return Array.CreateTakingOwnershipOfDisposableValue(valuesArray);
}
}
private (Array keys, Array values, int count) GetKeyValuePairs()
{
var self = (godot_dictionary)NativeValue;
godot_array keysArray;
NativeFuncs.godotsharp_dictionary_keys(ref NativeValue, out keysArray);
NativeFuncs.godotsharp_dictionary_keys(ref self, out keysArray);
var keys = Array.CreateTakingOwnershipOfDisposableValue(keysArray);
godot_array valuesArray;
NativeFuncs.godotsharp_dictionary_keys(ref NativeValue, out valuesArray);
NativeFuncs.godotsharp_dictionary_keys(ref self, out valuesArray);
var values = Array.CreateTakingOwnershipOfDisposableValue(valuesArray);
int count = NativeFuncs.godotsharp_dictionary_count(ref NativeValue);
int count = NativeFuncs.godotsharp_dictionary_count(ref self);
return (keys, values, count);
}
@ -131,16 +139,17 @@ namespace Godot.Collections
/// Returns the object at the given <paramref name="key"/>.
/// </summary>
/// <value>The object at the given <paramref name="key"/>.</value>
public unsafe object this[object key]
public object this[object key]
{
get
{
using godot_variant variantKey = Marshaling.mono_object_to_variant(key);
if (NativeFuncs.godotsharp_dictionary_try_get_value(ref NativeValue, &variantKey,
out godot_variant value).ToBool())
using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key);
var self = (godot_dictionary)NativeValue;
if (NativeFuncs.godotsharp_dictionary_try_get_value(ref self, variantKey,
out godot_variant value).ToBool())
{
using (value)
return Marshaling.variant_to_mono_object(&value);
return Marshaling.ConvertVariantToManagedObject(value);
}
else
{
@ -149,9 +158,10 @@ namespace Godot.Collections
}
set
{
using godot_variant variantKey = Marshaling.mono_object_to_variant(key);
using godot_variant variantValue = Marshaling.mono_object_to_variant(value);
NativeFuncs.godotsharp_dictionary_set_value(ref NativeValue, &variantKey, &variantValue);
using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key);
using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(value);
var self = (godot_dictionary)NativeValue;
NativeFuncs.godotsharp_dictionary_set_value(ref self, variantKey, variantValue);
}
}
@ -161,31 +171,38 @@ namespace Godot.Collections
/// </summary>
/// <param name="key">The key at which to add the object.</param>
/// <param name="value">The object to add.</param>
public unsafe void Add(object key, object value)
public void Add(object key, object value)
{
using godot_variant variantKey = Marshaling.mono_object_to_variant(key);
using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key);
if (NativeFuncs.godotsharp_dictionary_contains_key(ref NativeValue, &variantKey).ToBool())
var self = (godot_dictionary)NativeValue;
if (NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool())
throw new ArgumentException("An element with the same key already exists", nameof(key));
using godot_variant variantValue = Marshaling.mono_object_to_variant(value);
NativeFuncs.godotsharp_dictionary_add(ref NativeValue, &variantKey, &variantValue);
using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(value);
NativeFuncs.godotsharp_dictionary_add(ref self, variantKey, variantValue);
}
/// <summary>
/// Erases all items from this <see cref="Dictionary"/>.
/// </summary>
public void Clear() => NativeFuncs.godotsharp_dictionary_clear(ref NativeValue);
public void Clear()
{
var self = (godot_dictionary)NativeValue;
NativeFuncs.godotsharp_dictionary_clear(ref self);
}
/// <summary>
/// Checks if this <see cref="Dictionary"/> contains the given key.
/// </summary>
/// <param name="key">The key to look for.</param>
/// <returns>Whether or not this dictionary contains the given key.</returns>
public unsafe bool Contains(object key)
public bool Contains(object key)
{
using godot_variant variantKey = Marshaling.mono_object_to_variant(key);
return NativeFuncs.godotsharp_dictionary_contains_key(ref NativeValue, &variantKey).ToBool();
using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key);
var self = (godot_dictionary)NativeValue;
return NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool();
}
/// <summary>
@ -198,10 +215,11 @@ namespace Godot.Collections
/// Removes an element from this <see cref="Dictionary"/> by key.
/// </summary>
/// <param name="key">The key of the element to remove.</param>
public unsafe void Remove(object key)
public void Remove(object key)
{
using godot_variant variantKey = Marshaling.mono_object_to_variant(key);
NativeFuncs.godotsharp_dictionary_remove_key(ref NativeValue, &variantKey);
using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key);
var self = (godot_dictionary)NativeValue;
NativeFuncs.godotsharp_dictionary_remove_key(ref self, variantKey);
}
// ICollection
@ -215,7 +233,14 @@ namespace Godot.Collections
/// This is also known as the size or length of the dictionary.
/// </summary>
/// <returns>The number of elements.</returns>
public int Count => NativeFuncs.godotsharp_dictionary_count(ref NativeValue);
public int Count
{
get
{
var self = (godot_dictionary)NativeValue;
return NativeFuncs.godotsharp_dictionary_count(ref self);
}
}
/// <summary>
/// Copies the elements of this <see cref="Dictionary"/> to the given
@ -279,17 +304,19 @@ namespace Godot.Collections
}
}
private unsafe void UpdateEntry()
private void UpdateEntry()
{
_dirty = false;
NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref _dictionary.NativeValue, _index,
var self = (godot_dictionary)_dictionary.NativeValue;
NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref self, _index,
out godot_variant key,
out godot_variant value);
using (key)
using (value)
{
_entry = new DictionaryEntry(Marshaling.variant_to_mono_object(&key),
Marshaling.variant_to_mono_object(&value));
// FIXME: DictionaryEntry keys cannot be null, but Godot dictionaries allow null keys
_entry = new DictionaryEntry(Marshaling.ConvertVariantToManagedObject(key)!,
Marshaling.ConvertVariantToManagedObject(value));
}
}
@ -315,11 +342,12 @@ namespace Godot.Collections
/// Converts this <see cref="Dictionary"/> to a string.
/// </summary>
/// <returns>A string representation of this dictionary.</returns>
public override unsafe string ToString()
public override string ToString()
{
using godot_string str = default;
NativeFuncs.godotsharp_dictionary_to_string(ref NativeValue, &str);
return Marshaling.mono_string_from_godot(str);
var self = (godot_dictionary)NativeValue;
NativeFuncs.godotsharp_dictionary_to_string(ref self, out godot_string str);
using (str)
return Marshaling.ConvertStringToManaged(str);
}
}
@ -345,7 +373,11 @@ namespace Godot.Collections
{
private readonly Dictionary _underlyingDict;
internal ref godot_dictionary NativeValue => ref _underlyingDict.NativeValue;
internal ref godot_dictionary.movable NativeValue
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref _underlyingDict.NativeValue;
}
// ReSharper disable StaticMemberInGenericType
// Warning is about unique static fields being created for each generic type combination:
@ -375,10 +407,10 @@ namespace Godot.Collections
/// <returns>A new Godot Dictionary.</returns>
public Dictionary(IDictionary<TKey, TValue> dictionary)
{
_underlyingDict = new Dictionary();
if (dictionary == null)
throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'");
throw new ArgumentNullException(nameof(dictionary));
_underlyingDict = new Dictionary();
foreach (KeyValuePair<TKey, TValue> entry in dictionary)
Add(entry.Key, entry.Value);
@ -405,7 +437,7 @@ namespace Godot.Collections
/// <param name="from">The typed dictionary to convert.</param>
public static explicit operator Dictionary(Dictionary<TKey, TValue> from)
{
return from._underlyingDict;
return from?._underlyingDict;
}
/// <summary>
@ -428,19 +460,17 @@ namespace Godot.Collections
{
get
{
unsafe
using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
if (NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
variantKey, out godot_variant value).ToBool())
{
using godot_variant variantKey = Marshaling.mono_object_to_variant(key);
if (NativeFuncs.godotsharp_dictionary_try_get_value(ref _underlyingDict.NativeValue,
&variantKey, out godot_variant value).ToBool())
{
using (value)
return (TValue)Marshaling.variant_to_mono_object_of_type(&value, TypeOfValues);
}
else
{
throw new KeyNotFoundException();
}
using (value)
return (TValue)Marshaling.ConvertVariantToManagedObjectOfType(value, TypeOfValues);
}
else
{
throw new KeyNotFoundException();
}
}
set => _underlyingDict[key] = value;
@ -454,7 +484,8 @@ namespace Godot.Collections
get
{
godot_array keyArray;
NativeFuncs.godotsharp_dictionary_keys(ref _underlyingDict.NativeValue, out keyArray);
var self = (godot_dictionary)_underlyingDict.NativeValue;
NativeFuncs.godotsharp_dictionary_keys(ref self, out keyArray);
return Array<TKey>.CreateTakingOwnershipOfDisposableValue(keyArray);
}
}
@ -467,21 +498,23 @@ namespace Godot.Collections
get
{
godot_array valuesArray;
NativeFuncs.godotsharp_dictionary_values(ref _underlyingDict.NativeValue, out valuesArray);
var self = (godot_dictionary)_underlyingDict.NativeValue;
NativeFuncs.godotsharp_dictionary_values(ref self, out valuesArray);
return Array<TValue>.CreateTakingOwnershipOfDisposableValue(valuesArray);
}
}
private unsafe KeyValuePair<TKey, TValue> GetKeyValuePair(int index)
private KeyValuePair<TKey, TValue> GetKeyValuePair(int index)
{
NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref _underlyingDict.NativeValue, index,
var self = (godot_dictionary)_underlyingDict.NativeValue;
NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref self, index,
out godot_variant key,
out godot_variant value);
using (key)
using (value)
{
return new KeyValuePair<TKey, TValue>((TKey)Marshaling.variant_to_mono_object(&key),
(TValue)Marshaling.variant_to_mono_object(&value));
return new KeyValuePair<TKey, TValue>((TKey)Marshaling.ConvertVariantToManagedObject(key),
(TValue)Marshaling.ConvertVariantToManagedObject(value));
}
}
@ -510,10 +543,11 @@ namespace Godot.Collections
/// Removes an element from this <see cref="Dictionary{TKey, TValue}"/> by key.
/// </summary>
/// <param name="key">The key of the element to remove.</param>
public unsafe bool Remove(TKey key)
public bool Remove(TKey key)
{
using godot_variant variantKey = Marshaling.mono_object_to_variant(key);
return NativeFuncs.godotsharp_dictionary_remove_key(ref _underlyingDict.NativeValue, &variantKey).ToBool();
using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
return NativeFuncs.godotsharp_dictionary_remove_key(ref self, variantKey).ToBool();
}
/// <summary>
@ -522,16 +556,17 @@ namespace Godot.Collections
/// <param name="key">The key of the element to get.</param>
/// <param name="value">The value at the given <paramref name="key"/>.</param>
/// <returns>If an object was found for the given <paramref name="key"/>.</returns>
public unsafe bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
{
using godot_variant variantKey = Marshaling.mono_object_to_variant(key);
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref _underlyingDict.NativeValue,
&variantKey, out godot_variant retValue).ToBool();
using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
variantKey, out godot_variant retValue).ToBool();
using (retValue)
{
value = found ?
(TValue)Marshaling.variant_to_mono_object_of_type(&retValue, TypeOfValues) :
(TValue)Marshaling.ConvertVariantToManagedObjectOfType(retValue, TypeOfValues) :
default;
}
@ -562,19 +597,20 @@ namespace Godot.Collections
_underlyingDict.Clear();
}
unsafe bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
{
using godot_variant variantKey = Marshaling.mono_object_to_variant(item.Key);
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref _underlyingDict.NativeValue,
&variantKey, out godot_variant retValue).ToBool();
using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(item.Key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
variantKey, out godot_variant retValue).ToBool();
using (retValue)
{
if (!found)
return false;
using godot_variant variantValue = Marshaling.mono_object_to_variant(item.Value);
return NativeFuncs.godotsharp_variant_equals(&variantValue, &retValue).ToBool();
using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(item.Value);
return NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool();
}
}
@ -606,22 +642,23 @@ namespace Godot.Collections
}
}
unsafe bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
{
using godot_variant variantKey = Marshaling.mono_object_to_variant(item.Key);
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref _underlyingDict.NativeValue,
&variantKey, out godot_variant retValue).ToBool();
using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(item.Key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
variantKey, out godot_variant retValue).ToBool();
using (retValue)
{
if (!found)
return false;
using godot_variant variantValue = Marshaling.mono_object_to_variant(item.Value);
if (NativeFuncs.godotsharp_variant_equals(&variantValue, &retValue).ToBool())
using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(item.Value);
if (NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool())
{
return NativeFuncs.godotsharp_dictionary_remove_key(
ref _underlyingDict.NativeValue, &variantKey).ToBool();
ref self, variantKey).ToBool();
}
return false;

View file

@ -35,17 +35,14 @@ namespace Godot
if (!IsInstanceValid(obj))
return null;
using godot_ref weakRef = default;
unsafe
NativeFuncs.godotsharp_weakref(GetPtr(obj), out godot_ref weakRef);
using (weakRef)
{
NativeFuncs.godotsharp_weakref(GetPtr(obj), &weakRef);
if (weakRef.IsNull)
return null;
return (WeakRef)InteropUtils.UnmanagedGetManaged(weakRef.Reference);
}
if (weakRef.IsNull)
return null;
return (WeakRef)InteropUtils.UnmanagedGetManaged(weakRef._reference);
}
}
}

View file

@ -1,5 +1,4 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using Godot.Collections;
using Godot.NativeInterop;
@ -11,7 +10,7 @@ namespace Godot
/// Returns a list of all nodes assigned to the given <paramref name="group"/>.
/// </summary>
/// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam>
public unsafe Array<T> GetNodesInGroup<T>(StringName group) where T : class
public Array<T> GetNodesInGroup<T>(StringName group) where T : class
{
var array = GetNodesInGroup(group);
@ -29,19 +28,18 @@ namespace Godot
BindingFlags.Public | BindingFlags.NonPublic);
var nativeName = (StringName)field!.GetValue(null);
godot_string_name nativeNameAux = nativeName.NativeValue;
godot_array inputAux = array.NativeValue;
godot_array filteredArray;
NativeFuncs.godotsharp_array_filter_godot_objects_by_native(
&nativeNameAux, &inputAux, &filteredArray);
var nativeNameSelf = (godot_string_name)nativeName!.NativeValue;
var inputSelf = (godot_array)array.NativeValue;
NativeFuncs.godotsharp_array_filter_godot_objects_by_native(nativeNameSelf, inputSelf,
out godot_array filteredArray);
return Array<T>.CreateTakingOwnershipOfDisposableValue(filteredArray);
}
else
{
// Custom derived type
godot_array inputAux = array.NativeValue;
godot_array filteredArray;
NativeFuncs.godotsharp_array_filter_godot_objects_by_non_native(&inputAux, &filteredArray);
var inputSelf = (godot_array)array.NativeValue;
NativeFuncs.godotsharp_array_filter_godot_objects_by_non_native(inputSelf,
out godot_array filteredArray);
var filteredArrayWrapped = Array.CreateTakingOwnershipOfDisposableValue(filteredArray);

View file

@ -26,12 +26,12 @@ namespace Godot
/// <param name="bytes">Byte array that will be decoded to a <c>Variant</c>.</param>
/// <param name="allowObjects">If objects should be decoded.</param>
/// <returns>The decoded <c>Variant</c>.</returns>
public static unsafe object Bytes2Var(byte[] bytes, bool allowObjects = false)
public static object Bytes2Var(byte[] bytes, bool allowObjects = false)
{
using var varBytes = Marshaling.mono_array_to_PackedByteArray(bytes);
using godot_variant ret = default;
NativeFuncs.godotsharp_bytes2var(&varBytes, allowObjects.ToGodotBool(), &ret);
return Marshaling.variant_to_mono_object(&ret);
using var varBytes = Marshaling.ConvertSystemArrayToNativePackedByteArray(bytes);
NativeFuncs.godotsharp_bytes2var(varBytes, allowObjects.ToGodotBool(), out godot_variant ret);
using (ret)
return Marshaling.ConvertVariantToManagedObject(ret);
}
/// <summary>
@ -49,12 +49,12 @@ namespace Godot
/// </code>
/// </example>
/// <returns>The <c>Variant</c> converted to the given <paramref name="type"/>.</returns>
public static unsafe object Convert(object what, Variant.Type type)
public static object Convert(object what, Variant.Type type)
{
using var whatVariant = Marshaling.mono_object_to_variant(what);
using godot_variant ret = default;
NativeFuncs.godotsharp_convert(&whatVariant, (int)type, &ret);
return Marshaling.variant_to_mono_object(&ret);
using var whatVariant = Marshaling.ConvertManagedObjectToVariant(what);
NativeFuncs.godotsharp_convert(whatVariant, (int)type, out godot_variant ret);
using (ret)
return Marshaling.ConvertVariantToManagedObject(ret);
}
/// <summary>
@ -88,10 +88,10 @@ namespace Godot
/// </example>
/// <param name="var">Variable that will be hashed.</param>
/// <returns>Hash of the variable passed.</returns>
public static unsafe int Hash(object var)
public static int Hash(object var)
{
using var variant = Marshaling.mono_object_to_variant(var);
return NativeFuncs.godotsharp_hash(&variant);
using var variant = Marshaling.ConvertManagedObjectToVariant(var);
return NativeFuncs.godotsharp_hash(variant);
}
/// <summary>
@ -207,10 +207,10 @@ namespace Godot
/// </code>
/// </example>
/// <param name="message">Error message.</param>
public static unsafe void PushError(string message)
public static void PushError(string message)
{
using var godotStr = Marshaling.mono_string_to_godot(message);
NativeFuncs.godotsharp_pusherror(&godotStr);
using var godotStr = Marshaling.ConvertStringToNative(message);
NativeFuncs.godotsharp_pusherror(godotStr);
}
/// <summary>
@ -220,10 +220,10 @@ namespace Godot
/// GD.PushWarning("test warning"); // Prints "test warning" to debugger and terminal as warning call
/// </example>
/// <param name="message">Warning message.</param>
public static unsafe void PushWarning(string message)
public static void PushWarning(string message)
{
using var godotStr = Marshaling.mono_string_to_godot(message);
NativeFuncs.godotsharp_pushwarning(&godotStr);
using var godotStr = Marshaling.ConvertStringToNative(message);
NativeFuncs.godotsharp_pushwarning(godotStr);
}
/// <summary>
@ -242,11 +242,11 @@ namespace Godot
/// </code>
/// </example>
/// <param name="what">Arguments that will be printed.</param>
public static unsafe void Print(params object[] what)
public static void Print(params object[] what)
{
string str = string.Concat(GetPrintParams(what));
using var godotStr = Marshaling.mono_string_to_godot(str);
NativeFuncs.godotsharp_print(&godotStr);
using var godotStr = Marshaling.ConvertStringToNative(str);
NativeFuncs.godotsharp_print(godotStr);
}
/// <summary>
@ -273,11 +273,11 @@ namespace Godot
/// </code>
/// </example>
/// <param name="what">Arguments that will be printed.</param>
public static unsafe void PrintRich(params object[] what)
public static void PrintRich(params object[] what)
{
string str = string.Concat(GetPrintParams(what));
using var godotStr = Marshaling.mono_string_to_godot(str);
NativeFuncs.godotsharp_print_rich(&godotStr);
using var godotStr = Marshaling.ConvertStringToNative(str);
NativeFuncs.godotsharp_print_rich(godotStr);
}
/// <summary>
@ -297,11 +297,11 @@ namespace Godot
/// </code>
/// </example>
/// <param name="what">Arguments that will be printed.</param>
public static unsafe void PrintErr(params object[] what)
public static void PrintErr(params object[] what)
{
string str = string.Concat(GetPrintParams(what));
using var godotStr = Marshaling.mono_string_to_godot(str);
NativeFuncs.godotsharp_printerr(&godotStr);
using var godotStr = Marshaling.ConvertStringToNative(str);
NativeFuncs.godotsharp_printerr(godotStr);
}
/// <summary>
@ -319,11 +319,11 @@ namespace Godot
/// </code>
/// </example>
/// <param name="what">Arguments that will be printed.</param>
public static unsafe void PrintRaw(params object[] what)
public static void PrintRaw(params object[] what)
{
string str = string.Concat(GetPrintParams(what));
using var godotStr = Marshaling.mono_string_to_godot(str);
NativeFuncs.godotsharp_printraw(&godotStr);
using var godotStr = Marshaling.ConvertStringToNative(str);
NativeFuncs.godotsharp_printraw(godotStr);
}
/// <summary>
@ -335,11 +335,11 @@ namespace Godot
/// </code>
/// </example>
/// <param name="what">Arguments that will be printed.</param>
public static unsafe void PrintS(params object[] what)
public static void PrintS(params object[] what)
{
string str = string.Join(' ', GetPrintParams(what));
using var godotStr = Marshaling.mono_string_to_godot(str);
NativeFuncs.godotsharp_prints(&godotStr);
using var godotStr = Marshaling.ConvertStringToNative(str);
NativeFuncs.godotsharp_prints(godotStr);
}
/// <summary>
@ -351,11 +351,11 @@ namespace Godot
/// </code>
/// </example>
/// <param name="what">Arguments that will be printed.</param>
public static unsafe void PrintT(params object[] what)
public static void PrintT(params object[] what)
{
string str = string.Join('\t', GetPrintParams(what));
using var godotStr = Marshaling.mono_string_to_godot(str);
NativeFuncs.godotsharp_printt(&godotStr);
using var godotStr = Marshaling.ConvertStringToNative(str);
NativeFuncs.godotsharp_printt(godotStr);
}
/// <summary>
@ -520,12 +520,12 @@ namespace Godot
/// </summary>
/// <param name="what">Arguments that will converted to string.</param>
/// <returns>The string formed by the given arguments.</returns>
public static unsafe string Str(params object[] what)
public static string Str(params object[] what)
{
using var whatGodotArray = Marshaling.mono_array_to_Array(what);
using godot_string ret = default;
NativeFuncs.godotsharp_str(&whatGodotArray, &ret);
return Marshaling.mono_string_from_godot(ret);
using var whatGodotArray = Marshaling.ConvertSystemArrayToNativeGodotArray(what);
NativeFuncs.godotsharp_str(whatGodotArray, out godot_string ret);
using (ret)
return Marshaling.ConvertStringToManaged(ret);
}
/// <summary>
@ -540,12 +540,12 @@ namespace Godot
/// </example>
/// <param name="str">String that will be converted to Variant.</param>
/// <returns>The decoded <c>Variant</c>.</returns>
public static unsafe object Str2Var(string str)
public static object Str2Var(string str)
{
using var godotStr = Marshaling.mono_string_to_godot(str);
using godot_variant ret = default;
NativeFuncs.godotsharp_str2var(&godotStr, &ret);
return Marshaling.variant_to_mono_object(&ret);
using var godotStr = Marshaling.ConvertStringToNative(str);
NativeFuncs.godotsharp_str2var(godotStr, out godot_variant ret);
using (ret)
return Marshaling.ConvertVariantToManagedObject(ret);
}
/// <summary>
@ -557,13 +557,12 @@ namespace Godot
/// <param name="var">Variant that will be encoded.</param>
/// <param name="fullObjects">If objects should be serialized.</param>
/// <returns>The <c>Variant</c> encoded as an array of bytes.</returns>
public static unsafe byte[] Var2Bytes(object var, bool fullObjects = false)
public static byte[] Var2Bytes(object var, bool fullObjects = false)
{
using var variant = Marshaling.mono_object_to_variant(var);
using godot_packed_byte_array varBytes = default;
NativeFuncs.godotsharp_var2bytes(&variant, fullObjects.ToGodotBool(), &varBytes);
using var variant = Marshaling.ConvertManagedObjectToVariant(var);
NativeFuncs.godotsharp_var2bytes(variant, fullObjects.ToGodotBool(), out var varBytes);
using (varBytes)
return Marshaling.PackedByteArray_to_mono_array(&varBytes);
return Marshaling.ConvertNativePackedByteArrayToSystemArray(varBytes);
}
/// <summary>
@ -583,12 +582,12 @@ namespace Godot
/// </example>
/// <param name="var">Variant that will be converted to string.</param>
/// <returns>The <c>Variant</c> encoded as a string.</returns>
public static unsafe string Var2Str(object var)
public static string Var2Str(object var)
{
using var variant = Marshaling.mono_object_to_variant(var);
using godot_string ret = default;
NativeFuncs.godotsharp_var2str(&variant, &ret);
return Marshaling.mono_string_from_godot(ret);
using var variant = Marshaling.ConvertManagedObjectToVariant(var);
NativeFuncs.godotsharp_var2str(variant, out godot_string ret);
using (ret)
return Marshaling.ConvertStringToManaged(ret);
}
/// <summary>
@ -597,7 +596,7 @@ namespace Godot
/// <returns>The <see cref="Variant.Type"/> for the given <paramref name="type"/>.</returns>
public static Variant.Type TypeToVariantType(Type type)
{
return Marshaling.managed_to_variant_type(type, out bool _);
return Marshaling.ConvertManagedTypeToVariantType(type, out bool _);
}
}
}

View file

@ -10,7 +10,10 @@ using System.Runtime.InteropServices;
namespace Godot.NativeInterop
{
internal static class GodotBoolExtensions
// NOTES:
// ref structs cannot implement interfaces, but they still work in `using` directives if they declare Dispose()
public static class GodotBoolExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe godot_bool ToGodotBool(this bool @bool)
@ -35,9 +38,9 @@ namespace Godot.NativeInterop
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
public struct godot_ref : IDisposable
public ref struct godot_ref
{
internal IntPtr _reference;
private IntPtr _reference;
public void Dispose()
{
@ -47,7 +50,17 @@ namespace Godot.NativeInterop
_reference = IntPtr.Zero;
}
public bool IsNull => _reference == IntPtr.Zero;
public readonly IntPtr Reference
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _reference;
}
public readonly bool IsNull
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _reference == IntPtr.Zero;
}
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
@ -63,41 +76,53 @@ namespace Godot.NativeInterop
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
public struct godot_variant_call_error
public ref struct godot_variant_call_error
{
public godot_variant_call_error_error error;
public int argument;
public int expected;
private godot_variant_call_error_error error;
private int argument;
private int expected;
public godot_variant_call_error_error Error
{
readonly get => error;
set => error = value;
}
public int Argument
{
readonly get => argument;
set => argument = value;
}
public Godot.Variant.Type Expected
{
readonly get => (Godot.Variant.Type)expected;
set => expected = (int)value;
}
}
[StructLayout(LayoutKind.Explicit)]
// ReSharper disable once InconsistentNaming
public struct godot_variant : IDisposable
public ref struct godot_variant
{
// Variant.Type is generated as an enum of type long, so we can't use for the field as it must only take 32-bits.
[FieldOffset(0)] private int _typeField;
// There's padding here
[FieldOffset(8)] internal godot_variant_data _data;
public Variant.Type _type
{
get => (Variant.Type)_typeField;
set => _typeField = (int)value;
}
[FieldOffset(8)] private godot_variant_data _data;
[StructLayout(LayoutKind.Explicit)]
// ReSharper disable once InconsistentNaming
internal unsafe struct godot_variant_data
private unsafe ref struct godot_variant_data
{
[FieldOffset(0)] public godot_bool _bool;
[FieldOffset(0)] public long _int;
[FieldOffset(0)] public double _float;
[FieldOffset(0)] public Transform2D* _transform2d;
[FieldOffset(0)] public Transform2D* _transform2D;
[FieldOffset(0)] public AABB* _aabb;
[FieldOffset(0)] public Basis* _basis;
[FieldOffset(0)] public Transform3D* _transform3d;
[FieldOffset(0)] public Transform3D* _transform3D;
[FieldOffset(0)] public Vector4* _vector4;
[FieldOffset(0)] public Vector4i* _vector4i;
[FieldOffset(0)] public Projection* _projection;
@ -125,7 +150,7 @@ namespace Godot.NativeInterop
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
internal struct godot_variant_obj_data
public struct godot_variant_obj_data
{
public UInt64 id;
public IntPtr obj;
@ -133,7 +158,7 @@ namespace Godot.NativeInterop
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
private struct godot_variant_data_mem
public struct godot_variant_data_mem
{
#pragma warning disable 169
private real_t _mem0;
@ -144,9 +169,225 @@ namespace Godot.NativeInterop
}
}
public Variant.Type Type
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => (Variant.Type)_typeField;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _typeField = (int)value;
}
public godot_bool Bool
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._bool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _data._bool = value;
}
public long Int
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._int;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _data._int = value;
}
public double Float
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._float;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _data._float = value;
}
public readonly unsafe Transform2D* Transform2D
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _data._transform2D;
}
public readonly unsafe AABB* AABB
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _data._aabb;
}
public readonly unsafe Basis* Basis
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _data._basis;
}
public readonly unsafe Transform3D* Transform3D
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _data._transform3D;
}
public readonly unsafe Vector4* Vector4
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _data._vector4;
}
public readonly unsafe Vector4i* Vector4i
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _data._vector4i;
}
public readonly unsafe Projection* Projection
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _data._projection;
}
public godot_string_name StringName
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_string_name;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _data._m_string_name = value;
}
public godot_string String
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_string;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _data._m_string = value;
}
public Vector3 Vector3
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_vector3;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _data._m_vector3 = value;
}
public Vector3i Vector3i
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_vector3i;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _data._m_vector3i = value;
}
public Vector2 Vector2
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_vector2;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _data._m_vector2 = value;
}
public Vector2i Vector2i
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_vector2i;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _data._m_vector2i = value;
}
public Rect2 Rect2
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_rect2;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _data._m_rect2 = value;
}
public Rect2i Rect2i
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_rect2i;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _data._m_rect2i = value;
}
public Plane Plane
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_plane;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _data._m_plane = value;
}
public Quaternion Quaternion
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_quaternion;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _data._m_quaternion = value;
}
public Color Color
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_color;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _data._m_color = value;
}
public godot_node_path NodePath
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_node_path;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _data._m_node_path = value;
}
public RID RID
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_rid;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _data._m_rid = value;
}
public godot_callable Callable
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_callable;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _data._m_callable = value;
}
public godot_signal Signal
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_signal;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _data._m_signal = value;
}
public godot_dictionary Dictionary
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_dictionary;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _data._m_dictionary = value;
}
public godot_array Array
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_array;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _data._m_array = value;
}
public readonly IntPtr Object
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _data._m_obj_data.obj;
}
public void Dispose()
{
switch (_type)
switch (Type)
{
case Variant.Type.Nil:
case Variant.Type.Bool:
@ -166,15 +407,36 @@ namespace Godot.NativeInterop
}
NativeFuncs.godotsharp_variant_destroy(ref this);
_type = Variant.Type.Nil;
Type = Variant.Type.Nil;
}
[StructLayout(LayoutKind.Explicit)]
// ReSharper disable once InconsistentNaming
internal struct movable
{
// Variant.Type is generated as an enum of type long, so we can't use for the field as it must only take 32-bits.
[FieldOffset(0)] private int _typeField;
// There's padding here
[FieldOffset(8)] private godot_variant_data.godot_variant_data_mem _data;
public static unsafe explicit operator movable(in godot_variant value)
=> *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value));
public static unsafe explicit operator godot_variant(movable value)
=> *(godot_variant*)Unsafe.AsPointer(ref value);
public unsafe ref godot_variant DangerousSelfRef =>
ref CustomUnsafe.AsRef((godot_variant*)Unsafe.AsPointer(ref this));
}
}
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
public struct godot_string : IDisposable
public ref struct godot_string
{
internal IntPtr _ptr;
private IntPtr _ptr;
public void Dispose()
{
@ -184,15 +446,25 @@ namespace Godot.NativeInterop
_ptr = IntPtr.Zero;
}
public readonly IntPtr Buffer
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr;
}
// Size including the null termination character
public unsafe int Size => _ptr != IntPtr.Zero ? *((int*)_ptr - 1) : 0;
public readonly unsafe int Size
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr != IntPtr.Zero ? *((int*)_ptr - 1) : 0;
}
}
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
public struct godot_string_name : IDisposable
public ref struct godot_string_name
{
internal IntPtr _data;
private IntPtr _data;
public void Dispose()
{
@ -202,18 +474,41 @@ namespace Godot.NativeInterop
_data = IntPtr.Zero;
}
// An static method because an instance method could result in a hidden copy if called on an `in` parameter.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsEmpty(in godot_string_name name) =>
public readonly bool IsAllocated
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _data != IntPtr.Zero;
}
public readonly bool IsEmpty
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
// This is all that's needed to check if it's empty. Equivalent to `== StringName()` in C++.
name._data == IntPtr.Zero;
get => _data == IntPtr.Zero;
}
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
internal struct movable
{
private IntPtr _data;
public static unsafe explicit operator movable(in godot_string_name value)
=> *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value));
public static unsafe explicit operator godot_string_name(movable value)
=> *(godot_string_name*)Unsafe.AsPointer(ref value);
public unsafe ref godot_string_name DangerousSelfRef =>
ref CustomUnsafe.AsRef((godot_string_name*)Unsafe.AsPointer(ref this));
}
}
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
public struct godot_node_path : IDisposable
public ref struct godot_node_path
{
internal IntPtr _data;
private IntPtr _data;
public void Dispose()
{
@ -223,49 +518,98 @@ namespace Godot.NativeInterop
_data = IntPtr.Zero;
}
// An static method because an instance method could result in a hidden copy if called on an `in` parameter.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsEmpty(in godot_node_path nodePath) =>
// This is all that's needed to check if it's empty. It's what the `is_empty()` C++ method does.
nodePath._data == IntPtr.Zero;
}
[StructLayout(LayoutKind.Explicit)]
// ReSharper disable once InconsistentNaming
public struct godot_signal : IDisposable
{
[FieldOffset(0)] public godot_string_name _name;
// There's padding here on 32-bit
[FieldOffset(8)] public UInt64 _objectId;
public void Dispose()
public readonly bool IsAllocated
{
if (_name._data == IntPtr.Zero)
return;
NativeFuncs.godotsharp_signal_destroy(ref this);
_name._data = IntPtr.Zero;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _data != IntPtr.Zero;
}
public readonly bool IsEmpty
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
// This is all that's needed to check if it's empty. It's what the `is_empty()` C++ method does.
get => _data == IntPtr.Zero;
}
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
internal struct movable
{
private IntPtr _data;
public static unsafe explicit operator movable(in godot_node_path value)
=> *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value));
public static unsafe explicit operator godot_node_path(movable value)
=> *(godot_node_path*)Unsafe.AsPointer(ref value);
public unsafe ref godot_node_path DangerousSelfRef =>
ref CustomUnsafe.AsRef((godot_node_path*)Unsafe.AsPointer(ref this));
}
}
[StructLayout(LayoutKind.Explicit)]
// ReSharper disable once InconsistentNaming
public struct godot_callable : IDisposable
public ref struct godot_signal
{
[FieldOffset(0)] public godot_string_name _method;
[FieldOffset(0)] private godot_string_name _name;
// There's padding here on 32-bit
[FieldOffset(8)] public UInt64 _objectId;
[FieldOffset(8)] public IntPtr _custom;
[FieldOffset(8)] private UInt64 _objectId;
public godot_signal(godot_string_name name, ulong objectId)
{
_name = name;
_objectId = objectId;
}
public godot_string_name Name
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _name;
}
public UInt64 ObjectId
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _objectId;
}
public void Dispose()
{
if (_method._data == IntPtr.Zero && _custom == IntPtr.Zero)
if (!_name.IsAllocated)
return;
NativeFuncs.godotsharp_signal_destroy(ref this);
_name = default;
}
}
[StructLayout(LayoutKind.Explicit)]
// ReSharper disable once InconsistentNaming
public ref struct godot_callable
{
[FieldOffset(0)] private godot_string_name _method;
// There's padding here on 32-bit
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
[FieldOffset(8)] private UInt64 _objectId;
[FieldOffset(8)] private IntPtr _custom;
public godot_callable(godot_string_name method, ulong objectId) : this()
{
_method = method;
_objectId = objectId;
}
public void Dispose()
{
// _custom needs freeing as well
if (!_method.IsAllocated && _custom == IntPtr.Zero)
return;
NativeFuncs.godotsharp_callable_destroy(ref this);
_method._data = IntPtr.Zero;
_method = default;
_custom = IntPtr.Zero;
}
}
@ -275,29 +619,55 @@ namespace Godot.NativeInterop
// be re-assigned a new value (the copy constructor checks if `_p` is null so that's fine).
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
public struct godot_array : IDisposable
public ref struct godot_array
{
internal unsafe ArrayPrivate* _p;
private unsafe ArrayPrivate* _p;
[StructLayout(LayoutKind.Sequential)]
internal struct ArrayPrivate
private struct ArrayPrivate
{
private uint _safeRefCount;
internal VariantVector _arrayVector;
// There's more here, but we don't care as we never store this in C#
public VariantVector _arrayVector;
// There are more fields here, but we don't care as we never store this in C#
public readonly int Size
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _arrayVector.Size;
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct VariantVector
private struct VariantVector
{
internal IntPtr _writeProxy;
internal unsafe godot_variant* _ptr;
private IntPtr _writeProxy;
public unsafe godot_variant* _ptr;
public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0;
public readonly unsafe int Size
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr != null ? *((int*)_ptr - 1) : 0;
}
}
public unsafe int Size => _p != null ? _p->_arrayVector.Size : 0;
public readonly unsafe godot_variant* Elements
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _p->_arrayVector._ptr;
}
public readonly unsafe bool IsAllocated
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _p != null;
}
public readonly unsafe int Size
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _p != null ? _p->Size : 0;
}
public unsafe void Dispose()
{
@ -306,6 +676,22 @@ namespace Godot.NativeInterop
NativeFuncs.godotsharp_array_destroy(ref this);
_p = null;
}
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
internal struct movable
{
private unsafe ArrayPrivate* _p;
public static unsafe explicit operator movable(in godot_array value)
=> *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value));
public static unsafe explicit operator godot_array(movable value)
=> *(godot_array*)Unsafe.AsPointer(ref value);
public unsafe ref godot_array DangerousSelfRef =>
ref CustomUnsafe.AsRef((godot_array*)Unsafe.AsPointer(ref this));
}
}
// IMPORTANT:
@ -314,9 +700,15 @@ namespace Godot.NativeInterop
// be re-assigned a new value (the copy constructor checks if `_p` is null so that's fine).
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
public struct godot_dictionary : IDisposable
public ref struct godot_dictionary
{
internal IntPtr _p;
private IntPtr _p;
public readonly bool IsAllocated
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _p != IntPtr.Zero;
}
public void Dispose()
{
@ -325,14 +717,30 @@ namespace Godot.NativeInterop
NativeFuncs.godotsharp_dictionary_destroy(ref this);
_p = IntPtr.Zero;
}
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
internal struct movable
{
private IntPtr _p;
public static unsafe explicit operator movable(in godot_dictionary value)
=> *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value));
public static unsafe explicit operator godot_dictionary(movable value)
=> *(godot_dictionary*)Unsafe.AsPointer(ref value);
public unsafe ref godot_dictionary DangerousSelfRef =>
ref CustomUnsafe.AsRef((godot_dictionary*)Unsafe.AsPointer(ref this));
}
}
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
public struct godot_packed_byte_array : IDisposable
public ref struct godot_packed_byte_array
{
internal IntPtr _writeProxy;
internal unsafe byte* _ptr;
private IntPtr _writeProxy;
private unsafe byte* _ptr;
public unsafe void Dispose()
{
@ -342,15 +750,25 @@ namespace Godot.NativeInterop
_ptr = null;
}
public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0;
public readonly unsafe byte* Buffer
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr;
}
public readonly unsafe int Size
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr != null ? *((int*)_ptr - 1) : 0;
}
}
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
public struct godot_packed_int32_array : IDisposable
public ref struct godot_packed_int32_array
{
internal IntPtr _writeProxy;
internal unsafe int* _ptr;
private IntPtr _writeProxy;
private unsafe int* _ptr;
public unsafe void Dispose()
{
@ -360,15 +778,25 @@ namespace Godot.NativeInterop
_ptr = null;
}
public unsafe int Size => _ptr != null ? *(_ptr - 1) : 0;
public readonly unsafe int* Buffer
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr;
}
public readonly unsafe int Size
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr != null ? *(_ptr - 1) : 0;
}
}
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
public struct godot_packed_int64_array : IDisposable
public ref struct godot_packed_int64_array
{
internal IntPtr _writeProxy;
internal unsafe long* _ptr;
private IntPtr _writeProxy;
private unsafe long* _ptr;
public unsafe void Dispose()
{
@ -378,15 +806,25 @@ namespace Godot.NativeInterop
_ptr = null;
}
public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0;
public readonly unsafe long* Buffer
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr;
}
public readonly unsafe int Size
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr != null ? *((int*)_ptr - 1) : 0;
}
}
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
public struct godot_packed_float32_array : IDisposable
public ref struct godot_packed_float32_array
{
internal IntPtr _writeProxy;
internal unsafe float* _ptr;
private IntPtr _writeProxy;
private unsafe float* _ptr;
public unsafe void Dispose()
{
@ -396,15 +834,25 @@ namespace Godot.NativeInterop
_ptr = null;
}
public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0;
public readonly unsafe float* Buffer
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr;
}
public readonly unsafe int Size
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr != null ? *((int*)_ptr - 1) : 0;
}
}
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
public struct godot_packed_float64_array : IDisposable
public ref struct godot_packed_float64_array
{
internal IntPtr _writeProxy;
internal unsafe double* _ptr;
private IntPtr _writeProxy;
private unsafe double* _ptr;
public unsafe void Dispose()
{
@ -414,15 +862,25 @@ namespace Godot.NativeInterop
_ptr = null;
}
public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0;
public readonly unsafe double* Buffer
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr;
}
public readonly unsafe int Size
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr != null ? *((int*)_ptr - 1) : 0;
}
}
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
public struct godot_packed_string_array : IDisposable
public ref struct godot_packed_string_array
{
internal IntPtr _writeProxy;
internal unsafe godot_string* _ptr;
private IntPtr _writeProxy;
private unsafe godot_string* _ptr;
public unsafe void Dispose()
{
@ -432,15 +890,25 @@ namespace Godot.NativeInterop
_ptr = null;
}
public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0;
public readonly unsafe godot_string* Buffer
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr;
}
public readonly unsafe int Size
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr != null ? *((int*)_ptr - 1) : 0;
}
}
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
public struct godot_packed_vector2_array : IDisposable
public ref struct godot_packed_vector2_array
{
internal IntPtr _writeProxy;
internal unsafe Vector2* _ptr;
private IntPtr _writeProxy;
private unsafe Vector2* _ptr;
public unsafe void Dispose()
{
@ -450,15 +918,25 @@ namespace Godot.NativeInterop
_ptr = null;
}
public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0;
public readonly unsafe Vector2* Buffer
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr;
}
public readonly unsafe int Size
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr != null ? *((int*)_ptr - 1) : 0;
}
}
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
public struct godot_packed_vector3_array : IDisposable
public ref struct godot_packed_vector3_array
{
internal IntPtr _writeProxy;
internal unsafe Vector3* _ptr;
private IntPtr _writeProxy;
private unsafe Vector3* _ptr;
public unsafe void Dispose()
{
@ -468,15 +946,25 @@ namespace Godot.NativeInterop
_ptr = null;
}
public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0;
public readonly unsafe Vector3* Buffer
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr;
}
public readonly unsafe int Size
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr != null ? *((int*)_ptr - 1) : 0;
}
}
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
public struct godot_packed_color_array : IDisposable
public ref struct godot_packed_color_array
{
internal IntPtr _writeProxy;
internal unsafe Color* _ptr;
private IntPtr _writeProxy;
private unsafe Color* _ptr;
public unsafe void Dispose()
{
@ -486,6 +974,16 @@ namespace Godot.NativeInterop
_ptr = null;
}
public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0;
public readonly unsafe Color* Buffer
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr;
}
public readonly unsafe int Size
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _ptr != null ? *((int*)_ptr - 1) : 0;
}
}
}

View file

@ -1,5 +1,4 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Godot.Bridge;
@ -16,22 +15,19 @@ namespace Godot.NativeInterop
return null;
IntPtr gcHandlePtr;
godot_bool has_cs_script_instance = false.ToGodotBool();
godot_bool hasCsScriptInstance;
// First try to get the tied managed instance from a CSharpInstance script instance
unsafe
{
gcHandlePtr = NativeFuncs.godotsharp_internal_unmanaged_get_script_instance_managed(
unmanaged, &has_cs_script_instance);
}
gcHandlePtr = NativeFuncs.godotsharp_internal_unmanaged_get_script_instance_managed(
unmanaged, out hasCsScriptInstance);
if (gcHandlePtr != IntPtr.Zero)
return (Object)GCHandle.FromIntPtr(gcHandlePtr).Target;
// Otherwise, if the object has a CSharpInstance script instance, return null
if (has_cs_script_instance.ToBool())
if (hasCsScriptInstance.ToBool())
return null;
// If it doesn't have a CSharpInstance script instance, try with native instance bindings
@ -58,12 +54,9 @@ namespace Godot.NativeInterop
if (type == nativeType)
{
unsafe
{
godot_string_name nativeNameAux = nativeName.NativeValue;
NativeFuncs.godotsharp_internal_tie_native_managed_to_unmanaged(
GCHandle.ToIntPtr(gcHandle), unmanaged, &nativeNameAux, refCounted.ToGodotBool());
}
var nativeNameSelf = (godot_string_name)nativeName.NativeValue;
NativeFuncs.godotsharp_internal_tie_native_managed_to_unmanaged(
GCHandle.ToIntPtr(gcHandle), unmanaged, nativeNameSelf, refCounted.ToGodotBool());
}
else
{
@ -88,10 +81,10 @@ namespace Godot.NativeInterop
GCHandle.ToIntPtr(strongGCHandle), unmanaged);
}
public static unsafe Object EngineGetSingleton(string name)
public static Object EngineGetSingleton(string name)
{
using godot_string src = Marshaling.mono_string_to_godot(name);
return UnmanagedGetManaged(NativeFuncs.godotsharp_engine_get_singleton(&src));
using godot_string src = Marshaling.ConvertStringToNative(name);
return UnmanagedGetManaged(NativeFuncs.godotsharp_engine_get_singleton(src));
}
}
}

View file

@ -1,15 +1,23 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
// ReSharper disable InconsistentNaming
namespace Godot.NativeInterop
{
#if !NET
// This improves P/Invoke performance.
// The attribute is not available with .NET Core and it's not needed there.
[System.Security.SuppressUnmanagedCodeSecurity]
#endif
/*
* TODO:
* P/Invoke pins by-ref parameters in case the managed memory is moved.
* That's not needed here since we use "ref structs" which are stack-only.
* Unfortunately, the runtime is not smart enough and pins them anyway.
* We want to avoid pinning, so we must wrap these DllImports in methods
* that reinterpret refs and pointers with CustomUnsafe.AsPointer/AsRef.
* I wish such unnecessary boilerplate wasn't needed...
*/
[SuppressMessage("Interoperability", "CA1401",
MessageId = "P/Invokes should not be visible" /* Meh. What are you gonna do about it? */)]
public static unsafe partial class NativeFuncs
{
private const string GodotDllName = "__Internal";
@ -17,15 +25,15 @@ namespace Godot.NativeInterop
// Custom functions
[DllImport(GodotDllName)]
public static extern IntPtr godotsharp_method_bind_get_method(ref godot_string_name p_classname,
public static extern IntPtr godotsharp_method_bind_get_method(in godot_string_name p_classname,
char* p_methodname);
[DllImport(GodotDllName)]
public static extern delegate* unmanaged<IntPtr> godotsharp_get_class_constructor(
ref godot_string_name p_classname);
in godot_string_name p_classname);
[DllImport(GodotDllName)]
public static extern IntPtr godotsharp_engine_get_singleton(godot_string* p_name);
public static extern IntPtr godotsharp_engine_get_singleton(in godot_string p_name);
[DllImport(GodotDllName)]
internal static extern void godotsharp_internal_object_disposed(IntPtr ptr);
@ -35,61 +43,64 @@ namespace Godot.NativeInterop
[DllImport(GodotDllName)]
internal static extern void godotsharp_internal_object_connect_event_signal(IntPtr obj,
godot_string_name* eventSignal);
in godot_string_name eventSignal);
[DllImport(GodotDllName)]
internal static extern Error godotsharp_internal_signal_awaiter_connect(IntPtr source,
ref godot_string_name signal,
in godot_string_name signal,
IntPtr target, IntPtr awaiterHandlePtr);
[DllImport(GodotDllName)]
public static extern void godotsharp_internal_tie_native_managed_to_unmanaged(IntPtr gcHandleIntPtr,
IntPtr unmanaged, godot_string_name* nativeName, godot_bool refCounted);
internal static extern void godotsharp_internal_tie_native_managed_to_unmanaged(IntPtr gcHandleIntPtr,
IntPtr unmanaged, in godot_string_name nativeName, godot_bool refCounted);
[DllImport(GodotDllName)]
public static extern void godotsharp_internal_tie_user_managed_to_unmanaged(IntPtr gcHandleIntPtr,
internal static extern void godotsharp_internal_tie_user_managed_to_unmanaged(IntPtr gcHandleIntPtr,
IntPtr unmanaged, IntPtr scriptPtr, godot_bool refCounted);
[DllImport(GodotDllName)]
public static extern void godotsharp_internal_tie_managed_to_unmanaged_with_pre_setup(
internal static extern void godotsharp_internal_tie_managed_to_unmanaged_with_pre_setup(
IntPtr gcHandleIntPtr, IntPtr unmanaged);
[DllImport(GodotDllName)]
public static extern IntPtr godotsharp_internal_unmanaged_get_script_instance_managed(IntPtr p_unmanaged,
godot_bool* r_has_cs_script_instance);
internal static extern IntPtr godotsharp_internal_unmanaged_get_script_instance_managed(IntPtr p_unmanaged,
out godot_bool r_has_cs_script_instance);
[DllImport(GodotDllName)]
public static extern IntPtr godotsharp_internal_unmanaged_get_instance_binding_managed(IntPtr p_unmanaged);
internal static extern IntPtr godotsharp_internal_unmanaged_get_instance_binding_managed(IntPtr p_unmanaged);
[DllImport(GodotDllName)]
public static extern IntPtr godotsharp_internal_unmanaged_instance_binding_create_managed(IntPtr p_unmanaged,
internal static extern IntPtr godotsharp_internal_unmanaged_instance_binding_create_managed(IntPtr p_unmanaged,
IntPtr oldGCHandlePtr);
[DllImport(GodotDllName)]
public static extern IntPtr godotsharp_internal_new_csharp_script();
internal static extern IntPtr godotsharp_internal_new_csharp_script();
[DllImport(GodotDllName)]
public static extern void godotsharp_array_filter_godot_objects_by_native(godot_string_name* p_native_name,
godot_array* p_input, godot_array* r_output);
internal static extern void godotsharp_array_filter_godot_objects_by_native(in godot_string_name p_native_name,
in godot_array p_input, out godot_array r_output);
[DllImport(GodotDllName)]
public static extern void godotsharp_array_filter_godot_objects_by_non_native(godot_array* p_input,
godot_array* r_output);
internal static extern void godotsharp_array_filter_godot_objects_by_non_native(in godot_array p_input,
out godot_array r_output);
[DllImport(GodotDllName)]
public static extern void godotsharp_ref_destroy(ref godot_ref p_instance);
[DllImport(GodotDllName)]
public static extern void godotsharp_string_name_new_from_string(godot_string_name* dest, godot_string* name);
public static extern void godotsharp_string_name_new_from_string(out godot_string_name r_dest,
in godot_string p_name);
[DllImport(GodotDllName)]
public static extern void godotsharp_node_path_new_from_string(godot_node_path* dest, godot_string* name);
public static extern void godotsharp_node_path_new_from_string(out godot_node_path r_dest,
in godot_string p_name);
[DllImport(GodotDllName)]
public static extern void godotsharp_string_name_as_string(godot_string* r_dest, godot_string_name* p_name);
public static extern void
godotsharp_string_name_as_string(out godot_string r_dest, in godot_string_name p_name);
[DllImport(GodotDllName)]
public static extern void godotsharp_node_path_as_string(godot_string* r_dest, godot_node_path* p_np);
public static extern void godotsharp_node_path_as_string(out godot_string r_dest, in godot_node_path p_np);
[DllImport(GodotDllName)]
public static extern godot_packed_byte_array godotsharp_packed_byte_array_new_mem_copy(byte* p_src,
@ -124,16 +135,24 @@ namespace Godot.NativeInterop
int p_length);
[DllImport(GodotDllName)]
public static extern void godotsharp_packed_string_array_add(godot_packed_string_array* r_dest,
godot_string* p_element);
public static extern void godotsharp_packed_string_array_add(ref godot_packed_string_array r_dest,
in godot_string p_element);
[DllImport(GodotDllName)]
public static extern void godotsharp_callable_new_with_delegate(IntPtr p_delegate_handle,
godot_callable* r_callable);
out godot_callable r_callable);
[DllImport(GodotDllName)]
public static extern godot_bool godotsharp_callable_get_data_for_marshalling(godot_callable* p_callable,
IntPtr* r_delegate_handle, IntPtr* r_object, godot_string_name* r_name);
internal static extern godot_bool godotsharp_callable_get_data_for_marshalling(in godot_callable p_callable,
out IntPtr r_delegate_handle, out IntPtr r_object, out godot_string_name r_name);
[DllImport(GodotDllName)]
internal static extern godot_variant godotsharp_callable_call(in godot_callable p_callable,
godot_variant** p_args, int p_arg_count, out godot_variant_call_error p_call_error);
[DllImport(GodotDllName)]
internal static extern void godotsharp_callable_call_deferred(in godot_callable p_callable,
godot_variant** p_args, int p_arg_count);
// GDNative functions
@ -145,219 +164,223 @@ namespace Godot.NativeInterop
[DllImport(GodotDllName)]
public static extern godot_variant godotsharp_method_bind_call(IntPtr p_method_bind, IntPtr p_instance,
godot_variant** p_args, int p_arg_count, godot_variant_call_error* p_call_error);
godot_variant** p_args, int p_arg_count, out godot_variant_call_error p_call_error);
// variant.h
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_string_name(godot_variant* r_dest, godot_string_name* p_s);
public static extern void
godotsharp_variant_new_string_name(out godot_variant r_dest, in godot_string_name p_s);
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_node_path(godot_variant* r_dest, godot_node_path* p_np);
public static extern void godotsharp_variant_new_node_path(out godot_variant r_dest, in godot_node_path p_np);
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_object(godot_variant* r_dest, IntPtr p_obj);
public static extern void godotsharp_variant_new_object(out godot_variant r_dest, IntPtr p_obj);
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_transform2d(godot_variant* r_dest, Transform2D* p_t2d);
public static extern void godotsharp_variant_new_transform2d(out godot_variant r_dest, in Transform2D p_t2d);
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_vector4(godot_variant* r_dest, Vector4* p_vec4);
public static extern void godotsharp_variant_new_vector4(out godot_variant r_dest, in Vector4 p_vec4);
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_vector4i(godot_variant* r_dest, Vector4i* p_vec4i);
public static extern void godotsharp_variant_new_vector4i(out godot_variant r_dest, in Vector4i p_vec4i);
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_basis(godot_variant* r_dest, Basis* p_basis);
public static extern void godotsharp_variant_new_basis(out godot_variant r_dest, in Basis p_basis);
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_transform3d(godot_variant* r_dest, Transform3D* p_trans);
public static extern void godotsharp_variant_new_transform3d(out godot_variant r_dest, in Transform3D p_trans);
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_projection(godot_variant* r_dest, Projection* p_proj);
public static extern void godotsharp_variant_new_projection(out godot_variant r_dest, in Projection p_proj);
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_aabb(godot_variant* r_dest, AABB* p_aabb);
public static extern void godotsharp_variant_new_aabb(out godot_variant r_dest, in AABB p_aabb);
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_dictionary(godot_variant* r_dest, godot_dictionary* p_dict);
public static extern void godotsharp_variant_new_dictionary(out godot_variant r_dest,
in godot_dictionary p_dict);
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_array(godot_variant* r_dest, godot_array* p_arr);
public static extern void godotsharp_variant_new_array(out godot_variant r_dest, in godot_array p_arr);
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_packed_byte_array(godot_variant* r_dest,
godot_packed_byte_array* p_pba);
public static extern void godotsharp_variant_new_packed_byte_array(out godot_variant r_dest,
in godot_packed_byte_array p_pba);
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_packed_int32_array(godot_variant* r_dest,
godot_packed_int32_array* p_pia);
public static extern void godotsharp_variant_new_packed_int32_array(out godot_variant r_dest,
in godot_packed_int32_array p_pia);
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_packed_int64_array(godot_variant* r_dest,
godot_packed_int64_array* p_pia);
public static extern void godotsharp_variant_new_packed_int64_array(out godot_variant r_dest,
in godot_packed_int64_array p_pia);
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_packed_float32_array(godot_variant* r_dest,
godot_packed_float32_array* p_pra);
public static extern void godotsharp_variant_new_packed_float32_array(out godot_variant r_dest,
in godot_packed_float32_array p_pra);
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_packed_float64_array(godot_variant* r_dest,
godot_packed_float64_array* p_pra);
public static extern void godotsharp_variant_new_packed_float64_array(out godot_variant r_dest,
in godot_packed_float64_array p_pra);
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_packed_string_array(godot_variant* r_dest,
godot_packed_string_array* p_psa);
public static extern void godotsharp_variant_new_packed_string_array(out godot_variant r_dest,
in godot_packed_string_array p_psa);
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_packed_vector2_array(godot_variant* r_dest,
godot_packed_vector2_array* p_pv2a);
public static extern void godotsharp_variant_new_packed_vector2_array(out godot_variant r_dest,
in godot_packed_vector2_array p_pv2a);
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_packed_vector3_array(godot_variant* r_dest,
godot_packed_vector3_array* p_pv3a);
public static extern void godotsharp_variant_new_packed_vector3_array(out godot_variant r_dest,
in godot_packed_vector3_array p_pv3a);
[DllImport(GodotDllName)]
public static extern void godotsharp_variant_new_packed_color_array(godot_variant* r_dest,
godot_packed_color_array* p_pca);
public static extern void godotsharp_variant_new_packed_color_array(out godot_variant r_dest,
in godot_packed_color_array p_pca);
[DllImport(GodotDllName)]
public static extern godot_bool godotsharp_variant_as_bool(godot_variant* p_self);
public static extern godot_bool godotsharp_variant_as_bool(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern Int64 godotsharp_variant_as_int(godot_variant* p_self);
public static extern Int64 godotsharp_variant_as_int(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern double godotsharp_variant_as_float(godot_variant* p_self);
public static extern double godotsharp_variant_as_float(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern godot_string godotsharp_variant_as_string(godot_variant* p_self);
public static extern godot_string godotsharp_variant_as_string(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern Vector2 godotsharp_variant_as_vector2(godot_variant* p_self);
public static extern Vector2 godotsharp_variant_as_vector2(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern Vector2i godotsharp_variant_as_vector2i(godot_variant* p_self);
public static extern Vector2i godotsharp_variant_as_vector2i(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern Rect2 godotsharp_variant_as_rect2(godot_variant* p_self);
public static extern Rect2 godotsharp_variant_as_rect2(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern Rect2i godotsharp_variant_as_rect2i(godot_variant* p_self);
public static extern Rect2i godotsharp_variant_as_rect2i(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern Vector3 godotsharp_variant_as_vector3(godot_variant* p_self);
public static extern Vector3 godotsharp_variant_as_vector3(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern Vector3i godotsharp_variant_as_vector3i(godot_variant* p_self);
public static extern Vector3i godotsharp_variant_as_vector3i(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern Transform2D godotsharp_variant_as_transform2d(godot_variant* p_self);
public static extern Transform2D godotsharp_variant_as_transform2d(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern Vector4 godotsharp_variant_as_vector4(godot_variant* p_self);
public static extern Vector4 godotsharp_variant_as_vector4(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern Vector4i godotsharp_variant_as_vector4i(godot_variant* p_self);
public static extern Vector4i godotsharp_variant_as_vector4i(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern Plane godotsharp_variant_as_plane(godot_variant* p_self);
public static extern Plane godotsharp_variant_as_plane(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern Quaternion godotsharp_variant_as_quaternion(godot_variant* p_self);
public static extern Quaternion godotsharp_variant_as_quaternion(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern AABB godotsharp_variant_as_aabb(godot_variant* p_self);
public static extern AABB godotsharp_variant_as_aabb(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern Basis godotsharp_variant_as_basis(godot_variant* p_self);
public static extern Basis godotsharp_variant_as_basis(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern Transform3D godotsharp_variant_as_transform3d(godot_variant* p_self);
public static extern Transform3D godotsharp_variant_as_transform3d(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern Projection godotsharp_variant_as_projection(godot_variant* p_self);
public static extern Projection godotsharp_variant_as_projection(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern Color godotsharp_variant_as_color(godot_variant* p_self);
public static extern Color godotsharp_variant_as_color(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern godot_string_name godotsharp_variant_as_string_name(godot_variant* p_self);
public static extern godot_string_name godotsharp_variant_as_string_name(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern godot_node_path godotsharp_variant_as_node_path(godot_variant* p_self);
public static extern godot_node_path godotsharp_variant_as_node_path(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern RID godotsharp_variant_as_rid(godot_variant* p_self);
public static extern RID godotsharp_variant_as_rid(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern godot_callable godotsharp_variant_as_callable(godot_variant* p_self);
public static extern godot_callable godotsharp_variant_as_callable(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern godot_signal godotsharp_variant_as_signal(godot_variant* p_self);
public static extern godot_signal godotsharp_variant_as_signal(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern godot_dictionary godotsharp_variant_as_dictionary(godot_variant* p_self);
public static extern godot_dictionary godotsharp_variant_as_dictionary(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern godot_array godotsharp_variant_as_array(godot_variant* p_self);
public static extern godot_array godotsharp_variant_as_array(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern godot_packed_byte_array godotsharp_variant_as_packed_byte_array(godot_variant* p_self);
public static extern godot_packed_byte_array godotsharp_variant_as_packed_byte_array(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern godot_packed_int32_array godotsharp_variant_as_packed_int32_array(godot_variant* p_self);
public static extern godot_packed_int32_array godotsharp_variant_as_packed_int32_array(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern godot_packed_int64_array godotsharp_variant_as_packed_int64_array(godot_variant* p_self);
public static extern godot_packed_int64_array godotsharp_variant_as_packed_int64_array(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern godot_packed_float32_array godotsharp_variant_as_packed_float32_array(
godot_variant* p_self);
in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern godot_packed_float64_array godotsharp_variant_as_packed_float64_array(
godot_variant* p_self);
in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern godot_packed_string_array godotsharp_variant_as_packed_string_array(godot_variant* p_self);
public static extern godot_packed_string_array godotsharp_variant_as_packed_string_array(
in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern godot_packed_vector2_array godotsharp_variant_as_packed_vector2_array(
godot_variant* p_self);
in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern godot_packed_vector3_array godotsharp_variant_as_packed_vector3_array(
godot_variant* p_self);
in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern godot_packed_color_array godotsharp_variant_as_packed_color_array(godot_variant* p_self);
public static extern godot_packed_color_array godotsharp_variant_as_packed_color_array(in godot_variant p_self);
[DllImport(GodotDllName)]
public static extern godot_bool godotsharp_variant_equals(godot_variant* p_a, godot_variant* p_b);
public static extern godot_bool godotsharp_variant_equals(in godot_variant p_a, in godot_variant p_b);
// string.h
[DllImport(GodotDllName)]
public static extern void godotsharp_string_new_with_utf16_chars(godot_string* r_dest, char* p_contents);
public static extern void godotsharp_string_new_with_utf16_chars(out godot_string r_dest, char* p_contents);
// string_name.h
[DllImport(GodotDllName)]
public static extern void godotsharp_string_name_new_copy(godot_string_name* r_dest, godot_string_name* p_src);
public static extern void godotsharp_string_name_new_copy(out godot_string_name r_dest,
in godot_string_name p_src);
// node_path.h
[DllImport(GodotDllName)]
public static extern void godotsharp_node_path_new_copy(godot_node_path* r_dest, godot_node_path* p_src);
public static extern void godotsharp_node_path_new_copy(out godot_node_path r_dest, in godot_node_path p_src);
// array.h
[DllImport(GodotDllName)]
public static extern void godotsharp_array_new(godot_array* p_self);
public static extern void godotsharp_array_new(out godot_array r_dest);
[DllImport(GodotDllName)]
public static extern void godotsharp_array_new_copy(godot_array* r_dest, godot_array* p_src);
public static extern void godotsharp_array_new_copy(out godot_array r_dest, in godot_array p_src);
[DllImport(GodotDllName)]
public static extern godot_variant* godotsharp_array_ptrw(ref godot_array p_self);
@ -365,10 +388,11 @@ namespace Godot.NativeInterop
// dictionary.h
[DllImport(GodotDllName)]
public static extern void godotsharp_dictionary_new(godot_dictionary* p_self);
public static extern void godotsharp_dictionary_new(out godot_dictionary r_dest);
[DllImport(GodotDllName)]
public static extern void godotsharp_dictionary_new_copy(godot_dictionary* r_dest, godot_dictionary* p_src);
public static extern void godotsharp_dictionary_new_copy(out godot_dictionary r_dest,
in godot_dictionary p_src);
// destroy functions
@ -426,17 +450,17 @@ namespace Godot.NativeInterop
// Array
[DllImport(GodotDllName)]
public static extern int godotsharp_array_add(ref godot_array p_self, godot_variant* p_item);
public static extern int godotsharp_array_add(ref godot_array p_self, in godot_variant p_item);
[DllImport(GodotDllName)]
public static extern void
godotsharp_array_duplicate(ref godot_array p_self, godot_bool p_deep, out godot_array r_dest);
[DllImport(GodotDllName)]
public static extern int godotsharp_array_index_of(ref godot_array p_self, godot_variant* p_item);
public static extern int godotsharp_array_index_of(ref godot_array p_self, in godot_variant p_item);
[DllImport(GodotDllName)]
public static extern void godotsharp_array_insert(ref godot_array p_self, int p_index, godot_variant* p_item);
public static extern void godotsharp_array_insert(ref godot_array p_self, int p_index, in godot_variant p_item);
[DllImport(GodotDllName)]
public static extern void godotsharp_array_remove_at(ref godot_array p_self, int p_index);
@ -448,18 +472,18 @@ namespace Godot.NativeInterop
public static extern Error godotsharp_array_shuffle(ref godot_array p_self);
[DllImport(GodotDllName)]
public static extern void godotsharp_array_to_string(ref godot_array p_self, godot_string* r_str);
public static extern void godotsharp_array_to_string(ref godot_array p_self, out godot_string r_str);
// Dictionary
[DllImport(GodotDllName)]
public static extern godot_bool godotsharp_dictionary_try_get_value(ref godot_dictionary p_self,
godot_variant* p_key,
in godot_variant p_key,
out godot_variant r_value);
[DllImport(GodotDllName)]
public static extern void godotsharp_dictionary_set_value(ref godot_dictionary p_self, godot_variant* p_key,
godot_variant* p_value);
public static extern void godotsharp_dictionary_set_value(ref godot_dictionary p_self, in godot_variant p_key,
in godot_variant p_value);
[DllImport(GodotDllName)]
public static extern void godotsharp_dictionary_keys(ref godot_dictionary p_self, out godot_array r_dest);
@ -475,15 +499,15 @@ namespace Godot.NativeInterop
out godot_variant r_key, out godot_variant r_value);
[DllImport(GodotDllName)]
public static extern void godotsharp_dictionary_add(ref godot_dictionary p_self, godot_variant* p_key,
godot_variant* p_value);
public static extern void godotsharp_dictionary_add(ref godot_dictionary p_self, in godot_variant p_key,
in godot_variant p_value);
[DllImport(GodotDllName)]
public static extern void godotsharp_dictionary_clear(ref godot_dictionary p_self);
[DllImport(GodotDllName)]
public static extern godot_bool godotsharp_dictionary_contains_key(ref godot_dictionary p_self,
godot_variant* p_key);
in godot_variant p_key);
[DllImport(GodotDllName)]
public static extern void godotsharp_dictionary_duplicate(ref godot_dictionary p_self, godot_bool p_deep,
@ -491,149 +515,153 @@ namespace Godot.NativeInterop
[DllImport(GodotDllName)]
public static extern godot_bool godotsharp_dictionary_remove_key(ref godot_dictionary p_self,
godot_variant* p_key);
in godot_variant p_key);
[DllImport(GodotDllName)]
public static extern void godotsharp_dictionary_to_string(ref godot_dictionary p_self, godot_string* r_str);
public static extern void godotsharp_dictionary_to_string(ref godot_dictionary p_self, out godot_string r_str);
// StringExtensions
[DllImport(GodotDllName)]
public static extern void godotsharp_string_md5_buffer(godot_string* p_self,
godot_packed_byte_array* r_md5_buffer);
public static extern void godotsharp_string_md5_buffer(in godot_string p_self,
out godot_packed_byte_array r_md5_buffer);
[DllImport(GodotDllName)]
public static extern void godotsharp_string_md5_text(godot_string* p_self, godot_string* r_md5_text);
public static extern void godotsharp_string_md5_text(in godot_string p_self, out godot_string r_md5_text);
[DllImport(GodotDllName)]
public static extern int godotsharp_string_rfind(godot_string* p_self, godot_string* p_what, int p_from);
public static extern int godotsharp_string_rfind(in godot_string p_self, in godot_string p_what, int p_from);
[DllImport(GodotDllName)]
public static extern int godotsharp_string_rfindn(godot_string* p_self, godot_string* p_what, int p_from);
public static extern int godotsharp_string_rfindn(in godot_string p_self, in godot_string p_what, int p_from);
[DllImport(GodotDllName)]
public static extern void godotsharp_string_sha256_buffer(godot_string* p_self,
godot_packed_byte_array* r_sha256_buffer);
public static extern void godotsharp_string_sha256_buffer(in godot_string p_self,
out godot_packed_byte_array r_sha256_buffer);
[DllImport(GodotDllName)]
public static extern void godotsharp_string_sha256_text(godot_string* p_self, godot_string* r_sha256_text);
public static extern void godotsharp_string_sha256_text(in godot_string p_self,
out godot_string r_sha256_text);
[DllImport(GodotDllName)]
public static extern void godotsharp_string_simplify_path(godot_string* p_self, godot_string* r_simplified_path);
public static extern void godotsharp_string_simplify_path(in godot_string p_self,
out godot_string r_simplified_path);
// NodePath
[DllImport(GodotDllName)]
public static extern void godotsharp_node_path_get_as_property_path(ref godot_node_path p_self,
public static extern void godotsharp_node_path_get_as_property_path(in godot_node_path p_self,
ref godot_node_path r_dest);
[DllImport(GodotDllName)]
public static extern void godotsharp_node_path_get_concatenated_names(ref godot_node_path p_self,
godot_string* r_names);
public static extern void godotsharp_node_path_get_concatenated_names(in godot_node_path p_self,
out godot_string r_names);
[DllImport(GodotDllName)]
public static extern void godotsharp_node_path_get_concatenated_subnames(ref godot_node_path p_self,
godot_string* r_subnames);
public static extern void godotsharp_node_path_get_concatenated_subnames(in godot_node_path p_self,
out godot_string r_subnames);
[DllImport(GodotDllName)]
public static extern void godotsharp_node_path_get_name(ref godot_node_path p_self, int p_idx,
godot_string* r_name);
public static extern void godotsharp_node_path_get_name(in godot_node_path p_self, int p_idx,
out godot_string r_name);
[DllImport(GodotDllName)]
public static extern int godotsharp_node_path_get_name_count(ref godot_node_path p_self);
public static extern int godotsharp_node_path_get_name_count(in godot_node_path p_self);
[DllImport(GodotDllName)]
public static extern void godotsharp_node_path_get_subname(ref godot_node_path p_self, int p_idx,
godot_string* r_subname);
public static extern void godotsharp_node_path_get_subname(in godot_node_path p_self, int p_idx,
out godot_string r_subname);
[DllImport(GodotDllName)]
public static extern int godotsharp_node_path_get_subname_count(ref godot_node_path p_self);
public static extern int godotsharp_node_path_get_subname_count(in godot_node_path p_self);
[DllImport(GodotDllName)]
public static extern godot_bool godotsharp_node_path_is_absolute(ref godot_node_path p_self);
public static extern godot_bool godotsharp_node_path_is_absolute(in godot_node_path p_self);
// GD, etc
[DllImport(GodotDllName)]
public static extern void godotsharp_bytes2var(godot_packed_byte_array* p_bytes, godot_bool p_allow_objects,
godot_variant* r_ret);
internal static extern void godotsharp_bytes2var(in godot_packed_byte_array p_bytes,
godot_bool p_allow_objects,
out godot_variant r_ret);
[DllImport(GodotDllName)]
public static extern void godotsharp_convert(godot_variant* p_what, int p_type, godot_variant* r_ret);
internal static extern void godotsharp_convert(in godot_variant p_what, int p_type,
out godot_variant r_ret);
[DllImport(GodotDllName)]
public static extern int godotsharp_hash(godot_variant* var);
internal static extern int godotsharp_hash(in godot_variant p_var);
[DllImport(GodotDllName)]
public static extern IntPtr godotsharp_instance_from_id(ulong instanceId);
internal static extern IntPtr godotsharp_instance_from_id(ulong p_instance_id);
[DllImport(GodotDllName)]
public static extern void godotsharp_print(godot_string* p_what);
internal static extern void godotsharp_print(in godot_string p_what);
[DllImport(GodotDllName)]
public static extern void godotsharp_print_rich(godot_string* p_what);
public static extern void godotsharp_print_rich(in godot_string p_what);
[DllImport(GodotDllName)]
public static extern void godotsharp_printerr(godot_string* p_what);
internal static extern void godotsharp_printerr(in godot_string p_what);
[DllImport(GodotDllName)]
public static extern void godotsharp_printraw(godot_string* p_what);
internal static extern void godotsharp_printraw(in godot_string p_what);
[DllImport(GodotDllName)]
public static extern void godotsharp_prints(godot_string* p_what);
internal static extern void godotsharp_prints(in godot_string p_what);
[DllImport(GodotDllName)]
public static extern void godotsharp_printt(godot_string* p_what);
internal static extern void godotsharp_printt(in godot_string p_what);
[DllImport(GodotDllName)]
public static extern float godotsharp_randf();
internal static extern float godotsharp_randf();
[DllImport(GodotDllName)]
public static extern uint godotsharp_randi();
internal static extern uint godotsharp_randi();
[DllImport(GodotDllName)]
public static extern void godotsharp_randomize();
internal static extern void godotsharp_randomize();
[DllImport(GodotDllName)]
public static extern double godotsharp_randf_range(double from, double to);
internal static extern double godotsharp_randf_range(double from, double to);
[DllImport(GodotDllName)]
public static extern double godotsharp_randfn(double mean, double deviation);
internal static extern double godotsharp_randfn(double mean, double deviation);
[DllImport(GodotDllName)]
public static extern int godotsharp_randi_range(int from, int to);
internal static extern int godotsharp_randi_range(int from, int to);
[DllImport(GodotDllName)]
public static extern uint godotsharp_rand_from_seed(ulong seed, out ulong newSeed);
internal static extern uint godotsharp_rand_from_seed(ulong seed, out ulong newSeed);
[DllImport(GodotDllName)]
public static extern void godotsharp_seed(ulong seed);
internal static extern void godotsharp_seed(ulong seed);
[DllImport(GodotDllName)]
public static extern void godotsharp_weakref(IntPtr obj, godot_ref* r_weak_ref);
internal static extern void godotsharp_weakref(IntPtr p_obj, out godot_ref r_weak_ref);
[DllImport(GodotDllName)]
public static extern string godotsharp_str(godot_array* p_what, godot_string* r_ret);
internal static extern void godotsharp_str(in godot_array p_what, out godot_string r_ret);
[DllImport(GodotDllName)]
public static extern void godotsharp_str2var(godot_string* p_str, godot_variant* r_ret);
internal static extern void godotsharp_str2var(in godot_string p_str, out godot_variant r_ret);
[DllImport(GodotDllName)]
public static extern void godotsharp_var2bytes(godot_variant* what, godot_bool fullObjects,
godot_packed_byte_array* bytes);
internal static extern void godotsharp_var2bytes(in godot_variant p_what, godot_bool p_full_objects,
out godot_packed_byte_array r_bytes);
[DllImport(GodotDllName)]
public static extern void godotsharp_var2str(godot_variant* var, godot_string* r_ret);
internal static extern void godotsharp_var2str(in godot_variant p_var, out godot_string r_ret);
[DllImport(GodotDllName)]
public static extern void godotsharp_pusherror(godot_string* type);
internal static extern void godotsharp_pusherror(in godot_string p_str);
[DllImport(GodotDllName)]
public static extern void godotsharp_pushwarning(godot_string* type);
internal static extern void godotsharp_pushwarning(in godot_string p_str);
// Object
[DllImport(GodotDllName)]
public static extern string godotsharp_object_to_string(IntPtr ptr, godot_string* r_str);
public static extern void godotsharp_object_to_string(IntPtr ptr, out godot_string r_str);
}
}

View file

@ -1,83 +1,60 @@
using System;
using System.Runtime.CompilerServices;
// ReSharper disable InconsistentNaming
namespace Godot.NativeInterop
{
public static unsafe partial class NativeFuncs
public static partial class NativeFuncs
{
public static godot_string_name godotsharp_string_name_new_copy(godot_string_name* src)
public static godot_string_name godotsharp_string_name_new_copy(in godot_string_name src)
{
godot_string_name ret;
godotsharp_string_name_new_copy(&ret, src);
if (src.IsEmpty)
return default;
godotsharp_string_name_new_copy(out godot_string_name ret, src);
return ret;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_string_name godotsharp_string_name_new_copy(godot_string_name src)
=> godotsharp_string_name_new_copy(&src);
public static godot_node_path godotsharp_node_path_new_copy(godot_node_path* src)
public static godot_node_path godotsharp_node_path_new_copy(in godot_node_path src)
{
godot_node_path ret;
godotsharp_node_path_new_copy(&ret, src);
if (src.IsEmpty)
return default;
godotsharp_node_path_new_copy(out godot_node_path ret, src);
return ret;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_node_path godotsharp_node_path_new_copy(godot_node_path src)
=> godotsharp_node_path_new_copy(&src);
public static godot_array godotsharp_array_new()
{
godot_array ret;
godotsharp_array_new(&ret);
godotsharp_array_new(out godot_array ret);
return ret;
}
public static godot_array godotsharp_array_new_copy(godot_array* src)
public static godot_array godotsharp_array_new_copy(in godot_array src)
{
godot_array ret;
godotsharp_array_new_copy(&ret, src);
godotsharp_array_new_copy(out godot_array ret, src);
return ret;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_array godotsharp_array_new_copy(godot_array src)
=> godotsharp_array_new_copy(&src);
public static godot_dictionary godotsharp_dictionary_new()
{
godot_dictionary ret;
godotsharp_dictionary_new(&ret);
godotsharp_dictionary_new(out godot_dictionary ret);
return ret;
}
public static godot_dictionary godotsharp_dictionary_new_copy(godot_dictionary* src)
public static godot_dictionary godotsharp_dictionary_new_copy(in godot_dictionary src)
{
godot_dictionary ret;
godotsharp_dictionary_new_copy(&ret, src);
godotsharp_dictionary_new_copy(out godot_dictionary ret, src);
return ret;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_dictionary godotsharp_dictionary_new_copy(godot_dictionary src)
=> godotsharp_dictionary_new_copy(&src);
public static godot_string_name godotsharp_string_name_new_from_string(string name)
{
godot_string_name ret;
using godot_string src = Marshaling.mono_string_to_godot(name);
godotsharp_string_name_new_from_string(&ret, &src);
using godot_string src = Marshaling.ConvertStringToNative(name);
godotsharp_string_name_new_from_string(out godot_string_name ret, src);
return ret;
}
public static godot_node_path godotsharp_node_path_new_from_string(string name)
{
godot_node_path ret;
using godot_string src = Marshaling.mono_string_to_godot(name);
godotsharp_node_path_new_from_string(&ret, &src);
using godot_string src = Marshaling.ConvertStringToNative(name);
godotsharp_node_path_new_from_string(out godot_node_path ret, src);
return ret;
}
}

View file

@ -0,0 +1,20 @@
using System.Runtime.CompilerServices;
namespace Godot.NativeInterop
{
// Our source generators will add trampolines methods that access variant arguments.
// This struct makes that possible without having to enable `AllowUnsafeBlocks` in game projects.
public unsafe ref struct NativeVariantPtrArgs
{
private godot_variant** _args;
internal NativeVariantPtrArgs(godot_variant** args) => _args = args;
public ref godot_variant this[int index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref *_args[index];
}
}
}

View file

@ -2,13 +2,13 @@ using System;
namespace Godot.NativeInterop
{
internal ref struct VariantSpanDisposer
internal readonly ref struct VariantSpanDisposer
{
private readonly Span<godot_variant> _variantSpan;
private readonly Span<godot_variant.movable> _variantSpan;
// IMPORTANT: The span element must be default initialized.
// Make sure call Clear() on the span if it was created with stackalloc.
public VariantSpanDisposer(Span<godot_variant> variantSpan)
public VariantSpanDisposer(Span<godot_variant.movable> variantSpan)
{
_variantSpan = variantSpan;
}
@ -16,7 +16,7 @@ namespace Godot.NativeInterop
public void Dispose()
{
for (int i = 0; i < _variantSpan.Length; i++)
_variantSpan[i].Dispose();
_variantSpan[i].DangerousSelfRef.Dispose();
}
}
@ -24,7 +24,7 @@ namespace Godot.NativeInterop
{
// Used to make sure we always initialize the span values to the default,
// as we need that in order to safely dispose all elements after.
public static Span<godot_variant> Cleared(this Span<godot_variant> span)
public static Span<godot_variant.movable> Cleared(this Span<godot_variant.movable> span)
{
span.Clear();
return span;

View file

@ -1,5 +1,4 @@
using System;
using System.Runtime.CompilerServices;
// ReSharper disable InconsistentNaming
@ -8,378 +7,353 @@ namespace Godot.NativeInterop
public static class VariantUtils
{
public static godot_variant CreateFromRID(RID from)
=> new() { _type = Variant.Type.Rid, _data = { _m_rid = from } };
=> new() { Type = Variant.Type.Rid, RID = from };
public static godot_variant CreateFromBool(bool from)
=> new() { _type = Variant.Type.Bool, _data = { _bool = from.ToGodotBool() } };
=> new() { Type = Variant.Type.Bool, Bool = from.ToGodotBool() };
public static godot_variant CreateFromInt(long from)
=> new() { _type = Variant.Type.Int, _data = { _int = from } };
=> new() { Type = Variant.Type.Int, Int = from };
public static godot_variant CreateFromInt(ulong from)
=> new() { _type = Variant.Type.Int, _data = { _int = (long)from } };
=> new() { Type = Variant.Type.Int, Int = (long)from };
public static godot_variant CreateFromFloat(double from)
=> new() { _type = Variant.Type.Float, _data = { _float = from } };
=> new() { Type = Variant.Type.Float, Float = from };
public static godot_variant CreateFromVector2(Vector2 from)
=> new() { _type = Variant.Type.Vector2, _data = { _m_vector2 = from } };
=> new() { Type = Variant.Type.Vector2, Vector2 = from };
public static godot_variant CreateFromVector2i(Vector2i from)
=> new() { _type = Variant.Type.Vector2i, _data = { _m_vector2i = from } };
=> new() { Type = Variant.Type.Vector2i, Vector2i = from };
public static godot_variant CreateFromVector3(Vector3 from)
=> new() { _type = Variant.Type.Vector3, _data = { _m_vector3 = from } };
=> new() { Type = Variant.Type.Vector3, Vector3 = from };
public static godot_variant CreateFromVector3i(Vector3i from)
=> new() { _type = Variant.Type.Vector3i, _data = { _m_vector3i = from } };
=> new() { Type = Variant.Type.Vector3i, Vector3i = from };
public static godot_variant CreateFromRect2(Rect2 from)
=> new() { _type = Variant.Type.Rect2, _data = { _m_rect2 = from } };
=> new() { Type = Variant.Type.Rect2, Rect2 = from };
public static godot_variant CreateFromRect2i(Rect2i from)
=> new() { _type = Variant.Type.Rect2i, _data = { _m_rect2i = from } };
=> new() { Type = Variant.Type.Rect2i, Rect2i = from };
public static godot_variant CreateFromQuaternion(Quaternion from)
=> new() { _type = Variant.Type.Quaternion, _data = { _m_quaternion = from } };
=> new() { Type = Variant.Type.Quaternion, Quaternion = from };
public static godot_variant CreateFromColor(Color from)
=> new() { _type = Variant.Type.Color, _data = { _m_color = from } };
=> new() { Type = Variant.Type.Color, Color = from };
public static godot_variant CreateFromPlane(Plane from)
=> new() { _type = Variant.Type.Plane, _data = { _m_plane = from } };
=> new() { Type = Variant.Type.Plane, Plane = from };
public static unsafe godot_variant CreateFromTransform2D(Transform2D from)
public static godot_variant CreateFromTransform2D(Transform2D from)
{
godot_variant ret;
NativeFuncs.godotsharp_variant_new_transform2d(&ret, &from);
NativeFuncs.godotsharp_variant_new_transform2d(out godot_variant ret, from);
return ret;
}
public static unsafe godot_variant CreateFromVector4(Vector4 from)
public static godot_variant CreateFromVector4(Vector4 from)
{
godot_variant ret;
NativeFuncs.godotsharp_variant_new_vector4(&ret, &from);
NativeFuncs.godotsharp_variant_new_vector4(out godot_variant ret, from);
return ret;
}
public static unsafe godot_variant CreateFromVector4i(Vector4i from)
public static godot_variant CreateFromVector4i(Vector4i from)
{
godot_variant ret;
NativeFuncs.godotsharp_variant_new_vector4i(&ret, &from);
NativeFuncs.godotsharp_variant_new_vector4i(out godot_variant ret, from);
return ret;
}
public static unsafe godot_variant CreateFromBasis(Basis from)
public static godot_variant CreateFromBasis(Basis from)
{
godot_variant ret;
NativeFuncs.godotsharp_variant_new_basis(&ret, &from);
NativeFuncs.godotsharp_variant_new_basis(out godot_variant ret, from);
return ret;
}
public static unsafe godot_variant CreateFromTransform3D(Transform3D from)
public static godot_variant CreateFromTransform3D(Transform3D from)
{
godot_variant ret;
NativeFuncs.godotsharp_variant_new_transform3d(&ret, &from);
NativeFuncs.godotsharp_variant_new_transform3d(out godot_variant ret, from);
return ret;
}
public static unsafe godot_variant CreateFromProjection(Projection from)
public static godot_variant CreateFromProjection(Projection from)
{
godot_variant ret;
NativeFuncs.godotsharp_variant_new_projection(&ret, &from);
NativeFuncs.godotsharp_variant_new_projection(out godot_variant ret, from);
return ret;
}
public static unsafe godot_variant CreateFromAABB(AABB from)
public static godot_variant CreateFromAABB(AABB from)
{
godot_variant ret;
NativeFuncs.godotsharp_variant_new_aabb(&ret, &from);
NativeFuncs.godotsharp_variant_new_aabb(out godot_variant ret, from);
return ret;
}
// Explicit name to make it very clear
public static godot_variant CreateFromCallableTakingOwnershipOfDisposableValue(godot_callable from)
=> new() { _type = Variant.Type.Callable, _data = { _m_callable = from } };
=> new() { Type = Variant.Type.Callable, Callable = from };
// Explicit name to make it very clear
public static godot_variant CreateFromSignalTakingOwnershipOfDisposableValue(godot_signal from)
=> new() { _type = Variant.Type.Signal, _data = { _m_signal = from } };
=> new() { Type = Variant.Type.Signal, Signal = from };
// Explicit name to make it very clear
public static godot_variant CreateFromStringTakingOwnershipOfDisposableValue(godot_string from)
=> new() { _type = Variant.Type.String, _data = { _m_string = from } };
=> new() { Type = Variant.Type.String, String = from };
public static unsafe godot_variant CreateFromPackedByteArray(godot_packed_byte_array* from)
public static godot_variant CreateFromPackedByteArray(in godot_packed_byte_array from)
{
godot_variant ret;
NativeFuncs.godotsharp_variant_new_packed_byte_array(&ret, from);
NativeFuncs.godotsharp_variant_new_packed_byte_array(out godot_variant ret, from);
return ret;
}
public static unsafe godot_variant CreateFromPackedInt32Array(godot_packed_int32_array* from)
public static godot_variant CreateFromPackedInt32Array(in godot_packed_int32_array from)
{
godot_variant ret;
NativeFuncs.godotsharp_variant_new_packed_int32_array(&ret, from);
NativeFuncs.godotsharp_variant_new_packed_int32_array(out godot_variant ret, from);
return ret;
}
public static unsafe godot_variant CreateFromPackedInt64Array(godot_packed_int64_array* from)
public static godot_variant CreateFromPackedInt64Array(in godot_packed_int64_array from)
{
godot_variant ret;
NativeFuncs.godotsharp_variant_new_packed_int64_array(&ret, from);
NativeFuncs.godotsharp_variant_new_packed_int64_array(out godot_variant ret, from);
return ret;
}
public static unsafe godot_variant CreateFromPackedFloat32Array(godot_packed_float32_array* from)
public static godot_variant CreateFromPackedFloat32Array(in godot_packed_float32_array from)
{
godot_variant ret;
NativeFuncs.godotsharp_variant_new_packed_float32_array(&ret, from);
NativeFuncs.godotsharp_variant_new_packed_float32_array(out godot_variant ret, from);
return ret;
}
public static unsafe godot_variant CreateFromPackedFloat64Array(godot_packed_float64_array* from)
public static godot_variant CreateFromPackedFloat64Array(in godot_packed_float64_array from)
{
godot_variant ret;
NativeFuncs.godotsharp_variant_new_packed_float64_array(&ret, from);
NativeFuncs.godotsharp_variant_new_packed_float64_array(out godot_variant ret, from);
return ret;
}
public static unsafe godot_variant CreateFromPackedStringArray(godot_packed_string_array* from)
public static godot_variant CreateFromPackedStringArray(in godot_packed_string_array from)
{
godot_variant ret;
NativeFuncs.godotsharp_variant_new_packed_string_array(&ret, from);
NativeFuncs.godotsharp_variant_new_packed_string_array(out godot_variant ret, from);
return ret;
}
public static unsafe godot_variant CreateFromPackedVector2Array(godot_packed_vector2_array* from)
public static godot_variant CreateFromPackedVector2Array(in godot_packed_vector2_array from)
{
godot_variant ret;
NativeFuncs.godotsharp_variant_new_packed_vector2_array(&ret, from);
NativeFuncs.godotsharp_variant_new_packed_vector2_array(out godot_variant ret, from);
return ret;
}
public static unsafe godot_variant CreateFromPackedVector3Array(godot_packed_vector3_array* from)
public static godot_variant CreateFromPackedVector3Array(in godot_packed_vector3_array from)
{
godot_variant ret;
NativeFuncs.godotsharp_variant_new_packed_vector3_array(&ret, from);
NativeFuncs.godotsharp_variant_new_packed_vector3_array(out godot_variant ret, from);
return ret;
}
public static unsafe godot_variant CreateFromPackedColorArray(godot_packed_color_array* from)
public static godot_variant CreateFromPackedColorArray(in godot_packed_color_array from)
{
godot_variant ret;
NativeFuncs.godotsharp_variant_new_packed_color_array(&ret, from);
NativeFuncs.godotsharp_variant_new_packed_color_array(out godot_variant ret, from);
return ret;
}
public static unsafe godot_variant CreateFromArray(godot_array* from)
public static godot_variant CreateFromArray(godot_array from)
{
godot_variant ret;
NativeFuncs.godotsharp_variant_new_array(&ret, from);
NativeFuncs.godotsharp_variant_new_array(out godot_variant ret, from);
return ret;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe godot_variant CreateFromArray(godot_array from)
=> CreateFromArray(&from);
public static unsafe godot_variant CreateFromDictionary(godot_dictionary* from)
public static godot_variant CreateFromDictionary(godot_dictionary from)
{
godot_variant ret;
NativeFuncs.godotsharp_variant_new_dictionary(&ret, from);
NativeFuncs.godotsharp_variant_new_dictionary(out godot_variant ret, from);
return ret;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe godot_variant CreateFromDictionary(godot_dictionary from)
=> CreateFromDictionary(&from);
public static unsafe godot_variant CreateFromStringName(ref godot_string_name arg1)
public static godot_variant CreateFromStringName(godot_string_name from)
{
godot_variant ret;
godot_string_name src = arg1;
NativeFuncs.godotsharp_variant_new_string_name(&ret, &src);
NativeFuncs.godotsharp_variant_new_string_name(out godot_variant ret, from);
return ret;
}
public static unsafe godot_variant CreateFromNodePath(ref godot_node_path arg1)
public static godot_variant CreateFromNodePath(godot_node_path from)
{
godot_variant ret;
godot_node_path src = arg1;
NativeFuncs.godotsharp_variant_new_node_path(&ret, &src);
NativeFuncs.godotsharp_variant_new_node_path(out godot_variant ret, from);
return ret;
}
public static unsafe godot_variant CreateFromGodotObject(IntPtr from)
public static godot_variant CreateFromGodotObject(IntPtr from)
{
if (from == IntPtr.Zero)
return new godot_variant();
godot_variant ret;
NativeFuncs.godotsharp_variant_new_object(&ret, from);
NativeFuncs.godotsharp_variant_new_object(out godot_variant ret, from);
return ret;
}
// We avoid the internal call if the stored type is the same we want.
public static unsafe bool ConvertToBool(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Bool ?
(*p_var)._data._bool.ToBool() :
public static bool ConvertToBool(in godot_variant p_var)
=> p_var.Type == Variant.Type.Bool ?
p_var.Bool.ToBool() :
NativeFuncs.godotsharp_variant_as_bool(p_var).ToBool();
public static unsafe char ConvertToChar(godot_variant* p_var)
=> (char)((*p_var)._type == Variant.Type.Int ?
(*p_var)._data._int :
public static char ConvertToChar(in godot_variant p_var)
=> (char)(p_var.Type == Variant.Type.Int ?
p_var.Int :
NativeFuncs.godotsharp_variant_as_int(p_var));
public static unsafe sbyte ConvertToInt8(godot_variant* p_var)
=> (sbyte)((*p_var)._type == Variant.Type.Int ?
(*p_var)._data._int :
public static sbyte ConvertToInt8(in godot_variant p_var)
=> (sbyte)(p_var.Type == Variant.Type.Int ?
p_var.Int :
NativeFuncs.godotsharp_variant_as_int(p_var));
public static unsafe Int16 ConvertToInt16(godot_variant* p_var)
=> (Int16)((*p_var)._type == Variant.Type.Int ?
(*p_var)._data._int :
public static Int16 ConvertToInt16(in godot_variant p_var)
=> (Int16)(p_var.Type == Variant.Type.Int ?
p_var.Int :
NativeFuncs.godotsharp_variant_as_int(p_var));
public static unsafe Int32 ConvertToInt32(godot_variant* p_var)
=> (Int32)((*p_var)._type == Variant.Type.Int ?
(*p_var)._data._int :
public static Int32 ConvertToInt32(in godot_variant p_var)
=> (Int32)(p_var.Type == Variant.Type.Int ?
p_var.Int :
NativeFuncs.godotsharp_variant_as_int(p_var));
public static unsafe Int64 ConvertToInt64(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var);
public static Int64 ConvertToInt64(in godot_variant p_var)
=> p_var.Type == Variant.Type.Int ? p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var);
public static unsafe byte ConvertToUInt8(godot_variant* p_var)
=> (byte)((*p_var)._type == Variant.Type.Int ?
(*p_var)._data._int :
public static byte ConvertToUInt8(in godot_variant p_var)
=> (byte)(p_var.Type == Variant.Type.Int ?
p_var.Int :
NativeFuncs.godotsharp_variant_as_int(p_var));
public static unsafe UInt16 ConvertToUInt16(godot_variant* p_var)
=> (UInt16)((*p_var)._type == Variant.Type.Int ?
(*p_var)._data._int :
public static UInt16 ConvertToUInt16(in godot_variant p_var)
=> (UInt16)(p_var.Type == Variant.Type.Int ?
p_var.Int :
NativeFuncs.godotsharp_variant_as_int(p_var));
public static unsafe UInt32 ConvertToUInt32(godot_variant* p_var)
=> (UInt32)((*p_var)._type == Variant.Type.Int ?
(*p_var)._data._int :
public static UInt32 ConvertToUInt32(in godot_variant p_var)
=> (UInt32)(p_var.Type == Variant.Type.Int ?
p_var.Int :
NativeFuncs.godotsharp_variant_as_int(p_var));
public static unsafe UInt64 ConvertToUInt64(godot_variant* p_var)
=> (UInt64)((*p_var)._type == Variant.Type.Int ?
(*p_var)._data._int :
public static UInt64 ConvertToUInt64(in godot_variant p_var)
=> (UInt64)(p_var.Type == Variant.Type.Int ?
p_var.Int :
NativeFuncs.godotsharp_variant_as_int(p_var));
public static unsafe float ConvertToFloat32(godot_variant* p_var)
=> (float)((*p_var)._type == Variant.Type.Float ?
(*p_var)._data._float :
public static float ConvertToFloat32(in godot_variant p_var)
=> (float)(p_var.Type == Variant.Type.Float ?
p_var.Float :
NativeFuncs.godotsharp_variant_as_float(p_var));
public static unsafe double ConvertToFloat64(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Float ?
(*p_var)._data._float :
public static double ConvertToFloat64(in godot_variant p_var)
=> p_var.Type == Variant.Type.Float ?
p_var.Float :
NativeFuncs.godotsharp_variant_as_float(p_var);
public static unsafe Vector2 ConvertToVector2(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Vector2 ?
(*p_var)._data._m_vector2 :
public static Vector2 ConvertToVector2(in godot_variant p_var)
=> p_var.Type == Variant.Type.Vector2 ?
p_var.Vector2 :
NativeFuncs.godotsharp_variant_as_vector2(p_var);
public static unsafe Vector2i ConvertToVector2i(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Vector2i ?
(*p_var)._data._m_vector2i :
public static Vector2i ConvertToVector2i(in godot_variant p_var)
=> p_var.Type == Variant.Type.Vector2i ?
p_var.Vector2i :
NativeFuncs.godotsharp_variant_as_vector2i(p_var);
public static unsafe Rect2 ConvertToRect2(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Rect2 ?
(*p_var)._data._m_rect2 :
public static Rect2 ConvertToRect2(in godot_variant p_var)
=> p_var.Type == Variant.Type.Rect2 ?
p_var.Rect2 :
NativeFuncs.godotsharp_variant_as_rect2(p_var);
public static unsafe Rect2i ConvertToRect2i(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Rect2i ?
(*p_var)._data._m_rect2i :
public static Rect2i ConvertToRect2i(in godot_variant p_var)
=> p_var.Type == Variant.Type.Rect2i ?
p_var.Rect2i :
NativeFuncs.godotsharp_variant_as_rect2i(p_var);
public static unsafe Transform2D ConvertToTransform2D(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Transform2d ?
*(*p_var)._data._transform2d :
public static unsafe Transform2D ConvertToTransform2D(in godot_variant p_var)
=> p_var.Type == Variant.Type.Transform2d ?
*p_var.Transform2D :
NativeFuncs.godotsharp_variant_as_transform2d(p_var);
public static unsafe Vector3 ConvertToVector3(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Vector3 ?
(*p_var)._data._m_vector3 :
public static Vector3 ConvertToVector3(in godot_variant p_var)
=> p_var.Type == Variant.Type.Vector3 ?
p_var.Vector3 :
NativeFuncs.godotsharp_variant_as_vector3(p_var);
public static unsafe Vector3i ConvertToVector3i(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Vector3i ?
(*p_var)._data._m_vector3i :
public static Vector3i ConvertToVector3i(in godot_variant p_var)
=> p_var.Type == Variant.Type.Vector3i ?
p_var.Vector3i :
NativeFuncs.godotsharp_variant_as_vector3i(p_var);
public static unsafe Vector4 ConvertToVector4(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Vector4 ? *(*p_var)._data._vector4 : NativeFuncs.godotsharp_variant_as_vector4(p_var);
public static unsafe Vector4 ConvertToVector4(in godot_variant p_var)
=> p_var.Type == Variant.Type.Vector4 ?
*p_var.Vector4 :
NativeFuncs.godotsharp_variant_as_vector4(p_var);
public static unsafe Vector4i ConvertToVector4i(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Vector4i ? *(*p_var)._data._vector4i : NativeFuncs.godotsharp_variant_as_vector4i(p_var);
public static unsafe Vector4i ConvertToVector4i(in godot_variant p_var)
=> p_var.Type == Variant.Type.Vector4i ?
*p_var.Vector4i :
NativeFuncs.godotsharp_variant_as_vector4i(p_var);
public static unsafe Basis ConvertToBasis(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Basis ?
*(*p_var)._data._basis :
public static unsafe Basis ConvertToBasis(in godot_variant p_var)
=> p_var.Type == Variant.Type.Basis ?
*p_var.Basis :
NativeFuncs.godotsharp_variant_as_basis(p_var);
public static unsafe Quaternion ConvertToQuaternion(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Quaternion ?
(*p_var)._data._m_quaternion :
public static Quaternion ConvertToQuaternion(in godot_variant p_var)
=> p_var.Type == Variant.Type.Quaternion ?
p_var.Quaternion :
NativeFuncs.godotsharp_variant_as_quaternion(p_var);
public static unsafe Transform3D ConvertToTransform3D(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Transform3d ?
*(*p_var)._data._transform3d :
public static unsafe Transform3D ConvertToTransform3D(in godot_variant p_var)
=> p_var.Type == Variant.Type.Transform3d ?
*p_var.Transform3D :
NativeFuncs.godotsharp_variant_as_transform3d(p_var);
public static unsafe Projection ConvertToProjection(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Projection ? *(*p_var)._data._projection : NativeFuncs.godotsharp_variant_as_projection(p_var);
public static unsafe Projection ConvertToProjection(in godot_variant p_var)
=> p_var.Type == Variant.Type.Projection ?
*p_var.Projection :
NativeFuncs.godotsharp_variant_as_projection(p_var);
public static unsafe AABB ConvertToAABB(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Aabb ?
*(*p_var)._data._aabb :
public static unsafe AABB ConvertToAABB(in godot_variant p_var)
=> p_var.Type == Variant.Type.Aabb ?
*p_var.AABB :
NativeFuncs.godotsharp_variant_as_aabb(p_var);
public static unsafe Color ConvertToColor(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Color ?
(*p_var)._data._m_color :
public static Color ConvertToColor(in godot_variant p_var)
=> p_var.Type == Variant.Type.Color ?
p_var.Color :
NativeFuncs.godotsharp_variant_as_color(p_var);
public static unsafe Plane ConvertToPlane(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Plane ?
(*p_var)._data._m_plane :
public static Plane ConvertToPlane(in godot_variant p_var)
=> p_var.Type == Variant.Type.Plane ?
p_var.Plane :
NativeFuncs.godotsharp_variant_as_plane(p_var);
public static unsafe IntPtr ConvertToGodotObject(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Object ? (*p_var)._data._m_obj_data.obj : IntPtr.Zero;
public static IntPtr ConvertToGodotObject(in godot_variant p_var)
=> p_var.Type == Variant.Type.Object ? p_var.Object : IntPtr.Zero;
public static unsafe RID ConvertToRID(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Rid ?
(*p_var)._data._m_rid :
public static RID ConvertToRID(in godot_variant p_var)
=> p_var.Type == Variant.Type.Rid ?
p_var.RID :
NativeFuncs.godotsharp_variant_as_rid(p_var);
public static unsafe godot_string_name ConvertToStringName(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.StringName ?
NativeFuncs.godotsharp_string_name_new_copy(&(*p_var)._data._m_string_name) :
public static godot_string_name ConvertToStringName(in godot_variant p_var)
=> p_var.Type == Variant.Type.StringName ?
NativeFuncs.godotsharp_string_name_new_copy(p_var.StringName) :
NativeFuncs.godotsharp_variant_as_string_name(p_var);
public static unsafe godot_node_path ConvertToNodePath(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.NodePath ?
NativeFuncs.godotsharp_node_path_new_copy(&(*p_var)._data._m_node_path) :
public static godot_node_path ConvertToNodePath(in godot_variant p_var)
=> p_var.Type == Variant.Type.NodePath ?
NativeFuncs.godotsharp_node_path_new_copy(p_var.NodePath) :
NativeFuncs.godotsharp_variant_as_node_path(p_var);
public static unsafe godot_array ConvertToArray(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Array ?
NativeFuncs.godotsharp_array_new_copy(&(*p_var)._data._m_array) :
public static godot_array ConvertToArray(in godot_variant p_var)
=> p_var.Type == Variant.Type.Array ?
NativeFuncs.godotsharp_array_new_copy(p_var.Array) :
NativeFuncs.godotsharp_variant_as_array(p_var);
public static unsafe godot_dictionary ConvertToDictionary(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Dictionary ?
NativeFuncs.godotsharp_dictionary_new_copy(&(*p_var)._data._m_dictionary) :
public static godot_dictionary ConvertToDictionary(in godot_variant p_var)
=> p_var.Type == Variant.Type.Dictionary ?
NativeFuncs.godotsharp_dictionary_new_copy(p_var.Dictionary) :
NativeFuncs.godotsharp_variant_as_dictionary(p_var);
}
}

View file

@ -1,5 +1,4 @@
using System;
using System.Runtime.CompilerServices;
using Godot.NativeInterop;
namespace Godot
@ -42,7 +41,7 @@ namespace Godot
/// </example>
public sealed class NodePath : IDisposable
{
public godot_node_path NativeValue;
internal godot_node_path.movable NativeValue;
~NodePath()
{
@ -61,12 +60,12 @@ namespace Godot
public void Dispose(bool disposing)
{
// Always dispose `NativeValue` even if disposing is true
NativeValue.Dispose();
NativeValue.DangerousSelfRef.Dispose();
}
private NodePath(godot_node_path nativeValueToOwn)
{
NativeValue = nativeValueToOwn;
NativeValue = (godot_node_path.movable)nativeValueToOwn;
}
// Explicit name to make it very clear
@ -112,7 +111,7 @@ namespace Godot
public NodePath(string path)
{
if (!string.IsNullOrEmpty(path))
NativeValue = NativeFuncs.godotsharp_node_path_new_from_string(path);
NativeValue = (godot_node_path.movable)NativeFuncs.godotsharp_node_path_new_from_string(path);
}
/// <summary>
@ -125,22 +124,21 @@ namespace Godot
/// Converts this <see cref="NodePath"/> to a string.
/// </summary>
/// <param name="from">The <see cref="NodePath"/> to convert.</param>
public static implicit operator string(NodePath from) => from.ToString();
public static implicit operator string(NodePath from) => from?.ToString();
/// <summary>
/// Converts this <see cref="NodePath"/> to a string.
/// </summary>
/// <returns>A string representation of this <see cref="NodePath"/>.</returns>
public override unsafe string ToString()
public override string ToString()
{
if (IsEmpty)
return string.Empty;
godot_string dest;
godot_node_path src = NativeValue;
NativeFuncs.godotsharp_node_path_as_string(&dest, &src);
var src = (godot_node_path)NativeValue;
NativeFuncs.godotsharp_node_path_as_string(out godot_string dest, src);
using (dest)
return Marshaling.mono_string_from_godot(dest);
return Marshaling.ConvertStringToManaged(dest);
}
/// <summary>
@ -161,7 +159,8 @@ namespace Godot
public NodePath GetAsPropertyPath()
{
godot_node_path propertyPath = default;
NativeFuncs.godotsharp_node_path_get_as_property_path(ref NativeValue, ref propertyPath);
var self = (godot_node_path)NativeValue;
NativeFuncs.godotsharp_node_path_get_as_property_path(self, ref propertyPath);
return CreateTakingOwnershipOfDisposableValue(propertyPath);
}
@ -175,11 +174,12 @@ namespace Godot
/// </code>
/// </example>
/// <returns>The names concatenated with <c>/</c>.</returns>
public unsafe string GetConcatenatedNames()
public string GetConcatenatedNames()
{
using godot_string names = default;
NativeFuncs.godotsharp_node_path_get_concatenated_names(ref NativeValue, &names);
return Marshaling.mono_string_from_godot(names);
var self = (godot_node_path)NativeValue;
NativeFuncs.godotsharp_node_path_get_concatenated_names(self, out godot_string names);
using (names)
return Marshaling.ConvertStringToManaged(names);
}
/// <summary>
@ -193,11 +193,12 @@ namespace Godot
/// </code>
/// </example>
/// <returns>The subnames concatenated with <c>:</c>.</returns>
public unsafe string GetConcatenatedSubNames()
public string GetConcatenatedSubNames()
{
using godot_string subNames = default;
NativeFuncs.godotsharp_node_path_get_concatenated_subnames(ref NativeValue, &subNames);
return Marshaling.mono_string_from_godot(subNames);
var self = (godot_node_path)NativeValue;
NativeFuncs.godotsharp_node_path_get_concatenated_subnames(self, out godot_string subNames);
using (subNames)
return Marshaling.ConvertStringToManaged(subNames);
}
/// <summary>
@ -213,11 +214,12 @@ namespace Godot
/// </example>
/// <param name="idx">The name index.</param>
/// <returns>The name at the given index <paramref name="idx"/>.</returns>
public unsafe string GetName(int idx)
public string GetName(int idx)
{
using godot_string name = default;
NativeFuncs.godotsharp_node_path_get_name(ref NativeValue, idx, &name);
return Marshaling.mono_string_from_godot(name);
var self = (godot_node_path)NativeValue;
NativeFuncs.godotsharp_node_path_get_name(self, idx, out godot_string name);
using (name)
return Marshaling.ConvertStringToManaged(name);
}
/// <summary>
@ -228,7 +230,8 @@ namespace Godot
/// <returns>The number of node names which make up the path.</returns>
public int GetNameCount()
{
return NativeFuncs.godotsharp_node_path_get_name_count(ref NativeValue);
var self = (godot_node_path)NativeValue;
return NativeFuncs.godotsharp_node_path_get_name_count(self);
}
/// <summary>
@ -236,11 +239,12 @@ namespace Godot
/// </summary>
/// <param name="idx">The subname index.</param>
/// <returns>The subname at the given index <paramref name="idx"/>.</returns>
public unsafe string GetSubName(int idx)
public string GetSubName(int idx)
{
using godot_string subName = default;
NativeFuncs.godotsharp_node_path_get_subname(ref NativeValue, idx, &subName);
return Marshaling.mono_string_from_godot(subName);
var self = (godot_node_path)NativeValue;
NativeFuncs.godotsharp_node_path_get_subname(self, idx, out godot_string subName);
using (subName)
return Marshaling.ConvertStringToManaged(subName);
}
/// <summary>
@ -251,7 +255,8 @@ namespace Godot
/// <returns>The number of subnames in the path.</returns>
public int GetSubNameCount()
{
return NativeFuncs.godotsharp_node_path_get_subname_count(ref NativeValue);
var self = (godot_node_path)NativeValue;
return NativeFuncs.godotsharp_node_path_get_subname_count(self);
}
/// <summary>
@ -263,13 +268,14 @@ namespace Godot
/// <returns>If the <see cref="NodePath"/> is an absolute path.</returns>
public bool IsAbsolute()
{
return NativeFuncs.godotsharp_node_path_is_absolute(ref NativeValue).ToBool();
var self = (godot_node_path)NativeValue;
return NativeFuncs.godotsharp_node_path_is_absolute(self).ToBool();
}
/// <summary>
/// Returns <see langword="true"/> if the node path is empty.
/// </summary>
/// <returns>If the <see cref="NodePath"/> is empty.</returns>
public bool IsEmpty => godot_node_path.IsEmpty(in NativeValue);
public bool IsEmpty => NativeValue.DangerousSelfRef.IsEmpty;
}
}

View file

@ -1,7 +1,6 @@
using System;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using Godot.NativeInterop;
namespace Godot
@ -47,16 +46,13 @@ namespace Godot
while (top != null && top != native)
{
foreach (var eventSignal in top.GetEvents(
BindingFlags.DeclaredOnly | BindingFlags.Instance |
BindingFlags.NonPublic | BindingFlags.Public)
.Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any()))
BindingFlags.DeclaredOnly | BindingFlags.Instance |
BindingFlags.NonPublic | BindingFlags.Public)
.Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any()))
{
unsafe
{
using var eventSignalName = new StringName(eventSignal.Name);
godot_string_name eventSignalNameAux = eventSignalName.NativeValue;
NativeFuncs.godotsharp_internal_object_connect_event_signal(NativePtr, &eventSignalNameAux);
}
using var eventSignalName = new StringName(eventSignal.Name);
var eventSignalNameSelf = (godot_string_name)eventSignalName.NativeValue;
NativeFuncs.godotsharp_internal_object_connect_event_signal(NativePtr, eventSignalNameSelf);
}
top = top.BaseType;
@ -128,11 +124,11 @@ namespace Godot
/// Converts this <see cref="Object"/> to a string.
/// </summary>
/// <returns>A string representation of this object.</returns>
public override unsafe string ToString()
public override string ToString()
{
using godot_string str = default;
NativeFuncs.godotsharp_object_to_string(GetPtr(this), &str);
return Marshaling.mono_string_from_godot(str);
NativeFuncs.godotsharp_object_to_string(GetPtr(this), out godot_string str);
using (str)
return Marshaling.ConvertStringToManaged(str);
}
/// <summary>
@ -189,7 +185,7 @@ namespace Godot
return assemblyName.Name == "GodotSharp" || assemblyName.Name == "GodotSharpEditor";
}
internal unsafe bool InternalGodotScriptCallViaReflection(string method, godot_variant** args, int argCount,
internal bool InternalGodotScriptCallViaReflection(string method, NativeVariantPtrArgs args, int argCount,
out godot_variant ret)
{
// Performance is not critical here as this will be replaced with source generators.
@ -213,13 +209,13 @@ namespace Godot
for (int i = 0; i < paramCount; i++)
{
invokeParams[i] = Marshaling.variant_to_mono_object_of_type(
invokeParams[i] = Marshaling.ConvertVariantToManagedObjectOfType(
args[i], parameters[i].ParameterType);
}
object retObj = methodInfo.Invoke(this, invokeParams);
ret = Marshaling.mono_object_to_variant(retObj);
ret = Marshaling.ConvertManagedObjectToVariant(retObj);
return true;
}
}
@ -231,7 +227,7 @@ namespace Godot
return false;
}
internal unsafe bool InternalGodotScriptSetFieldOrPropViaReflection(string name, godot_variant* value)
internal bool InternalGodotScriptSetFieldOrPropViaReflection(string name, in godot_variant value)
{
// Performance is not critical here as this will be replaced with source generators.
Type top = GetType();
@ -245,7 +241,7 @@ namespace Godot
if (fieldInfo != null)
{
object valueManaged = Marshaling.variant_to_mono_object_of_type(value, fieldInfo.FieldType);
object valueManaged = Marshaling.ConvertVariantToManagedObjectOfType(value, fieldInfo.FieldType);
fieldInfo.SetValue(this, valueManaged);
return true;
@ -257,7 +253,8 @@ namespace Godot
if (propertyInfo != null)
{
object valueManaged = Marshaling.variant_to_mono_object_of_type(value, propertyInfo.PropertyType);
object valueManaged =
Marshaling.ConvertVariantToManagedObjectOfType(value, propertyInfo.PropertyType);
propertyInfo.SetValue(this, valueManaged);
return true;
@ -284,7 +281,7 @@ namespace Godot
if (fieldInfo != null)
{
object valueManaged = fieldInfo.GetValue(this);
value = Marshaling.mono_object_to_variant(valueManaged);
value = Marshaling.ConvertManagedObjectToVariant(valueManaged);
return true;
}
@ -295,7 +292,7 @@ namespace Godot
if (propertyInfo != null)
{
object valueManaged = propertyInfo.GetValue(this);
value = Marshaling.mono_object_to_variant(valueManaged);
value = Marshaling.ConvertManagedObjectToVariant(valueManaged);
return true;
}
@ -306,7 +303,7 @@ namespace Godot
return false;
}
internal unsafe void InternalRaiseEventSignal(godot_string_name* eventSignalName, godot_variant** args,
internal unsafe void InternalRaiseEventSignal(in godot_string_name eventSignalName, NativeVariantPtrArgs args,
int argc)
{
// Performance is not critical here as this will be replaced with source generators.
@ -360,9 +357,9 @@ namespace Godot
var managedArgs = new object[argc];
for (uint i = 0; i < argc; i++)
for (int i = 0; i < argc; i++)
{
managedArgs[i] = Marshaling.variant_to_mono_object_of_type(
managedArgs[i] = Marshaling.ConvertVariantToManagedObjectOfType(
args[i], parameterInfos[i].ParameterType);
}
@ -379,7 +376,8 @@ namespace Godot
IntPtr methodBind;
fixed (char* methodChars = method)
{
methodBind = NativeFuncs.godotsharp_method_bind_get_method(ref type.NativeValue, methodChars);
var typeSelf = (godot_string_name)type.NativeValue;
methodBind = NativeFuncs.godotsharp_method_bind_get_method(typeSelf, methodChars);
}
if (methodBind == IntPtr.Zero)
@ -391,7 +389,8 @@ namespace Godot
internal static unsafe delegate* unmanaged<IntPtr> ClassDB_get_constructor(StringName type)
{
// for some reason the '??' operator doesn't support 'delegate*'
var nativeConstructor = NativeFuncs.godotsharp_get_class_constructor(ref type.NativeValue);
var typeSelf = (godot_string_name)type.NativeValue;
var nativeConstructor = NativeFuncs.godotsharp_get_class_constructor(typeSelf);
if (nativeConstructor == null)
throw new NativeConstructorNotFoundException(type);

View file

@ -73,7 +73,7 @@ namespace Godot
case 3:
return w;
default:
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(index));
}
}
set
@ -93,7 +93,7 @@ namespace Godot
w = value;
break;
default:
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(index));
}
}
}

View file

@ -8,19 +8,21 @@ namespace Godot
{
private bool _completed;
private object[] _result;
private Action _action;
private Action _continuation;
public SignalAwaiter(Object source, StringName signal, Object target)
{
NativeFuncs.godotsharp_internal_signal_awaiter_connect(Object.GetPtr(source), ref signal.NativeValue,
using godot_string_name signalSrc = NativeFuncs.godotsharp_string_name_new_copy(
(godot_string_name)(signal?.NativeValue ?? default));
NativeFuncs.godotsharp_internal_signal_awaiter_connect(Object.GetPtr(source), in signalSrc,
Object.GetPtr(target), GCHandle.ToIntPtr(GCHandle.Alloc(this)));
}
public bool IsCompleted => _completed;
public void OnCompleted(Action action)
public void OnCompleted(Action continuation)
{
this._action = action;
_continuation = continuation;
}
public object[] GetResult() => _result;
@ -48,11 +50,11 @@ namespace Godot
object[] signalArgs = new object[argCount];
for (int i = 0; i < argCount; i++)
signalArgs[i] = Marshaling.variant_to_mono_object(args[i]);
signalArgs[i] = Marshaling.ConvertVariantToManagedObject(*args[i]);
awaiter._result = signalArgs;
awaiter._action?.Invoke();
awaiter._continuation?.Invoke();
}
catch (Exception e)
{

View file

@ -3,7 +3,7 @@ namespace Godot
/// <summary>
/// Represents a signal defined in an object.
/// </summary>
public struct SignalInfo
public readonly struct SignalInfo
{
private readonly Object _owner;
private readonly StringName _signalName;

View file

@ -1,12 +1,13 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Security;
using System.Text;
using System.Text.RegularExpressions;
using Godot.NativeInterop;
#nullable enable
namespace Godot
{
/// <summary>
@ -1077,12 +1078,12 @@ namespace Godot
/// <seealso cref="MD5Text(string)"/>
/// <param name="instance">The string to hash.</param>
/// <returns>The MD5 hash of the string.</returns>
public static unsafe byte[] MD5Buffer(this string instance)
public static byte[] MD5Buffer(this string instance)
{
using godot_string instanceStr = Marshaling.mono_string_to_godot(instance);
using godot_packed_byte_array md5Buffer = default;
NativeFuncs.godotsharp_string_md5_buffer(&instanceStr, &md5Buffer);
return Marshaling.PackedByteArray_to_mono_array(&md5Buffer);
using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
NativeFuncs.godotsharp_string_md5_buffer(instanceStr, out var md5Buffer);
using (md5Buffer)
return Marshaling.ConvertNativePackedByteArrayToSystemArray(md5Buffer);
}
/// <summary>
@ -1091,12 +1092,12 @@ namespace Godot
/// <seealso cref="MD5Buffer(string)"/>
/// <param name="instance">The string to hash.</param>
/// <returns>The MD5 hash of the string.</returns>
public static unsafe string MD5Text(this string instance)
public static string MD5Text(this string instance)
{
using godot_string instanceStr = Marshaling.mono_string_to_godot(instance);
using godot_string md5Text = default;
NativeFuncs.godotsharp_string_md5_text(&instanceStr, &md5Text);
return Marshaling.mono_string_from_godot(md5Text);
using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
NativeFuncs.godotsharp_string_md5_text(instanceStr, out var md5Text);
using (md5Text)
return Marshaling.ConvertStringToManaged(md5Text);
}
/// <summary>
@ -1251,11 +1252,11 @@ namespace Godot
/// <param name="what">The substring to search in the string.</param>
/// <param name="from">The position at which to start searching.</param>
/// <returns>The position at which the substring was found, or -1 if not found.</returns>
public static unsafe int RFind(this string instance, string what, int from = -1)
public static int RFind(this string instance, string what, int from = -1)
{
using godot_string instanceStr = Marshaling.mono_string_to_godot(instance);
using godot_string whatStr = Marshaling.mono_string_to_godot(instance);
return NativeFuncs.godotsharp_string_rfind(&instanceStr, &whatStr, from);
using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
using godot_string whatStr = Marshaling.ConvertStringToNative(instance);
return NativeFuncs.godotsharp_string_rfind(instanceStr, whatStr, from);
}
/// <summary>
@ -1267,11 +1268,11 @@ namespace Godot
/// <param name="what">The substring to search in the string.</param>
/// <param name="from">The position at which to start searching.</param>
/// <returns>The position at which the substring was found, or -1 if not found.</returns>
public static unsafe int RFindN(this string instance, string what, int from = -1)
public static int RFindN(this string instance, string what, int from = -1)
{
using godot_string instanceStr = Marshaling.mono_string_to_godot(instance);
using godot_string whatStr = Marshaling.mono_string_to_godot(instance);
return NativeFuncs.godotsharp_string_rfindn(&instanceStr, &whatStr, from);
using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
using godot_string whatStr = Marshaling.ConvertStringToNative(instance);
return NativeFuncs.godotsharp_string_rfindn(instanceStr, whatStr, from);
}
/// <summary>
@ -1326,12 +1327,12 @@ namespace Godot
/// <seealso cref="SHA256Text(string)"/>
/// <param name="instance">The string to hash.</param>
/// <returns>The SHA-256 hash of the string.</returns>
public static unsafe byte[] SHA256Buffer(this string instance)
public static byte[] SHA256Buffer(this string instance)
{
using godot_string instanceStr = Marshaling.mono_string_to_godot(instance);
using godot_packed_byte_array sha256Buffer = default;
NativeFuncs.godotsharp_string_sha256_buffer(&instanceStr, &sha256Buffer);
return Marshaling.PackedByteArray_to_mono_array(&sha256Buffer);
using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
NativeFuncs.godotsharp_string_sha256_buffer(instanceStr, out var sha256Buffer);
using (sha256Buffer)
return Marshaling.ConvertNativePackedByteArrayToSystemArray(sha256Buffer);
}
/// <summary>
@ -1340,12 +1341,12 @@ namespace Godot
/// <seealso cref="SHA256Buffer(string)"/>
/// <param name="instance">The string to hash.</param>
/// <returns>The SHA-256 hash of the string.</returns>
public static unsafe string SHA256Text(this string instance)
public static string SHA256Text(this string instance)
{
using godot_string instanceStr = Marshaling.mono_string_to_godot(instance);
using godot_string sha256Text = default;
NativeFuncs.godotsharp_string_sha256_text(&instanceStr, &sha256Text);
return Marshaling.mono_string_from_godot(sha256Text);
using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
NativeFuncs.godotsharp_string_sha256_text(instanceStr, out var sha256Text);
using (sha256Text)
return Marshaling.ConvertStringToManaged(sha256Text);
}
/// <summary>
@ -1396,12 +1397,12 @@ namespace Godot
/// <summary>
/// Returns a simplified canonical path.
/// </summary>
public static unsafe string SimplifyPath(this string instance)
public static string SimplifyPath(this string instance)
{
using godot_string instanceStr = Marshaling.mono_string_to_godot(instance);
using godot_string simplifiedPath = default;
NativeFuncs.godotsharp_string_simplify_path(&instanceStr, &simplifiedPath);
return Marshaling.mono_string_from_godot(simplifiedPath);
using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
NativeFuncs.godotsharp_string_simplify_path(instanceStr, out godot_string simplifiedPath);
using (simplifiedPath)
return Marshaling.ConvertStringToManaged(simplifiedPath);
}
/// <summary>
@ -1602,7 +1603,7 @@ namespace Godot
/// <seealso cref="XMLUnescape(string)"/>
/// <param name="instance">The string to escape.</param>
/// <returns>The escaped string.</returns>
public static string XMLEscape(this string instance)
public static string? XMLEscape(this string instance)
{
return SecurityElement.Escape(instance);
}
@ -1614,9 +1615,9 @@ namespace Godot
/// <seealso cref="XMLEscape(string)"/>
/// <param name="instance">The string to unescape.</param>
/// <returns>The unescaped string.</returns>
public static string XMLUnescape(this string instance)
public static string? XMLUnescape(this string instance)
{
return SecurityElement.FromString(instance).Text;
return SecurityElement.FromString(instance)?.Text;
}
}
}

View file

@ -1,5 +1,4 @@
using System;
using System.Runtime.CompilerServices;
using Godot.NativeInterop;
namespace Godot
@ -13,7 +12,7 @@ namespace Godot
/// </summary>
public sealed class StringName : IDisposable
{
public godot_string_name NativeValue;
internal godot_string_name.movable NativeValue;
~StringName()
{
@ -32,12 +31,12 @@ namespace Godot
public void Dispose(bool disposing)
{
// Always dispose `NativeValue` even if disposing is true
NativeValue.Dispose();
NativeValue.DangerousSelfRef.Dispose();
}
private StringName(godot_string_name nativeValueToOwn)
{
NativeValue = nativeValueToOwn;
NativeValue = (godot_string_name.movable)nativeValueToOwn;
}
// Explicit name to make it very clear
@ -58,7 +57,7 @@ namespace Godot
public StringName(string name)
{
if (!string.IsNullOrEmpty(name))
NativeValue = NativeFuncs.godotsharp_string_name_new_from_string(name);
NativeValue = (godot_string_name.movable)NativeFuncs.godotsharp_string_name_new_from_string(name);
}
/// <summary>
@ -71,28 +70,27 @@ namespace Godot
/// Converts a <see cref="StringName"/> to a string.
/// </summary>
/// <param name="from">The <see cref="StringName"/> to convert.</param>
public static implicit operator string(StringName from) => from.ToString();
public static implicit operator string(StringName from) => from?.ToString();
/// <summary>
/// Converts this <see cref="StringName"/> to a string.
/// </summary>
/// <returns>A string representation of this <see cref="StringName"/>.</returns>
public override unsafe string ToString()
public override string ToString()
{
if (IsEmpty)
return string.Empty;
godot_string dest;
godot_string_name src = NativeValue;
NativeFuncs.godotsharp_string_name_as_string(&dest, &src);
var src = (godot_string_name)NativeValue;
NativeFuncs.godotsharp_string_name_as_string(out godot_string dest, src);
using (dest)
return Marshaling.mono_string_from_godot(dest);
return Marshaling.ConvertStringToManaged(dest);
}
/// <summary>
/// Check whether this <see cref="StringName"/> is empty.
/// </summary>
/// <returns>If the <see cref="StringName"/> is empty.</returns>
public bool IsEmpty => godot_string_name.IsEmpty(in NativeValue);
public bool IsEmpty => NativeValue.DangerousSelfRef.IsEmpty;
}
}

View file

@ -93,7 +93,7 @@ namespace Godot
case 2:
return origin;
default:
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(column));
}
}
set
@ -110,7 +110,7 @@ namespace Godot
origin = value;
return;
default:
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(column));
}
}
}

View file

@ -52,7 +52,7 @@ namespace Godot
case 3:
return origin;
default:
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(column));
}
}
set
@ -72,7 +72,7 @@ namespace Godot
origin = value;
return;
default:
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(column));
}
}
}
@ -168,7 +168,7 @@ namespace Godot
/// <param name="target">The object to look at.</param>
/// <param name="up">The relative up direction.</param>
/// <returns>The resulting transform.</returns>
public Transform3D LookingAt(Vector3 target, Vector3 up)
public readonly Transform3D LookingAt(Vector3 target, Vector3 up)
{
Transform3D t = this;
t.SetLookAt(origin, target, up);
@ -194,7 +194,7 @@ namespace Godot
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
/// <param name="angle">The angle to rotate, in radians.</param>
/// <returns>The rotated transformation matrix.</returns>
public Transform3D Rotated(Vector3 axis, real_t angle)
public readonly Transform3D Rotated(Vector3 axis, real_t angle)
{
return new Transform3D(new Basis(axis, angle), new Vector3()) * this;
}
@ -443,7 +443,7 @@ namespace Godot
/// </summary>
/// <param name="obj">The object to compare with.</param>
/// <returns>Whether or not the transform and the object are exactly equal.</returns>
public override bool Equals(object obj)
public override readonly bool Equals(object obj)
{
if (obj is Transform3D)
{
@ -460,7 +460,7 @@ namespace Godot
/// </summary>
/// <param name="other">The other transform to compare.</param>
/// <returns>Whether or not the matrices are exactly equal.</returns>
public bool Equals(Transform3D other)
public readonly bool Equals(Transform3D other)
{
return basis.Equals(other.basis) && origin.Equals(other.origin);
}

View file

@ -62,7 +62,7 @@ namespace Godot
case 1:
return y;
default:
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(index));
}
}
set
@ -76,7 +76,7 @@ namespace Godot
y = value;
return;
default:
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(index));
}
}
}

View file

@ -62,7 +62,7 @@ namespace Godot
case 1:
return y;
default:
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(index));
}
}
set
@ -76,7 +76,7 @@ namespace Godot
y = value;
return;
default:
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(index));
}
}
}

View file

@ -74,7 +74,7 @@ namespace Godot
case 2:
return z;
default:
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(index));
}
}
set
@ -91,7 +91,7 @@ namespace Godot
z = value;
return;
default:
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(index));
}
}
}

View file

@ -74,7 +74,7 @@ namespace Godot
case 2:
return z;
default:
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(index));
}
}
set
@ -91,7 +91,7 @@ namespace Godot
z = value;
return;
default:
throw new IndexOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(index));
}
}
}

View file

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<InlineIL />
</Weavers>

View file

@ -0,0 +1,93 @@
<Project>
<!-- Generate Godot.NativeInterop.CustomUnsafe C# class-->
<!--
Ref structs are not allowed as generic type parameters, so we can't use Unsafe.AsPointer<T>/AsRef<T>.
As a workaround we generate overloads of those methods for our structs using Fody with inline IL.
-->
<ItemGroup>
<PackageReference Include="Fody" Version="6.6.0" PrivateAssets="all" />
<PackageReference Include="InlineIL.Fody" Version="1.7.1" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<GodotInteropStructs Include="godot_ref" />
<GodotInteropStructs Include="godot_variant_call_error" />
<GodotInteropStructs Include="godot_variant" />
<GodotInteropStructs Include="godot_string" />
<GodotInteropStructs Include="godot_string_name" />
<GodotInteropStructs Include="godot_node_path" />
<GodotInteropStructs Include="godot_signal" />
<GodotInteropStructs Include="godot_callable" />
<GodotInteropStructs Include="godot_array" />
<GodotInteropStructs Include="godot_dictionary" />
<GodotInteropStructs Include="godot_packed_byte_array" />
<GodotInteropStructs Include="godot_packed_int32_array" />
<GodotInteropStructs Include="godot_packed_int64_array" />
<GodotInteropStructs Include="godot_packed_float32_array" />
<GodotInteropStructs Include="godot_packed_float64_array" />
<GodotInteropStructs Include="godot_packed_string_array" />
<GodotInteropStructs Include="godot_packed_vector2_array" />
<GodotInteropStructs Include="godot_packed_vector3_array" />
<GodotInteropStructs Include="godot_packed_color_array" />
</ItemGroup>
<Target Name="GenerateGodotCustomUnsafe"
DependsOnTargets="_GenerateGodotCustomUnsafe"
BeforeTargets="PrepareForBuild;CompileDesignTime;BeforeCompile;CoreCompile">
<ItemGroup>
<Compile Include="$(IntermediateOutputPath)CustomUnsafe.%(GodotInteropStructs.Identity).g.cs" />
<FileWrites Include="$(IntermediateOutputPath)CustomUnsafe.%(GodotInteropStructs.Identity).g.cs" />
</ItemGroup>
</Target>
<Target Name="_GenerateGodotCustomUnsafe"
Inputs="$(MSBuildProjectFile);$(MSBuildThisFileDirectory);@(GodotInteropStructs)"
Outputs="$(IntermediateOutputPath)CustomUnsafe.%(GodotInteropStructs.Identity).g.cs">
<PropertyGroup>
<GodotInteropStruct>%(GodotInteropStructs.Identity)</GodotInteropStruct>
<GenerateGodotCustomUnsafeCode><![CDATA[
using System.Runtime.CompilerServices%3b
using InlineIL%3b
using static InlineIL.IL.Emit%3b
namespace Godot.NativeInterop
{
public static partial class CustomUnsafe
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe $(GodotInteropStruct)* AsPointer(ref $(GodotInteropStruct) value)
{
Ldarg(nameof(value))%3b
Conv_U()%3b
return ($(GodotInteropStruct)*)IL.ReturnPointer()%3b
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe $(GodotInteropStruct)* ReadOnlyRefAsPointer(in $(GodotInteropStruct) value)
{
Ldarg(nameof(value))%3b
Conv_U()%3b
return ($(GodotInteropStruct)*)IL.ReturnPointer()%3b
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe ref $(GodotInteropStruct) AsRef($(GodotInteropStruct)* source)
{
return ref *source%3b
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe ref $(GodotInteropStruct) AsRef(in $(GodotInteropStruct) source)
{
return ref *ReadOnlyRefAsPointer(in source)%3b
}
}
}
]]></GenerateGodotCustomUnsafeCode>
</PropertyGroup>
<WriteLinesToFile Lines="$(GenerateGodotCustomUnsafeCode)"
File="$(IntermediateOutputPath)CustomUnsafe.%(GodotInteropStructs.Identity).g.cs"
Overwrite="True" WriteOnlyWhenDifferent="True" />
</Target>
</Project>

View file

@ -10,6 +10,8 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>9</LangVersion>
<AnalysisMode>Recommended</AnalysisMode>
<!-- Disabled temporarily as it pollutes the warnings, but we need to document public APIs. -->
<NoWarn>CS1591</NoWarn>
</PropertyGroup>
@ -20,6 +22,12 @@
<PackageReference Include="ReflectionAnalyzers" Version="0.1.22-dev" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers" />
<!--PackageReference Include="IDisposableAnalyzers" Version="3.4.13" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers" /-->
</ItemGroup>
<!-- Targets for generating Godot.NativeInterop.CustomUnsafe -->
<Import Project="GenerateGodotCustomUnsafe.targets" />
<ItemGroup>
<None Include="GenerateGodotCustomUnsafe.targets" />
</ItemGroup>
<!-- Sources -->
<ItemGroup>
<Compile Include="Core\AABB.cs" />
<Compile Include="Core\Array.cs" />
@ -62,6 +70,7 @@
<Compile Include="Core\NativeInterop\ExceptionUtils.cs" />
<Compile Include="Core\NativeInterop\InteropUtils.cs" />
<Compile Include="Core\NativeInterop\NativeFuncs.extended.cs" />
<Compile Include="Core\NativeInterop\NativeVariantPtrArgs.cs" />
<Compile Include="Core\NativeInterop\VariantSpanHelpers.cs" />
<Compile Include="Core\NativeInterop\VariantUtils.cs" />
<Compile Include="Core\NodePath.cs" />

View file

@ -445,6 +445,21 @@ GD_PINVOKE_EXPORT bool godotsharp_callable_get_data_for_marshalling(const Callab
}
}
GD_PINVOKE_EXPORT godot_variant godotsharp_callable_call(Callable *p_callable, const Variant **p_args, const int32_t p_arg_count, Callable::CallError *p_call_error) {
godot_variant ret;
memnew_placement(&ret, Variant);
Variant *ret_val = (Variant *)&ret;
p_callable->callp(p_args, p_arg_count, *ret_val, *p_call_error);
return ret;
}
GD_PINVOKE_EXPORT void godotsharp_callable_call_deferred(Callable *p_callable, const Variant **p_args, const int32_t p_arg_count) {
p_callable->call_deferredp(p_args, p_arg_count);
}
// GDNative functions
// gdnative.h
@ -1241,7 +1256,7 @@ GD_PINVOKE_EXPORT void godotsharp_object_to_string(Object *p_ptr, godot_string *
#endif
// We need this to prevent the functions from being stripped.
void *godotsharp_pinvoke_funcs[176] = {
void *godotsharp_pinvoke_funcs[178] = {
(void *)godotsharp_method_bind_get_method,
(void *)godotsharp_get_class_constructor,
(void *)godotsharp_engine_get_singleton,
@ -1274,6 +1289,8 @@ void *godotsharp_pinvoke_funcs[176] = {
(void *)godotsharp_packed_string_array_add,
(void *)godotsharp_callable_new_with_delegate,
(void *)godotsharp_callable_get_data_for_marshalling,
(void *)godotsharp_callable_call,
(void *)godotsharp_callable_call_deferred,
(void *)godotsharp_method_bind_ptrcall,
(void *)godotsharp_method_bind_call,
(void *)godotsharp_variant_new_string_name,